bs-js-compiler.txt 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. ometa BSJSParser <: 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. iName = firstAndRest(#nameFirst, #nameRest):r -> r.join(''),
  7. isKeyword :x = ?BSJSParser._isKeyword(x),
  8. name = iName:n ~isKeyword(n) -> [#name, n=='self' ? '$elf' : n],
  9. keyword = iName:k isKeyword(k) -> [k, k],
  10. hexDigit = char:x {this.hexDigits.indexOf(x.toLowerCase())}:v ?(v >= 0) -> v,
  11. hexLit = hexLit:n hexDigit:d -> (n * 16 + d)
  12. | hexDigit,
  13. number = ``0x'' hexLit:n -> [#number, n]
  14. | digit+:ws ('.' digit+ | empty -> []):fs -> [#number, parseFloat(ws.join('') + '.' +
  15. fs.join(''))],
  16. escapeChar = '\\' char:c -> unescape('\\' + c),
  17. str = seq('"""') (escapeChar | ~seq('"""') char)*:cs seq('"""') -> [#string, cs.join('')]
  18. | '\'' (escapeChar | ~'\'' char)*:cs '\'' -> [#string, cs.join('')]
  19. | '"' (escapeChar | ~'"' char)*:cs '"' -> [#string, cs.join('')]
  20. | ('#' | '`') iName:n -> [#string, n],
  21. special = ( '(' | ')' | '{' | '}' | '[' | ']' | ','
  22. | ';' | '?' | ':' | ``!=='' | ``!='' | ``==='' | ``==''
  23. | ``='' | ``>='' | '>' | ``<='' | '<' | ``++'' | ``+=''
  24. | '+' | ``--'' | ``-='' | '-' | ``*='' | '*' | ``/=''
  25. | '/' | ``%='' | '%' | ``&&='' | ``&&'' | ``||='' | ``||''
  26. | '.' | '!' ):s -> [s, s],
  27. tok = spaces (name | keyword | number | str | special),
  28. toks = token*:ts spaces end -> ts,
  29. token :tt = tok:t ?(t[0] == tt) -> t[1],
  30. spacesNoNl = (~'\n' space)*,
  31. expr = orExpr:e ( "?" expr:t ":" expr:f -> [#condExpr, e, t, f]
  32. | "=" expr:rhs -> [#set, e, rhs]
  33. | "+=" expr:rhs -> [#mset, e, "+", rhs]
  34. | "-=" expr:rhs -> [#mset, e, "-", rhs]
  35. | "*=" expr:rhs -> [#mset, e, "*", rhs]
  36. | "/=" expr:rhs -> [#mset, e, "/", rhs]
  37. | "%=" expr:rhs -> [#mset, e, "%", rhs]
  38. | "&&=" expr:rhs -> [#mset, e, "&&", rhs]
  39. | "||=" expr:rhs -> [#mset, e, "||", rhs]
  40. | empty -> e
  41. ),
  42. orExpr = orExpr:x "||" andExpr:y -> [#binop, "||", x, y]
  43. | andExpr,
  44. andExpr = andExpr:x "&&" eqExpr:y -> [#binop, "&&", x, y]
  45. | eqExpr,
  46. eqExpr = eqExpr:x ( "==" relExpr:y -> [#binop, "==", x, y]
  47. | "!=" relExpr:y -> [#binop, "!=", x, y]
  48. | "===" relExpr:y -> [#binop, "===", x, y]
  49. | "!==" relExpr:y -> [#binop, "!==", x, y]
  50. )
  51. | relExpr,
  52. relExpr = relExpr:x ( ">" addExpr:y -> [#binop, ">", x, y]
  53. | ">=" addExpr:y -> [#binop, ">=", x, y]
  54. | "<" addExpr:y -> [#binop, "<", x, y]
  55. | "<=" addExpr:y -> [#binop, "<=", x, y]
  56. | "instanceof" addExpr:y -> [#binop, "instanceof", x, y]
  57. )
  58. | addExpr,
  59. addExpr = addExpr:x "+" mulExpr:y -> [#binop, "+", x, y]
  60. | addExpr:x "-" mulExpr:y -> [#binop, "-", x, y]
  61. | mulExpr,
  62. mulExpr = mulExpr:x "*" unary:y -> [#binop, "*", x, y]
  63. | mulExpr:x "/" unary:y -> [#binop, "/", x, y]
  64. | mulExpr:x "%" unary:y -> [#binop, "%", x, y]
  65. | unary,
  66. unary = "-" postfix:p -> [#unop, "-", p]
  67. | "+" postfix:p -> [#unop, "+", p]
  68. | "++" postfix:p -> [#preop, "++", p]
  69. | "--" postfix:p -> [#preop, "--", p]
  70. | "!" unary:p -> [#unop, "!", p]
  71. | "void" unary:p -> [#unop, "void", p]
  72. | "delete" unary:p -> [#unop, "delete", p]
  73. | "typeof" unary:p -> [#unop, "typeof", p]
  74. | postfix,
  75. postfix = primExpr:p ( spacesNoNl "++" -> [#postop, "++", p]
  76. | spacesNoNl "--" -> [#postop, "--", p]
  77. | empty -> p
  78. ),
  79. primExpr = primExpr:p ( "[" expr:i "]" -> [#getp, i, p]
  80. | "." "name":m "(" listOf(#expr, ','):as ")" -> [#send, m, p].concat(as)
  81. | "." "name":f -> [#getp, [#string, f], p]
  82. | "(" listOf(#expr, ','):as ")" -> [#call, p].concat(as)
  83. )
  84. | primExprHd,
  85. primExprHd = "(" expr:e ")" -> e
  86. | "this" -> [#this]
  87. | "name":n -> [#get, n]
  88. | "number":n -> [#number, n]
  89. | "string":s -> [#string, s]
  90. | "function" funcRest
  91. | "new" "name":n "(" listOf(#expr, ','):as ")" -> [#new, n].concat(as)
  92. | "[" listOf(#expr, ','):es "]" -> [#arr].concat(es)
  93. | json,
  94. json = "{" listOf(#jsonBinding, ','):bs "}" -> [#json].concat(bs),
  95. jsonBinding = jsonPropName:n ":" expr:v -> [#binding, n, v],
  96. jsonPropName = "name" | "number" | "string",
  97. formal = spaces "name",
  98. funcRest = "(" listOf(#formal, ','):fs ")" "{" srcElems:body "}" -> [#func, fs, body],
  99. sc = spacesNoNl ('\n' | &'}' | end)
  100. | ";",
  101. binding = "name":n ( "=" expr
  102. | empty -> [#get, 'undefined'] ):v -> [#var, n, v],
  103. block = "{" srcElems:ss "}" -> ss,
  104. stmt = block
  105. | "var" listOf(#binding, ','):bs sc -> [#begin].concat(bs)
  106. | "if" "(" expr:c ")" stmt:t ( "else" stmt
  107. | empty -> [#get, 'undefined'] ):f -> [#if, c, t, f]
  108. | "while" "(" expr:c ")" stmt:s -> [#while, c, s]
  109. | "do" stmt:s "while" "(" expr:c ")" sc -> [#doWhile, s, c]
  110. | "for" "(" ( "var" binding
  111. | expr
  112. | empty -> [#get, 'undefined'] ):i
  113. ";" ( expr
  114. | empty -> [#get, 'true'] ):c
  115. ";" ( expr
  116. | empty -> [#get, 'undefined'] ):u
  117. ")" stmt:s -> [#for, i, c, u, s]
  118. | "for" "(" ( "var" "name":n -> [#var, n, [#get, 'undefined']]
  119. | expr ):v
  120. "in" expr:e
  121. ")" stmt:s -> [#forIn, v, e, s]
  122. | "switch" "(" expr:e ")" "{"
  123. ( "case" expr:c ":" srcElems:cs -> [#case, c, cs]
  124. | "default" ":" srcElems:cs -> [#default, cs] )*:cs
  125. "}" -> [#switch, e].concat(cs)
  126. | "break" sc -> [#break]
  127. | "continue" sc -> [#continue]
  128. | "throw" spacesNoNl expr:e sc -> [#throw, e]
  129. | "try" block:t "catch" "(" "name":e ")" block:c
  130. ( "finally" block
  131. | empty -> [#get, 'undefined'] ):f -> [#try, t, e, c, f]
  132. | "return" ( expr
  133. | empty -> [#get, 'undefined'] ):e sc -> [#return, e]
  134. | "with" "(" expr:x ")" stmt:s -> [#with, x, s]
  135. | expr:e sc -> e
  136. | ";" -> [#get, "undefined"],
  137. srcElem = "function" "name":n funcRest:f -> [#var, n, f]
  138. | stmt,
  139. srcElems = srcElem*:ss -> [#begin].concat(ss),
  140. topLevel = srcElems:r spaces end -> r
  141. }
  142. BSJSParser.hexDigits = "0123456789abcdef"
  143. BSJSParser.keywords = { }
  144. keywords = ["break", "case", "catch", "continue", "default", "delete", "do", "else", "finally", "for", "function", "if", "in",
  145. "instanceof", "new", "return", "switch", "this", "throw", "try", "typeof", "var", "void", "while", "with", "ometa"]
  146. for (var idx = 0; idx < keywords.length; idx++)
  147. BSJSParser.keywords[keywords[idx]] = true
  148. BSJSParser._isKeyword = function(k) { return this.keywords.hasOwnProperty(k) }
  149. ometa BSSemActionParser <: BSJSParser {
  150. curlySemAction = "{" expr:r sc "}" spaces -> r
  151. | "{" (srcElem:s &srcElem -> s)*:ss
  152. ( expr:r sc -> [#return, r] | srcElem):s {ss.push(s)}
  153. "}" spaces -> [#send, #call,
  154. [#func, [], [#begin].concat(ss)],
  155. [#this]],
  156. semAction = curlySemAction
  157. | primExpr:r spaces -> r
  158. }
  159. ometa BSJSTranslator {
  160. trans = [:t apply(t):ans] -> ans,
  161. curlyTrans = [#begin curlyTrans:r] -> r
  162. | [#begin trans*:rs] -> ('{' + rs.join(';') + '}')
  163. | trans:r -> ('{' + r + '}'),
  164. this -> 'this',
  165. break -> 'break',
  166. continue -> 'continue',
  167. number :n -> ('(' + n + ')'),
  168. string :s -> s.toProgramString(),
  169. arr trans*:xs -> ('[' + xs.join(',') + ']'),
  170. unop :op trans:x -> ('(' + op + ' ' + x + ')'),
  171. getp trans:fd trans:x -> (x + '[' + fd + ']'),
  172. get :x -> x,
  173. set trans:lhs trans:rhs -> ('(' + lhs + '=' + rhs + ')'),
  174. mset trans:lhs :op trans:rhs -> ('(' + lhs + op + '=' + rhs + ')'),
  175. binop :op trans:x trans:y -> ('(' + x + ' ' + op + ' ' + y + ')'),
  176. preop :op trans:x -> (op + x),
  177. postop :op trans:x -> (x + op),
  178. return trans:x -> ('return ' + x),
  179. with trans:x curlyTrans:s -> ('with(' + x + ')' + s),
  180. if trans:cond curlyTrans:t curlyTrans:e -> ('if(' + cond + ')' + t + 'else' + e),
  181. condExpr trans:cond trans:t trans:e -> ('(' + cond + '?' + t + ':' + e + ')'),
  182. while trans:cond curlyTrans:body -> ('while(' + cond + ')' + body),
  183. doWhile curlyTrans:body trans:cond -> ('do' + body + 'while(' + cond + ')'),
  184. for trans:init trans:cond trans:upd
  185. curlyTrans:body -> ('for(' + init + ';' + cond + ';' + upd + ')' + body),
  186. forIn trans:x trans:arr curlyTrans:body -> ('for(' + x + ' in ' + arr + ')' + body),
  187. begin trans:x end -> x,
  188. begin (trans:x
  189. ( (?(x[x.length - 1] == '}') | end) -> x
  190. | empty -> (x + ';')
  191. )
  192. )*:xs -> ('{' + xs.join('') + '}'),
  193. func :args curlyTrans:body -> ('(function (' + args.join(',') + ')' + body + ')'),
  194. call trans:fn trans*:args -> (fn + '(' + args.join(',') + ')'),
  195. send :msg trans:recv trans*:args -> (recv + '.' + msg + '(' + args.join(',') + ')'),
  196. new :cls trans*:args -> ('new ' + cls + '(' + args.join(',') + ')'),
  197. var :name trans:val -> ('var ' + name + '=' + val),
  198. throw trans:x -> ('throw ' + x),
  199. try curlyTrans:x :name curlyTrans:c curlyTrans:f -> ('try ' + x + 'catch(' + name + ')' + c + 'finally' + f),
  200. json trans*:props -> ('({' + props.join(',') + '})'),
  201. binding :name trans:val -> (name.toProgramString() + ': ' + val),
  202. switch trans:x trans*:cases -> ('switch(' + x + '){' + cases.join(';') + '}'),
  203. case trans:x trans:y -> ('case ' + x + ': '+ y),
  204. default trans:y -> ('default: ' + y)
  205. }