// 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
}

L.matchAll('6*(4+3)', 'expr')






// 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')






// 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') 

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')







// we can write 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)
 











// 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 + ')')
}

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)








