// a simple recognizer, produces no useful value ometa L { number = digit+, addExpr = addExpr '+' mulExpr | addExpr '-' mulExpr | mulExpr, mulExpr = mulExpr '*' primExpr | mulExpr '/' primExpr | primExpr, primExpr = '(' expr ')' | number, expr = addExpr } alert(L.matchAll('6*(4+3)', 'expr')) //This produces a ( for an unknown reason. // a recognizer that also interprets ometa Calc { digit = ^digit:d -> d.digitValue(), number = number:n digit:d -> (n * 10 + d) | digit, addExpr = addExpr:x '+' mulExpr:y -> (x + y) | addExpr:x '-' mulExpr:y -> (x - y) | mulExpr, mulExpr = mulExpr:x '*' primExpr:y -> (x * y) | mulExpr:x '/' primExpr:y -> (x / y) | primExpr, primExpr = '(' expr:x ')' -> x | number, expr = addExpr } Calc.matchAll('6*(4+3)', 'expr') //What is a ^ for and why is splitting the digits of a number up necessary? // parser and simple interpreter combo ometa CalcParser { digit = ^digit:d -> d.digitValue(), number = number:n digit:d -> (n * 10 + d) | digit, addExpr = addExpr:x '+' mulExpr:y -> ['add', x, y] | addExpr:x '-' mulExpr:y -> ['sub', x, y] | mulExpr, mulExpr = mulExpr:x '*' primExpr:y -> ['mul', x, y] | mulExpr:x '/' primExpr:y -> ['div', x, y] | primExpr, primExpr = '(' expr:x ')' -> x | number:n -> ['num', n], expr = addExpr } tree = CalcParser.matchAll('6*(4+3)', 'expr') //Neat non-typed functionality. Previous example will return answer, this returns the tree. ometa CalcInterpreter { interp = ['num' anything:x] -> x | ['add' interp:x interp:y] -> (x + y) | ['sub' interp:x interp:y] -> (x - y) | ['mul' interp:x interp:y] -> (x * y) | ['div' interp:x interp:y] -> (x / y) } CalcInterpreter.match(tree, 'interp') //takes a parse tree in and outputs the answer. Combining two previous examples. neat. // we can do a compiler instead ometa CalcCompiler { comp = ['num' anything:x] -> x.toString() | ['add' comp:x comp:y] -> ('(' + x + '+' + y + ')') | ['sub' comp:x comp:y] -> ('(' + x + '-' + y + ')') | ['mul' comp:x comp:y] -> ('(' + x + '*' + y + ')') | ['div' comp:x comp:y] -> ('(' + x + '/' + y + ')') } code = CalcCompiler.match(tree, 'comp') eval(code) 42 //First line outputs an equation, eval() evaluates it. //What does eval() it base it on? // spice things up with ML-like syntax ometa CalcCompiler { comp ['num' anything:x] -> x.toString(), comp ['add' comp:x comp:y] -> ('(' + x + '+' + y + ')'), comp ['sub' comp:x comp:y] -> ('(' + x + '-' + y + ')'), comp ['mul' comp:x comp:y] -> ('(' + x + '*' + y + ')'), comp ['div' comp:x comp:y] -> ('(' + x + '/' + y + ')') } //For some reason if you print it to this, you get [object Object]. what is that? code = CalcCompiler.match(tree, 'comp') eval(code) // a neat trick: dispatch on node tags using higher-order rule "apply" ometa CalcCompiler { comp [anything:t apply(t):ans] -> ans, num anything:x -> x.toString(), add comp:x comp:y -> ('(' + x + '+' + y + ')'), sub comp:x comp:y -> ('(' + x + '-' + y + ')'), mul comp:x comp:y -> ('(' + x + '*' + y + ')'), div comp:x comp:y -> ('(' + x + '/' + y + ')') } code = CalcCompiler.match(tree, 'comp') eval(code) //generics?