- Domain Specific Language (DSL) for sharing data or making a task simpler
- template language (dust, handlebars, lisplate)
- maybe you want your own ES2017 to ES5
- port a language/environment (porting Smallbasic to a browser)
- create a whole new langauge
- "Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should."
- A task may require a custom DSL to process data from a 3rd party API
- It can be a learning experience to better understand how languages you use work, thus becoming better
- Just please don't fill the world with DSLs for everything
- why do people use NodeJS? Is it because they don't want to use different languages? People aren't going to learn a very specific DSL if they don't have to
- what is a compiler? compilers use some magic to take my code and make an executable, right?
- no. they are just programs too
- compilers just transform some input into some output
- think of a compiler as a giant "map" function
- sound just like every other program you wrote?
- Technically, a transpiler is a compiler. The definition of a compiler is a program which transforms a source language into a destination language.
- the term "compiler" is generally used when the end result is machine code, bytecode, assembly-like
- "transpiler" is generally used when the end result is another high level language
- there are 4 main steps to processing
- parsing -> AST -> transform -> output code
- the parsing step makes sense of source code and turns it into something that can be manipulated later
- generally, there's another step (tokenizing), but some parsers do this at the same time
- PEG (Parsing Expression Grammer) is a language to describe languages
- PEGjs is a tool to take PEG syntax with embedded JS and generate a parser for you
- Each statement defined in PEGjs will have a return which specifies the AST
- Dust?
- lisplate
- Smallbasic
- Abstract Syntax Trees store information at nodes about what the user wanted
- an AST can be represented in many ways. Objects, arrays, it's all up to you
- the critical thing is you have a consistent method and a way to differentiate "If" from "For"
- A Literal knows it has a literal which may be an Integer
- A block knows it has a list of things to do
- An If node knows it has a condition, a block, and it may have an else block
- A For node knows it has an initial, a condition, a step, and a block
- Transformations take a tree and produce a new tree
- Recursion becomes your friend as you dive through the nodes
- Optimizations (dead code elimination, using a more efficient form like x*2 == x << 1, etc)
- Reducing complex nodes into a combination of simpler nodes
- This is an optional step, not everyone will require transforms
-
output code can just about be anything
-
This is somewhat like a transform step where we produce code instead of a new tree
-
machine code / assembly
-
JavaScript ES5 / ES6
-
Some horribly looking form of JS that runs in a browser by unreadable to anyone
-
Some other "Intermediate language" for another thing to process
-
think about what nodes you have. Maybe you have an If node. What does If look like in your target language?
-
['if', [myCondition, thenBlock, elseBlock]] -> if (myCondition) { outputBlock(thenBlock) } else { outputBlock(elseBlock) }
-
turn that into a function like "outputIfStatement(astNode: AST): String"
-
we also would need an "outputBlock(astNode: AST): String" that is called
- A group of functions that your end users use to do things
- string.length, Date functions, look at MDN at how big the standard library is
- you may compile to a language (such as JS) and just pass through to that language's standard library.
- you may have a combination, some pass through, and some you extend what is available