bs-ometa-compiler.txt 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. ometa BSOMetaParser <: Parser {
  2. fromTo :x :y = seq(x) (~seq(y) char)* seq(y),
  3. space = ^space | fromTo('//', '\n') | fromTo('/*', '*/'),
  4. nameFirst = '_' | '$' | letter,
  5. nameRest = nameFirst | digit,
  6. tsName = firstAndRest(#nameFirst, #nameRest):xs -> xs.join(''),
  7. name = spaces tsName,
  8. eChar = '\\' char:c -> unescape('\\' +c)
  9. | char,
  10. tsString = '\'' (~'\'' eChar)*:xs '\'' -> xs.join(''),
  11. characters = '`' '`' (~('\'' '\'') eChar)*:xs '\'' '\'' -> [#App, #seq, xs.join('').toProgramString()],
  12. sCharacters = '"' (~'"' eChar)*:xs '"' -> [#App, #token, xs.join('').toProgramString()],
  13. string = (('#' | '`') tsName | tsString):xs -> [#App, #exactly, xs.toProgramString()],
  14. number = ('-' | empty -> ''):sign digit+:ds -> [#App, #exactly, sign + ds.join('')],
  15. keyword :xs = token(xs) ~letterOrDigit -> xs,
  16. args = '(' listOf(#hostExpr, ','):xs ")" -> xs
  17. | empty -> [],
  18. application = "^" name:rule args:as -> [#App, "super", "'" + rule + "'"].concat(as)
  19. | name:grm "." name:rule args:as -> [#App, "foreign", grm, "'" + rule + "'"].concat(as)
  20. | name:rule args:as -> [#App, rule].concat(as),
  21. hostExpr = BSSemActionParser.expr:r BSJSTranslator.trans(r),
  22. curlyHostExpr = BSSemActionParser.curlySemAction:r BSJSTranslator.trans(r),
  23. primHostExpr = BSSemActionParser.semAction:r BSJSTranslator.trans(r),
  24. atomicHostExpr = curlyHostExpr | primHostExpr,
  25. semAction = curlyHostExpr:x -> [#Act, x]
  26. | "!" atomicHostExpr:x -> [#Act, x],
  27. arrSemAction = "->" atomicHostExpr:x -> [#Act, x],
  28. semPred = "?" atomicHostExpr:x -> [#Pred, x],
  29. expr = expr5(true):x ("|" expr5(true))+:xs -> [#Or, x].concat(xs)
  30. | expr5(true):x ("||" expr5(true))+:xs -> [#XOr, x].concat(xs)
  31. | expr5(false),
  32. expr5 :ne = interleavePart:x ("&&" interleavePart)+:xs -> [#Interleave, x].concat(xs)
  33. | expr4(ne),
  34. interleavePart = "(" expr4(true):part ")" -> ["1", part]
  35. | expr4(true):part modedIPart(part),
  36. modedIPart = [#And [#Many :part]] -> ["*", part]
  37. | [#And [#Many1 :part]] -> ["+", part]
  38. | [#And [#Opt :part]] -> ["?", part]
  39. | :part -> ["1", part],
  40. expr4 :ne = expr3*:xs arrSemAction:act -> [#And].concat(xs).concat([act])
  41. | ?ne expr3+:xs -> [#And].concat(xs)
  42. | ?(ne == false) expr3*:xs -> [#And].concat(xs),
  43. optIter :x = '*' -> [#Many, x]
  44. | '+' -> [#Many1, x]
  45. | '?' -> [#Opt, x]
  46. | empty -> x,
  47. optBind :x = ':' name:n -> { this.locals.push(n); [#Set, n, x] }
  48. | empty -> x,
  49. expr3 = ":" name:n -> { this.locals.push(n); [#Set, n, [#App, #anything]] }
  50. | (expr2:x optIter(x) | semAction):e optBind(e)
  51. | semPred,
  52. expr2 = "~" expr2:x -> [#Not, x]
  53. | "&" expr1:x -> [#Lookahead, x]
  54. | expr1,
  55. expr1 = application
  56. | ( keyword('undefined') | keyword('nil')
  57. | keyword('true') | keyword('false') ):x -> [#App, #exactly, x]
  58. | spaces (characters | sCharacters | string | number)
  59. | "[" expr:x "]" -> [#Form, x]
  60. | "<" expr:x ">" -> [#ConsBy, x]
  61. | "@<" expr:x ">" -> [#IdxConsBy, x]
  62. | "(" expr:x ")" -> x,
  63. ruleName = name
  64. | spaces tsString,
  65. rule = &(ruleName:n) !(this.locals = ['$elf=this', '_fromIdx=this.input.idx'])
  66. rulePart(n):x ("," rulePart(n))*:xs -> [#Rule, n, this.locals, [#Or, x].concat(xs)],
  67. rulePart :rn = ruleName:n ?(n == rn) expr4:b1 ( "=" expr:b2 -> [#And, b1, b2]
  68. | empty -> b1
  69. ),
  70. grammar = keyword('ometa') name:n
  71. ( "<:" name | empty -> 'OMeta' ):sn
  72. "{" listOf(#rule, ','):rs "}" BSOMetaOptimizer.optimizeGrammar(
  73. [#Grammar, n, sn].concat(rs)
  74. )
  75. }
  76. // By dispatching on the head of a list, the following idiom allows translators to avoid doing a linear search.
  77. // (Note that the "=" in a rule definition is optional, so you can give your rules an "ML feel".)
  78. ometa BSOMetaTranslator {
  79. App 'super' anything+:args -> [this.sName, '._superApplyWithArgs(this,', args.join(','), ')'] .join(''),
  80. App :rule anything+:args -> ['this._applyWithArgs("', rule, '",', args.join(','), ')'] .join(''),
  81. App :rule -> ['this._apply("', rule, '")'] .join(''),
  82. Act :expr -> expr,
  83. Pred :expr -> ['this._pred(', expr, ')'] .join(''),
  84. Or transFn*:xs -> ['this._or(', xs.join(','), ')'] .join(''),
  85. XOr transFn*:xs {xs.unshift((this.name + "." + this.rName).toProgramString())}
  86. -> ['this._xor(', xs.join(','), ')'] .join(''),
  87. And notLast(#trans)*:xs trans:y
  88. {xs.push('return ' + y)} -> ['(function(){', xs.join(';'), '}).call(this)'] .join(''),
  89. And -> 'undefined',
  90. Opt transFn:x -> ['this._opt(', x, ')'] .join(''),
  91. Many transFn:x -> ['this._many(', x, ')'] .join(''),
  92. Many1 transFn:x -> ['this._many1(', x, ')'] .join(''),
  93. Set :n trans:v -> [n, '=', v] .join(''),
  94. Not transFn:x -> ['this._not(', x, ')'] .join(''),
  95. Lookahead transFn:x -> ['this._lookahead(', x, ')'] .join(''),
  96. Form transFn:x -> ['this._form(', x, ')'] .join(''),
  97. ConsBy transFn:x -> ['this._consumedBy(', x, ')'] .join(''),
  98. IdxConsBy transFn:x -> ['this._idxConsumedBy(', x, ')'] .join(''),
  99. JumpTable jtCase*:cases -> this.jumpTableCode(cases),
  100. Interleave intPart*:xs -> ['this._interleave(', xs.join(','), ')'] .join(''),
  101. Rule :name {this.rName = name}
  102. locals:ls trans:body -> ['\n"', name, '":function(){', ls, 'return ', body, '}'] .join(''),
  103. Grammar :name :sName
  104. {this.name = name}
  105. {this.sName = sName}
  106. trans*:rules -> [name, '=objectThatDelegatesTo(', sName, ',{', rules.join(','), '})'].join(''),
  107. intPart = [:mode transFn:part] -> (mode.toProgramString() + "," + part),
  108. jtCase = [:x trans:e] -> [x.toProgramString(), e],
  109. locals = [string+:vs] -> ['var ', vs.join(','), ';'] .join('')
  110. | [] -> '',
  111. trans = [:t apply(t):ans] -> ans,
  112. transFn = trans:x -> ['(function(){return ', x, '})'] .join('')
  113. }
  114. BSOMetaTranslator.jumpTableCode = function(cases) {
  115. var buf = new StringBuffer()
  116. buf.nextPutAll("(function(){switch(this._apply('anything')){")
  117. for (var i = 0; i < cases.length; i += 1)
  118. buf.nextPutAll("case " + cases[i][0] + ":return " + cases[i][1] + ";")
  119. buf.nextPutAll("default: throw fail}}).call(this)")
  120. return buf.contents()
  121. }