eval(readFile("naerbnic-ometa2-base")) ometa OMeta2Parser <: Parser { nameFirst = '_' | '$' | letter, nameRest = nameFirst | digit, tsName = firstAndRest(#nameFirst, #nameRest):xs -> xs.join(''), name = spaces tsName, eChar = '\\' char:c -> unescape('\\' +c) | char, tsString = '\'' (~'\'' eChar)*:xs '\'' -> xs.join(''), characters = '`' '`' (~('\'' '\'') eChar)*:xs '\'' '\'' -> [#App, #seq, xs.join('').toProgramString()], sCharacters = '"' (~'"' eChar)*:xs '"' -> [#App, #token, xs.join('').toProgramString()], string = (('#' | '`') tsName | tsString):xs -> [#App, #exactly, xs.toProgramString()], number = ('-' | empty -> ''):sign digit+:ds -> [#App, #exactly, sign + ds.join('')], keyword :xs = token(xs) ~letterOrDigit -> xs, args = "(" listOf(#hostExpr, ','):xs ")" -> xs | empty -> [], application = name:rule args:as -> [#App, rule].concat(as), hostExpr = foreign(BSJSParser, #expr):r foreign(BSJSTranslator, #trans, r), atomicHostExpr = foreign(BSJSParser, #semAction):r foreign(BSJSTranslator, #trans, r), 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 = "<" hostExpr:he ">" -> [#HostExprApp, he] | 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, rule = name:n name+:args "=" expr:e -> [#RuleFunction, n, args, [#RuleBody, e]] | name:n "=" expr:e -> [#Rule, n, [#RuleBody, e]], rule = &(name:n) !(self.locals = ['$elf=this']) rulePart(n):x ("," rulePart(n))*:xs -> [#Rule, n, self.locals, [#Or, x].concat(xs)], rulePart :rn = name:n ?(n == rn) expr4:b1 ( "=" expr:b2 -> [#And, b1, b2] | empty -> b1 ), grammar = keyword('ometa') name:n ( "<:" name | empty -> 'OMeta2' ):sn "{" listOf(#rule, ','):rs "}" -> [#Grammar, n, sn].concat(rs) } // By dispatching on the head of a list, the following idiom allows translators to avoid doing a linear search. // (Note that the "=" in a rule definition is optional, which can be used to get an ML "feel".) ometa OMeta2Translator { trans [:t apply(t):ans] -> ans, App 'super' :name rulescope*:args -> ['$result = $result.applyNext($parser.super.getRule(', name, ').curry([', args.join(','),'), $parser)'].join(''), App :rule rulescope*:args -> ['$result = $result.applyNext(', rule, '.curry([' , args.join(','), ']), $parser)' ] .join(''), HostExprApp :code -> ['$result = $result.applyNext(', code, ', $parser)'] .join(''), Act :expr -> ['$result = $result.withValue(', expr, ')'].join(''), Pred :expr -> ['$parser.pred(', expr, ')'] .join(''), Or transFn*:xs -> ['$result = $parser.or($result.input,', xs.join(','), ')'] .join(''), And trans+:xs -> { ['(function(){', xs.join(';'), '})()'].join('') }, And -> '(function(){})', Many transFn:x -> ['$result = $parser.many($result.input,', x, ')'] .join(''), Many1 transFn:x -> ['$result = $parser.many1($result.input, ', x, ')'] .join(''), Set :n trans:v -> [v, '; $context.', n, '= $result.value'].join(''), Not transFn:x -> ['$result = $parser.not($result.input,', x, ')'] .join(''), Lookahead transFn:x -> ['$result = $parser.lookahead($result.input,', x, ')'] .join(''), Form transFn:x -> ['$result = $parser.form($result.input,', x, ')'] .join(''), RuleFunction :name fnargs:args trans:e -> ['"', name, '":function(', fnargs, '){', body, '}'] .join(''), Rule :name trans:body -> ['"', name, '": new Rule(', body, ').memoize("', name, '")'] .join(''), RuleBody trans:e -> ['function($parser, input){ var $result = new RuleInitial(input); var $context = $parser.rules.delegated({}); with($context){', e, '} return $result}'] .join(''), Grammar :name :sName !(self.sName = sName) trans*:rules -> [name, '=', sName, '.delegated({ super: ', sName, ', rules: ', sName, '.rules.delegated({', rules.join(','), '}) })'] .join(''), locals = [string+:vs] -> ['var ', vs.join(','), ';'] .join('') | [] -> '', transFn = trans:x -> ['new Rule(function($parser, $input){$result = new RuleInitial($input); ', x ,'; return $result})'].join(''), rulescope = trans:e -> e } ometa OMeta2JSParser <: BSJSParser { srcElem = spaces foreign(OMeta2Parser, #grammar):r sc -> r | super(#srcElem) } ometa OMeta2JSTranslator <: BSJSTranslator { Grammar = foreign(OMeta2Translator, #Grammar) } ast = OMeta2JSParser.matchAll(' ometa TestGrammar { number = digit+:dig anything:any end -> dig.concat([any]).join("") }', 'topLevel') getProperties = function(obj) { a = [] for(var x in obj) { a.push(x) } return a } //OMeta2JSTranslator.match(ast, 'trans') eval(OMeta2JSTranslator.match(ast, 'trans')) TestGrammar.matchAll('012a', 'number')