# 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/`. If your system happens to have a `make` implementation compatible with **GNU Make**, you can just run: > make Otherwise, something like this should work: > $(CC) -std=c11 -o milly -Iinclude/ src/*.c ## 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 `ref` cell - 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 milly's full grammar is specified as a pair of lex and yacc files in `ref_parser/`. kakoune plugin for milly is in `extra/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 _ = Nothing | lookup 0 = Just x | lookup n = lookup (subtract n 1) xs typecheck eval : env -> term -> value def eval e = match lookup idx e { case -> v case -> abort "Variable out of scope" } | eval e = Int x | eval e = Closure e t | eval e = let def new_env = add_binding (eval e t2) e in eval new_env t1 ```