Skip to content

Commit

Permalink
Read operator data from operator JSON tables
Browse files Browse the repository at this point in the history
  • Loading branch information
rocky committed Nov 23, 2024
1 parent e715104 commit 8b3f7b1
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 170 deletions.
177 changes: 19 additions & 158 deletions mathics/core/parser/operators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Mathics3 Operator tables.
This information is controlled by data from the MathicsScanner Project,
from YAML tables which are converted to JSON.
The dictionary from these which are read in here, are used by the
Mathics3 parser.
"""


import os.path as osp
Expand All @@ -12,169 +19,23 @@
except ImportError:
import json as ujson # type: ignore[no-redef]

# Load the conversion tables from disk
# Load Mathics3 operator information from JSON. This file is derived from a
# Mathics3 Operator Data YAML file in MathicsScanner.
operator_tables_path = osp.join(ROOT_DIR, "data", "operator-tables.json")
assert osp.exists(
operator_tables_path
), f"Internal error: Operator precedence tables are missing; expected to be in {operator_tables_path}"
), f"Internal error: Mathics3 Operator information are missing; expected to be in {operator_tables_path}"
with open(operator_tables_path, "r") as f:
OPERATOR_DATA = ujson.load(f)


prefix_ops = {
"Get": 720,
"PreIncrement": 660,
"PreDecrement": 660,
"Del": 550,
"Minus": 480,
"Square": 540,
"ForAll": 240,
"Exists": 240,
"NotExists": 240,
"Not": 230,
"Information": 5001,
"Definition": 5000,
"InterpretedBox": 670,
}

postfix_ops = {
"Unset": 670,
"Conjugate": 670,
"Transpose": 670,
"ConjugateTranspose": 670,
"Derivative": 670,
"Increment": 660,
"Decrement": 660,
"Factorial": 610,
"Factorial2": 610,
"Repeated": 170,
"RepeatedNull": 170,
"Function": 90,
}

left_binary_ops = {
"Divide": 470,
"PlusMinus": 310,
"MinusPlus": 310,
"Subtract": 310,
"LeftTee": 190,
"DoubleLeftTee": 190,
"Condition": 130,
"ReplaceAll": 110,
"ReplaceRepeated": 110,
"Because": 50,
"PutAppend": 30,
"Put": 30,
"Postfix": 70,
}

right_binary_ops = {
"Apply": 620,
"Map": 620,
"MapAll": 620,
"Power": 590,
"Implies": 200,
"RightTee": 190,
"DoubleRightTee": 190,
"SuchThat": 180,
"Rule": 120,
"RuleDelayed": 120,
"AddTo": 100,
"SubtractFrom": 100,
"TimesBy": 100,
"DivideBy": 100,
"Therefore": 50,
"UpSet": 40,
"Set": 40,
"SetDelayed": 40,
"UpSetDelayed": 40,
}

flat_binary_ops = {
"MessageName": 750,
"Composition": 625,
"StringJoin": 600,
"SmallCircle": 530,
"CircleDot": 520,
"NonCommutativeMultiply": 510,
"Cross": 500,
"Union": 300,
"Dot": 490,
"Backslash": 460,
"Diamond": 450,
"Wedge": 440,
"Vee": 430,
"CircleTimes": 420,
"CenterDot": 410,
"Times": 400,
"VerticalTilde": 370,
"Coproduct": 360,
"Cap": 350,
"Cup": 340,
"Star": 390,
"CirclePlus": 330,
"CircleMinus": 330,
"Plus": 310,
"Intersection": 305,
"VerticalBar": 280,
"NotVerticalBar": 280,
"DoubleVerticalBar": 280,
"NotDoubleVerticalBar": 280,
"SameQ": 290,
"UnsameQ": 290,
"Equal": 290,
"Unequal": 290,
"Greater": 290,
"Less": 290,
"GreaterEqual": 290,
"LessEqual": 290,
"Element": 250,
"NotElement": 250,
"Subset": 250,
"Superset": 250,
# HACK: although the should be 215 for all boolean_ops we adjust slightly
# to get the subprecedences correct
"And": 225,
"Nand": 225,
"Xor": 220,
"Xnor": 220,
"Or": 215,
"Nor": 215,
"Equivalent": 205,
"Alternatives": 160,
"StringExpression": 135,
"Colon": 80,
"VerticalSeparator": 60,
"CompoundExpression": 10,
}

nonassoc_binary_ops = {
"UndirectedEdge": 120,
"DirectedEdge": 128,
"PatternTest": 680,
}

ternary_ops = {
"Span": 305,
"Infix": 630,
}

misc_ops = {
"DifferentialD": 550,
"Sum": 320,
"Pattern": 150,
"Optional": 140,
"SqrtBox": 670,
"RadicalBox": 670,
"FractionBox": 670,
"OverscriptBox": 710,
"UnderscriptBox": 710,
"SubscriptBox": 695,
"FormBox": 670,
"SuperscriptBox": 590,
"UnderoverscriptBox": 700,
"SubsuperscriptBox": 690,
}
flat_binary_ops = OPERATOR_DATA["flat-binary-operators"]
left_binary_ops = OPERATOR_DATA["left-binary-operators"]
misc_ops = OPERATOR_DATA["miscellaneous-operators"]
nonassoc_binary_ops = OPERATOR_DATA["non-associative-binary-operators"]
postfix_ops = OPERATOR_DATA["postfix-operators"]
prefix_ops = OPERATOR_DATA["prefix-operators"]
right_binary_ops = OPERATOR_DATA["right-binary-operators"]
ternary_ops = OPERATOR_DATA["ternary-operators"]

inequality_ops = ["Less", "LessEqual", "Greater", "GreaterEqual", "Equal", "Unequal"]

Expand Down
23 changes: 11 additions & 12 deletions mathics/core/parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
flat_binary_ops,
inequality_ops,
left_binary_ops,
misc_ops,
nonassoc_binary_ops,
postfix_ops,
prefix_ops,
Expand Down Expand Up @@ -795,7 +794,7 @@ def b_SqrtBox(self, box0, token: Token, p: int) -> Optional[Node]:
if box0 is not None:
return None
self.consume()
q = misc_ops["SqrtBox"]
q = all_ops["SqrtBox"]
box1 = self.parse_box(q)
if self.next().tag == "OtherscriptBox":
self.consume()
Expand All @@ -805,7 +804,7 @@ def b_SqrtBox(self, box0, token: Token, p: int) -> Optional[Node]:
return Node("SqrtBox", box1)

def b_SuperscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
q = misc_ops["SuperscriptBox"]
q = all_ops["SuperscriptBox"]
if q < p:
return None
if box1 is None:
Expand All @@ -814,13 +813,13 @@ def b_SuperscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
box2 = self.parse_box(q)
if self.next().tag == "OtherscriptBox":
self.consume()
box3 = self.parse_box(misc_ops["SubsuperscriptBox"])
box3 = self.parse_box(all_ops["SubsuperscriptBox"])
return Node("SubsuperscriptBox", box1, box3, box2)
else:
return Node("SuperscriptBox", box1, box2)

def b_SubscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
q = misc_ops["SubscriptBox"]
q = all_ops["SubscriptBox"]
if q < p:
return None
if box1 is None:
Expand All @@ -829,13 +828,13 @@ def b_SubscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
box2 = self.parse_box(q)
if self.next().tag == "OtherscriptBox":
self.consume()
box3 = self.parse_box(misc_ops["SubsuperscriptBox"])
box3 = self.parse_box(all_ops["SubsuperscriptBox"])
return Node("SubsuperscriptBox", box1, box2, box3)
else:
return Node("SubscriptBox", box1, box2)

def b_UnderscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
q = misc_ops["UnderscriptBox"]
q = all_ops["UnderscriptBox"]
if q < p:
return None
if box1 is None:
Expand All @@ -844,13 +843,13 @@ def b_UnderscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
box2 = self.parse_box(q)
if self.next().tag == "OtherscriptBox":
self.consume()
box3 = self.parse_box(misc_ops["UnderoverscriptBox"])
box3 = self.parse_box(all_ops["UnderoverscriptBox"])
return Node("UnderoverscriptBox", box1, box2, box3)
else:
return Node("UnderscriptBox", box1, box2)

def b_FractionBox(self, box1, token: Token, p: int) -> Optional[Node]:
q = misc_ops["FractionBox"]
q = all_ops["FractionBox"]
if q < p:
return None
if box1 is None:
Expand All @@ -860,7 +859,7 @@ def b_FractionBox(self, box1, token: Token, p: int) -> Optional[Node]:
return Node("FractionBox", box1, box2)

def b_FormBox(self, box1, token: Token, p: int) -> Optional[Node]:
q = misc_ops["FormBox"]
q = all_ops["FormBox"]
if q < p:
return None
if box1 is None:
Expand All @@ -874,7 +873,7 @@ def b_FormBox(self, box1, token: Token, p: int) -> Optional[Node]:
return Node("FormBox", box2, box1)

def b_OverscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
q = misc_ops["OverscriptBox"]
q = all_ops["OverscriptBox"]
if q < p:
return None
if box1 is None:
Expand All @@ -883,7 +882,7 @@ def b_OverscriptBox(self, box1, token: Token, p: int) -> Optional[Node]:
box2 = self.parse_box(q)
if self.next().tag == "OtherscriptBox":
self.consume()
box3 = self.parse_box(misc_ops["UnderoverscriptBox"])
box3 = self.parse_box(all_ops["UnderoverscriptBox"])
return Node("UnderoverscriptBox", box1, box3, box2)
else:
return Node("OverscriptBox", box1, box2)

0 comments on commit 8b3f7b1

Please sign in to comment.