diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2017-11-13 01:45:18 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2017-11-13 01:45:21 -0500 |
| commit | 6ee8b48ce8f2189c23f8bf64bcf93e2210e67d26 (patch) | |
| tree | ca5f90322a000a56d267130bdfd23f0b873ee2f4 | |
| parent | 5cc96a0fb06fa7d86563f4cb64e5fa9d4f6a09f9 (diff) | |
A basic expander.
This doesn't support macro expansion, but does support some basic syntax
niceties. Macro expansion requires quote and quasiquote support.
| -rw-r--r-- | actinide/__init__.py | 5 | ||||
| -rw-r--r-- | actinide/expander.py | 34 | ||||
| -rw-r--r-- | primer.py | 8 |
3 files changed, 41 insertions, 6 deletions
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 @@ -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) |
