diff --git a/lib/grammar.js b/lib/grammar.js index 78499d2f..9507b5dc 100644 --- a/lib/grammar.js +++ b/lib/grammar.js @@ -58,7 +58,12 @@ }), o('REGEX', function() { return new Literal($1); }), o('BOOL', function() { - return new Literal($1 === 'undefined' ? 'void 0' : $1); + var val; + val = new Literal($1); + if ($1 === 'undefined') { + val.isUndefined = true; + } + return val; }) ], Assign: [ diff --git a/lib/nodes.js b/lib/nodes.js index 38d51947..07df6369 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -221,6 +221,9 @@ expr = this.expressions[len]; if (!(expr instanceof Comment)) { this.expressions[len] = expr.makeReturn(); + if (expr instanceof Return && !expr.expression) { + this.expressions.splice(len, 1); + } break; } } @@ -351,7 +354,7 @@ }; Literal.prototype.compileNode = function(o) { var code; - code = this.value.reserved ? "\"" + this.value + "\"" : this.value; + code = this.isUndefined ? 'void 0' : this.value.reserved ? "\"" + this.value + "\"" : this.value; if (this.isStatement()) { return "" + this.tab + code + ";"; } else { @@ -365,8 +368,10 @@ })(); exports.Return = Return = (function() { __extends(Return, Base); - function Return(expression) { - this.expression = expression; + function Return(expr) { + if (expr && !expr.unwrap().isUndefined) { + this.expression = expr; + } } Return.prototype.children = ['expression']; Return.prototype.isStatement = YES; diff --git a/lib/parser.js b/lib/parser.js index 3f96303b..bc5a5a19 100755 --- a/lib/parser.js +++ b/lib/parser.js @@ -71,7 +71,14 @@ case 30:this.$ = new yy.Literal($$[$0]); break; case 31:this.$ = new yy.Literal($$[$0]); break; -case 32:this.$ = new yy.Literal($$[$0] === 'undefined' ? 'void 0' : $$[$0]); +case 32:this.$ = (function () { + var val; + val = new yy.Literal($$[$0]); + if ($$[$0] === 'undefined') { + val.isUndefined = true; + } + return val; + }()); break; case 33:this.$ = new yy.Assign($$[$0-2], $$[$0]); break; diff --git a/src/grammar.coffee b/src/grammar.coffee index 586a1491..23462ca6 100644 --- a/src/grammar.coffee +++ b/src/grammar.coffee @@ -127,7 +127,9 @@ grammar = o 'JS', -> new Literal $1 o 'REGEX', -> new Literal $1 o 'BOOL', -> - new Literal if $1 is 'undefined' then 'void 0' else $1 + val = new Literal $1 + val.isUndefined = yes if $1 is 'undefined' + val ] # Assignment of a variable, property, or index to a value. diff --git a/src/nodes.coffee b/src/nodes.coffee index 5b515941..ac96d9d7 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -196,6 +196,7 @@ exports.Expressions = class Expressions extends Base expr = @expressions[len] if expr not instanceof Comment @expressions[len] = expr.makeReturn() + @expressions.splice(len, 1) if expr instanceof Return and not expr.expression break this @@ -289,7 +290,12 @@ exports.Literal = class Literal extends Base if not (o and (o.loop or o.block and (@value isnt 'continue'))) then this else no compileNode: (o) -> - code = if @value.reserved then "\"#{@value}\"" else @value + code = if @isUndefined + 'void 0' + else if @value.reserved + "\"#{@value}\"" + else + @value if @isStatement() then "#{@tab}#{code};" else code toString: -> @@ -300,7 +306,8 @@ exports.Literal = class Literal extends Base # A `return` is a *pureStatement* -- wrapping it in a closure wouldn't # make sense. exports.Return = class Return extends Base - constructor: (@expression) -> + constructor: (expr) -> + @expression = expr if expr and not expr.unwrap().isUndefined children: ['expression']