diff --git a/.projectile b/.projectile new file mode 100644 index 0000000..4a48308 --- /dev/null +++ b/.projectile @@ -0,0 +1,3 @@ +- /dist +- /build +- /venv diff --git a/Makefile b/Makefile index e0733b2..f0c6b7d 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,6 @@ test: . venv/bin/activate && ./smallscheme/main.py fact.scm . venv/bin/activate && ./smallscheme/main.py -t tests.scm - lint: . venv/bin/activate && pycodestyle smallscheme @@ -37,6 +36,8 @@ pip-docker-test: build-docker-test: docker build -t smallscheme -f Dockerfile.build . +alltests: test build-docker-test + release: ./bumpver . venv/bin/activate && python setup.py sdist diff --git a/smallscheme/dtypes.py b/smallscheme/dtypes.py new file mode 100644 index 0000000..c88c66d --- /dev/null +++ b/smallscheme/dtypes.py @@ -0,0 +1,17 @@ +def atom(x): + return 'atom', x + +def list_(x): + return 'list', x + +def bool_(x): + return 'bool', x + +def int_(x): + return 'int', x + +def float_(x): + return 'float', x + +def typ(x): + return x[0] diff --git a/smallscheme/parse.py b/smallscheme/parse.py new file mode 100644 index 0000000..2620fb2 --- /dev/null +++ b/smallscheme/parse.py @@ -0,0 +1,59 @@ +import lark +from smallscheme.dtypes import * + +grammar = ''' +start : _exprs +_exprs : _e* _e +_e : ATOM + | _num + | BOOL + | list +TRUE : "#t" +FALSE : "#f" +BOOL : TRUE | FALSE +list : "(" _exprs? ")" +INT : /[-+]?[0-9]+/ +ATOM : /[a-zA-Z]+[a-zA-Z0-9\-\?\!]*/ + | /[\*\/\=\>\<]/ + | /[\-\+](?![0-9])/ +FLOAT : /[-+]?[0-9]+\.[0-9]*/ +_num : INT | FLOAT +COMMENT : ";" /(.)*/ NEWLINE? + +%import common.WS +%import common.NEWLINE +%ignore WS +%ignore COMMENT + ''' + +parser = lark.Lark(grammar) + +def convert_ast(ast): + """ + Re-cast the Lark representation of the parse tree into our own. + + 'start' is always the top of the tree and `convert_ast` returns a + list of zero or more parsed expressions. + + All other entrypoints are recursively converted into the + appropriate atom, list, int, float etc. + """ + if type(ast) is lark.tree.Tree: + if ast.data == "start": + return [convert_ast(x) for x in ast.children] + if ast.data == "list": + return list_([convert_ast(x) for x in ast.children]) + if type(ast) is lark.lexer.Token: + ty = ast.type.lower() + if ty == "int": + return int_(int(ast.value)) + if ty == "float": + return float_(float(ast.value)) + elif ty == "bool": + return bool_(True if ast.value == "#t" else False) + elif ty == "atom": + return atom(ast.value) + raise Exception("Unparsed AST: '%s'" % ast) + +def parse_str(x): + return convert_ast(parser.parse(x)) diff --git a/smallscheme/scheme.py b/smallscheme/scheme.py index 57120ba..c042831 100755 --- a/smallscheme/scheme.py +++ b/smallscheme/scheme.py @@ -4,83 +4,11 @@ import re import sys from functools import reduce - -parser = lark.Lark( - ''' -start : _exprs -_exprs : _e* _e -_e : ATOM - | _num - | BOOL - | list -TRUE : "#t" -FALSE : "#f" -BOOL : TRUE | FALSE -list : "(" _exprs? ")" -INT : /[-+]?[0-9]+/ -ATOM : /[a-zA-Z]+[a-zA-Z0-9\-\?\!]*/ - | /[\*\/\=\>\<]/ - | /[\-\+](?![0-9])/ -FLOAT : /[-+]?[0-9]+\.[0-9]*/ -_num : INT | FLOAT -COMMENT : ";" /(.)*/ NEWLINE? - -%import common.WS -%import common.NEWLINE -%ignore WS -%ignore COMMENT - ''') - -def atom(x): - return 'atom', x - -def list_(x): - return 'list', x - -def bool_(x): - return 'bool', x - -def int_(x): - return 'int', x - -def float_(x): - return 'float', x - -def typ(x): - return x[0] +from smallscheme.parse import parse_str +from smallscheme.dtypes import * noop = 'nop', None -def convert_ast(ast): - """ - Re-cast the Lark representation of the parse tree into our own. - - 'start' is always the top of the tree and `convert_ast` returns a - list of zero or more parsed expressions. - - All other entrypoints are recursively converted into the - appropriate atom, list, int, float etc. - """ - if type(ast) is lark.tree.Tree: - if ast.data == "start": - return [convert_ast(x) for x in ast.children] - if ast.data == "list": - return list_([convert_ast(x) for x in ast.children]) - if type(ast) is lark.lexer.Token: - ty = ast.type.lower() - if ty == "int": - return int_(int(ast.value)) - if ty == "float": - return float_(float(ast.value)) - elif ty == "bool": - return bool_(True if ast.value == "#t" else False) - elif ty == "atom": - return atom(ast.value) - raise Exception("Unparsed AST: '%s'" % ast) - -def parse_str(x): - return convert_ast(parser.parse(x)) - def argstype(args): # FIXME: Unit test for argument types arglist = [x for (x, _) in args] diff --git a/smallscheme/test_parse.py b/smallscheme/test_parse.py index 51a4102..607eed9 100644 --- a/smallscheme/test_parse.py +++ b/smallscheme/test_parse.py @@ -1,4 +1,5 @@ -from smallscheme.scheme import * +from smallscheme.dtypes import * +from smallscheme.parse import parse_str from smallscheme.test_util import teq def test_parse_str(): diff --git a/smallscheme/test_scheme.py b/smallscheme/test_scheme.py index 8dd6a84..759078f 100644 --- a/smallscheme/test_scheme.py +++ b/smallscheme/test_scheme.py @@ -1,5 +1,7 @@ import sys -from smallscheme.scheme import * +from smallscheme.dtypes import * +from smallscheme.parse import parse_str +from smallscheme.scheme import evalu, printable_value from smallscheme.test_util import teq def test_evalu():