|
|
||
|---|---|---|
| examples | ||
| include | ||
| kakoune_rc | ||
| ref_parser | ||
| src | ||
| .gitignore | ||
| Makefile | ||
| README.md | ||
README.md
milly
milly is an hobby, and should not be taken seriously.
Interpreter for a Minimal ML-like language whose ideal goal is to be used for bootstrapping compilers and interpreters.
How to build
milly's interpreter is written in portable ISO C11, sources are in src/ and header files are in include/.
In order to build it, you must have GNU Make installed (in the future i'll try to remove this dependency) and you just have to run:
$ make
in the project root to obtain the executable milly.
The language
milly is a minimal dialect of Standard ML and Haskell, here is a list of the features (or better, limitations) I want to introduce:
- Keep the implementation <5000 LOC
- Eager evaluation (call by value)
- Algebraic Datatypes (pretty useful for representing syntax trees)
- First class functions
- Pattern patching (pretty useful for analyzing syntax trees)
- Integers, booleans, strings
- Mutable
refcell - FFI to C
- Polymorphic types à la Hindley Milner (probably unfeasible)
- Automatic currying of functions, with optimised partial evaluation (unfeasible)
- Delimited continuations (this is an overkill)
- Easy syntax allowing easy kakoune support
- A formal specification (this should be quite manageable to do, and also a good way to learn denotational semantics)
milly's full grammar is specified as a pair of lex and yacc files in ref_parser/.
kakoune plugin for milly is in kakoune_rc/milly.kak.
Here is a small example of the syntax:
# Helpers
datatype 'a list {
Cons of ('a, 'a list),
Empty
}
datatype 'a maybe {
Just of 'a,
Nothing
}
# Lambda calculus term, nameless representation
datatype term {
Var of int,
Int of int,
Abs of term,
App of (term, term)
}
# Result of the evaluation
datatype value {
Int of int,
Closure of (env, term)
}
alias env = value list
typecheck add_binding : value -> env -> env
def add_binding v env = Cons v env
typecheck lookup : int -> env -> value maybe
def lookup _ <Empty> = Nothing
| lookup 0 <Cons x xs> = Just x
| lookup n <Cons x xs> = lookup (subtract n 1) xs
typecheck eval : env -> term -> value
def eval e <Var idx> =
match lookup idx e {
case <Just v> -> v
case <Nothing> -> abort "Variable out of scope"
}
| eval e <Int x> = Int x
| eval e <Abs t> = Closure e t
| eval e <App t1 t2> =
let def new_env = add_binding (eval e t2) e
in eval new_env t1