Browse files

for (own foo in bar). TODO: Figure out how to avoid making OWN a token

  • Loading branch information...
1 parent 88e8cd9 commit 0737f7635f10ce6cf85c992985cf90509f906974 @wycats committed Oct 16, 2011
Showing with 94 additions and 19 deletions.
  1. +7 −4 lib/grammar.y
  2. +1 −0 lib/lexer.l
  3. +3 −2 lib/nodes.js
  4. +54 −6 lib/stringify.js
  5. +29 −7 test/stringify-test.js
View
11 lib/grammar.y
@@ -863,7 +863,9 @@ IfStatement
;
IterationStatement
- : DO Statement WHILE '(' Expr ')' ';'
+ : FOR '(' OWN LeftHandSideExpr INTOKEN Expr ')' Statement
+ { $$ = yy.Node('ForInStatement', $LeftHandSideExpr, $Expr, $Statement, 'own', yy.loc([@$,@8])); }
+ | DO Statement WHILE '(' Expr ')' ';'
{ $$ = yy.Node('DoWhileStatement', $Statement, $Expr,yy.loc([@$,@7])); }
| DO Statement WHILE '(' Expr ')' error
{ $$ = yy.Node('DoWhileStatement', $Statement, $Expr,yy.loc([@$,@6])); }
@@ -884,13 +886,14 @@ IterationStatement
yy.Node('VariableDeclaration',"const", $4, yy.loc([@3,@4])),
$ExprOpt1, $ExprOpt2, $Statement, yy.loc([@$,@10])); }
| FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement
- { $$ = yy.Node('ForInStatement', $LeftHandSideExpr, $Expr, $Statement, false, yy.loc([@$,@7])); }
+ { $$ = yy.Node('ForInStatement',
+ $LeftHandSideExpr, $Expr, $Statement, null, yy.loc([@$,@7])); }
| FOR '(' VarOrLet Expr ')' Statement
{ $$ = yy.Node('ForInStatement', $3,
- $Expr, $Statement, false, yy.loc([@$,@6])); }
+ $Expr, $Statement, null, yy.loc([@$,@6])); }
| FOR '(' VarOrLetInitNoIn Expr ')' Statement
{ $$ = yy.Node('ForInStatement', $3,
- $Expr, $Statement, false, yy.loc([@$,@6])); }
+ $Expr, $Statement, null, yy.loc([@$,@6])); }
;
VarOrLet
View
1 lib/lexer.l
@@ -110,6 +110,7 @@ RCLASS "["({BSL}|[^\\\]])*"]"
"else" return 'ELSE'
"finally" return 'FINALLY'
"for" return 'FOR'
+"own" return 'OWN'
"function" return 'FUNCTION'
"if" return 'IF'
"in" return 'INTOKEN'
View
5 lib/nodes.js
@@ -271,11 +271,12 @@ def('ForStatement', function (init, test, update, body, loc) {
if (init) convertExprToPattern(init);
});
-def('ForInStatement', function (left, right, body, each, loc) {
+def('ForInStatement', function (left, right, body, type, loc) {
this.left = left;
this.right = right;
this.body = body;
- this.each = !!each;
+ this.each = type === 'each';
+ this.own = type === 'own';
this.loc = loc;
convertExprToPattern(left);
});
View
60 lib/stringify.js
@@ -5,7 +5,23 @@
var Reflect = require("./reflect");
-var indentChar = " ";
+var indentChar = " ", vars = [], currentVar = 0;
+
+var util = require("util")
+
+// TODO: Scope variables by function scope
+function getVar() {
+ var newVar;
+ if (currentVar === 0) {
+ newVar = "_ref";
+ } else {
+ newVar = "_ref" + currentVar;
+ }
+
+ currentVar++;
+ vars.push(newVar);
+ return newVar;
+}
function assertEq (val, expected) {
if (val !== expected)
@@ -543,7 +559,7 @@ function sourceElement(n, indent) {
}
case "ForInStatement":
- return indent + forHead(n, indent) + substmt(n.body, indent);
+ return decaf_handleOwn(n, indent) + indent + forHead(n, indent) + substmt(n.body, indent);
case "DoWhileStatement":
{
@@ -642,6 +658,31 @@ function decaf_handleFunctionDeclSpread(n) {
}
}
+function decaf_handleOwn(n, indent) {
+ if (n.own) {
+ var leftString = expr(n.left, indent, 0, false), varName, rightString, originalRight;
+
+ //console.log(n.right)
+
+ if (n.right.callee) {
+ rightString = varName = getVar();
+ originalRight = n.right;
+ n.right = { name: varName, loc: null, type: 'Identifier' }
+ } else {
+ rightString = expr(n.right, indent, 0, false);
+ }
+
+ var ast = Reflect.parse("if (!" + rightString + ".hasOwnProperty(" + leftString + ")) { continue; }");
+ n.body.body.unshift(ast.body[0]);
+
+ if (varName) {
+ return indent + varName + " = " + expr(originalRight, indent, 0, false) + ";\n";
+ }
+ }
+
+ return "";
+}
+
function decaf_handleCallSpread(n, indent, callback) {
var len = n.arguments.length - 1, params = n.arguments, spread, ast;
@@ -665,9 +706,9 @@ function decaf_handleCallSpread(n, indent, callback) {
// x.y.z
if (object2) {
- // TODO: More robust variable system
- var calleeString = "(var _ref=" + toString(object1) + ")." + toString(callee.property);
- var thisString = "_ref";
+ var ref = getVar();
+ var calleeString = "(" + ref + "=" + toString(object1) + ")." + toString(callee.property);
+ var thisString = ref;
// x.y
} else if (object1) {
var calleeString = toString(callee);
@@ -687,7 +728,14 @@ function stringify(n, newIndentChar) {
//if (n.type != "Program")
//throw new TypeError("argument must be a Program parse node");
if (newIndentChar) indentChar = newIndentChar;
- return values(n.body, function (x){return sourceElement(x, "")}).join("");
+
+ // reset variable counters
+ vars = [];
+ currentVar = 0;
+
+ var body = values(n.body, function (x){return sourceElement(x, "")}).join("");
+ var varString = vars.length ? "var " + vars.join(", ") + ";\n" : ""
+ return varString + body;
}
exports.stringify = stringify;
View
36 test/stringify-test.js
@@ -286,11 +286,33 @@ function runUnitTests() {
["x.y(...z)", "x.y.apply(x, z);\n"],
["x.y(z, ...a)", "x.y.apply(x, [z].concat([].slice.call(a)));\n"],
["x.y(z, a, ...b)", "x.y.apply(x, [z, a].concat([].slice.call(b)));\n"],
- ["x.y.z(...a)", "(var _ref=x.y).z.apply(_ref, a);\n"],
- ["x.y.z(a, ...b)", "(var _ref=x.y).z.apply(_ref, [a].concat([].slice.call(b)));\n"],
- ["x.y.z(a, b, ...c)", "(var _ref=x.y).z.apply(_ref, [a, b].concat([].slice.call(c)));\n"],
- ["@x.y.z(a, b, ...c)", "(var _ref=this.x.y).z.apply(_ref, [a, b].concat([].slice.call(c)));\n"],
- ["x.y.z(a, @b, ...c)", "(var _ref=x.y).z.apply(_ref, [a, this.b].concat([].slice.call(c)));\n"],
+ ["x.y.z(...a)", "var _ref;\n(_ref=x.y).z.apply(_ref, a);\n"],
+ ["x.y.z(a, ...b)", "var _ref;\n(_ref=x.y).z.apply(_ref, [a].concat([].slice.call(b)));\n"],
+ ["x.y.z(a, b, ...c)", "var _ref;\n(_ref=x.y).z.apply(_ref, [a, b].concat([].slice.call(c)));\n"],
+ ["@x.y.z(a, b, ...c)", "var _ref;\n(_ref=this.x.y).z.apply(_ref, [a, b].concat([].slice.call(c)));\n"],
+ ["x.y.z(a, @b, ...c)", "var _ref;\n(_ref=x.y).z.apply(_ref, [a, this.b].concat([].slice.call(c)));\n"],
+
+ // for (own foo in bar)
+ [("for (own foo in bar) {\n" +
+ " console.log(foo);\n" +
+ "}"),
+ ("for (foo in bar) {\n" +
+ " if (!bar.hasOwnProperty(foo)) {\n" +
+ " continue;\n" +
+ " }\n" +
+ " console.log(foo);\n" +
+ "}\n")],
+ [("for (own foo in bar.baz()) {\n" +
+ " console.log(foo);\n" +
+ "}"),
+ ("var _ref;\n" +
+ "_ref = bar.baz();\n" +
+ "for (foo in _ref) {\n" +
+ " if (!_ref.hasOwnProperty(foo)) {\n" +
+ " continue;\n" +
+ " }\n" +
+ " console.log(foo);\n" +
+ "}\n")]
];
for (var i = 0; i < tests.length; i++) {
@@ -320,8 +342,8 @@ function runUnitTests() {
}
if (a !== b) {
print("FAIL - Mismatch.");
- print("got: " + String(a));
- print("expected: " + String(b));
+ print("got: \n" + String(a));
+ print("expected: \n" + String(b));
print();
}
}

0 comments on commit 0737f76

Please sign in to comment.