Last active
January 1, 2016 00:39
-
-
Save stianeikeland/8067556 to your computer and use it in GitHub Desktop.
XMASLANG to Javascript compiler - AST from jison
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%lex | |
%% | |
\s+ /* skip whitespace */ | |
\n+ /* skip whitespace */ | |
[0-9]+ return 'NUMBER' | |
"->" return 'MAP' | |
"=?" return 'FILTER' | |
"$" return 'REDUCE' | |
"*" return '*' | |
"KAKE" return 'KAKE' | |
"/" return '/' | |
"#" return 'LIST' | |
"-" return '-' | |
"+" return '+' | |
"%" return '%' | |
">" return '>' | |
"=" return '=' | |
"|" return 'RUNFUNC' | |
"[" return '[' | |
"]" return ']' | |
[a-zA-Z]+ return 'VAR' | |
"?" return "IF" | |
"<" return 'FUNCSTART' | |
<<EOF>> return 'EOF' | |
. return 'INVALID' | |
/lex | |
%start expressions | |
%% /* language grammar */ | |
expressions | |
: e EOF | |
{ typeof console !== 'undefined' ? console.log($1) : print($1); | |
return $1; } | |
; | |
e | |
: '+' e e | |
{{ $$ = {type: '+', a: $2, b: $3};}} | |
| '-' e e | |
{{ $$ = {type: '-', a: $2, b: $3};}} | |
| '*' e e | |
{{ $$ = {type: '*', a: $2, b: $3};}} | |
| '/' e e | |
{{ $$ = {type: '/', a: $2, b: $3};}} | |
| '%' e e | |
{{ $$ = {type: '%', a: $2, b: $3};}} | |
| 'FUNCSTART' e e '>' '[' e ']' | |
{{ | |
$$ = {type: 'FUNCRUN', arg: $2, body: $3, val: $6} | |
}} | |
| 'FUNCSTART' e e '>' | |
{{ | |
$$ = {type: 'FUNCTION', arg: $2, body: $3}; | |
}} | |
| '>' e e | |
{{ $$ = {type: '>', a: $2, b: $3};}} | |
| '=' e e | |
{{ $$ = {type: '==', a: $2, b: $3};}} | |
| 'VAR' | |
{{ $$ = {type: 'VAR', name: $1};}} | |
| 'MAP' e e | |
{{ | |
$$ = {type: 'MAP', list: $2, func: $3} | |
}} | |
| 'FILTER' e e | |
{{ | |
$$ = {type: 'FILTER', list: $2, func: $3} | |
}} | |
| 'REDUCE' e e e e | |
{{ | |
$$ = {type: 'REDUCE', list: $2, var: $3, initial: $4, func: $5} | |
}} | |
| 'KAKE' e e | |
{{ | |
$$ = ['KAKE', $2, $3]; | |
}} | |
| 'RUNFUNC' e e | |
{{ | |
$$ = {type: "RUNFUNC", func: $3, arg: $2} | |
}} | |
| 'IF' e e e | |
{{ | |
$$ = {type: 'IF', test: $2, a: $3, b: $4}; | |
}} | |
| 'LIST' e | |
{{ | |
$$ = {type: 'LIST', a: $2} | |
}} | |
| NUMBER | |
{{ | |
$$ = {type: 'INT', value: Number(yytext)}; | |
}} | |
; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
parser = (require './ast').parser | |
assert = require 'assert' | |
programmet = ' | |
-+ | |
+/|+5++3 1 1 <x +2x> | |
$->#2<x 1>s 1<i+s i> | |
+||#5<x ->x<y+$x z 100 <k - z k | |
>y> > <x $x a 0 <b +a b> > | - | |
$ ->#10<x#x>x0<y+x$y z0<y+y z>> | |
$ ->->#30<x+x1> <x% | |
$->#10<a*a$=?->#<foo?=foo*2 | |
4<bar*+foo bar bar>[-20 15] | |
100000>[ | |
|->#||1 <x+1x> | |
<x+1x> | |
<x |1 <x+1x>> | |
<r $r p 0 <q +p q> > | |
]<i+100i> <x>x100> | |
acc 0 < item + acc item > > | |
merryxmas 1<b + merryxmas b> | |
x> | |
ac 0 < m + m ac > | |
<x*113x> | |
|||*|||1<x 1><x+|1<x 1>x><x* | |
||1<x 1><x+|1<x 1>x>x> | |
|||1<x 1><x+|1<x 1>x><x+ | |
||1<x 1><x+||1<x 1><x+ | |
|1<x 1>x>x>x><x+ | |
|||1<x 1><x+|1<x 1>x><x+ | |
||1<x 1><x+||1<x 1><x+ | |
|1<x 1>x>x>x>x><x+|* | |
|||1<x 1><x+|1<x 1>x><x* | |
||1<x 1><x+|1<x 1>x>x> | |
|||1<x 1><x+|1<x 1>x><x+ | |
||1<x 1><x+||1<x 1><x+ | |
|1<x 1>x>x>x><x+|||1<x 1><x+ | |
|1<x 1>x><x+||1<x 1><x+ | |
||1<x 1><x+ | |
|1<x 1>x>x>x>x>x><x+||* | |
|||1<x 1><x+|1<x 1>x><x* | |
||1<x 1><x+|1<x 1>x>x> | |
|||1<x 1><x+|1<x 1>x><x+ | |
||1<x 1><x+||1<x 1><x+ | |
|1<x 1>x>x>x><x+|||1<x 1><x+ | |
|1<x 1>x><x+||1<x 1><x+ | |
||1<x 1><x+|1<x 1>x>x>x>x><x+ | |
|*|||1<x 1><x+|1<x 1>x><x* | |
||1<x 1><x+|1<x 1>x>x> | |
|||1<x 1><x+|1<x 1>x><x+ | |
||1<x 1><x+||1<x 1><x+ | |
|1<x 1>x>x>x><x+|||1<x 1><x+ | |
|1<x 1>x><x+||1<x 1><x+ | |
||1<x 1><x+|1<x 1>x>x>x>x>x>x> | |
||#80 <r =?r <e > e 80>> | |
<s $s acc 0 <i + a i>> | |
' | |
reduceTemplate = '(function() { | |
var __arr = %%LIST%%; | |
var %%ACCNAME%% = %%ACCVALUE%%; | |
var __func = %%FUNCTION%%; | |
for (var __i = 0; __i < __arr.length; __i++) { | |
%%ACCNAME%% = __func(__arr[__i]); | |
} | |
return %%ACCNAME%%; | |
})()' | |
genList = (listEnd) -> | |
"((function(_end){var _arr = [];for(var _i = 0; _i <= _end; _i++){_arr.push(_i);};return _arr;})(#{listEnd}))" | |
genIf = (node) -> | |
t = p node.test | |
a = p node.a | |
b = p node.b | |
"((#{t}) ? #{a} : #{b})" | |
genFunc = (node) -> | |
arg = p node.arg | |
body = p node.body | |
"(function(#{arg}){return (#{body});})" | |
runFunc = (node) -> | |
func = p node.func | |
arg = p node.arg | |
"((#{func})(#{arg}))" | |
genMap = (node) -> | |
list = p node.list | |
func = p node.func | |
"((#{list}).map(#{func}))" | |
genFilter = (node) -> | |
list = p node.list | |
func = p node.func | |
"((#{list}).filter(#{func}))" | |
genReduce = (node) -> | |
list = p node.list | |
func = p node.func | |
variable = p node.var | |
initial = p node.initial | |
template = reduceTemplate | |
template = template.replace /%%ACCNAME%%/g, variable | |
template = template.replace /%%LIST%%/g, list | |
template = template.replace /%%ACCVALUE%%/g, initial | |
template = template.replace /%%FUNCTION%%/g, func | |
template | |
genRunFunc = (node) -> | |
val = p node.val | |
body = p node.body | |
arg = p node.arg | |
"((function(#{arg}){return (#{body});})(#{val}))" | |
p = (node) -> | |
switch node.type | |
when "INT" then "(#{node.value})" | |
when "*" then "(#{p node.a} * #{p node.b})" | |
when "+" then "(#{p node.a} + #{p node.b})" | |
when "-" then "(#{p node.a} - #{p node.b})" | |
when "/" then "(#{p node.a} / #{p node.b})" | |
when "%" then "(#{p node.a} % #{p node.b})" | |
when ">" then "(#{p node.a} > #{p node.b})" | |
when "==" then "(#{p node.a} == #{p node.b})" | |
when "VAR" then "#{node.name}" | |
when "LIST" then genList p node.a | |
when "IF" then genIf node | |
when "FUNCTION" then genFunc node | |
when "RUNFUNC" then runFunc node | |
when "MAP" then genMap node | |
when "FILTER" then genFilter node | |
when "REDUCE" then genReduce node | |
when "FUNCRUN" then genRunFunc node | |
else throw Error 'Not implemented' | |
e = (prog) -> eval p parser.parse prog | |
ep = (prog) -> console.log e prog | |
debug = (prog) -> console.log p parser.parse prog | |
ep programmet | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
assert.equal 2, e "2" | |
assert.equal 6, e "* 2 3" | |
assert.equal 5, e "+ 2 3" | |
assert.equal 1, e "- 3 2" | |
assert.equal 3, e "/ 6 2" | |
assert.equal 2, e "% 6 4" | |
assert.ok e "> 6 4" | |
assert.ok e "= 6 6" | |
assert.deepEqual [0..5], e "#5" | |
assert.equal 3, e "? > 3 2 3 2" | |
assert.equal 3, e "<x + x 1>[2]" | |
assert.equal 3, e "| 2 <x + x 1>" | |
assert.deepEqual [0,5,10], e "-> #2 <x * x 5>" | |
assert.deepEqual [2], e "=? #2 <x > x 1>" | |
assert.equal 4, e "$ #2 kake 1 < x + kake x>" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment