def e_Postfix(self, expr1, token, p): q = left_binary_ops["Postfix"] if q < p: return None self.consume() # postix has lowest prec and is left assoc expr2 = self.parse_exp(q + 1) return Node(expr2, expr1)
def p_SlotSequence(self, token): self.consume() text = token.text if len(text) == 2: n = "1" else: n = text[2:] return Node("SlotSequence", Number(n))
def parse_binary(self, expr1, token, p): tag = token.tag q = binary_ops[tag] if q < p: return None self.consume() if tag not in right_binary_ops: q += 1 expr2 = self.parse_exp(q) # flatten or associate if tag in nonassoc_binary_ops and expr1.get_head_name() == tag and not expr1.parenthesised: self.tokeniser.sntx_message(token.pos) raise InvalidSyntaxError() result = Node(tag, expr1, expr2) if tag in flat_binary_ops: result.flatten() return result
def testSet(self): self.check('x = y', Node('Set', Symbol('x'), Symbol('y'))) self.check('x := y', Node('SetDelayed', Symbol('x'), Symbol('y'))) self.check('x ^= y', Node('UpSet', Symbol('x'), Symbol('y'))) self.check('x ^:= y', Node('UpSetDelayed', Symbol('x'), Symbol('y'))) self.check('x =.', Node('Unset', Symbol('x'))) self.check('x/:1=1', Node('TagSet', Symbol('x'), Number('1'), Number('1'))) self.check('x/:1:=1', Node('TagSetDelayed', Symbol('x'), Number('1'), Number('1'))) self.check('x/:1=.', Node('TagUnset', Symbol('x'), Number('1'))) self.check('f /: f[x_] + f[y_] := x + y', 'TagSetDelayed[f, f[x_] + f[y_], x + y]')
def parse_binary(self, expr1, token, p): tag = token.tag q = binary_ops[tag] if q < p: return None self.consume() if tag not in right_binary_ops: q += 1 expr2 = self.parse_exp(q) # flatten or associate if tag in nonassoc_binary_ops and expr1.get_head_name( ) == tag and not expr1.parenthesised: self.tokeniser.sntx_message(token.pos) raise InvalidSyntaxError() result = Node(tag, expr1, expr2) if tag in flat_binary_ops: result.flatten() return result
def p_Minus(self, token): self.consume() q = prefix_ops["Minus"] expr = self.parse_exp(q) if isinstance(expr, Number) and not expr.value.startswith("-"): expr.value = "-" + expr.value return expr else: return Node("Times", Number("1", sign=-1), expr).flatten()
def e_Infix(self, expr1, token, p): q = ternary_ops['Infix'] if q < p: return None self.consume() expr2 = self.parse_exp(q + 1) self.expect('Infix') expr3 = self.parse_exp(q + 1) return Node(expr2, expr1, expr3)
def b_FractionBox(self, box1, token, p): q = misc_ops['FractionBox'] if q < p: return None if box1 is None: box1 = String('') self.consume() box2 = self.parse_box(q + 1) return Node('FractionBox', box1, box2)
def p_Minus(self, token): self.consume() q = prefix_ops['Minus'] expr = self.parse_exp(q) if isinstance(expr, Number) and not expr.value.startswith('-'): expr.value = '-' + expr.value return expr else: return Node('Times', Number('-1'), expr).flatten()
def testFunctional(self): self.check('expr1 @ expr2', Node('expr1', Symbol('expr2'))) self.check('f @@ expr', Node('Apply', Symbol('f'), Symbol('expr'))) self.check('f /@ expr', Node('Map', Symbol('f'), Symbol('expr'))) self.check('f @@@ expr', Node('Apply', Symbol('f'), Symbol('expr'), Node('List', Number('1')))) self.check('f //@ expr', Node('MapAll', Symbol('f'), Symbol('expr'))) self.check('a @@ b @@ c', Node('Apply', Symbol('a'), Node('Apply', Symbol('b'), Symbol('c')))) self.check('a /@ b @@ c', 'Map[a, Apply[b, c]]') self.check('a @@ b /@ c', 'Apply[a, Map[b, c]]')
def parse_e(self): result = [] while self.next().tag != 'END': result.append(self.parse_exp(0)) if len(result) > 1: return Node('Times', *result) if len(result) == 1: return result[0] else: return None
def p_LeftRowBox(self, token): self.consume() children = [] self.box_depth += 1 self.bracket_depth += 1 token = self.next() while token.tag not in ('RightRowBox', 'OtherscriptBox'): children.append(self.parse_box(0)) token = self.next() if len(children) == 0: result = String('') elif len(children) == 1: result = children[0] else: result = Node('RowBox', Node('List', *children)) self.expect('RightRowBox') self.box_depth -= 1 self.bracket_depth -= 1 result.parenthesised = True return result
def testComment(self): self.check('145 (* abf *) 345', Node('Times', Number('145'), Number('345'))) self.check(r'(*"\"\*)', None) self.check(r'(**)', None) self.check(r'(*)*)', None) self.incomplete_error(r'(*(*(*') self.incomplete_error(r'(*(*)') self.incomplete_error(r'(*(**)') self.invalid_error(r'*)') self.invalid_error(r'(**)*)') self.invalid_error(r'(*(*(**)*)*)*)') self.check(r'(*(*)*) (*)*)*)', None)
def p_LeftRowBox(self, token): self.consume() children = [] self.box_depth += 1 self.bracket_depth += 1 token = self.next() while token.tag not in ("RightRowBox", "OtherscriptBox"): newnode = self.parse_box(0) children.append(newnode) token = self.next() if len(children) == 0: result = String("") elif len(children) == 1: result = children[0] else: result = Node("RowBox", Node("List", *children)) self.expect("RightRowBox") self.box_depth -= 1 self.bracket_depth -= 1 result.parenthesised = True return result
def e_RawLeftBracket(self, expr, token, p): q = all_ops['Part'] if q < p: return None self.consume() self.bracket_depth += 1 token = self.next_noend() if token.tag == 'RawLeftBracket': self.consume() seq = self.parse_seq() self.expect('RawRightBracket') self.expect('RawRightBracket') self.bracket_depth -= 1 return Node('Part', expr, *seq) else: seq = self.parse_seq() self.expect('RawRightBracket') self.bracket_depth -= 1 result = Node(expr, *seq) result.parenthesised = True return result
def p_Slot(self, token): self.consume() text = token.text if len(text) == 1: n = Number('1') else: n = text[1:] if n.isdigit(): n = Number(n) else: n = String(n) return Node('Slot', n)
def testSet(self): self.check("x = y", Node("Set", Symbol("x"), Symbol("y"))) self.check("x := y", Node("SetDelayed", Symbol("x"), Symbol("y"))) self.check("x ^= y", Node("UpSet", Symbol("x"), Symbol("y"))) self.check("x ^:= y", Node("UpSetDelayed", Symbol("x"), Symbol("y"))) self.check("x =.", Node("Unset", Symbol("x"))) self.check("x/:1=1", Node("TagSet", Symbol("x"), Number("1"), Number("1"))) self.check( "x/:1:=1", Node("TagSetDelayed", Symbol("x"), Number("1"), Number("1"))) self.check("x/:1=.", Node("TagUnset", Symbol("x"), Number("1"))) self.check("f /: f[x_] + f[y_] := x + y", "TagSetDelayed[f, f[x_] + f[y_], x + y]")
def testList(self): self.check('{x, y}', Node('List', Symbol('x'), Symbol('y'))) self.check('{1}', Node('List', Number('1'))) self.check('{}', Node('List')) self.check('{a,}', Node('List', Symbol('a'), Symbol('Null'))) self.check('{,}', Node('List', Symbol('Null'), Symbol('Null'))) self.check('{a, b,}', Node('List', Symbol('a'), Symbol('b'), Symbol('Null'))) self.check('{,a}', Node('List', Symbol('Null'), Symbol('a'))) self.check('{, a, b}', Node('List', Symbol('Null'), Symbol('a'), Symbol('b'))) self.check( '{,a,b,}', Node('List', Symbol('Null'), Symbol('a'), Symbol('b'), Symbol('Null')))
def testComment(self): self.check("145 (* abf *) 345", Node("Times", Number("145"), Number("345"))) self.check(r'(*"\"\*)', None) self.check(r"(**)", None) self.check(r"(*)*)", None) self.incomplete_error(r"(*(*(*") self.incomplete_error(r"(*(*)") self.incomplete_error(r"(*(**)") self.invalid_error(r"*)") self.invalid_error(r"(**)*)") self.invalid_error(r"(*(*(**)*)*)*)") self.check(r"(*(*)*) (*)*)*)", None)
def testList(self): self.check("{x, y}", Node("List", Symbol("x"), Symbol("y"))) self.check("{1}", Node("List", Number("1"))) self.check("{}", Node("List")) self.check("{a,}", Node("List", Symbol("a"), Symbol("Null"))) self.check("{,}", Node("List", Symbol("Null"), Symbol("Null"))) self.check("{a, b,}", Node("List", Symbol("a"), Symbol("b"), Symbol("Null"))) self.check("{,a}", Node("List", Symbol("Null"), Symbol("a"))) self.check("{, a, b}", Node("List", Symbol("Null"), Symbol("a"), Symbol("b"))) self.check( "{,a,b,}", Node("List", Symbol("Null"), Symbol("a"), Symbol("b"), Symbol("Null")), )
def e_TagSet(self, expr1, token, p): q = all_ops['Set'] if q < p: return None self.consume() expr2 = self.parse_exp(q + 1) # examine next token token = self.next_noend() tag = token.tag if tag == 'Set': head = 'TagSet' elif tag == 'SetDelayed': head = 'TagSetDelayed' elif tag == 'Unset': head = 'TagUnset' else: self.tokeniser.sntx_message(token.pos) raise InvalidSyntaxError() self.consume() if head == 'TagUnset': return Node(head, expr1, expr2) expr3 = self.parse_exp(q + 1) return Node(head, expr1, expr2, expr3)
def parse_p(self): token = self.next_noend() tag = token.tag method = getattr(self, 'p_' + tag, None) if method is not None: return method(token) elif tag in prefix_ops: self.consume() q = prefix_ops[tag] child = self.parse_exp(q) return Node(tag, child) else: self.tokeniser.sntx_message(token.pos) raise InvalidSyntaxError()
def e_RawColon(self, expr1, token, p): head_name = expr1.get_head_name() if head_name == 'Symbol': head = 'Pattern' elif head_name in ('Blank', 'BlankSequence', 'BlankNullSequence', 'Pattern', 'Optional'): head = 'Optional' else: return None q = all_ops[head] if p == 151: return None self.consume() expr2 = self.parse_exp(q + 1) return Node(head, expr1, expr2)
def testExpression(self): self.check('expr1[expr2]', Node('expr1', Symbol('expr2'))) self.check('expr1[expr2][expr3]', Node(Node('expr1', Symbol('expr2')), Symbol('expr3'))) self.check('expr1[[expr2]]', Node('Part', Symbol('expr1'), Symbol('expr2'))) self.check( 'expr1[[expr2, expr3]]', Node('Part', Symbol('expr1'), Symbol('expr2'), Symbol('expr3'))) self.check( 'expr1[[expr2]][[expr3]]', Node('Part', Node('Part', Symbol('expr1'), Symbol('expr2')), Symbol('expr3'))) self.check('expr1 ~ expr2 ~ expr3', Node('expr2', Symbol('expr1'), Symbol('expr3'))) self.check('x~f~y', 'f[x, y]')
def testTimes(self): self.check('1 2', Node('Times', Number('1'), Number('2'))) self.check('1*2', Node('Times', Number('1'), Number('2'))) self.check('1 2 3', Node('Times', Number('1'), Number('2'), Number('3'))) self.check( '(1 2) 3', Node('Times', Node('Times', Number('1'), Number('2')), Number('3'))) self.check('1*2*3', Node('Times', Number('1'), Number('2'), Number('3'))) self.check( 'x ^ 2 y', Node('Times', Node('Power', Symbol('x'), Number('2')), Symbol('y')))
def e_Semicolon(self, expr1, token, p): q = flat_binary_ops['CompoundExpression'] if q < p: return None self.consume() # XXX this has to come before call to self.next() pos = self.tokeniser.pos messages = list(self.feeder.messages) # So that e.g. 'x = 1;' doesn't wait for newline in the frontend tag = self.next().tag if tag == 'END' and self.bracket_depth == 0: expr2 = Symbol('Null') return Node('CompoundExpression', expr1, expr2).flatten() # XXX look for next expr otherwise backtrack try: expr2 = self.parse_exp(q + 1) except TranslateError: self.backtrack(pos) self.feeder.messages = messages expr2 = Symbol('Null') return Node('CompoundExpression', expr1, expr2).flatten()
def e_MessageName(self, expr1, token, p): leaves = [expr1] while self.next().tag == 'MessageName': self.consume() token = self.next() if token.tag == 'Symbol': # silently convert Symbol to String self.consume() leaf = String(token.text) elif token.tag == 'String': leaf = self.p_String(token) else: self.tokeniser.sntx_message(token.pos) raise InvalidSyntaxError() leaves.append(leaf) return Node('MessageName', *leaves)
def testOptional(self): self.check('x:expr', Node('Pattern', Symbol('x'), Symbol('expr'))) self.check( 'x_:expr', Node('Optional', Node('Pattern', Symbol('x'), Node('Blank')), Symbol('expr'))) self.check( 'f:a|b', Node('Pattern', Symbol('f'), Node('Alternatives', Symbol('a'), Symbol('b')))) self.check('rev:(True|False):False', 'Optional[Pattern[rev, Alternatives[True, False]], False]')
def testTimes(self): self.check("1 2", Node("Times", Number("1"), Number("2"))) self.check("1*2", Node("Times", Number("1"), Number("2"))) self.check("1 2 3", Node("Times", Number("1"), Number("2"), Number("3"))) self.check( "(1 2) 3", Node("Times", Node("Times", Number("1"), Number("2")), Number("3")), ) self.check("1*2*3", Node("Times", Number("1"), Number("2"), Number("3"))) self.check( "x ^ 2 y", Node("Times", Node("Power", Symbol("x"), Number("2")), Symbol("y")), )
def testExpression(self): self.check("expr1[expr2]", Node("expr1", Symbol("expr2"))) self.check("expr1[expr2][expr3]", Node(Node("expr1", Symbol("expr2")), Symbol("expr3"))) self.check("expr1[[expr2]]", Node("Part", Symbol("expr1"), Symbol("expr2"))) self.check( "expr1[[expr2, expr3]]", Node("Part", Symbol("expr1"), Symbol("expr2"), Symbol("expr3")), ) self.check( "expr1[[expr2]][[expr3]]", Node("Part", Node("Part", Symbol("expr1"), Symbol("expr2")), Symbol("expr3")), ) self.check("expr1 ~ expr2 ~ expr3", Node("expr2", Symbol("expr1"), Symbol("expr3"))) self.check("x~f~y", "f[x, y]")
def testFunctional(self): self.check("expr1 @ expr2", Node("expr1", Symbol("expr2"))) self.check("f @@ expr", Node("Apply", Symbol("f"), Symbol("expr"))) self.check("f /@ expr", Node("Map", Symbol("f"), Symbol("expr"))) self.check( "f @@@ expr", Node("Apply", Symbol("f"), Symbol("expr"), Node("List", Number("1"))), ) self.check("f //@ expr", Node("MapAll", Symbol("f"), Symbol("expr"))) self.check( "a @@ b @@ c", Node("Apply", Symbol("a"), Node("Apply", Symbol("b"), Symbol("c"))), ) self.check("a /@ b @@ c", "Map[a, Apply[b, c]]") self.check("a @@ b /@ c", "Apply[a, Map[b, c]]")