Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds grako as dependency #2

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion expressions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .compiler import *

__version__ = '0.2.2'
__version__ = '0.2.3'

3 changes: 1 addition & 2 deletions expressions/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ def _default(self, ast, node_type=None, *args):
def variable(self, ast):
# Note: ast is expected to be a _Result() from the `reference` rule
value = ast.value
if not isinstance(ast, _Result):
import pdb; pdb.set_trace()
assert isinstance(ast, _Result)
result = self.compiler.compile_variable(self.context, value)
return _Result(result)

Expand Down
6 changes: 3 additions & 3 deletions expressions/grammar.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ term(binary) = factor {('*' | '/' | '%') factor} ;
factor(unary) = ('+' | '-' | '~') factor | power ;
power = atom ['^' factor] ;

atom = NUMBER
| STRING
atom = NUMBER
| STRING
| function
| variable
| ( '(' @:test ')' );
Expand All @@ -30,7 +30,7 @@ reference = { @+:NAME '.'} @+:NAME;
NUMBER = ?/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/? ;
STRING = ?/'[^'\\\r\n]*(?:\\.[^'\\\r\n]*)*'/? ;

comparison_operator = ('=' | '!=' | '<' | '<=' | '>' | '>='
comparison_operator = ('=' | '!=' | '<=' | '<' | '>=' | '>'
| 'in' | 'is' );

(* Allow any unicode character to be an identifier *)
Expand Down
32 changes: 19 additions & 13 deletions expressions/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from grako.parsing import graken, Parser


__version__ = (2014, 9, 19, 16, 34, 11, 4)
__version__ = (2015, 6, 29, 20, 16, 29, 0)

__all__ = [
'ExpressionParser',
Expand All @@ -25,10 +25,13 @@


class ExpressionParser(Parser):
def __init__(self, whitespace=None, nameguard=True, **kwargs):
def __init__(self, whitespace=None, nameguard=None, **kwargs):
super(ExpressionParser, self).__init__(
whitespace=whitespace,
nameguard=nameguard,
comments_re=None,
eol_comments_re=None,
ignorecase=None,
**kwargs
)

Expand Down Expand Up @@ -139,9 +142,7 @@ def block0():
self._token('/')
with self._option():
self._token('%')
with self._option():
self._token('//')
self._error('expecting one of: % * / //')
self._error('expecting one of: % * /')
self._factor_()
self._closure(block0)

Expand Down Expand Up @@ -247,22 +248,22 @@ def _comparison_operator_(self):
with self._group():
with self._choice():
with self._option():
self._token('==')
self._token('=')
with self._option():
self._token('!=')
with self._option():
self._token('<')
with self._option():
self._token('<=')
with self._option():
self._token('>')
self._token('<')
with self._option():
self._token('>=')
with self._option():
self._token('>')
with self._option():
self._token('in')
with self._option():
self._token('is')
self._error('expecting one of: != < <= == > >= in is')
self._error('expecting one of: != < <= = > >= in is')

@graken()
def _NAME_(self):
Expand Down Expand Up @@ -340,7 +341,7 @@ def NAME(self, ast):
return ast


def main(filename, startrule, trace=False, whitespace=None):
def main(filename, startrule, trace=False, whitespace=None, nameguard=None):
import json
with open(filename) as f:
text = f.read()
Expand All @@ -350,7 +351,8 @@ def main(filename, startrule, trace=False, whitespace=None):
startrule,
filename=filename,
trace=trace,
whitespace=whitespace)
whitespace=whitespace,
nameguard=nameguard)
print('AST:')
print(ast)
print()
Expand All @@ -374,6 +376,9 @@ def __call__(self, parser, namespace, values, option_string):
parser = argparse.ArgumentParser(description="Simple parser for Expression.")
parser.add_argument('-l', '--list', action=ListRules, nargs=0,
help="list all rules and exit")
parser.add_argument('-n', '--no-nameguard', action='store_true',
dest='no_nameguard',
help="disable the 'nameguard' feature")
parser.add_argument('-t', '--trace', action='store_true',
help="output trace information")
parser.add_argument('-w', '--whitespace', type=str, default=string.whitespace,
Expand All @@ -387,5 +392,6 @@ def __call__(self, parser, namespace, values, option_string):
args.file,
args.startrule,
trace=args.trace,
whitespace=args.whitespace
whitespace=args.whitespace,
nameguard=not args.no_nameguard
)
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

setup(
name = "expressions",
version = "0.2.2",
version = "0.2.3",

packages = find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
package_data = {
Expand All @@ -21,6 +21,8 @@
'Topic :: Utilities'
],

install_requires='grako==3.6.1',

test_suite = "tests",

# metadata for upload to PyPI
Expand Down
48 changes: 47 additions & 1 deletion tests/test_expressions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- encoding: utf8 -*-
import unittest
from expressions import Compiler, IdentifierPreprocessor
from expressions import Compiler
from expressions import Variable, Function, UnaryOperator, BinaryOperator

class ValidatingCompiler(Compiler):
Expand Down Expand Up @@ -90,6 +90,30 @@ def test_operator(self):
self.assertEqual(result.left, 1)
self.assertEqual(result.right, 2)

result = compiler.compile("1 = 2")
self.assertIsInstance(result, BinaryOperator)
self.assertEqual(result.operator, "=")
self.assertEqual(result.left, 1)
self.assertEqual(result.right, 2)

result = compiler.compile("1 != 2")
self.assertIsInstance(result, BinaryOperator)
self.assertEqual(result.operator, "!=")
self.assertEqual(result.left, 1)
self.assertEqual(result.right, 2)

result = compiler.compile("1 >= 2")
self.assertIsInstance(result, BinaryOperator)
self.assertEqual(result.operator, ">=")
self.assertEqual(result.left, 1)
self.assertEqual(result.right, 2)

result = compiler.compile("1 <= 2")
self.assertIsInstance(result, BinaryOperator)
self.assertEqual(result.operator, "<=")
self.assertEqual(result.left, 1)
self.assertEqual(result.right, 2)

@unittest.skip("later")
def test_validating_compiler(self):
compiler = ValidatingCompiler()
Expand All @@ -108,7 +132,26 @@ def test_function_call_compile(self):
result = compiler.compile("f(x, y)")
self.assertEqual("CALL f(x, y)", result)

class IdentifierPreprocessor(Compiler):
"""
CustomCompiler, just for testing
"""
def __init__(self):
super(IdentifierPreprocessor, self).__init__()

self.variables = set()
self.functions = set()

def compile_variable(self, context, variable):
self.variables.add(variable)
return variable

def compile_function(self, context, function, args):
self.functions.add(function)
return function

class CustomCompilersTestCase(unittest.TestCase):

def test_preprocessor(self):
pp = IdentifierPreprocessor()
pp.compile("foo(a + b) * bar(b + c)")
Expand All @@ -128,3 +171,6 @@ def test_preprocessor_unique(self):

self.assertEqual(functions, ["foo"])
self.assertEqual(variables, ["a", "b", "c"])

if __name__ == '__main__':
unittest.main()