mirror of
https://github.com/jamiebuilds/the-super-tiny-compiler.git
synced 2024-10-27 20:34:08 +00:00
bdc62b6542
fixes #1
376 lines
14 KiB
JavaScript
376 lines
14 KiB
JavaScript
/**
|
|
* TTTTTTTTTTTTTTTTTTTTTTTHHHHHHHHH HHHHHHHHHEEEEEEEEEEEEEEEEEEEEEE
|
|
* T:::::::::::::::::::::TH:::::::H H:::::::HE::::::::::::::::::::E
|
|
* T:::::::::::::::::::::TH:::::::H H:::::::HE::::::::::::::::::::E
|
|
* T:::::TT:::::::TT:::::THH::::::H H::::::HHEE::::::EEEEEEEEE::::E
|
|
* TTTTTT T:::::T TTTTTT H:::::H H:::::H E:::::E EEEEEE
|
|
* T:::::T H:::::H H:::::H E:::::E
|
|
* T:::::T H::::::HHHHH::::::H E::::::EEEEEEEEEE
|
|
* T:::::T H:::::::::::::::::H E:::::::::::::::E
|
|
* T:::::T H:::::::::::::::::H E:::::::::::::::E
|
|
* T:::::T H::::::HHHHH::::::H E::::::EEEEEEEEEE
|
|
* T:::::T H:::::H H:::::H E:::::E
|
|
* T:::::T H:::::H H:::::H E:::::E EEEEEE
|
|
* TT:::::::TT HH::::::H H::::::HHEE::::::EEEEEEEE:::::E
|
|
* T:::::::::T H:::::::H H:::::::HE::::::::::::::::::::E
|
|
* T:::::::::T H:::::::H H:::::::HE::::::::::::::::::::E
|
|
* TTTTTTTTTTT HHHHHHHHH HHHHHHHHHEEEEEEEEEEEEEEEEEEEEEE
|
|
*
|
|
* SSSSSSSSSSSSSSS UUUUUUUU UUUUUUUUPPPPPPPPPPPPPPPPP EEEEEEEEEEEEEEEEEEEEEERRRRRRRRRRRRRRRRR
|
|
* SS:::::::::::::::SU::::::U U::::::UP::::::::::::::::P E::::::::::::::::::::ER::::::::::::::::R
|
|
* S:::::SSSSSS::::::SU::::::U U::::::UP::::::PPPPPP:::::P E::::::::::::::::::::ER::::::RRRRRR:::::R
|
|
* S:::::S SSSSSSSUU:::::U U:::::UUPP:::::P P:::::PEE::::::EEEEEEEEE::::ERR:::::R R:::::R
|
|
* S:::::S U:::::U U:::::U P::::P P:::::P E:::::E EEEEEE R::::R R:::::R
|
|
* S:::::S U:::::U U:::::U P::::P P:::::P E:::::E R::::R R:::::R
|
|
* S::::SSSS U:::::U U:::::U P::::PPPPPP:::::P E::::::EEEEEEEEEE R::::RRRRRR:::::R
|
|
* SS::::::SSSSS U:::::U U:::::U P:::::::::::::PP E:::::::::::::::E R:::::::::::::RR
|
|
* SSS::::::::SS U:::::U U:::::U P::::PPPPPPPPP E:::::::::::::::E R::::RRRRRR:::::R
|
|
* SSSSSS::::S U:::::U U:::::U P::::P E::::::EEEEEEEEEE R::::R R:::::R
|
|
* S:::::S U:::::U U:::::U P::::P E:::::E R::::R R:::::R
|
|
* S:::::S U::::::U U::::::U P::::P E:::::E EEEEEE R::::R R:::::R
|
|
* SSSSSSS S:::::S U:::::::UUU:::::::U PP::::::PP EE::::::EEEEEEEE:::::ERR:::::R R:::::R
|
|
* S::::::SSSSSS:::::S UU:::::::::::::UU P::::::::P E::::::::::::::::::::ER::::::R R:::::R
|
|
* S:::::::::::::::SS UU:::::::::UU P::::::::P E::::::::::::::::::::ER::::::R R:::::R
|
|
* SSSSSSSSSSSSSSS UUUUUUUUU PPPPPPPPPP EEEEEEEEEEEEEEEEEEEEEERRRRRRRR RRRRRRR
|
|
*
|
|
* TTTTTTTTTTTTTTTTTTTTTTTIIIIIIIIIINNNNNNNN NNNNNNNNYYYYYYY YYYYYYY
|
|
* T:::::::::::::::::::::TI::::::::IN:::::::N N::::::NY:::::Y Y:::::Y
|
|
* T:::::::::::::::::::::TI::::::::IN::::::::N N::::::NY:::::Y Y:::::Y
|
|
* T:::::TT:::::::TT:::::TII::::::IIN:::::::::N N::::::NY::::::Y Y::::::Y
|
|
* TTTTTT T:::::T TTTTTT I::::I N::::::::::N N::::::NYYY:::::Y Y:::::YYY
|
|
* T:::::T I::::I N:::::::::::N N::::::N Y:::::Y Y:::::Y
|
|
* T:::::T I::::I N:::::::N::::N N::::::N Y:::::Y:::::Y
|
|
* T:::::T I::::I N::::::N N::::N N::::::N Y:::::::::Y
|
|
* T:::::T I::::I N::::::N N::::N:::::::N Y:::::::Y
|
|
* T:::::T I::::I N::::::N N:::::::::::N Y:::::Y
|
|
* T:::::T I::::I N::::::N N::::::::::N Y:::::Y
|
|
* T:::::T I::::I N::::::N N:::::::::N Y:::::Y
|
|
* TT:::::::TT II::::::IIN::::::N N::::::::N Y:::::Y
|
|
* T:::::::::T I::::::::IN::::::N N:::::::N YYYY:::::YYYY
|
|
* T:::::::::T I::::::::IN::::::N N::::::N Y:::::::::::Y
|
|
* TTTTTTTTTTT IIIIIIIIIINNNNNNNN NNNNNNN YYYYYYYYYYYYY
|
|
*
|
|
* CCCCCCCCCCCCC OOOOOOOOO MMMMMMMM MMMMMMMMPPPPPPPPPPPPPPPPP IIIIIIIIIILLLLLLLLLLL EEEEEEEEEEEEEEEEEEEEEERRRRRRRRRRRRRRRRR
|
|
* CCC::::::::::::C OO:::::::::OO M:::::::M M:::::::MP::::::::::::::::P I::::::::IL:::::::::L E::::::::::::::::::::ER::::::::::::::::R
|
|
* CC:::::::::::::::C OO:::::::::::::OO M::::::::M M::::::::MP::::::PPPPPP:::::P I::::::::IL:::::::::L E::::::::::::::::::::ER::::::RRRRRR:::::R
|
|
* C:::::CCCCCCCC::::CO:::::::OOO:::::::OM:::::::::M M:::::::::MPP:::::P P:::::PII::::::IILL:::::::LL EE::::::EEEEEEEEE::::ERR:::::R R:::::R
|
|
* C:::::C CCCCCCO::::::O O::::::OM::::::::::M M::::::::::M P::::P P:::::P I::::I L:::::L E:::::E EEEEEE R::::R R:::::R
|
|
* C:::::C O:::::O O:::::OM:::::::::::M M:::::::::::M P::::P P:::::P I::::I L:::::L E:::::E R::::R R:::::R
|
|
* C:::::C O:::::O O:::::OM:::::::M::::M M::::M:::::::M P::::PPPPPP:::::P I::::I L:::::L E::::::EEEEEEEEEE R::::RRRRRR:::::R
|
|
* C:::::C O:::::O O:::::OM::::::M M::::M M::::M M::::::M P:::::::::::::PP I::::I L:::::L E:::::::::::::::E R:::::::::::::RR
|
|
* C:::::C O:::::O O:::::OM::::::M M::::M::::M M::::::M P::::PPPPPPPPP I::::I L:::::L E:::::::::::::::E R::::RRRRRR:::::R
|
|
* C:::::C O:::::O O:::::OM::::::M M:::::::M M::::::M P::::P I::::I L:::::L E::::::EEEEEEEEEE R::::R R:::::R
|
|
* C:::::C O:::::O O:::::OM::::::M M:::::M M::::::M P::::P I::::I L:::::L E:::::E R::::R R:::::R
|
|
* C:::::C CCCCCCO::::::O O::::::OM::::::M MMMMM M::::::M P::::P I::::I L:::::L LLLLLL E:::::E EEEEEE R::::R R:::::R
|
|
* C:::::CCCCCCCC::::CO:::::::OOO:::::::OM::::::M M::::::MPP::::::PP II::::::IILL:::::::LLLLLLLLL:::::LEE::::::EEEEEEEE:::::ERR:::::R R:::::R
|
|
* CC:::::::::::::::C OO:::::::::::::OO M::::::M M::::::MP::::::::P I::::::::IL::::::::::::::::::::::LE::::::::::::::::::::ER::::::R R:::::R
|
|
* CCC::::::::::::C OO:::::::::OO M::::::M M::::::MP::::::::P I::::::::IL::::::::::::::::::::::LE::::::::::::::::::::ER::::::R R:::::R
|
|
* CCCCCCCCCCCCC OOOOOOOOO MMMMMMMM MMMMMMMMPPPPPPPPPP IIIIIIIIIILLLLLLLLLLLLLLLLLLLLLLLLEEEEEEEEEEEEEEEEEEEEEERRRRRRRR RRRRRRR
|
|
*
|
|
* =======================================================================================================================================================================
|
|
* =======================================================================================================================================================================
|
|
* =======================================================================================================================================================================
|
|
* =======================================================================================================================================================================
|
|
*/
|
|
|
|
/**
|
|
* ============================================================================
|
|
* (/^▽^)/
|
|
* THE TOKENIZER!
|
|
* ============================================================================
|
|
*/
|
|
function tokenizer(input) {
|
|
var current = 0;
|
|
var tokens = [];
|
|
|
|
while (current < input.length) {
|
|
var char = input[current];
|
|
|
|
if (char === '(') {
|
|
tokens.push({
|
|
type: 'paren',
|
|
value: '('
|
|
});
|
|
current++;
|
|
continue;
|
|
}
|
|
|
|
if (char === ')') {
|
|
tokens.push({
|
|
type: 'paren',
|
|
value: ')'
|
|
});
|
|
current++;
|
|
continue;
|
|
}
|
|
|
|
var WHITESPACE = /\s/;
|
|
if (WHITESPACE.test(char)) {
|
|
current++;
|
|
continue;
|
|
}
|
|
|
|
var NUMBERS = /[0-9]/;
|
|
if (NUMBERS.test(char)) {
|
|
var value = '';
|
|
|
|
while (NUMBERS.test(char)) {
|
|
value += char;
|
|
char = input[++current];
|
|
}
|
|
|
|
tokens.push({
|
|
type: 'number',
|
|
value: value
|
|
});
|
|
|
|
continue;
|
|
}
|
|
|
|
var LETTERS = /[a-zA-Z]/;
|
|
if (LETTERS.test(char)) {
|
|
var value = '';
|
|
|
|
while (LETTERS.test(char)) {
|
|
value += char;
|
|
char = input[++current];
|
|
}
|
|
|
|
tokens.push({
|
|
type: 'name',
|
|
value: value
|
|
});
|
|
|
|
continue;
|
|
}
|
|
|
|
throw new TypeError('I dont know what this character is: ' + char);
|
|
}
|
|
|
|
return tokens;
|
|
}
|
|
|
|
/**
|
|
* ============================================================================
|
|
* ヽ/❀o ل͜ o\ノ
|
|
* THE PARSER!!!
|
|
* ============================================================================
|
|
*/
|
|
|
|
function parser(tokens) {
|
|
var current = 0;
|
|
|
|
function walk() {
|
|
var token = tokens[current];
|
|
|
|
if (token.type === 'number') {
|
|
current++;
|
|
|
|
return {
|
|
type: 'NumberLiteral',
|
|
value: token.value
|
|
};
|
|
}
|
|
|
|
if (
|
|
token.type === 'paren' &&
|
|
token.value === '('
|
|
) {
|
|
current++;
|
|
|
|
var node = {
|
|
type: 'CallExpression',
|
|
name: tokens[current].value,
|
|
params: []
|
|
};
|
|
|
|
current++;
|
|
|
|
while (
|
|
token.type !== 'paren' ||
|
|
token.value !== ')'
|
|
) {
|
|
node.params.push(walk());
|
|
token = tokens[current];
|
|
}
|
|
|
|
current++;
|
|
|
|
return node;
|
|
}
|
|
|
|
throw new TypeError(token.type);
|
|
}
|
|
|
|
var program = {
|
|
type: 'Program',
|
|
body: []
|
|
};
|
|
|
|
while (current < tokens.length) {
|
|
program.body.push(walk());
|
|
}
|
|
|
|
return program;
|
|
}
|
|
|
|
/**
|
|
* ============================================================================
|
|
* ⌒(❀>◞౪◟<❀)⌒
|
|
* THE TRAVERSER!!!
|
|
* ============================================================================
|
|
*/
|
|
|
|
function traverser(program, visitor) {
|
|
|
|
function traverseArray(array, parent) {
|
|
array.forEach(function(child) {
|
|
traverseNode(child, parent);
|
|
});
|
|
}
|
|
|
|
function traverseNode(node, parent) {
|
|
var method = visitor[node.type];
|
|
|
|
if (method) {
|
|
method(node, parent);
|
|
}
|
|
|
|
switch (node.type) {
|
|
case 'Program':
|
|
traverseArray(node.body, node);
|
|
break;
|
|
case 'CallExpression':
|
|
traverseArray(node.params, node);
|
|
break;
|
|
case 'NumberLiteral':
|
|
break;
|
|
default:
|
|
throw new TypeError(node.type);
|
|
}
|
|
}
|
|
|
|
traverseNode(program, null);
|
|
}
|
|
|
|
/**
|
|
* ============================================================================
|
|
* ⁽(◍˃̵͈̑ᴗ˂̵͈̑)⁽
|
|
* THE TRANSFORMER!!!
|
|
* ============================================================================
|
|
*/
|
|
|
|
function transformer(program) {
|
|
var ast = {
|
|
type: 'Program',
|
|
body: []
|
|
};
|
|
|
|
program._context = ast.body;
|
|
|
|
traverser(program, {
|
|
NumberLiteral: function(node, parent) {
|
|
parent._context.push({
|
|
type: 'NumberLiteral',
|
|
value: node.value
|
|
});
|
|
},
|
|
|
|
CallExpression: function(node, parent) {
|
|
var expression = {
|
|
type: 'CallExpression',
|
|
callee: {
|
|
type: 'Identifier',
|
|
name: node.name
|
|
},
|
|
arguments: []
|
|
};
|
|
|
|
node._context = expression.arguments;
|
|
|
|
if (parent.type !== 'CallExpression') {
|
|
expression = {
|
|
type: 'ExpressionStatement',
|
|
expression: expression
|
|
};
|
|
}
|
|
|
|
parent._context.push(expression);
|
|
}
|
|
});
|
|
|
|
return ast;
|
|
}
|
|
|
|
/**
|
|
* ============================================================================
|
|
* ヾ(〃^∇^)ノ♪
|
|
* THE CODE GENERATOR!!!!
|
|
* ============================================================================
|
|
*/
|
|
|
|
function codeGenerator(node) {
|
|
switch (node.type) {
|
|
case 'Program':
|
|
return node.body.map(codeGenerator)
|
|
.join('\n');
|
|
|
|
case 'ExpressionStatement':
|
|
return (
|
|
codeGenerator(node.expression) +
|
|
';'
|
|
);
|
|
|
|
case 'CallExpression':
|
|
return (
|
|
codeGenerator(node.callee) +
|
|
'(' +
|
|
node.arguments.map(codeGenerator)
|
|
.join(', ') +
|
|
')'
|
|
);
|
|
|
|
case 'Identifier':
|
|
return node.name;
|
|
|
|
case 'NumberLiteral':
|
|
return node.value;
|
|
|
|
default:
|
|
throw new TypeError(node.type);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ============================================================================
|
|
* (۶* ‘ヮ’)۶”
|
|
* !!!!!!!!THE COMPILER!!!!!!!!
|
|
* ============================================================================
|
|
*/
|
|
|
|
function compiler(input) {
|
|
var tokens = tokenizer(input);
|
|
var ast = parser(tokens);
|
|
var newAst = transformer(ast);
|
|
var output = codeGenerator(newAst);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
/**
|
|
* ============================================================================
|
|
* (๑˃̵ᴗ˂̵)و
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!YOU MADE IT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
* ============================================================================
|
|
*/
|
|
|
|
// Now I'm just exporting everything...
|
|
module.exports = {
|
|
tokenizer: tokenizer,
|
|
parser: parser,
|
|
transformer: transformer,
|
|
codeGenerator: codeGenerator,
|
|
compiler: compiler
|
|
};
|