From 6ee8b48ce8f2189c23f8bf64bcf93e2210e67d26 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Mon, 13 Nov 2017 01:45:18 -0500 Subject: A basic expander. This doesn't support macro expansion, but does support some basic syntax niceties. Macro expansion requires quote and quasiquote support. --- actinide/__init__.py | 5 +++-- actinide/expander.py | 34 ++++++++++++++++++++++++++++++++++ primer.py | 8 ++++---- 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 actinide/expander.py diff --git a/actinide/__init__.py b/actinide/__init__.py index afa27d8..0278cd8 100644 --- a/actinide/__init__.py +++ b/actinide/__init__.py @@ -1,4 +1,4 @@ -from . import builtin, ports, symbol_table, reader, evaluator, types +from . import builtin, ports, symbol_table, reader, expander, evaluator, types class Session(object): def __init__(self): @@ -8,7 +8,8 @@ class Session(object): def read(self, port): if types.string_p(port): port = ports.string_to_input_port(port) - return reader.read(port, self.symbols) + form = reader.read(port, self.symbols) + return expander.expand(form, self.symbols) def eval(self, form): cps = evaluator.eval(form, self.environment, self.symbols, None) diff --git a/actinide/expander.py b/actinide/expander.py new file mode 100644 index 0000000..46a98ce --- /dev/null +++ b/actinide/expander.py @@ -0,0 +1,34 @@ +# ## EXPANDER + +from .types import * + +# Expand and syntax-check a form. +# +# This replaces shorthand notations, such as ``(define (a b c) body)``, with +# their longhand equivalents (``(define a (lambda (b c) body)))``). +# +# Because this deals with unevaluated programs, this algorithm can safely +# recurse: the input depth simply isn't that large. +def expand(form, symbols): + if nil_p(form) or not list_p(form): + return form + # huge cheat. Working with python lists is hugely easier for this than + # working with conses, and it's after midnight. Flatten the form, expand it, + # and reconstitute it. This incurs two bonus copies per form: suck it up. + symb, *args = flatten(form) + if symb == symbols['if'] and len(args) == 2: + args.append(None) + elif symb == symbols['define']: + decl, *body = args + if list_p(decl): + decl = flatten(decl) + name, *formals = decl + lambda_ = list(symbols['lambda'], list(*formals), *body) + args = [name, lambda_] + elif symb == symbols['lambda']: + formals, *body = args + if len(body) != 1: + body = [list(symbols['begin'], *body)] + args = [formals, *body] + form = list(symb, *[expand(subform, symbols) for subform in args]) + return form diff --git a/primer.py b/primer.py index 2c6d73a..b223550 100644 --- a/primer.py +++ b/primer.py @@ -9,10 +9,10 @@ program = session.read(""" 1 1.0 "Hello" - (define a - (lambda (b) (values 1 2.2 "three" a b))) - (define pp - (lambda () (pp))) + (define (a b) + (values 1 2.2 "three" a b)) + (define (pp) (pp)) + (print (a "foo")) (print (eval (list (symbol "a") "bar"))) (print 0 (values 1 2 3) 4 5) -- cgit v1.2.3