Lisp Like Language

This is available online at https://github.com/kerspoon/lipy2.

I have been developing LiPi to teach me various programming concepts. It is a small lisp/scheme like programming language made in python.

It is broken down into a number of separate modules:

  • lex - tokenise a string into a list of string tokens
  • parse - convert tokens into LiPi datatypes
  • datatypes - all the data in scheme is of one of these types
  • environment - anything defined in lipy get stored in an environment
  • function - all built in lipy function calls (including special forms) as well as the default environment
  • main - tests and misc
  • prelude - some default scheme functions taken from Haskell

Each datatype can define a number of different operations which makes up the core of the program:

  • eval - this is what gets called when it is evaluated.
  • str - this turns it into a string for output.
  • apply - this deals with it being called like a function.
  • eq - tests for equality

Even the datatypes of function and class are handled this way. For instance a tidied version of the apply function for Lambda (the datatype of functions) is below:

def __call__(self, args, env):
    """__call__ :: SchemePair -> Environment"""

    if self.macro:
        # expand in a new env
        mac = self.expand_macro(args, env)
        # call in the *old* env.
        return mac.scm_eval(env)

    # eval all args and return as a list
    evaled_args = [arg.scm_eval(env) for arg in to_list(args)]

    # extend the Environment with the new frame
    # the new frame is simply the evaled args mapped to the
    # parameters of the function
    new_env = extended_env(self.scm_vars, evaled_args, env)

    # eval the body of the lambda in the new Environment
    return self.body.scm_eval(new_env)

Note that macros are simply a function that doesn’t eval it’s arguments before being called. Instead it calls the function once to expand the macro and then calls the result as a normal function.

It has a test suite of around 200 different items. These are mostly basic functionality checks. As it lacks a lot of important system calls it is not suitable as a general programming language.

This is my 5th lisp implementation, the previous ones have been in C++, D, D again, and a previous version in Python.