From b5261abb6b05310b7797633bc5fcf7239c893c7e Mon Sep 17 00:00:00 2001 From: satyr Date: Wed, 29 Sep 2010 11:30:05 +0900 Subject: [PATCH] nodes: made ExistenceNode omit `typeof` for known variables --- lib/lexer.js | 4 ++-- lib/nodes.js | 34 +++++++++++++++------------------- src/nodes.coffee | 16 ++++++++++------ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/lexer.js b/lib/lexer.js index e319721f..68c8bccf 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -547,14 +547,14 @@ if (!(tok = last(this.tokens, index))) { return null; } - return (tok[0] = (typeof newTag !== "undefined" && newTag !== null) ? newTag : tok[0]); + return (tok[0] = (newTag != null) ? newTag : tok[0]); }; Lexer.prototype.value = function(index, val) { var tok; if (!(tok = last(this.tokens, index))) { return null; } - return (tok[1] = (typeof val !== "undefined" && val !== null) ? val : tok[1]); + return (tok[1] = (val != null) ? val : tok[1]); }; Lexer.prototype.unfinished = function() { var prev, value; diff --git a/lib/nodes.js b/lib/nodes.js index 9e6f643a..ec21a082 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1,5 +1,5 @@ (function() { - var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NO, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, YES, _ref, compact, del, ends, flatten, include, indexOf, last, literal, merge, starts, utility; + var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NO, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, TAB, THIS, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, YES, _ref, compact, del, ends, flatten, include, indexOf, last, literal, merge, starts, utility; var __extends = function(child, parent) { var ctor = function(){}; ctor.prototype = parent.prototype; @@ -16,6 +16,9 @@ NO = function() { return false; }; + THIS = function() { + return this; + }; exports.BaseNode = (function() { BaseNode = function() { this.tags = {}; @@ -148,9 +151,7 @@ }; BaseNode.prototype["class"] = 'BaseNode'; BaseNode.prototype.children = []; - BaseNode.prototype.unwrap = function() { - return this; - }; + BaseNode.prototype.unwrap = THIS; BaseNode.prototype.isStatement = NO; BaseNode.prototype.isPureStatement = NO; BaseNode.prototype.isComplex = YES; @@ -281,9 +282,7 @@ ReturnNode.prototype.isStatement = YES; ReturnNode.prototype.isPureStatement = YES; ReturnNode.prototype.children = ['expression']; - ReturnNode.prototype.makeReturn = function() { - return this; - }; + ReturnNode.prototype.makeReturn = THIS; ReturnNode.prototype.compile = function(o) { var expr; expr = this.expression.makeReturn(); @@ -337,10 +336,10 @@ return this.properties.length ? this : this.base; }; ValueNode.prototype.isStatement = function(o) { - return this.base.isStatement && this.base.isStatement(o) && !this.hasProperties(); + return this.base.isStatement(o) && !this.properties.length; }; ValueNode.prototype.isNumber = function() { - return this.base instanceof LiteralNode && this.base.value.match(NUMBER); + return this.base instanceof LiteralNode && NUMBER.test(this.base.value); }; ValueNode.prototype.cacheIndexes = function(o) { var _len, _ref2, _ref3, copy, first, i, index, indexVar, prop; @@ -421,9 +420,7 @@ __extends(CommentNode, BaseNode); CommentNode.prototype["class"] = 'CommentNode'; CommentNode.prototype.isStatement = YES; - CommentNode.prototype.makeReturn = function() { - return this; - }; + CommentNode.prototype.makeReturn = THIS; CommentNode.prototype.compileNode = function(o) { return this.tab + '/*' + this.comment.replace(/\n/g, '\n' + this.tab) + '*/'; }; @@ -1207,14 +1204,14 @@ exports.WhileNode = (function() { WhileNode = function(condition, opts) { WhileNode.__super__.constructor.call(this); - if (opts && opts.invert) { + if (opts == null ? undefined : opts.invert) { if (condition instanceof OpNode) { condition = new ParentheticalNode(condition); } condition = new OpNode('!', condition); } this.condition = condition; - this.guard = opts && opts.guard; + this.guard = opts == null ? undefined : opts.guard; return this; }; __extends(WhileNode, BaseNode); @@ -1465,9 +1462,7 @@ ThrowNode.prototype["class"] = 'ThrowNode'; ThrowNode.prototype.children = ['expression']; ThrowNode.prototype.isStatement = YES; - ThrowNode.prototype.makeReturn = function() { - return this; - }; + ThrowNode.prototype.makeReturn = THIS; ThrowNode.prototype.compileNode = function(o) { return "" + (this.tab) + "throw " + (this.expression.compile(o)) + ";"; }; @@ -1485,14 +1480,15 @@ ExistenceNode.prototype.compileNode = function(o) { var test; test = ExistenceNode.compileTest(o, this.expression)[0]; - return this.parenthetical ? test.substring(1, test.length - 1) : test; + return this.parenthetical ? test.slice(1, -1) : test; }; ExistenceNode.compileTest = function(o, variable) { var _ref2, first, second; _ref2 = variable.compileReference(o, { precompile: true }), first = _ref2[0], second = _ref2[1]; - return [("(typeof " + (first) + " !== \"undefined\" && " + (second) + " !== null)"), second]; + first = first === second && o.scope.check(first) ? ("(" + (first) + " != null)") : ("(typeof " + (first) + " !== \"undefined\" && " + (second) + " !== null)"); + return [first, second]; }; return ExistenceNode; }).call(this); diff --git a/src/nodes.coffee b/src/nodes.coffee index 40222d5a..ced11bd4 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -331,10 +331,10 @@ exports.ValueNode = class ValueNode extends BaseNode # Values are considered to be statements if their base is a statement. isStatement: (o) -> - @base.isStatement and @base.isStatement(o) and not @hasProperties() + @base.isStatement(o) and not @properties.length isNumber: -> - @base instanceof LiteralNode and @base.value.match NUMBER + @base instanceof LiteralNode and NUMBER.test @base.value # If the value node has indexes containing function calls, and the value node # needs to be used twice, in compound assignment ... then we need to cache @@ -1071,11 +1071,11 @@ exports.WhileNode = class WhileNode extends BaseNode constructor: (condition, opts) -> super() - if opts and opts.invert + if opts?.invert condition = new ParentheticalNode condition if condition instanceof OpNode condition = new OpNode('!', condition) @condition = condition - @guard = opts and opts.guard + @guard = opts?.guard addBody: (body) -> @body = body @@ -1302,14 +1302,18 @@ exports.ExistenceNode = class ExistenceNode extends BaseNode compileNode: (o) -> test = ExistenceNode.compileTest(o, @expression)[0] - if @parenthetical then test.substring(1, test.length - 1) else test + if @parenthetical then test.slice 1, -1 else test # The meat of the **ExistenceNode** is in this static `compileTest` method # because other nodes like to check the existence of their variables as well. # Be careful not to double-evaluate anything. @compileTest: (o, variable) -> [first, second] = variable.compileReference o, precompile: yes - ["(typeof #{first} !== \"undefined\" && #{second} !== null)", second] + first = if first is second and o.scope.check first + "(#{first} != null)" + else + "(typeof #{first} !== \"undefined\" && #{second} !== null)" + [first, second] #### ParentheticalNode