A gentle introduction to the JavaScript AST
or
How I learned to stop worrying and build my own tools and transforms
://about#me
- Björn Brauer
- Hamburg
- Freelance (currently having fun at Costa Digital)
- JavaScript magician
- @ZauberNerd
- <3 programming, table foosball, close-up magic, beer
What we will talk about
- What is an AST?
- quick overview
- how is it generated?
- what is it used for?
- What can I do with it?
- learn about your language
- build custom transforms
- analyze your programs
- Questions & Answers
Quick overview
hh.js('2016-06-15'); hh.js('2016-06-15');Abstract(*) Syntax Tree
- Tree-like data structure
- represents the syntactic structure of source code
- generated by a parser (+ lexer)
- used for compilation, transpilation, etc
- (*) doesn't contain stylistic elements
/*spaces*/ hh.js(('2016-06-15')); // commentsHow is it generated?
v a r a n s w e r = 4 2 ;
- v
- va
- var
- var
- answer
- =
- 42
- ;
- answer
- answe
- answ
- ans
- an
- a
- 4
- 42
- =
- ;
[
{ type: "Keyword", value: "var" },
{ type: "Identifier", value: "answer" },
{ type: "Punctuator", value: "=" },
{ type: "Numeric", value: 42 },
{ type: "Punctuator", value: ";" },
]{
"type": "Program",
"body": [{
"type": "VariableDeclaration",
"kind": "var",
"declarations": [{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "answer"
},
"init": {
"type": "NumericLiteral",
"value": 42
}
}]
}]
}Tokens
AST
Lexer / Scanner
Parser
How is it generated?
- Grammar definitions
- Parser generators
How is it generated?
Grammar definition
%lex
DecimalDigit [0-9]
DecimalDigits [0-9]+
NonZeroDigit [1-9]
HexDigit [0-9a-fA-F]
UnicodeIdentifierStart [\xaa\xb5\xba\xc0-...]
UnicodeIdentifierPart [\xaa\xb5\xba\xc0-...]
IdentifierStart {UnicodeIdentifierStart}|[$_a-zA-Z]|("\\"[u]{HexDigit}{4})
IdentifierPart {IdentifierStart}|{UnicodeIdentifierPart}|[0-9]
Identifier {IdentifierStart}{IdentifierPart}*
SignedInteger [+-]?[0-9]+
LineContinuation \\(\r\n|\r|\n)
NonEscapeCharacter [^\'\"\\bfnrtv0-9xu]
CharacterEscapeSequence {SingleEscapeCharacter}|{NonEscapeCharacter}
EscapeSequence {CharacterEscapeSequence}|{OctalEscapeSequence}|{HexEscapeSequence}|{UnicodeEscapeSequence}
DoubleStringCharacter ([^\"\\\n\r]+)|(\\{EscapeSequence})|{LineContinuation}
SingleStringCharacter ([^\'\\\n\r]+)|(\\{EscapeSequence})|{LineContinuation}
StringLiteral (\"{DoubleStringCharacter}*\")|(\'{SingleStringCharacter}*\')How is it generated?
Grammar definition
%start Program /* Define Start Production */
%% /* Define Grammar Productions */
Statement
: Block
| VariableStatement
| ExpressionStatement
| IfStatement
| IterationStatement
| ReturnStatement
;
Block
: "{" StatementList "}"
{ $$ = new BlockStatementNode($2, createSourceLocation(null, @1, @3)); }
;
StatementList
: StatementList Statement
{ $$ = $1.concat($2); }
|
{ $$ = []; }
;
VariableStatement
: "VAR" VariableDeclarationList
{ $$ = new VariableDeclarationNode($2, "var", createSourceLocation(null, @1, @2)); }
;What is it used for?
- as part of a compiler (frontend)
- transpiling (transforming code to a different format)
- code completion
- checking / linting
- source maps
- ...many other things
What can I do with it?
Build your own transforms
-
babel plugins
- specify in .babelrc
- are run during transpilation
- changes code for the compiler/bundler
-
jscodeshift
- "codemods" are run on existing codebase
- change code in your own codebase
export default function ({types: t}) {
const canReplace = ({ specifiers }) => {
return specifiers.length > 0 && specifiers.every((specifier) => {
return t.isImportSpecifier(specifier)
&& specifier.imported.name !== 'default';
});
};
const replace = (specifiers) => {
return specifiers.map(({local, imported}) => {
return t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(local.name))],
t.stringLiteral(`react-router/lib/${imported.name}`)
);
});
};
return {
visitor: {
ImportDeclaration(path) {
if (path.node.source.value === 'react-router') {
if (canReplace(path.node)) {
path.replaceWithMultiple(replace(path.node.specifiers));
}
}
}
}
};
}
babel plugin transform-react-router-optimize
Analyze your programs
- custom eslint rules
- code intelligence
- statistics
Learn about your language
- deeper understanding of the language constructs
- insights into compiler theory
- AST explorer
Thank you!
Questions?
Introduction to the JavaScript AST
By Björn Brauer
Introduction to the JavaScript AST
A beginner friendly introduction to what the JS AST is, how it works and how you can use it to build powerful tools and transforms.
- 631