Skip to content

Commit

Permalink
Begin adding parser tests; fix unary +/- inconsistency
Browse files Browse the repository at this point in the history
Don't have a leading +/- be part of the regex for literal numbers as 
this subtly changes the logic for numbers vs other expressions: `-5**2` 
should evaluate to -25 because it is *meant* to parse as `-(5**2)`. 
However, with the current logic, the `-` is parsed as part of the number 
and so this parses as `(-5)**2`, which evaluates to 25.
  • Loading branch information
jonathanhogg committed Dec 29, 2024
1 parent 16f6991 commit 4b6293c
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/flitter/language/grammar.lark
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ NAME : /[_\p{alpha}][_\p{alnum}]*'*/i
NODE : /![_\p{alpha}][_\p{alnum}]*'*/i
TAG : /#[_\p{alpha}][_\p{alnum}]*'*/i
SYMBOL : /:[_\p{alpha}][_\p{alnum}]*'*/i
NUMBER : /[-+]?([0-9][_0-9]*(\.[0-9][_0-9]*)?|\.[0-9][_0-9]*)([eE][-+]?[0-9][_0-9]*)?[pnuµmkMGT]?/
NUMBER : /([0-9][_0-9]*(\.[0-9][_0-9]*)?|\.[0-9][_0-9]*)([eE][-+]?[0-9][_0-9]*)?[pnuµmkMGT]?/
STRING : /('''([^'\\]|\\.|'{1,2}(?!'))*'''|'([^'\n\\]|\\.)*'|"""([^"\\]|\\.|"{1,2}(?!"))*"""|"([^"\n\\]|\\.)*")/
_HASHBANG : /#!.*\r?\n/
_LPAREN : "("
Expand Down
43 changes: 43 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Flitter parser tests
"""

import unittest

from flitter.language.tree import (
Literal, Name, Top, Export, Sequence,
Positive, Negative, Power, Add, Subtract, Multiply, Divide, FloorDivide, Modulo,
# Ceil, Floor, Fract,
# Contains, EqualTo, NotEqualTo, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo,
# Not, And, Or, Xor,
# Range, Slice, Lookup,
# Tag, Attributes, Append,
# Let, Call, For, IfElse,
# Import, Function,
# Binding, PolyBinding, IfCondition
)
from flitter.language.parser import parse


class ParserTestCase(unittest.TestCase):
def assertParsesTo(self, code, expression):
self.maxDiff = 1000
if not isinstance(expression, Top):
if not isinstance(expression, Sequence):
expression = Sequence((expression, Export(None)))
elif not isinstance(expression.expressions[-1], Export):
expression = Sequence(expression.expressions + (Export(None),))
expression = Top((), expression)
self.assertEqual(repr(parse(code)), repr(expression))


class TestPrecedence(ParserTestCase):
def test_maths_literals(self):
self.assertParsesTo("0-1//2%3++4*-5**6/7",
Add(Subtract(Literal(0), Modulo(FloorDivide(Literal(1), Literal(2)), Literal(3))),
Divide(Multiply(Positive(Literal(4)), Negative(Power(Literal(5), Literal(6)))), Literal(7))))

def test_maths_names(self):
self.assertParsesTo("a-b//c%d++e*-f**g/h",
Add(Subtract(Name('a'), Modulo(FloorDivide(Name('b'), Name('c')), Name('d'))),
Divide(Multiply(Positive(Name('e')), Negative(Power(Name('f'), Name('g')))), Name('h'))))

0 comments on commit 4b6293c

Please sign in to comment.