Skip to content

Instantly share code, notes, and snippets.

@moriyoshi
Created July 27, 2013 08:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save moriyoshi/6094257 to your computer and use it in GitHub Desktop.
Save moriyoshi/6094257 to your computer and use it in GitHub Desktop.
var xaxtsuxo = (function () {
var KEYWORDS = {
'division': 'DIVISION',
'end': 'END',
'run': 'RUN',
'if': 'IF',
'then': 'THEN',
'for': 'FOR',
'in': 'IN',
'or': 'OR',
'ana': 'AND',
'to': 'TO',
'by': 'BY',
'on': 'ON',
'upon': 'UPON',
'at': 'AT',
'from': 'FROM',
'with': 'WITH',
'yields': 'YIELDS',
'true': 'true',
'false': 'false',
'->': 'YIELDS',
'+=': 'ADD_ASSIGN',
'-=': 'SUB_ASSIGN',
'*=': 'MUL_ASSIGN',
'/=': 'DIV_ASSIGN',
'&&': 'AND_SIGN',
'||': 'OR_SIGN',
'.': 'EOS',
'(': 'LPAREN',
')': 'RPAREN',
'[': 'LBRACKET',
']': 'RBRACKET',
'{': 'LBRACE',
'}': 'RBRACE',
'&': 'BITWISE_AND',
'|': 'BITWISE_OR',
'^': 'BITWISE_XOR',
'!': 'NOT_SIGN',
'*': 'MUL_SIGN',
'+': 'ADD_SIGN',
'/': 'DIV_SIGN',
'-': 'SUB_SIGN',
';': 'SEMICOLON',
':': 'COLON'
};
function createTokenizer(s) {
var TOKEN_REGEX = /(\r\n|\r|\n)|([ \t]+)|([ぁぃぅぇぉっゃゅょ]+)|(<\?php)|(division|end|if|then|for|in|or|and|not|to|by|on|upon|at|from|with|yields|true|false|->|\+=|-=|\*=|\/=|&&|\|\||[.,:;()[\]{}~&|!^*+\/-])|([a-zA-Z_][a-zA-Z0-9_]*)|((?:[0-9]+(>:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?)/gi;
var line = 0, column = 0, undone = [], eof = false;
var retval = function () {
if (undone.length > 0) {
return undone.shift();
}
var m = null;
var retval = null;
if (!eof)
m = TOKEN_REGEX.exec(s);
if (!m) {
eof = true;
return ['EOF', null, line, column];
}
if (m[1]) {
retval = ['EOL', m[0], line, column];
line++;
column = 0;
return retval;
} else if (m[2]) {
retval = ['WS', m[0], line, column];
} else if (m[3]) {
retval = ['ぁっぉ', m[0], line, column];
} else if (m[4]) {
retval = ['PHP', m[0], line, column];
} else if (m[6]) {
retval = ['IDENT', m[0], line, column];
} else if (m[7]) {
retval = ['NUMBER', m[0], line, column];
} else if (m[5]) {
retval = [KEYWORDS[m[0].toLowerCase()], m[0], line, column];
}
column += m[0].length;
return retval;
};
retval.undo = function (t) {
undone.push(t);
};
return retval;
}
function humanFriendlyEnum(list) {
if (list.length == 0) {
throw 'list is empty';
} else if (list.length == 1) {
return list[0];
} else {
return list.slice(0, list.length - 1).join(', ') + ' and ' + list[list.length - 1];
}
}
function parse(_) {
var STATEMENTS = {
assign: function () {
var t;
var numberOrVariable = parseExpr();
if ((t = __())[0] != 'TO') {
syntaxError(['TO'], t);
}
var variable = parseVariable();
t = __();
if (t[0] != 'EOL' && t[0] != 'EOS')
syntaxError(['EOL', 'EOS'], t);
_.undo(t);
return {
t: 'ASSIGN',
c: [
variable,
numberOrVariable
]
};
},
add: function () {
var t;
var numberOrVariable = parseExpr();
if ((t = __())[0] != 'TO') {
syntaxError(['TO'], t);
}
var variable = parseVariable();
t = __();
if (t[0] != 'EOL' && t[0] != 'EOS')
syntaxError(['EOL', 'EOS'], t);
_.undo(t);
return {
t: 'ASSIGN',
c: [
variable,
{
t: 'ADD',
c: [ variable, numberOrVariable ]
}
]
};
},
sub: function () {
var t;
var numberOrVariable = parseExpr();
if ((t = __())[0] != 'FROM') {
syntaxError(['FROM'], t);
}
var variable = parseVariable();
t = __();
if (t[0] != 'EOL' && t[0] != 'EOS')
syntaxError(['EOL', 'EOS'], t);
_.undo(t);
return {
t: 'ASSIGN',
c: [
variable,
{
t: 'SUB',
c: [ variable, numberOrVariable ]
}
]
};
},
multiply: function () {
var t;
var variable = parseVariable();
if ((t = __())[0] != 'BY') {
syntaxError(['BY'], t);
}
var numberOrVariable = parseExpr();
t = __();
if (t[0] != 'EOL' && t[0] != 'EOS')
syntaxError(['EOL', 'EOS'], t);
_.undo(t);
return {
t: 'ASSIGN',
c: [
variable,
{
t: 'MULTIPLY',
c: [ variable, numberOrVariable ]
}
]
};
},
display: function () {
var t;
var io = null;
var numberOrVariable = parseExpr();
t = __();
switch (t[0]) {
case 'EOL':
case 'EOS':
_.undo(t);
break;
case 'UPON':
io = parseIO();
break;
default:
syntaxError(['EOL', 'EOS', 'UPON'], t);
}
return {
t: 'DISPLAY',
c: [ io, numberOrVariable ]
};
},
stop: function () {
var t = __();
if (t[0] != 'IDENT' && t[1].toLowerCase() != 'run')
syntaxError(['RUN'], t);
return { t: 'STOP', c: null };
}
};
var kw = [];
for (var k in STATEMENTS)
kw.push(k.toUpperCase());
function __() {
var t;
do {
t = _();
} while (t[0] == 'WS');
return t;
}
function syntaxError(expecting, t) {
throw 'Expecting ' + humanFriendlyEnum(expecting) + ', got ' + t[1] + ' at line ' + (t[2] + 1) + ', column ' + (t[3] + 1);
}
function parseExpr() {
var t = __();
switch (t[0]) {
case 'NUMBER':
return {
t: 'NUMBER',
c: t[1]
};
case 'IDENT':
return {
t: 'VARIABLE',
c: t[1]
};
case 'TRUE':
return {
t: 'BOOL',
c: true
};
case 'FALSE':
return {
t: 'BOOL',
c: false
};
default:
syntaxError(['NUMBER', 'IDENT'], t);
}
}
function parseVariable() {
var t = __();
if (t[0] != 'IDENT')
syntaxError(['IDENT'], t);
return {
t: 'VARIABLE',
c: t[1]
};
}
function parseIO() {
var t = __();
if (t[0] != 'IDENT')
syntaxError(['IDENT'], t);
return {
t: 'IO',
c: t[1]
};
}
function parseYields(ident) {
return {
t: 'FUNCTION',
c: parseStatements()
};
}
function parseStatements() {
var retval = [];
for (;;) {
var t = __();
switch (t[0]) {
case 'IDENT':
var nt = __();
if (nt[0] == 'YIELDS') {
retval.push(parseYields(t));
} else {
_.undo(nt);
var stmt = STATEMENTS[t[1].toLowerCase()];
if (!stmt) {
syntaxError(kw.concat(['EOL', 'EOS']), t);
}
retval.push(stmt());
}
case 'EOL':
break;
case 'EOS':
return retval;
default:
syntaxError(['IDENT', 'EOL', 'EOS'], t);
}
}
}
function parseDivision() {
var t;
t = __();
switch (t[0]) {
case 'ぁっぉ':
if ((t = __())[0] != 'DIVISION') {
syntaxError(['DIVISION'], t);
}
if ((t = __())[0] != 'EOS') {
syntaxError(['EOS'], t);
}
if ((t = __())[0] != 'EOL') {
syntaxError(['EOL'], t);
}
return {
t: 'ぁっぉ',
c: parseStatements()
};
case 'PHP':
return {
t: 'ぁっぉ',
c: parseStatements()
};
default:
syntaxError(['ぁっぉ', 'PHP'], t);
}
}
return parseDivision();
}
var evaluate = (function () {
var x = {
'ぁっぉ': function (ctx, n) {
for (var i = 0; i < n.c.length; i++)
evaluate(ctx, n.c[i]);
},
ASSIGN: function (ctx, n) {
return (ctx.vars[n.c[0].c] = evaluate(ctx, n.c[1]));
},
ADD: function (ctx, n) {
return evaluate(ctx, n.c[0]) + evaluate(ctx, n.c[1]);
},
MULTIPLY: function (ctx, n) {
return evaluate(ctx, n.c[0]) * evaluate(ctx, n.c[1]);
},
VARIABLE: function (ctx, n) {
var val = ctx.vars[n.c];
if (val === void(0))
throw "variable " + n.c + " is not defined";
return val;
},
NUMBER: function (ctx, n) {
return eval(n.c);
},
DISPLAY: function (ctx, n) {
switch ((n.c[0].c || 'console').toLowerCase()) {
case 'dialog':
alert(evaluate(ctx, n.c[1]));
break;
case 'console':
console.log(evaluate(ctx, n.c[1]));
break;
}
},
STOP: function (ctx, n) {}
};
function evaluate(ctx, n) { return x[n.t](ctx, n); }
return evaluate;
})();
var compileNode = (function () {
var stream = [];
var x = {
'ぁっぉ': function (ctx, n) {
var retval = [];
for (var i = 0; i < n.c.length; i++)
retval.push.apply(retval, compileNode(ctx, n.c[i]).concat([';', '\n']));
return retval;
},
ASSIGN: function (ctx, n) {
ctx.vars[n.c[0].c] = true;
return [n.c[0].c, ' = '].concat(compileNode(ctx, n.c[1]));
},
ADD: function (ctx, n) {
return ['('].concat(compileNode(ctx, n.c[0])).concat([' + ']).concat(compileNode(ctx, n.c[1])).concat([')']);
},
MULTIPLY: function (ctx, n) {
return ['('].concat(compileNode(ctx, n.c[0])).concat([' * ']).concat(compileNode(ctx, n.c[1])).concat([')'])
},
VARIABLE: function (ctx, n) {
var val = ctx.vars[n.c];
if (val === void(0))
throw "variable " + n.c + " is not defined";
return [n.c];
},
NUMBER: function (ctx, n) {
return [n.c];
},
DISPLAY: function (ctx, n) {
switch ((n.c[0].c || 'console').toLowerCase()) {
case 'dialog':
return ['alert', '('].concat(compileNode(ctx, n.c[1])).concat([')']);
case 'console':
return ['console.log', '('].concat(compileNode(ctx, n.c[1])).concat([')']);
}
},
STOP: function (ctx, n) { return []; }
};
function compileNode(ctx, n) { return x[n.t](ctx, n); }
return compileNode;
})();
return {
createTokenizer: createTokenizer,
parse: parse,
compileNode: compileNode,
compile: function compile(script) {
return compileNode({ vars: {} }, parse(createTokenizer(script))).join('');
}
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment