diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2017-11-13 01:00:33 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2017-11-13 01:01:34 -0500 |
| commit | 5cc96a0fb06fa7d86563f4cb64e5fa9d4f6a09f9 (patch) | |
| tree | 40052668ffe030452b45e3a2d6be8d8fc24acdee /tests/forms.py | |
| parent | 6a635660bd7b47238642d4a552782687352555ac (diff) | |
Big-ass coding binge presents: a Lisp.
This implements a continuation-passing interpreter, which means we get tail calls ferfree. I stopped short of implementing call/cc, because I don't think we need it, but we can get there if we have to.
Diffstat (limited to 'tests/forms.py')
| -rw-r--r-- | tests/forms.py | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/tests/forms.py b/tests/forms.py new file mode 100644 index 0000000..1a49636 --- /dev/null +++ b/tests/forms.py @@ -0,0 +1,76 @@ +from hypothesis.strategies import integers, decimals as hypo_decimals, booleans, characters, text, tuples, lists as hypo_lists, just, one_of +from hypothesis.strategies import deferred, recursive + +from actinide.symbol_table import * +from actinide.types import * + +# Generators for forms. Where these generators create a symbol, they will use +# the global symbol table defined in this module. Do not do this in your own +# code! A global symbol table is a memory leak, and only the fact that tests +# exit before they can do any substantial damage prevents this from being a +# bigger problem. +# +# Each generator produces the parsed version of a form. + +symbol_table = SymbolTable() + +# Generates nil. +def nils(): + return just(None) + +# Generates integers. +def ints(): + return integers() + +# Generates language decimals. +def decimals(): + return hypo_decimals(allow_nan=False, allow_infinity=False) + +# Generates booleans. +def bools(): + return booleans() + +# Generates strings. +def strings(): + return text() + +# Generates any character legal in a symbol, which cannot be part of some other +# kind of atom. +def symbol_characters(): + return characters(blacklist_characters='01234567890#. \t\n();"') + +# Generates symbols guaranteed not to conflict with other kinds of literal. This +# is a subset of the legal symbols. +def symbols(): + return text(symbol_characters(), min_size=1)\ + .map(lambda item: symbol_table[item]) + +# Generates atoms. +def atoms(): + return one_of( + nils(), + ints(), + decimals(), + bools(), + strings(), + symbols(), + ) + +# Generates arbitrary conses, with varying depth. This may happen to generate +# lists by accident. +def conses(): + return recursive( + tuples(atoms(), atoms()).map(lambda elems: cons(*elems)), + lambda children: tuples(children | atoms(), children | atoms()).map(lambda elems: cons(*elems)), + ) + +# Generates lists, with varying depth. +def lists(): + return recursive( + hypo_lists(atoms()).map(lambda elems: list(*elems)), + lambda children: hypo_lists(children | atoms()).map(lambda elems: list(*elems)), + ) + +# Generates random forms. +def forms(): + return one_of(nils(), ints(), bools(), strings(), symbols(), conses(), lists()) |
