Worlds2.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /*
  2. Copyright (c) 2008, 2010 Alessandro Warth <awarth@cs.ucla.edu>
  3. Limitations:
  4. * assignments into the properties of "arguments" (e.g., arguments[5] = 1234) don't modify their respective variables
  5. * for-in doesn't work when the loop variable is a property access (e.g., for (x.y in ys) ...)
  6. */
  7. Array.prototype.each = function(f) {
  8. for (var idx = 0; idx < this.length; idx++)
  9. f(this[idx], idx)
  10. }
  11. ometa WJSParser <: BSJSParser {
  12. isKeyword :x = ?(x == 'thisWorld')
  13. | super('isKeyword', x),
  14. primExprHd = "thisWorld" -> ['thisWorld']
  15. | super('primExprHd'),
  16. stmt = "in" expr:w block:b -> ['in', w, b]
  17. | super('stmt')
  18. }
  19. makeFunction = function(fs, body) {
  20. return '(function() { var staticScope = thisScope;' +
  21. ' var r = function() {' +
  22. ' var oldScope = thisScope;' +
  23. ' thisScope = staticScope.makeChild();' +
  24. ' thisScope.set("arguments", arguments);' +
  25. ' thisWorld.set(arguments, "length", arguments.length);' +
  26. ' for (var i = 0; i < arguments.length; i++) thisWorld.set(arguments, i, arguments[i]);' +
  27. ' try { ' + fs + body + '}' +
  28. ' finally { thisScope = oldScope }};' +
  29. ' baseWorld.set(r, "prototype", {parent: Object.prototype});' +
  30. ' return r })()' }
  31. makeIn = function(w, body) {
  32. return '{ try { worldStack.push(thisWorld); thisWorld = ' + w + '; ' + body + '} ' +
  33. 'finally { thisWorld = worldStack.pop() }' +
  34. 'undefined }'
  35. }
  36. makeForIn = function(v, e, s, decl) {
  37. var p = tempnam(), ps = tempnam()
  38. var r = 'for (var ' + p + ' in ' + ps + ' = thisWorld.props(' + e + ', {})) {' +
  39. 'if (!' + ps + '.hasOwnProperty(' + p + ')) continue; ' +
  40. 'thisScope.set("' + v + '", ' + p + '); ' + s +
  41. '}'
  42. if (decl)
  43. r = 'thisScope.decl("' + v + '", undefined); ' + r
  44. r = '{ var ' + ps + ' = undefined; ' + r + '}'
  45. return r
  46. }
  47. ometa WJSTranslator <: BSJSTranslator {
  48. initialize = { self.level = 0 },
  49. fargs = [anything*:fs] -> { var ss = []
  50. fs.each(function(v, i) { ss.push('thisScope.decl("' + v +
  51. '", arguments[' + i + ']);') })
  52. ss.join('') },
  53. thisWorld -> 'thisWorld',
  54. var :n trans:v -> ('thisScope.decl("' + n + '", ' + v + ')'),
  55. get :n -> ('thisScope.get("' + n + '")'),
  56. getp trans:p ['get' 'arguments'] -> ('arguments[' + p + ']'),
  57. getp trans:p trans:x -> ('thisWorld.get(' + x + ', ' + p + ')'),
  58. set ['get' :n] trans:v -> ('thisScope.set("' + n + '", ' + v + ')'),
  59. set ['getp' trans:p ['get' 'arguments']] trans:v -> 'UNSUPPORTED OPERATION',
  60. set ['getp' trans:p trans:x] trans:v -> ('thisWorld.set(' + x + ', ' + p + ', ' + v + ')'),
  61. mset ['get' :n] :op trans:rhs -> ('thisScope.set("' + n + '", thisScope.get("' + n + '")' + op + rhs + ')'),
  62. mset ['getp' trans:p trans:x] :op trans:rhs -> ('(function(r, p) { return thisWorld.set(r, p, thisWorld.get(r, p) ' +
  63. op + ' ' + rhs + ') })(' + x + ', ' + p + ')'),
  64. preop :op ['get' :n] -> ('thisScope.set("' + n + '", thisScope.get("' + n + '")' + op[0] + '1)'),
  65. preop :op ['getp' trans:p trans:x] -> ('(function(r, p) { return thisWorld.set(r, p, thisWorld.get(r, p) ' +
  66. op[0] + ' 1) })(' + x + ', ' + p + ')'),
  67. postop :op ['get' :n] -> ('(function(n) { var ans = thisScope.get(n); ' +
  68. 'thisScope.set(n, ans ' + op[0] + ' 1); ' +
  69. 'return ans })("' + n + '")'),
  70. postop :op ['getp' trans:p trans:x] -> ('(function(r, p) { var ans = thisWorld.get(r, p); ' +
  71. 'thisWorld.set(r, p, ans ' + op[0] + ' 1); ' +
  72. 'return ans })(' + x + ', ' + p + ')'),
  73. binop 'instanceof' trans:x trans:y -> ('instanceOf(' + x + ', ' + y + ')'),
  74. binop :op trans:x trans:y -> ('(' + x + ' ' + op + ' ' + y + ')'),
  75. call trans:f trans*:as -> ('(' + f + ')(' + as.join(',') + ')'),
  76. send :m trans:r trans*:as -> ('send("' + m + '", ' + r + ', [' + as.join(',') + '])'),
  77. new :x trans*:as -> ('thisScope.get("' + x + '").worldsNew(' + as.join(',') + ')'),
  78. func fargs:fs {self.level++} trans:body
  79. {self.level--} -> makeFunction(fs, body),
  80. in trans:w trans:b -> makeIn(w, b),
  81. arr trans*:xs -> ('[' + xs.join(',') + '].toWJSArray()'),
  82. json trans*:xs -> ('({' + xs.join(',') + '}).toWJSObject()'),
  83. try curlyTrans:x :name curlyTrans:c curlyTrans:f -> { var e = tempnam()
  84. 'try ' + x +
  85. 'catch(' + e + ') {thisScope.decl("' + name + '", ' + e + '); ' + c + '}' +
  86. 'finally' + f },
  87. forIn ['get' :v ] trans:e trans:s -> makeForIn(v, e, s, false),
  88. forIn ['var' :v :init] trans:e trans:s -> makeForIn(v, e, s, true)
  89. }
  90. compileWJS = function(code) {
  91. var tree = WJSParser.matchAll(code, "topLevel", undefined, function(m, i) { throw fail.delegated({errorPos: i}) })
  92. //print("parsed: " + tree)
  93. var code = WJSTranslator.match(tree, 'trans')
  94. //print("compiled: " + code)
  95. return code
  96. }
  97. thisScope.decl("eval", function(s) { return eval(compileWJS(s)) })
  98. oldPrint = print
  99. print = function(x) { oldPrint(x == undefined || x == null ? x : send("toString", x)) }
  100. translateCode = compileWJS