diff --git a/repl.py b/repl.py index efeb57d..6182f1a 100644 --- a/repl.py +++ b/repl.py @@ -1,5 +1,4 @@ import wasp -import wasp.parser import readline @@ -29,21 +28,20 @@ if __name__ == "__main__": # http://stackoverflow.com/questions/5637124 #readline.set_completer(complete) + context = wasp.Context() + for line in Reader(">> ", banner="WASP %s" % wasp.VERSION): if line == "" or line is None: continue try: - ptree = wasp.parser.parse(line) - except ValueError, e: + ast = context['read'](line) + except wasp.lib.ReadError, e: print "Parse error:", e.message continue - print " ^ %s" % ptree try: - ast = ptree.ast() - except ValueError, e: - print "AST error:", e.message + print context['eval'](ast, context) + except wasp.SymbolError, e: + print "Undefined symbol:", e.message continue - print " ‡ %r" % ast - #ast.eval() diff --git a/test.py b/test.py index 7d21a23..e5d4b82 100644 --- a/test.py +++ b/test.py @@ -40,6 +40,12 @@ class TestParser(TestCase): self.assertRaises(ValueError, parser.parse("(42")) +class TestAST(TestCase): + def test_lists_in_list(self): + ptree = parser.parse("(+ (* 4 5) (* 3 2))") + repr(ptree.ast()) + + if __name__ == '__main__': import unittest unittest.main() diff --git a/wasp/__init__.py b/wasp/__init__.py index a4e55ec..367f7b8 100644 --- a/wasp/__init__.py +++ b/wasp/__init__.py @@ -1 +1,31 @@ +from __future__ import print_function + + +import wasp.lib as lib + + VERSION = '0.0.1' + + +class SymbolError(Exception): + pass + + +class Context(object): + symbols = { + '+': lib.plus, + '-': lib.minus, + '*': lib.multiply, + '/': lib.div, + 'read': lib.read, + 'eval': lib.eval, + 'print': lib.print, + 'apply': lib.apply, + 'quote': lib.quote, + } + + def __getitem__(self, symbol): + try: + return self.symbols[symbol] + except KeyError: + raise SymbolError(symbol) diff --git a/wasp/ast.py b/wasp/ast.py index f1727f8..6986edd 100644 --- a/wasp/ast.py +++ b/wasp/ast.py @@ -7,8 +7,8 @@ class List(Node): self.car = car self.cdr = cdr - def eval(self): - pass + def eval(self, context): + return context['apply'](self.car, self.cdr, context) def __repr__(self): return "" % (self.car, self.cdr) @@ -26,7 +26,7 @@ class Number(Atom): def __init__(self, value): self.value = value - def eval(self): + def eval(self, context): return self.value def __repr__(self): @@ -45,8 +45,8 @@ class Symbol(Atom): def __init__(self, value): self.value = value - def eval(self): - return self.value + def eval(self, context): + return context[self.value] def __repr__(self): return "" % self.value @@ -56,7 +56,7 @@ class String(Atom): def __init__(self, value): self.value = value - def eval(self): + def eval(self, context): return self.value def __repr__(self): @@ -67,8 +67,8 @@ class Quote(Node): def __init__(self, sexpr): self.sexpr = sexpr - def eval(self): - return self.sexpr.eval() + def eval(self, context): + return context['quote'](self.sexpr) def __repr__(self): return "" % self.sexpr diff --git a/wasp/lib.py b/wasp/lib.py new file mode 100644 index 0000000..9017530 --- /dev/null +++ b/wasp/lib.py @@ -0,0 +1,64 @@ +from __future__ import print_function + +import wasp.parser + + +py_print = print +py_eval = eval + + +class ReadError(Exception): + pass + + +def plus(a, b): + return a + b + + +def minus(a, b): + return a - b + + +def multiply(a, b): + return a * b + + +def div(a, b): + return a / b + + +def read(string): + try: + ptree = wasp.parser.parse(string) + except ValueError, e: + raise ReadError(e.message) + py_print(" ^ %s" % ptree) + + try: + ast = ptree.ast() + except ValueError, e: + raise ReadError(e.message) + py_print(" ‡ %r" % ast) + + return ast + + +def eval(ast, context): + # eval value unless list + # eval args unless lazy + # eval call + return ast.eval(context) + + +def apply(a, b, context): + # move to eval + args = [arg.eval(context) for arg in b] + return a.eval(context)(*args) + + +def quote(a): + return a + + +def print(string): + py_print(string)