diff --git a/Objective-J/ObjJAcornCompiler.js b/Objective-J/ObjJAcornCompiler.js index 57657769b..e5aac0072 100644 --- a/Objective-J/ObjJAcornCompiler.js +++ b/Objective-J/ObjJAcornCompiler.js @@ -348,7 +348,7 @@ Program: function(node, st, c) { for (var i = 0; i < node.body.length; ++i) { c(node.body[i], st, "Statement"); } - CONCAT(st.compiler.jsBuffer,st.compiler.source.substring(st.compiler.lastPos, node.end)); + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.end)); // Check maybe warnings var maybeWarnings = st.maybeWarnings(); if (maybeWarnings) for (var i = 0; i < maybeWarnings.length; i++) { @@ -405,6 +405,37 @@ VariableDeclaration: function(node, scope, c) { } }, AssignmentExpression: function(node, st, c) { + if (node.left.type === "Dereference") { + // @deref(x) = z -> x(z) etc + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start)); + + // Output the dereference function, "(...)(z)" + CONCAT(st.compiler.jsBuffer, "("); + // What's being dereferenced could itself be an expression, such as when dereferencing a deref. + st.compiler.lastPos = node.left.expr.start; + c(node.left.expr, st, "Expression"); + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.left.expr.end)); + CONCAT(st.compiler.jsBuffer, ")("); + + // Now "(x)(...)". We have to manually expand +=, -=, *= etc. + if (node.operator !== "=") { + // Output the whole .left, not just .left.expr. + st.compiler.lastPos = node.left.start; + c(node.left, st, "Expression"); + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.left.end)); + CONCAT(st.compiler.jsBuffer, " " + node.operator.substring(0, 1) + " "); + } + + st.compiler.lastPos = node.right.start; + c(node.right, st, "Expression"); + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.right.end)); + CONCAT(st.compiler.jsBuffer, ")"); + + st.compiler.lastPos = node.end; + + return; + } + var saveAssignment = st.assignment; st.assignment = true; c(node.left, st, "Expression"); @@ -833,6 +864,26 @@ SelectorLiteralExpression: function(node, st, c) { CONCAT(st.compiler.jsBuffer, "\")"); st.compiler.lastPos = node.end; }, +Reference: function(node, st, c) { + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start)); + CONCAT(st.compiler.jsBuffer, "function(__input) { if (arguments.length) return "); + CONCAT(st.compiler.jsBuffer, node.element.name); + CONCAT(st.compiler.jsBuffer, " = __input; return "); + CONCAT(st.compiler.jsBuffer, node.element.name); + CONCAT(st.compiler.jsBuffer, "; }"); + st.compiler.lastPos = node.end; +}, +Dereference: function(node, st, c) { + // @deref(y) -> y() + // @deref(@deref(y)) -> y()() + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start)); + st.compiler.lastPos = node.expr.start; + c(node.expr, st, "Expression"); + CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.expr.end)); + CONCAT(st.compiler.jsBuffer, "()"); + st.compiler.lastPos = node.end; + +}, Literal: function(node, st, c) { if (node.raw && node.raw.charAt(0) === "@") { diff --git a/Objective-J/acorn.js b/Objective-J/acorn.js index d40104433..e4adc242e 100644 --- a/Objective-J/acorn.js +++ b/Objective-J/acorn.js @@ -274,6 +274,7 @@ if (!exports.acorn) { var _end = {keyword: "end"}, _import = {keyword: "import", afterImport: true}; var _action = {keyword: "action"}, _selector = {keyword: "selector"}, _class = {keyword: "class"}, _global = {keyword: "global"}; var _dictionaryLiteral = {keyword: "{"}, _arrayLiteral = {keyword: "["}; + var _ref = {keyword: "ref"}, _deref = {keyword: "deref"}; // Objective-J keywords @@ -302,7 +303,8 @@ if (!exports.acorn) { // Map Objective-J "@" keyword names to token types. var objJAtKeywordTypes = {"implementation": _implementation, "outlet": _outlet, "accessors": _accessors, "end": _end, - "import": _import, "action": _action, "selector": _selector, "class": _class, "global": _global}; + "import": _import, "action": _action, "selector": _selector, "class": _class, "global": _global, + "ref": _ref, "deref": _deref}; // Punctuation token types. Again, the `type` property is purely for debugging. @@ -1174,7 +1176,7 @@ if (!exports.acorn) { // to. function checkLVal(expr) { - if (expr.type !== "Identifier" && expr.type !== "MemberExpression") + if (expr.type !== "Identifier" && expr.type !== "MemberExpression" && expr.type !== "Dereference") raise(expr.start, "Assigning to rvalue"); if (strict && expr.type === "Identifier" && isStrictBadIdWord(expr.name)) raise(expr.start, "Assigning to " + expr.name + " in strict mode"); @@ -1924,6 +1926,26 @@ if (!exports.acorn) { expect(_parenR, "Expected closing ')' after selector"); return finishNode(node, "SelectorLiteralExpression"); + case _ref: + var node = startNode(); + next(); + expect(_parenL, "Expected '(' after '@ref'"); + node.element = parseIdent(node, _parenR); + expect(_parenR, "Expected closing ')' after ref"); + return finishNode(node, "Reference"); + + case _deref: + var node = startNode(); + next(); + expect(_parenL, "Expected '(' after '@deref'"); + node.expr = parseExpression(true, true); + expect(_parenR, "Expected closing ')' after deref"); + + if (node.expr.type !== "Identifier" && node.expr.type !== "MemberExpression" && node.expr.type !== "Reference" && node.expr.type !== "Dereference") + raise(node, "Dereference of " + node.expr.type); + + return finishNode(node, "Dereference"); + default: unexpected(); } diff --git a/Objective-J/acornwalk.js b/Objective-J/acornwalk.js index 470fbb88a..326d0dc72 100644 --- a/Objective-J/acornwalk.js +++ b/Objective-J/acornwalk.js @@ -228,6 +228,14 @@ if (!exports.acorn) { exports.SelectorLiteralExpression = ignore; + exports.Reference = function(node, st, c) { + c(node.element, st, "Identifier"); + } + + exports.Dereference = function(node, st, c) { + c(node.expr, st, "Expression"); + } + // A custom walker that keeps track of the scope chain and the // variables defined in it. function makeScope(prev) {