From 6389474709779cb02ef61ec705db2223ddeb8896 Mon Sep 17 00:00:00 2001 From: Ryan Hendrickson Date: Sun, 7 Feb 2016 17:03:06 -0500 Subject: [PATCH 1/2] update lib --- lib/lexer.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/lexer.js b/lib/lexer.js index a0a62434d..38a2ea00b 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -900,11 +900,6 @@ exports.doLiteral = function(code, index){ } tag = 'UNARY'; break; - case '&': - if (!able(this.tokens)) { - tag = 'LITERAL'; - } - break; case '|': tag = 'BITWISE'; break; From 4a207180f4f4613be1d6de83e441b37b2b1ae3d4 Mon Sep 17 00:00:00 2001 From: Ryan Hendrickson Date: Sun, 7 Feb 2016 17:12:34 -0500 Subject: [PATCH 2/2] add robustness to generated loop code Certain expressions--integers (with or without a preceding +/-), null, and void--when used as sources of for loops resulted in illegal JavaScript being generated. While (42).length is a silly but legal thing to do, 42.length is an actual SyntaxError in JS. This commit adds checks to wrap potentially problematic expressions in parentheses. --- lib/ast.js | 12 ++++++++---- src/ast.ls | 8 +++++--- test/loop.ls | 10 ++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 79c9dc90a..a6f801be1 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -274,10 +274,14 @@ SourceNode::to-string = (...args) -> return [sub, ref, [ref.value]]; } }, - compileLoopReference: function(o, name, ret){ - var ref$, asn, tmp; + compileLoopReference: function(o, name, ret, safeAccess){ + var ref$, code, asn, tmp; if (this instanceof Var && o.scope.check(this.value) || this instanceof Unary && ((ref$ = this.op) === '+' || ref$ === '-') && (-1 / 0 < (ref$ = +this.it.value) && ref$ < 1 / 0) || this instanceof Literal && !this.isComplex()) { - return [ref$ = this.compile(o), ref$]; + code = this.compile(o, LEVEL_PAREN); + if (safeAccess && !(this instanceof Var)) { + code = "(" + code + ")"; + } + return [code, code]; } asn = Assign(Var(tmp = o.scope.temporary(name)), this); ret || (asn['void'] = true); @@ -3695,7 +3699,7 @@ exports.For = For = (function(superclass){ this.item = Var(o.scope.temporary('x')); } if (this.item || this.object && this.own || this['let']) { - ref$ = this.source.compileLoopReference(o, 'ref', !this.object), svar = ref$[0], srcPart = ref$[1]; + ref$ = this.source.compileLoopReference(o, 'ref', !this.object, true), svar = ref$[0], srcPart = ref$[1]; svar === srcPart || temps.push(svar); } else { svar = srcPart = this.source.compile(o, LEVEL_PAREN); diff --git a/src/ast.ls b/src/ast.ls index dd9d98472..3cf6c3e1a 100644 --- a/src/ast.ls +++ b/src/ast.ls @@ -199,11 +199,13 @@ SourceNode::to-string = (...args) -> if once then [sub, ref <<< {+temp}] else [sub, ref, [ref.value]] # Compiles to a variable/source pair suitable for looping. - compile-loop-reference: (o, name, ret) -> + compile-loop-reference: (o, name, ret, safe-access) -> if this instanceof Var and o.scope.check @value or this instanceof Unary and @op in <[ + - ]> and -1/0 < +@it.value < 1/0 or this instanceof Literal and not @is-complex! - return [@compile o] * 2 + code = @compile o, LEVEL_PAREN + code = "(#code)" if safe-access and this not instanceof Var + return [code] * 2 asn = Assign Var(tmp = o.scope.temporary name), this ret or asn.void = true [tmp; asn.compile o, if ret then LEVEL_CALL else LEVEL_PAREN] @@ -2352,7 +2354,7 @@ class exports.For extends While else @item = Var o.scope.temporary \x if @ref if @item or @object and @own or @let - [svar, srcPart] = @source.compile-loop-reference o, \ref, not @object + [svar, srcPart] = @source.compile-loop-reference o, \ref, not @object, true svar is srcPart or temps.push svar else svar = srcPart = @source.compile o, LEVEL_PAREN diff --git a/test/loop.ls b/test/loop.ls index 5ff9939a2..6f3b03365 100644 --- a/test/loop.ls +++ b/test/loop.ls @@ -686,3 +686,13 @@ eq 1, i o = { [k, -> v] for let k, v of {a: 1, b: 2} } eq 1 o.a! eq 2 o.b! + +# Certain literals could result in illegal JavaScript if not carefully +# handled. These are all nonsensical use cases and could just as easily +# be LiveScript syntax errors. The thing to avoid is for them to be JavaScript +# syntax errors; lsc should never produce illegal JavaScript on any input, +# silly or otherwise. +deep-equal [] [0 for x in 42] +deep-equal [] [0 for x in -42] +throws "Cannot read property 'length' of null" -> [0 for x in null] +throws "Cannot read property 'length' of undefined" -> [0 for x in void]