function unProgramString(s) { return Function('return ' + s).call(this) } function toCProgramString(s) { var args = []; var strings = []; // '+' is used for concatentation s = s.replace(/\.concat\(([^)]*)\)/g, function(x, code) { return " + " + code; }); // '%' is used for join s = s.replace(/\.join\((.*?)\)/g, function(x, code) { return " % " + code; }); // pull out strings s = s.replace(/(\".*?\")/g, function(x, str) { strings.push(str); return "^"; }); // pull out arguments s = s.replace(/([a-zA-Z][a-z-A-Z0-9]*)/g, function(x, name) { args.push(name); return "."; }); // push strings back s = s.replace(/\^/g, function(x, str) { return strings.shift(); }); // revert % to J s = s.replace(/%/g, function(x, str) { return "J"; }); if(s == ".") { return args[0]; } return "OMETA_CONTENT((" + s + (args.length ? "), ": ")") + args.join(", ") + ")"; } function format(source, data) { return source.replace(/<%(.*?)%>/g, function(x, code) { return Function('with(this){ return ' + code + '}').call(data) }) } ometa OMetaCTranslator { trans [:t apply(t):ans] -> ans, App 'super' :rule anything*:args -> format("ometa_applyWithArgs(this, \"^<% rule %>\", <% args.length %><% args.length ? ', ' : '' %><% args.join(', ') %>)", {rule: unProgramString(rule), args: args.map(toCProgramString) }), App 'foreign' :o :rule anything+:args -> format("ometa_foreign(this, <% o %>, <% rule %>, <% args.length %><% args.length ? ', ' : '' %><% args.join(', ') %>)", {o: o, rule: rule, args: args.map(toCProgramString) }), App :rule anything+:args -> format("ometa_applyWithArgs(this, \"<% rule %>\", <% args.length %>, <% args.join(', ') %>)", {rule: rule, args: args.map(toCProgramString) }), App :rule -> format("ometa_apply(this, \"<% rule %>\")", {rule: rule}), Act :expr -> toCProgramString(expr), Pred :expr -> format("ometa_pred(this, <% expr %>)", {expr: toCProgramString(expr)}), Or transFn*:xs -> format("ometa_or(this, <% xs.length %>, <% xs.join(', ') %>)", {xs: xs}), And trans*:xs -> format("({ <% xs.join('; ') %>; })", {xs: xs}), And -> "NULL", Many transFn:x -> format("ometa_many(this, <% x %>, NULL)", {x: x}), Many1 transFn:x -> format("ometa_many1(this, <% x %>)", {x: x}), Set :n trans:v -> format("<% n %> = <% v %>", {n: n, v: v}), Not transFn:x -> format("ometa_not(this, <% x %>)", {x: x}), Lookahead transFn:x -> format("ometa_lookahead(this, <% x %>)", {x: x}), Form transFn:x -> format("ometa_form(this, <% x %>)", {x: x}), ConsBy transFn:x -> format("ometa_consumedBy(this, <% x %>)", {x: x}), IdxConsBy transFn:x -> format("ometa_idxConsumedBy(this, <% x %>)", {x: x}), JumpTable jtCase*:cases -> this.jumpTableCode(cases), Interleave intPart*:xs -> format("ometa_interleave(this, <% xs.length/2 %>, <% xs.join(', ') %>)", {xs: xs}), Rule :name locals:ls trans:body -> format("OMETA_RULE(<% name %>, <% locals %>return <% body %>)", {name: name, locals: ls, body: body}), Grammar :name :sName trans*:rules -> format("OMETA(<% name %>, <% sName %>,\n\t<% rules.join('\\n\\t') %>)", {sName: sName, name: name, rules: rules}), intPart = [:mode transFn:part] -> (mode.toProgramString() + ", " + part), jtCase = [:x trans:e] -> [x.toProgramString(), e], locals = [:x :y local+:vs] -> format("struct ometaContent <% vs.join(', ') %>; ", {vs: vs}) | [anything*] -> '', local = string:s -> format("*<% s %>", {s: s}), transFn = trans:x -> format("({struct ometaContent *$$(void){return <% x %>;}$$;})", {x: x}) } OMetaCTranslator.jumpTableCode = function(cases) { var buf = new StringBuffer() buf.nextPutAll("({struct ometaContent *___x = OMETA_APPLY(anything);") for (var i = 0; i < cases.length; i += 1) buf.nextPutAll("ometaContent_same(___x, " + toCProgramString(cases[i][0]) + ") ? " + cases[i][1] + " : ") buf.nextPutAll("NULL;})") return buf.contents() } function myTranslateCode(s) { var translationError = function(m, i) { alert("Translation error - please tell Alex about this!"); throw fail }, tree = BSOMetaParser.matchAll(s, "grammar", undefined, function(m, i) { throw objectThatDelegatesTo(fail, {errorPos: i}) }) return OMetaCTranslator.match(tree, "trans", undefined, translationError) } myTranslateCode(""" ometa OMetaParser { fromTo :x :y = seq(x) (~seq(y) char)* seq(y), space = super(#space) | fromTo('//', '\n') | fromTo('/*', '*/'), nameFirst = '_' | '$' | letter, nameRest = nameFirst | digit, tsName = firstAndRest(#nameFirst, #nameRest):xs -> xs.join(''), name = spaces tsName, eChar = '\\' char:c -> ('\\' + c) | char, tsString = '\'' (~'\'' eChar)*:xs '\'' -> xs.join(''), characters = '`' '`' (~('\'' '\'') eChar)*:xs '\'' '\'' -> [`App, `seq, xs.join('')], sCharacters = '"' (~'"' eChar)*:xs '"' -> [`App, `token, xs.join('')], string = (('#' | '`') tsName | tsString):xs -> [`App, `exactly, xs], number = ('-' | empty -> ''):sign digit+:ds -> [`App, `exactly, sign + ds.join('')], keyword :xs = token(xs) ~letterOrDigit -> xs, hostExpr = foreign(BSSemActionParser, `expr):r foreign(BSJSTranslator, `trans, r), atomicHostExpr = foreign(BSSemActionParser, `semAction):r foreign(BSJSTranslator, `trans, r), args = '(' listOf(`hostExpr, ','):xs ")" -> xs | empty -> [], application = "^" name:rule args:as -> [`App, "^"+rule].concat(as) | name:grm "." name:rule args:as -> [`App, `foreign, grm, rule].concat(as) | name:rule args:as -> [`App, rule].concat(as), semAction = ("!" | "->") atomicHostExpr:x -> [`Act, x], semPred = "?" atomicHostExpr:x -> [`Pred, x], expr = listOf(#expr4, '|'):xs -> [`Or].concat(xs), expr4 = expr3*:xs -> [`And].concat(xs), optIter :x = "*" -> [`Many, x] | "+" -> [`Many1, x] | empty -> x, expr3 = expr2:x optIter(x):x ( ':' name:n -> [`Set, n, x] | empty -> x ) | ":" name:n -> [`Set, n, [`App, `anything]], expr2 = "~" expr2:x -> [`Not, x] | "&" expr1:x -> [`Lookahead, x] | expr1, expr1 = application | semAction | semPred | ( keyword('undefined') | keyword('nil') | keyword('true') | keyword('false') ):x -> [`App, #exactly, x] | spaces (characters | sCharacters | string | number) | "[" expr:x "]" -> [`Form, x] | "(" expr:x ")" -> x, ruleName = name | spaces tsString, rule = &(ruleName:n) rulePart(n):x ("," rulePart(n))*:xs -> [`Rule, n, [`Or, x].concat(xs)], rulePart :rn = ruleName:n ?(n == rn) expr4:b1 ( "=" expr:b2 -> [`And, b1, b2] | empty -> b1 ), grammar = keyword('ometa') name:n ( "<:" name | empty -> 'OMeta' ):sn "{" listOf(#rule, ','):rs "}" -> [`Grammar, n, sn].concat(rs) } """)