What does HackerNews think of Vacietis?

C to Common Lisp compiler

Language: Common Lisp

Project name: Vacietis

URL: https://github.com/vsedach/Vacietis

Programming language used for the compiler: Common Lisp

Compiles to: Common Lisp

  > Why is this a worst case for Haskell?
You generally don't want a garbage collector in the core request-dispatch loop, and Haskell's lazy evaluation makes it really easy to accidentally write code that can't be compiled to efficient output. It's not impossible to write a high-performance HTTP server in Haskell[0], but the skill requirement is much higher than in C++, Rust, or Go[1].

  > is the average LISP developer anymore likely to make a non industrial
  > code base than a Rust developer?
Yes. Not because of the developer, but because of how extremely flexible and dynamic the Lisp-family languages are. The power and joy of Lisp is in how it's almost a meta-language, so every project can become its own EDSL. The most famous (infamous?) example of this is Vacietis[2], which is a Common Lisp library that allows C code to be imported directly(!!).

[0] IIRC the Yesod framework's Warp does well on benchmarks, and when you look at code like https://github.com/yesodweb/wai/blob/master/warp/Network/Wai... you can see the lengths they had to go through to work around the choice of implementation language.

[1] Go has a garbage collector, but exposes the stack/heap distinction more directly than Haskell, so it's easier to write allocation-free code in hot paths.

[2] https://github.com/vsedach/Vacietis

How about C?

https://news.ycombinator.com/item?id=25531871

https://github.com/vsedach/Vacietis

================

Vacietis is a C compiler for Common Lisp systems.

Vacietis works by loading C code into a Common Lisp runtime as though it were Lisp code, where it can then be compiled or evaled. The loaded C code has the same function calling convention as regular CL code and uses the same numerical representations. C memory is backed by regular Common Lisp arrays.

Vacietis comes with a libc implemented in portable Common Lisp.

The Common Lisp specification has the entire reader algorithm laid out[1]. It fits on a single page, and it's really easy to understand.

Note, however, that there is heavy lifting done by the default read-table (the CL reader is table-based and is dynamically modifiable[2]), so you will only be able to read tokens if you implement what is on that page.

However, the most common characters are nearly trivial to implement: #\( #\" #\' as well as the most common dispatch characters for #\#

1: http://www.lispworks.com/documentation/HyperSpec/Body/02_b.h...

2: Someone modified the lisp reader to be able to read in valid C89 code, and implemented a backend to compile that to common-lisp: https://github.com/vsedach/Vacietis

Here's a real-word C compiler where the sizeof() everything is 1; https://github.com/vsedach/Vacietis

For another example, the LLVM webassembly backend doesn't put the call stack in the same address space as the heap at all.

The Vacietis (https://github.com/vsedach/Vacietis/) reader can be easily adapted to do that. You can see examples in the unit tests:

https://github.com/vsedach/Vacietis/blob/master/test/reader-...

As-is, C block constructs get mapped directly to Common Lisp special forms like tagbody and prog because those implement a superset of C control flow semantics. Pick different names in vacietis.c and you have an AST.

Great work David, glad to see an update after almost 5 years!

I looked into Clue for compiling C to Common Lisp before writing https://github.com/vsedach/Vacietis because I wanted something that would interop better with CL types and be able to run self-contained.

To provide more precedents and a little history:

The first C "interpreters" I know of were for Lisp machines: Symbolics' C compiler (http://www.bitsavers.org/pdf/symbolics/software/genera_8/Use...) and Scott Burson's (hn user ScottBurson) ZetaC for TI Explorers/LMIs and Symbolics 3600s (now available under the public domain: http://www.bitsavers.org/bits/TI/Explorer/zeta-c/). Neither of them are interpreters, just "interactive" compilers like Lisp ones are.

I am writing a C to Common Lisp translator right now (https://github.com/vsedach/Vacietis). This is surprisingly easy because C is largely a small subset of Common Lisp. Pointers are trivial to implement with closures (Oleg explains how: http://okmij.org/ftp/Scheme/pointer-as-closure.txt but I discovered the technique independently around 2004). The only problem is how to deal with casting arrays of integers (or whatever) to arrays of bytes. But that's a problem for portable C software anyway. I think I'll also need a little source fudging magic for setjmp/longjmp. Otherwise the project is now where you can compile-file/load a C file just like you do a Lisp file by setting the readtable. There's a few things I need to finish with #includes, enums, stdlib and the variable-length struct hack, but that should be done in the next few weeks.

This should also extend to "compiling" C to other languages like JavaScript, without having to go through the whole "emulate LLVM or MIPS" garbage that other projects like that do. I think I figured out how to do gotos in JavaScript by using a trampoline with local CPS-rewriting, which is IMO the largest challenge for an interoperable C->JS translator.

As to how to do this for C++, don't ask me. According to the CERN people, CINT has "slightly less than 400,000 lines of code." (http://root.cern.ch/drupal/content/cint). What a joke.