An ultra-simplified example of a modern compiler written in JavaScript
github.com
github.com
In this case I believe the "compiler" is an "ast printer".
I'm not sure why that would be so significant. Don't get me wrong, I'm sure targeting some real machine code presents plenty of unique difficulties—but the interesting thing about compilation to me (and I'd wager a significant proportion of other readers here) is effective ways of structuring translation processes.
In the case of this project, the goal is to be a minimal demonstration, distilling the essence of how a compiler is structured. The fact that the output language is not machine code doesn't affect the essential structure of a compiler (as far as I know).
My understanding is that having something like LLVM’s IR, for instance, is part of its decoupling the compiler frontend/backend, but probably wouldn’t be desirable for a single language compiler. But maybe I’m mistaken, or you are referring to something else :)
That said I think what they're getting at is that the interesting bits of modern compilers are transforms between ASTs to lower from one IR to another either to perform some kind of optimization or to replace an abstraction with an implementation before it gets to codegen.
For example if you have generators in your language it's pretty easy to see how to turn a "yield" statement into an AST node. But to actually make the system work you'll probably need a compiler pass over your AST to transform coroutine definitions to subroutine definitions and a state machine to represent the execution context and a constructor/destructor for the state.
Same goes for all interesting language concepts, in the compiler the interesting bit is the pass that transforms the top level AST/IR into more explicit IR and going through the pipeline to get to codegen. Which is as complex as everything else these days when it needs to be fast.
The example talks about this but doesn't dive too deep.
I'm sure someone will disagree with me, but to me, the point of IR is that it's a concretization, not an abstraction. Consider that your source code can look like
int foo(void);
or class C;
or template<class T> struct vector;
then you see that all of these translate into an AST, but don't result in any code getting generated. Conversely, given a template definition for vector, vector<int> and vector<string> would result in multiple intermediate representations for the exact same chunk of AST.Calling the parsed representations of these "intermediate representations" when they're not corresponding to generated code would render the term practically useless. You might as well call the source code itself IR at that point and claim IR has no value.
I've written a couple of interpreters now, and even a simple maths-compiler that generated assembly-language output.
One of the things that made me postpone these projects for years was seeing so many parser/lexer examples which were just evaluating simple expressions such as "3 + 4", or "3 + 4 * 5". Going from there to a real language with functions, conditionals, etc, is a big step with no guidance.
Still this is a nice project, and it is well-documented even if it is "small".
For an input of "(add 2 (subtract 4 2))" you get an output of "add(2, subtract(4, 2));"
The JS example wrote everything from scratch, so to do the same, I wrote my own parser combinator library (based on https://www.cs.nott.ac.uk/~pszgmh/monparsing.pdf), but you could use an existing library, and get rid of `Parser.hs`.
I began tinkering with F# recently and found that ML languages are perfect for parsing. Is there a version of this in F# or ocaml?
[1] https://medium.com/@javierwchavarri/building-the-super-tiny-...
https://www.masswerk.at/demospace/eal/eal.htm
See the page source for the code. (Probably fun, old syntax both for HTML and JS, pre-ECMA JavaScript [meaning, the semicolon isn't a delimiter, but a separator], even the indentation style is outdated. Mind that back then, even the support of JS object literals wasn't guaranteed.)
Syntax, etc: https://www.masswerk.at/demospace/eal/syntax.htm
Byte code reference: https://www.masswerk.at/demospace/eal/pcode.htm
https://www.destroyallsoftware.com/screencasts/catalog/a-com...
I don't know my dates well enough. But is there anything in here that isn't at least 50 years old?
The high-level is tokenize->parse->ast_transform->codegen.
The low-level looks like `char = input[++current];`