Memo is a simple language designed to demonstrate the use of automatic memory management and garbage collection in a toy environment. Memo is deliberately not Turing complete—it has no conditionals or loops—and only contains a small number of operations for manipulating objects.
Memo programs are structured as a series of expressions, one per line. Expressions return values, so:
a = 5
Returns 5. This also allows you to print a value using a bare variable, as in:
a
This is useful as there is no print function.
Memo comes with three native types. The first two of these are familiar:
The only other data type in Memo is the Tuple, which represents
an ordered set of values, each of which can be either an integer or a
a pointer. Tuples are wrapped in parentheses, as in
(1 2 3)
. Unlike Python lists or JS lists—but like Rust or Python tuples—you
can't extend tuples, so a tuple of length X
can't be turned
into a tuple of length Y
, though of course you can create
a new tuple of the right size.
This isn't a particularly rich type system, but it's actually sufficient to construct a variety of data structures, as anyone who has worked with Lisp, will recognize. For example you can make a list of integers out of 2-valued tuple objects, with the first value of each tuple being an integer and the second value being a pointer to the next tuple.
Like any language, Memo has named variables. All variables are
global and variables are automatically created upon assignment
without the need for let
or var
(simple, remember?).
It's not legal to read variables which haven't
been assigned to yet.
Variables in Memo are named in the usual fashion, as strings
of letters and numbers starting with a letter, e.g., tmp1
.
So, for instance, the following code:
a = 20
Creates a variable a
and assigns the value 20.
You create a tuple in the way you expect:
a = (1 2 3)
This code automatically allocates a tuple of size 3 on the heap and
assigns the address to a
. It's also legal to have tuples contain
other tuples, which really just means that one of the elements of the
tuple is the address of another tuple.
a = (1 2 3 (4 5))
Variables themselves aren't typed, so it's perfectly legal to do:
a = (1 2) # a is a pointer to the tuple (1 2)
a = 20 # a is the integer 20
In order to make this work, internally Memo keeps track of whether a
given value is a pointer or an integer by coloring the pointers. This
should be familiar if you've used other weakly typed languages like
Python or JavaScript. The inner values in a tuple are addressed with
the notation a.0
, a.1
, and so on.
Variables never go out of scope, but you can assign them to null
,
which has most of the same effect, except that they're still floating
around in the namespace.
Comment start with #
and continue to the remainder of the line. They
can be at the beginning of a line or after an expression.
Memo does not currently automatically garbage collect, as then
we'd need to tune when it happenes. Instead you
invoke the GC using a pseudoinstruction of the form #gc
. This
is only sort of part of the language in that it tells the interpreter
to invoke the GC but the details of the GC are exposed to the outside
to allow you to see it operate step by step.