From 5cc96a0fb06fa7d86563f4cb64e5fa9d4f6a09f9 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Mon, 13 Nov 2017 01:00:33 -0500 Subject: 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. --- tests/forms.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tests/forms.py (limited to 'tests/forms.py') 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()) -- cgit v1.2.3