diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2017-11-18 18:29:11 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2017-11-18 18:29:11 -0500 |
| commit | a6dcdcad4fd8407cbd67fb1c2d293f0d3be88914 (patch) | |
| tree | bdacc6cc67b9b454405434f829bfd9992ecd7419 | |
| parent | 8d289bffdd2bf2062a6677530c4a4226175d87b2 (diff) | |
Macro-binding glue, and a let macro
| -rw-r--r-- | README.rst | 8 | ||||
| -rw-r--r-- | actinide/__init__.py | 22 | ||||
| -rw-r--r-- | actinide/builtin.py | 17 | ||||
| -rw-r--r-- | actinide/expander.py | 2 | ||||
| -rw-r--r-- | actinide/stdlib.py | 15 |
5 files changed, 60 insertions, 4 deletions
@@ -174,7 +174,10 @@ layer to map Python return values to Actinide value lists. The ``bind_void`` helper ultimately calls that module's ``wrap_void`` to wrap the function, and ``bind_fn`` calls ``wrap_fn``. (Tuple-returning functions do not need to be wrapped.) If you prefer to manually bind functions using ``bind``, they must be -wrapped appropriately. +wrapped appropriately. An equivalent set of methods, ``macro_bind``, +``macro_bind_void``, ``macro_bind_fn``, and ``macro_bind_builtin`` bind values +to entries in the top-level macro table, instead of the top-level environment, +and allow extension of the language's syntax. Finally, Actinide can bind specially-crafted Python modules. If a module contains a top-level symbol named ``An`` (for the informal chemical symbol for @@ -201,6 +204,9 @@ The symbol must be bound to an instance of the ``Registry`` class from the def two_values(): return 1, "Two" + # @An.macro_bind, @An.macro_void, @An.macro_fn, and @An.macro_builtin follow + # the same pattern. + Going the other direction, values can be extracted from bindings in the session using the ``get`` method: diff --git a/actinide/__init__.py b/actinide/__init__.py index 90ccbfb..cfcb921 100644 --- a/actinide/__init__.py +++ b/actinide/__init__.py @@ -37,16 +37,31 @@ class BaseSession(object): def bind_builtin(self, fn): name = builtin.lisp_name(fn) - if name is None: - raise ValueError("Anonymous functions must be bound using `bind`") symb = self.symbol(name) self.bind(symb, fn) return symb + def macro_bind(self, symb, value): + self.macros[self.symbol(symb)] = value + + def macro_bind_void(self, fn): + return self.macro_bind_builtin(builtin.wrap_void(fn)) + + def macro_bind_fn(self, fn): + return self.macro_bind_builtin(builtin.wrap_fn(fn)) + + def macro_bind_builtin(self, fn): + name = builtin.lisp_name(fn) + symb = self.symbol(name) + self.macro_bind(symb, fn) + return symb + def bind_module(self, module): registry = module.An for name, binding in registry.bindings: self.bind(name, binding) + for name, binding in registry.macros: + self.macro_bind(name, binding) def get(self, symb): symb = self.symbol(symb) @@ -80,5 +95,8 @@ class BaseSession(object): class Session(BaseSession): def standard_library(self): + @self.macro_bind_fn + def let(bindings, *body): + return stdlib.let(self.symbols, bindings, *body) self.bind_module(stdlib) self.bind_module(ports) diff --git a/actinide/builtin.py b/actinide/builtin.py index 485fa96..e8132af 100644 --- a/actinide/builtin.py +++ b/actinide/builtin.py @@ -78,6 +78,7 @@ def wrap_fn(fn): class Registry(object): def __init__(self): self.bindings = [] + self.macros = [] def bind(self, name, value): self.bindings.append((name, value)) @@ -94,3 +95,19 @@ class Registry(object): def builtin(self, f): self.bind(lisp_name(f), f) return f + + def macro_bind(self, name, value): + self.macros.append((name, value)) + return value + + def macro_void(self, f): + self.macro_bind(lisp_name(f), wrap_void(f)) + return f + + def macro_fn(self, f): + self.macro_bind(lisp_name(f), wrap_fn(f)) + return f + + def macro_builtin(self, f): + self.macro_bind(lisp_name(f), f) + return f diff --git a/actinide/expander.py b/actinide/expander.py index 9518854..432f698 100644 --- a/actinide/expander.py +++ b/actinide/expander.py @@ -36,7 +36,7 @@ def expand_subforms(list, symbols, macros): if nil_p(list): return nil if not cons_p(list): - return expand_subforms(list, symbols, macros) + return list head, tail = uncons(list) return cons( expand(head, symbols, macros), diff --git a/actinide/stdlib.py b/actinide/stdlib.py index 8abf71c..6edaf78 100644 --- a/actinide/stdlib.py +++ b/actinide/stdlib.py @@ -66,3 +66,18 @@ def and_(a, b): @An.fn def or_(a, b): return op.or_(a, b) + +def let(symbols, bindings, *body): + if nil_p(bindings): + return list(*body) + + binding, bindings = uncons(bindings) + name, value = flatten(binding) + + return list( + append( + list(symbols['lambda'], list(name)), + let(symbols, bindings, *body), + ), + value + ) |
