Coder Social home page Coder Social logo

0xekez / lisp Goto Github PK

View Code? Open in Web Editor NEW
54.0 3.0 2.0 252 KB

A lisp JIT compiler and interpreter built with cranelift.

Rust 92.30% Common Lisp 6.86% Emacs Lisp 0.39% NewLisp 0.42% Python 0.03%
programming-language lisp-interpreter rust interpreter lisp cranelift

lisp's Introduction

A little lisp compiler and interpereter. The compiler is just in time and written with Cranelift.

>> (import 'format)
>> (let say-hello (fn (name)
                      (printf "hello {}!" name)))
>> (say-hello "Lisp")
hello Lisp!

Performance Example

Consider everyone's favorite fib function in this lisp and in Python:

(let fib (fn (n)
	     (if (lt n 2)
		 n
	       (add (fib (sub n 2)) (fib (sub n 1))))))
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

The JIT compiler can compute (fib 40) in 2.3 seconds. It takes Python 35 seconds.

Take this with a grain of salt because there are many things Python can do very elegantly that are still awkward in here and I'm sure there are places where python's C bindings give it a leg up. The point is that in this case both languages are very similar looking but one is much, much quicker.

The compiler also doesn't have a garbage collector yet but who really needs one if you can run everything faster than a gc cycle ;)

here are example programs.

lisp's People

Contributors

0xekez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

lisp's Issues

License

Is it ok to reuse this under the MIT license? I don't see a license file anywhere

Pay for what you use: varadic functions

Varadic functions require that we heap allocate function arguments. This is slow. Most existing Lust programs do not use varadic functions - in that situation we don't need to heap allocate arguments.

Trouble with doing this is that it adds a lot of code complexity (two implementations of function calls) and once there is a standard library which will use varadic functions most Lust programs are liable to use varadic functions.

Garbage Collection

We now have heap allocation wired up in lustc. This means that its time to start thinking about garbage collection. For now I have wrapped malloc in an alloc function. In 164 Hilfinger uses a similar method and I believe that later we ought to be able to add some machinery to alloc to track allocations and later garbage collect.

Add unit testing for Lust programs

At the moment there is no way to test that errors are being displayed properly because they print to stdout and don't leave much of a trace. As time goes on and there is more need for this sort of thing we should consider adding some sort of btest like unit test framework so that we can compare the output of lust programs to a baseline.

Use Vec more appropriately when representing lists

Most operations on lists in Lust occur at the beginning. car, cdr, and cons all operate on the first item in the list. Meanwhile, Rust's vector class is designed for things to change at the end. As a result we're abusing the data structure when we're constantly popping and inserting data at the front.

One way to get around this would be to represent Lust lists as a reversed vector. Under the hood, lists would be represented by Vec still, but the first item in a Lust list would correspond to the last item in the corresponding vector. I believe this would be markedly more performant.

Last night I tried to see if this would be a simple change, but I don't think it will. There are quite a few places where indexing the complex with varadic functions and etc. It also makes code really ugly to be constantly using the reverse of the index you want. We'd probably be well served to wrap Vec in some sort of LustVec class and then use that instead of Vec.

This would be a good learning experience working with more complex data types in Lust as well.

Write a high level bytecode compiler

Here is a nice write up of roughly what I'd imagine. Doing this would serve two purposes:

  1. It would allow us to emit better error messages because we could keep location information around while compiling expressions
  2. It would be the first step in moving towards compiling Lust. Later a JIT might be happier compiling that byte code to machine code.

I think it would be fine to keep the byte code very high level. Environments could remain roughly how they are now and we could possibly avoid typing by still keeping things in an enum. The goal wouldn't be performance so much as it would be to lower the Lust code into a simpler form more for executing and catch some additional errors along the way.

Support compilation to object files

Having a JIT is nice and makes testing pretty easy but at the end of the day the ability to compile to native object files is very important to me because it opens up the possibility of writing a self hosting version of Lust (this is very far down the line though.)

A branch of the simple jit demo shows approximately how this is done. Based on this I don't believe that doing this will require too much additional work as the architecture seems to be similar enough.

Handle blank lines in repl

Currently panics on the cleanup branch. Something to do with locations being one past the end I suspect. Not high priority right now.

Don't compile primitive functions that we don't need

Right now at the beginning of compilation we emit all of the primitive functions into the JIT. We don't need to do this. We should add a pass to the compiler that locates primitives that appear in non-head positions of lists and only compiles those ones.

Change `import` to `require`

Right now our import function is liable to get caught in a loop if files import each other. This isn't so good. I'd like to change import to require like Emacs Lisp. This way we could more clearly indicate that we're just requiring that the file is loaded. import gives the idea that you're actively evaluating the file when you import it.

Parse negative numeric literals

Optionally we could use ~ to indicate negation, but that seems like a lot of confusion for a little bit of saved time on the tokenizer.

car and cdr have different behavior when called on empty list

In the interpreter (car ()) and (cdr ()) yield () whereas in the compiler both calls result in a type error.

Currently, my preference is for the compilers behavior. It seems like if you ask for the second item of an empty list that is indeed an error. Right now it can be a little confusing but once we get around to improving the compiler's error messages I suspect we can make that error more obvious.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.