Install dependencies and run the tests:
➜ hello-jison git:(master) cd ast
➜ ast git:(master) npm test
> [email protected] test
> cd ast && npx mocha test/test.mjs
✓ transpile(test1.calc, out1.js)
✓ transpile(test2.calc, out2.js)
✓ transpile(test3.calc, out3.js)
3 passing (13ms)
In this folder we have the data
folder with
- the input files
test1.calc
,test2.calc
andtest3.calc
- the expected javascript output files
correct1.js
,correct2.js
andcorrect3.js
- the expected output files
correct-out1.txt
,correct-out2.txt
andcorrect-out3.txt
.
➜ ast git:(master) tree test
test
├── data
│ ├── correct-out1.txt
│ ├── correct-out2.txt
│ ├── correct-out3.txt
│ ├── correct1.js
│ ├── correct2.js
│ ├── correct3.js
│ ├── test1.calc
│ ├── test2.calc
│ └── test3.calc
├── test-description.mjs
└── test.mjs
1 directory, 11 files
The script calc2js.mjs
is a simple translator from infix minus expressions to JavaScript:
➜ ast git:(master) ✗ ./calc2js.mjs --help
Usage: calc2js [options] <filename>
Arguments:
filename file with the original code
Options:
-V, --version output the version number
-o, --output <filename> file in which to write the output
-h, --help display help for command
➜ ast git:(master) ✗ cat test/data/test1.calc
4 - 2 - 1
➜ ast git:(master) ✗ ./calc2js.mjs test/data/test1.calc
console.log(4 - 2 - 1);
The file minus-ast.jison is a simple parser from infix minus expressions expr
producing a espree compatible AST for the statement console.log(expr)
.
%{
const { buildRoot, buildBinaryExpression, buildLiteral } = require('./ast-build');
%}
%left '-'
%%
es: e { return buildRoot($1); }
;
e:
e '-' e { $$ = buildBinaryExpression($1, '-', $3) }
| N { $$ = buildLiteral($1); }
;
The script use_minus.js is a simple parser from infix minus expressions expr
producing a espree compatible AST for the statement console.log(expr)
. That is, we
wrap the input expression with a console.log
statement.
ast git:(master) ./use_minus.js "2-1-1" > ast.json
See the file ast.json for the output of the command above.
The script ast2js.js uses escodegen.generate to traverse a espree compatible AST producing as output the corresponding JavaScript:
➜ ast git:(master) ✗ ./ast2js.js './ast.json'
console.log(2 - 1 - 1);
It is simple to build the tree for a literal:
function buildLiteral(value) {
return {
type: "Literal",
value: Number(value),
raw: value,
};
}
To build the tree for a binary expression, we build the left and right children and then the binary expression itself:
function buildBinaryExpression(left, op, right) {
return {
type: "BinaryExpression",
left: left,
operator: op,
right: right,
};
}
The function buildRoot
in ast-build.js wraps the JS expression of the AST in a console.log
statement.:
function buildRoot(child) {
return {
type: "Program",
body: [
{
type: "ExpressionStatement",
expression: {
type: "CallExpression",
callee: {
type: "MemberExpression",
object: {
type: "Identifier",
name: "console",
},
property: {
type: "Identifier",
name: "log",
},
computed: false,
},
arguments: [child],
},
},
],
sourceType: "script",
};
}