// Oz Parser ometa OzParser <: Parser { lower = char:d ?(d >= 'a' && d <= 'z') -> d, upper = char:d ?(d >= 'A' && d <= 'Z') -> d, digit = char:d ?(d >= '0' && d <= '9') -> d.digitValue(), alphanum = lower | upper | digit | '_', number = number:n digit:d -> (10*n + d) | digit, oz_int = spaces number:i -> ['Int', i], oz_atom = spaces lower+:a -> ['Atom', a.join('')], oz_var = spaces upper:u alphanum*:vs -> ['Var', u+vs.join('')], label = oz_atom | oz_var, feature = oz_int | oz_atom | oz_var, field = spaces feature:f ':' subexp:e -> ['Field', f, e], oz_record= spaces label:l "(" field*:fs ")"-> ['Record', l, fs], basics = oz_record | "unit" -> ['Atom', 'unit'] | "false" -> ['Atom', 'false'] | "true" -> ['Atom', 'true'] | "_" -> ['Var', '_'] | oz_int | oz_var | oz_atom, subexp = basics | "(" exp:e ")" -> e, monoop = "~" -> 'Negate' | "!!" -> 'GetReadOnly' | "@" -> 'GetCellValue', binop = "+" -> 'Add' | "-" -> 'Sub', exp = monoop:m exp:e -> [m, e] | exp:e1 binop:b subexp:e2 -> [b, e1, e2] | subexp, decl = oz_var | stmt, stmt = stmt:s1 stmt:s2 -> ['Stmt', s1, s2] | "local" decl+:ds "in" stmt:s "end" -> ['Local', ds, s] | "proc" "{" exp:p exp+:a "}" stmt:b "end" -> ['Proc', p, a, b] | "{" exp:p exp+:a "}" -> ['ProcCall', p, a] | "if" exp:c "then" stmt:st "else" stmt:sf "end" -> ['If', c, st, sf] | "case" exp:e "of" basics:p "then" stmt:st "else" stmt:sf "end" -> ['Case', e, p, st, sf] | "lock" exp:e "then" stmt:s "end" -> ['Lock', e, s] | "thread" stmt:s "end" -> ['Thread', s] | "try" stmt:s "catch" exp:e "then" stmt:sf "end" -> ['Try', s, e, sf] | "raise" exp:e "end" -> ['Raise', e] | exp:e1 "=" exp:e2 -> ['Unify', e1, e2] | "skip" -> ['Skip'] } OzParser.matchAll('case 1 of 1 then skip else skip end', 'stmt') ometa ExtendedOzParser <: OzParser { list = exp:e list:l -> ['Record','|',[['Field', 1, e], ['Field', 2, l]]] | exp:e -> ['Record','|',[['Field', 1, e], ['Field', 2, ['Atom', 'nil']]]], exp = "[" list:l "]" -> l | subexp:fst "|" exp:snd -> ['Record','|',[['Field', 1, fst], ['Field', 2, snd]]] | super("exp") } ExtendedOzParser.matchAll('X|(Y+(X|Z))', 'exp') [Record, |, [[Field, 1, [Var, X]], [Field, 2, [Add, [Var, Y], [Record, |, [[Field, 1, [Var, X]], [Field, 2, [Var, Z]]]]]]]] ometa ClosureConversion { basic = ['Atom' anything]:oz_atom -> oz_atom | ['Int' anything]:oz_int -> oz_int | ['Var' anything]:oz_var {self.lookup(oz_var)}:oz_var2 -> oz_var2 | ['Record' anything:l fields:fs] -> ['Record', l, fs], fields = anything:fs -> fs, monoexp = [anything:op exp:e] -> [op, e], binexp = [anything:op exp:e1 exp:e2] -> [op, e1, e2], exp = basic | monoexp | binexp, decl = ['Var' anything]:v {self.add(v,v)} -> v, decls = [ decl+ ], stmt = ['Stmt' stmt:s1 stmt:s2] -> ['Stmt', s1, s2] | ['Local' decls:ds stmt:s1 {self.remove(ds)} ] -> ['Local', ds, s1] | ['Unify' exp:e1 exp:e2] -> ['Unify', e1, e2] | ['Proc' {self.env}:env2 {self.env = {}} anything:p // Using anything explicitly because otherwise the semantic action is used as a pattern { self.add(p,p) } decls:args { for (v in args) { self.add(v,v) } } stmt:s1 { self.remove([p]); self.remove(args); free = this.env this.env = env2} ] -> ['Proc', p, args, s1] | ['Skip'] } ClosureConversion.initialize = function() { this.env = {}; var v = ['Var', 'X']; this.env[v] = ['Var', 'Y']; this.field_nb = 0; } ClosureConversion.lookup = function(v) { var v2 = this.env[v]; if(v2 != undefined) { return v2; } else { v2 = ['GetField', ['Var', 'K'], this.field_nb++]; this.env[v] = v2; return v2; } } ClosureConversion.add = function(e1,e2) { this.env[e1] = e2; return e2; } ClosureConversion.remove = function(ds) { for (v in ds) { delete this.env[v]; } } ClosureConversion.proc_decl = function(p, args, stmt) { // Remove stuff so that free variables stand out } tree=OzParser.matchAll('proc {P A B} A=B X=B end A=A', 'stmt') ClosureConversion.match(tree, 'stmt') ometa CodeGen { basic = ['Atom' :a] -> a | ['Int' :i] -> i.toString() | ['Var' :v] -> v | ['Record' anything:l fields:fs] -> (l+'('+fs+')'), fields = anything:fs -> fs, exp = basic, decl = ['Var' :v] -> v, stmt = ['Stmt' stmt:s1 stmt:s2] -> (s1+s2) | ['Local' [decl+]:ds stmt:s1 ] -> ('{store_var_ref '+ds.join(' ')+'; '+s1+'}') | ['Unify' exp:e1 exp:e2] -> ('assert(unify('+e1+','+e2+'));') | ['Proc' :p decls:args stmt:s1] -> ('void '+p+'('+args+'){'+s1+'}') | ['Skip'] -> (';') } CodeGen.match(['Local',[['Var','A']], ['Skip']], 'stmt') CodeGen.match(['Unify', ['Var','A'], ['Var','A']], 'stmt') CodeGen.match(['Proc', ['Var','P'], [], ['Skip']])