diff --git a/src/lexer.coffee b/src/lexer.coffee index bedbb831..359b96de 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -335,7 +335,7 @@ exports.Lexer = class Lexer prev[0] = 'COMPOUND_ASSIGN' prev[1] += '=' return value.length - if value is ';' + if value is ';' @seenFor = no tag = 'TERMINATOR' else if value in MATH then tag = 'MATH' @@ -528,9 +528,9 @@ exports.Lexer = class Lexer if contents in ['\n', quote] then contents else match body = body.replace /// #{quote} ///g, '\\$&' quote + @escapeLines(body, heredoc) + quote - + # Throws a syntax error on the current `@line`. - error: (message) -> + error: (message) -> throw SyntaxError "#{message} on line #{ @line + 1}" # Constants diff --git a/src/nodes.coffee b/src/nodes.coffee index 65c45893..b580e20a 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -948,13 +948,13 @@ exports.Class = class Class extends Base @addBoundFunctions o call = Closure.wrap @body - + if @parent @superClass = new Literal o.scope.freeVariable 'super', no @body.expressions.unshift new Extends lname, @superClass call.args.push @parent call.variable.params.push new Param @superClass - + klass = new Parens call, yes klass = new Assign @variable, klass if @variable klass.compile o @@ -1228,7 +1228,7 @@ exports.Splat = class Splat extends Base compile: (o) -> if @index? then @compileParam o else @name.compile o - + unwrap: -> @name # Utility function that converts an arbitrary number of elements, mixed with @@ -1379,12 +1379,12 @@ exports.Op = class Op extends Base unfoldSoak: (o) -> @operator in ['++', '--', 'delete'] and unfoldSoak o, this, 'first' - + generateDo: (exp) -> passedParams = [] func = if exp instanceof Assign and (ref = exp.value.unwrap()) instanceof Code ref - else + else exp for param in func.params or [] if param.value @@ -1396,9 +1396,9 @@ exports.Op = class Op extends Base call.do = yes call - compileNode: (o) -> + compileNode: (o) -> isChain = @isChainable() and @first.isChainable() - # In chains, there's no need to wrap bare obj literals in parens, + # In chains, there's no need to wrap bare obj literals in parens, # as the chained expression is wrapped. @first.front = @front unless isChain return @compileUnary o if @isUnary() @@ -1435,7 +1435,7 @@ exports.Op = class Op extends Base parts.push ' ' if op in ['new', 'typeof', 'delete'] or plusMinus and @first instanceof Op and @first.operator is op if (plusMinus && @first instanceof Op) or (op is 'new' and @first.isStatement o) - @first = new Parens @first + @first = new Parens @first parts.push @first.compile o, LEVEL_OP parts.reverse() if @flip parts.join '' @@ -1503,15 +1503,15 @@ exports.Try = class Try extends Base o.indent += TAB errorPart = if @error then " (#{ @error.compile o }) " else ' ' tryPart = @attempt.compile o, LEVEL_TOP - + catchPart = if @recovery o.scope.add @error.value, 'param' unless o.scope.check @error.value " catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}" else unless @ensure or @recovery ' catch (_error) {}' - + ensurePart = if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else '' - + """#{@tab}try { #{tryPart} #{@tab}}#{ catchPart or '' }#{ensurePart}""" @@ -1844,7 +1844,7 @@ Closure = literalArgs: (node) -> node instanceof Literal and node.value is 'arguments' and not node.asKey - + literalThis: (node) -> (node instanceof Literal and node.value is 'this' and not node.asKey) or (node instanceof Code and node.bound) diff --git a/src/rewriter.coffee b/src/rewriter.coffee index 133a5aeb..5c44640f 100644 --- a/src/rewriter.coffee +++ b/src/rewriter.coffee @@ -70,14 +70,14 @@ class exports.Rewriter # its paired close. We have the mis-nested outdent case included here for # calls that close on the same line, just before their outdent. closeOpenCalls: -> - + condition = (token, i) -> token[0] in [')', 'CALL_END'] or token[0] is 'OUTDENT' and @tag(i - 1) is ')' - + action = (token, i) -> @tokens[if token[0] is 'OUTDENT' then i - 1 else i][0] = 'CALL_END' - + @scanTokens (token, i) -> @detectEnd i + 1, condition, action if token[0] is 'CALL_START' 1 @@ -85,13 +85,13 @@ class exports.Rewriter # The lexer has tagged the opening parenthesis of an indexing operation call. # Match it with its paired close. closeOpenIndexes: -> - - condition = (token, i) -> + + condition = (token, i) -> token[0] in [']', 'INDEX_END'] - - action = (token, i) -> + + action = (token, i) -> token[0] = 'INDEX_END' - + @scanTokens (token, i) -> @detectEnd i + 1, condition, action if token[0] is 'INDEX_START' 1 @@ -99,28 +99,28 @@ class exports.Rewriter # Object literals may be written with implicit braces, for simple cases. # Insert the missing braces here, so that the parser doesn't have to. addImplicitBraces: -> - + stack = [] start = null startsLine = null sameLine = yes startIndent = 0 - + condition = (token, i) -> [one, two, three] = @tokens[i + 1 .. i + 3] return no if 'HERECOMMENT' is one?[0] [tag] = token sameLine = no if tag in LINEBREAKS ((tag in ['TERMINATOR', 'OUTDENT'] or (tag in IMPLICIT_END and sameLine)) and - ((!startsLine and @tag(i - 1) isnt ',') or + ((!startsLine and @tag(i - 1) isnt ',') or not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':'))) or (tag is ',' and one and one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT']) - + action = (token, i) -> tok = @generate '}', '}', token[2] @tokens.splice i, 0, tok - + @scanTokens (token, i, tokens) -> if (tag = token[0]) in EXPRESSION_START stack.push [(if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag), i] @@ -147,9 +147,9 @@ class exports.Rewriter # Insert the implicit parentheses here, so that the parser doesn't have to # deal with them. addImplicitParentheses: -> - + noCall = seenSingle = seenControl = no - + condition = (token, i) -> [tag] = token return yes if not seenSingle and token.fromThen @@ -161,10 +161,10 @@ class exports.Rewriter (tag isnt 'INDENT' or (@tag(i - 2) not in ['CLASS', 'EXTENDS'] and @tag(i - 1) not in IMPLICIT_BLOCK and not ((post = @tokens[i + 1]) and post.generated and post[0] is '{'))) - - action = (token, i) -> + + action = (token, i) -> @tokens.splice i, 0, @generate 'CALL_END', ')', token[2] - + @scanTokens (token, i, tokens) -> tag = token[0] noCall = yes if tag in ['CLASS', 'IF'] @@ -190,16 +190,16 @@ class exports.Rewriter # blocks, so it doesn't need to. ')' can close a single-line block, # but we need to make sure it's balanced. addImplicitIndentation: -> - + starter = indent = outdent = null - + condition = (token, i) -> token[1] isnt ';' and token[0] in SINGLE_CLOSERS and not (token[0] is 'ELSE' and starter not in ['IF', 'THEN']) - + action = (token, i) -> @tokens.splice (if @tag(i - 1) is ',' then i - 1 else i), 0, outdent - + @scanTokens (token, i, tokens) -> [tag] = token if tag is 'TERMINATOR' and @tag(i + 1) is 'THEN' @@ -225,16 +225,16 @@ class exports.Rewriter # Tag postfix conditionals as such, so that we can parse them with a # different precedence. tagPostfixConditionals: -> - + original = null - - condition = (token, i) -> + + condition = (token, i) -> token[0] in ['TERMINATOR', 'INDENT'] - + action = (token, i) -> if token[0] isnt 'INDENT' or (token.generated and not token.fromThen) - original[0] = 'POST_' + original[0] - + original[0] = 'POST_' + original[0] + @scanTokens (token, i) -> return 1 unless token[0] is 'IF' original = token @@ -247,7 +247,7 @@ class exports.Rewriter outdent = ['OUTDENT', 2, token[2]] indent.generated = outdent.generated = yes if implicit [indent, outdent] - + # Create a generated token: one that exists due to a use of implicit syntax. generate: (tag, value, line) -> tok = [tag, value, line] diff --git a/test/assignment.coffee b/test/assignment.coffee index 4fe503b3..4b13f9fa 100644 --- a/test/assignment.coffee +++ b/test/assignment.coffee @@ -291,14 +291,14 @@ test "#1348, #1216: existential assignment compilation", -> eq nonce, b #the first ?= compiles into a statement; the second ?= compiles to a ternary expression eq a ?= b ?= 1, nonce - + e ?= f ?= g ?= 1 eq e + g, 2 - + #need to ensure the two vars are not defined, hence the strange names; # broke earlier when using c ?= d ?= 1 because `d` is declared elsewhere eq und1_1348 ?= und2_1348 ?= 1, 1 - + if a then a ?= 2 else a = 3 eq a, nonce @@ -307,14 +307,14 @@ test "#1591, #1101: splatted expressions in destructuring assignment must be ass for nonref in ['', '""', '0', 'f()', '(->)'].concat CoffeeScript.RESERVED eq nonce, (try CoffeeScript.compile "[#{nonref}...] = v" catch e then nonce) -test "#1643: splatted accesses in destructuring assignments should not be declared as variables", -> +test "#1643: splatted accesses in destructuring assignments should not be declared as variables", -> nonce = {} accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'C::', 'f().a', 'o?.a', 'o?.a.b', 'f?().a'] for access in accesses for i,j in [1,2,3] #position can matter - code = + code = """ - nonce = {}; nonce2 = {}; nonce3 = {}; + nonce = {}; nonce2 = {}; nonce3 = {}; @o = o = new (class C then a:{}); f = -> o [#{new Array(i).join('x,')}#{access}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3] unless #{access}[0] is nonce and #{access}[1] is nonce2 and #{access}[2] is nonce3 then throw new Error('[...]') @@ -326,7 +326,7 @@ test "#1643: splatted accesses in destructuring assignments should not be declar for i,j in [1,2,3] code = """ - nonce = {}; nonce2 = {}; nonce3 = {}; + nonce = {}; nonce2 = {}; nonce3 = {}; [#{new Array(i).join('x,')}#{subpattern}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3] unless sub is nonce and sub2 is nonce2 and sub3 is nonce3 then throw new Error('[sub...]') """ @@ -335,5 +335,5 @@ test "#1643: splatted accesses in destructuring assignments should not be declar test "#1838: Regression with variable assignment", -> name = 'dave' - - eq name, 'dave' \ No newline at end of file + + eq name, 'dave' diff --git a/test/classes.coffee b/test/classes.coffee index 23a7ea00..e34527e3 100644 --- a/test/classes.coffee +++ b/test/classes.coffee @@ -272,22 +272,22 @@ test "nothing classes", -> c = class ok c instanceof Function - - + + test "classes with static-level implicit objects", -> - + class A @static = one: 1 two: 2 - + class B @static = one: 1, two: 2 - + eq A.static.one, 1 eq A.static.two, undefined eq (new A).two, 2 - + eq B.static.one, 1 eq B.static.two, 2 eq (new B).two, undefined @@ -546,61 +546,61 @@ test "#1598: super works for static methods too", -> 'pass? ' + super eq Child.method(), 'pass? yes' - + test "#1842: Regression with bound functions within bound class methods", -> - + class Store @bound: => do => eq this, Store - + Store.bound() - + # And a fancier case: - + class Store - + eq this, Store - + @bound: => do => eq this, Store - + @unbound: -> eq this, Store - + instance: => ok this instanceof Store - + Store.bound() Store.unbound() (new Store).instance() - + test "#1876: Class @A extends A", -> class A class @A extends A - + ok (new @A) instanceof A - + test "#1813: Passing class definitions as expressions", -> ident = (x) -> x - + result = ident class A then x = 1 - + eq result, A - + result = ident class B extends A x = 1 - + eq result, B - + test "#494: Named classes", -> - + class A eq A.name, 'A' - + class A.B - eq A.B.name, 'B' - - class A.B["C"] + eq A.B.name, 'B' + + class A.B["C"] ok A.B.C.name isnt 'C' diff --git a/test/eval.coffee b/test/eval.coffee index b507832b..d42a704f 100644 --- a/test/eval.coffee +++ b/test/eval.coffee @@ -8,7 +8,7 @@ if vm = require? 'vm' result = CoffeeScript.eval code eq result, 'global superpower!' eq fhqwhgads, 'global superpower!' - + test "CoffeeScript.eval can run in, and modify, a Script context sandbox", -> sandbox = vm.Script.createContext() sandbox.foo = 'bar' @@ -18,7 +18,7 @@ if vm = require? 'vm' result = CoffeeScript.eval code, {sandbox} eq result, 'not bar!' eq sandbox.foo, 'not bar!' - + test "CoffeeScript.eval can run in, but cannot modify, an ordinary object sandbox", -> sandbox = {foo: 'bar'} code = ''' @@ -26,4 +26,4 @@ if vm = require? 'vm' ''' result = CoffeeScript.eval code, {sandbox} eq result, 'not bar!' - eq sandbox.foo, 'bar' \ No newline at end of file + eq sandbox.foo, 'bar' diff --git a/test/exception_handling.coffee b/test/exception_handling.coffee index 5f9daf05..332b432a 100644 --- a/test/exception_handling.coffee +++ b/test/exception_handling.coffee @@ -88,15 +88,15 @@ test "try/catch with empty catch as last statement in a function body", -> try nonce catch err eq nonce, fn() - - + + # Catch leads to broken scoping: #1595 test "try/catch with a reused variable name.", -> do -> - try + try inner = 5 catch inner # nothing eq typeof inner, 'undefined' - + diff --git a/test/formatting.coffee b/test/formatting.coffee index dcbd01e8..cc086d59 100644 --- a/test/formatting.coffee +++ b/test/formatting.coffee @@ -131,7 +131,7 @@ test "#1195 Ignore trailing semicolons (before newlines or as the last char in a unless f() is nonce then throw new Error('; before linebreak should = newline') """ CoffeeScript.run(preNewline(n), bare: true) for n in [1,2,3] - + lastChar = '-> lastChar;' doesNotThrow -> CoffeeScript.compile lastChar, bare: true diff --git a/test/functions.coffee b/test/functions.coffee index aff4f704..12b13837 100644 --- a/test/functions.coffee +++ b/test/functions.coffee @@ -65,7 +65,7 @@ eq obj, obj.nested() test "even more fancy bound functions", -> - obj = + obj = one: -> do => return this.two() @@ -182,7 +182,7 @@ test "arguments vs parameters", -> test "#1844: bound functions in nested comprehensions causing empty var statements", -> a = ((=>) for a in [0] for b in [0]) eq 1, a.length - + test "#1859: inline function bodies shouldn't modify prior postfix ifs", -> list = [1, 2, 3] ok true if list.some (x) -> x is 2 diff --git a/test/objects.coffee b/test/objects.coffee index e2cf00c4..06226ffd 100644 --- a/test/objects.coffee +++ b/test/objects.coffee @@ -237,17 +237,17 @@ test "#1322: implicit call against implicit object with block comments", -> test "#1513: Top level bare objs need to be wrapped in parens for unary and existence ops", -> doesNotThrow -> CoffeeScript.run "{}?", bare: true doesNotThrow -> CoffeeScript.run "{}.a++", bare: true - + test "#1871: Special case for IMPLICIT_END in the middle of an implicit object", -> result = 'result' ident = (x) -> x - + result = ident one: 1 if false - + eq result, 'result' result = ident one: 1 two: 2 for i in [1..3] - - eq result.two.join(' '), '2 2 2' + + eq result.two.join(' '), '2 2 2' diff --git a/test/operators.coffee b/test/operators.coffee index f258fc1d..2ae0c6a9 100644 --- a/test/operators.coffee +++ b/test/operators.coffee @@ -263,9 +263,9 @@ test "#1102: String literal prevents line continuation", -> test "#1703, ---x is invalid JS", -> x = 2 eq (- --x), -1 - + test "Regression with implicit calls against an indented assignment", -> - eq 1, a = + eq 1, a = 1 - + eq a, 1