Skip to content

Instantly share code, notes, and snippets.

@stianeikeland
Last active January 1, 2016 00:39
Show Gist options
  • Save stianeikeland/8067556 to your computer and use it in GitHub Desktop.
Save stianeikeland/8067556 to your computer and use it in GitHub Desktop.
XMASLANG to Javascript compiler - AST from jison
%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)};
}}
;
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
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