Memo Language Logo

Memo Language Definition

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.

Expressions

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.

Data Types

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.

Variable Naming and Addressing

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.

Comments

Comment start with # and continue to the remainder of the line. They can be at the beginning of a line or after an expression.

Invoking the Garbage Collector

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.