Elm compiler written in Elm
Elm compiler written in Elm!
elm-in-elmis focused on readability, beauty, approachability, simplicity, great docs and great tests first, and only then completeness and speed.
wheresyntax, etc.
In short,
elm-in-elmaims to unblock and encourage people to play with compilers and the Elm language itself, explore new frontiers and have fun!
:tv: For more context and information, you can watch Martin Janiczek's talk from Elm Europe 2019 which served as an unveiling of
elm-in-elmto public. Here are :bar_chart: the slides.
This is :negativesquaredcrossmark::negativesquaredcrossmark::negativesquaredcrossmark: NOT THE REASON and NOT THE GOAL :negativesquaredcrossmark::negativesquaredcrossmark::negativesquaredcrossmark: of
elm-in-elm. We don't want to and aren't planning to divide the community into multiple Elm derivatives, and will actively try to prevent that.
elm-in-elmis, for all intents and purposes, a sandbox, a place to try out ideas, an experimentation environment.
elm-in-elmconsists of:
It is written in Elm, and compiles Elm to JavaScript, but lays the foundation to be able to compile to different targets in the future.
:warning: Warning!
elm-in-elmis definitely not ready for usage yet, even though its library is published already. The main blocker is the parsers for expressions not being all implemented yet. See theparsecolumn in the table below.
Please yes! :heart: Feel free to look around the help wanted or good first issue issues, have a look around the codebase for some general nitpicks or refactorings, or hit us up on Discord!
| | parser tests | optimize tests | emit tests | parse | desugar | infer types | optimize | emit | | ----------------- | -------------------- | -------------------- | -------------------- | -------------------- | ------------------ | -------------------- | -------------------- | -------------------- | | integers | :heavycheckmark: | :warning: [2] | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :warning: [2] | :heavycheckmark: | | floats | :heavycheckmark: | :x: [5] | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :x: [5] | :heavycheckmark: | | characters | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | strings | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | booleans | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | variables | :warning: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | lists | :heavycheckmark: | :x: [6] | :warning: [1] | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :x: [6] | :warning: [1] | | binary operators | :warning: [3] | :heavycheckmark: | :heavycheckmark: | :warning: [3] | :heavycheckmark: | :x: | :warning: | :warning: | | lambdas | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :warning: | :heavycheckmark: | | function calls | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | if...then...else | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | let..in | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :warning: | :heavycheckmark: | :warning: | | case...of | :warning: [4] | :x: | :x: | :warning: [4] | :x: | :x: | :x: | :x: | | records | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | record accessors | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | | record updates | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | | unit type | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | tuples, 3-tuples | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | type annotations | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | type aliases | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :warning: [7] | :heavycheckmark: | :heavycheckmark: | | custom types | :heavycheckmark: | :x: | :x: | :heavycheckmark: | :x: | :x: | :x: | :x: | | custom operators | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | | shaders (?) | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
emitwill have to change a bit: conversion from target platform lists to Elm "custom type" lists is now missing; tracked in #29
stil4m/elm-syntaxfor the parsers?
elm-syntax- it would save us so much trouble. But that would not be ideal in some regards:
elm-community/parser-combinatorsstyle - we'd like, again because of the learning resource goal, to have the parsers written in idiomatic
elm/parserstyle
But yeah, there's definitely a little bit of NIH syndrome happening :wink:
The easy way: if you have Nix installed, run
$ nix-shelland you'll drop into a shell that has all the dev dependencies set up and ready!
Alternatively, this is what the project needs.
$ make
Essentially compiles the compiler (using the official Elm compiler :wink: ) to a
build/elm.jsfile and runs it using
node.
Very handy for running the whole compiler pipeline on an example project living in
example-project/, which the CLI is currently hardcoded to try and compile! In some cases this might be more convenient than writing tests - just add an interesting snippet to
example-project/src/Main.elm,
Debug.logwhat you need in the compiler itself, and
make!
So absolutely feel free to go bonkers on that
example-project/- it's there for developer convenience!
$ make test
Runs
elm-teston the test suite (gasp!)
$ make format
Runs elm-format. Make sure to format code before submitting a pull request!
This is a brain-dump of some low-level stuff. (High-level stuff should be in the roadmap.) My apologies if it's hard to make sense of this! ~janiczek
elm-in-elm(ie. talks about Haskell hierarchical optimizations etc.)
Main.compilewith official compiler's
Compile.compile- is that a better API?
Stage.InferTypes.generateEquations, the
Typed.Letcase. This paper might have a parable written well enough that we might actually understand type schemes from this. Otherwise, "Write you a Haskell" for the rescue! There is also the Damas and Milner paper proving the inferred type is the most general one.
D. Leijen, “Extensible records with scoped labels,” in Revised Selected Papersfrom the Sixth Symposium on Trends in Functional Programming, TFP 2005,Tallinn, Estonia, 23-24 September 2005.(M. C. J. D. van Eekelen, ed.), vol. 6 of Trends in Functional Programming, pp. 179–194, Intellect, 2005.
ainstead of
type #0or something).
Stage.InferTypes.getType
( and(|>)fusion (eg. transform bothx |> fandf intof x)
Lambdacase of
Stage.PrepareForBackend.findDependenciesworks correctly
(a,b) => a+binstead of
(a) => (b) => a+b)?
let? How does official compiler do it? Seems the dependency graph will have to be computed for its binidng too, similarly to how the path to
maingets computed for the program itself.
Stage.Emit.emitExpr, the
Letcase.
Common.unalias
Stage.Desugar.findModuleOfVar
|