def assert_exp_length(ast, length): if len(ast) > length: msg = "Malformed %s, too many arguments: %s" % (ast[0], unparse(ast)) raise LispError(msg) elif len(ast) < length: msg = "Malformed %s, too few arguments: %s" % (ast[0], unparse(ast)) raise LispError(msg)
def unparse(ast): """Turns an AST back into lisp program source""" if is_boolean(ast): return "#t" if ast else "#f" elif is_list(ast): if len(ast) > 0 and ast[0] == "quote": return "'%s" % unparse(ast[1]) else: return "(%s)" % " ".join([unparse(x) for x in ast]) else: # integers or symbols (or lambdas) return str(ast)
def interpret(source, env=None): """ Interpret a lisp program statement Accepts a program statement as a string, interprets it, and then returns the resulting lisp expression as string. """ if env is None: env = Environment() return unparse(evaluate(parse(source), env))
def interpret_file(filename, env=None): """ Interpret a lisp file Accepts the name of a lisp file containing a series of statements. Returns the value of the last expression of the file. """ if env is None: env = Environment() with open(filename, 'r') as sourcefile: source = "".join(sourcefile.readlines()) asts = parse_multiple(source) results = [evaluate(ast, env) for ast in asts] return unparse(results[-1])
def test_unparse_quotes(): assert_equals("'foo", unparse(["quote", "foo"])) assert_equals("'(1 2 3)", unparse(["quote", [1, 2, 3]]))
def test_unparse_list(): assert_equals("(1 2 3)", unparse([1, 2, 3])) assert_equals("(if #t 42 #f)", unparse(["if", True, 42, False]))
def test_unparse_symbol(): assert_equals("+", unparse("+")) assert_equals("foo", unparse("foo")) assert_equals("lambda", unparse("lambda"))
def test_unparse_int(): assert_equals("1", unparse(1)) assert_equals("1337", unparse(1337)) assert_equals("-42", unparse(-42))
def test_unparse_other_quotes(): assert_equals("'foo", unparse(["quote", "foo"])) assert_equals("'(1 2 3)", unparse(["quote", [1, 2, 3]]))
def test_unparse_bool(): assert_equals("#t", unparse(True)) assert_equals("#f", unparse(False))
def test_unparse_list(): assert_equals("((foo bar) baz)", unparse([["foo", "bar"], "baz"]))
def test_unparse_empty_list(): assert_equals("()", unparse([]))
def test_expand_crazy_quote_combo(): """One final test to see that quote expansion works.""" source = "'(this ''''(makes ''no) 'sense)" assert_equals(source, unparse(parse(source)))
def assert_boolean(p, exp=None): if not is_boolean(p): msg = "Boolean required, got '%s'. " % unparse(p) if exp is not None: msg += "Offending expression: %s" % unparse(exp) raise LispTypeError(msg)
def test_unparse_atoms(): assert_equals("123", unparse(123)) assert_equals("#t", unparse(True)) assert_equals("#f", unparse(False)) assert_equals("foo", unparse("foo"))
def test_unparse_quotes(): assert_equals( "''(foo 'bar '(1 2))", unparse( ["quote", ["quote", ["foo", ["quote", "bar"], ["quote", [1, 2]]]]]))
def test_unparse_another_list(): assert_equals("(1 2 3)", unparse([1, 2, 3])) assert_equals("(if #t 42 #f)", unparse(["if", True, 42, False]))
def test_unparse_quotes(): assert_equals("''(foo 'bar '(1 2))", unparse( ["quote", ["quote", ["foo", ["quote", "bar"], ["quote", [1, 2]]]]]))