diff --git a/lib/coffee-script.js b/lib/coffee-script.js index 15c795f1..abe025d1 100755 --- a/lib/coffee-script.js +++ b/lib/coffee-script.js @@ -27,11 +27,11 @@ throw err; } }); - exports.tokens = function(code) { - return lexer.tokenize(code); + exports.tokens = function(code, options) { + return lexer.tokenize(code, options); }; - exports.nodes = function(code) { - return parser.parse(lexer.tokenize(code)); + exports.nodes = function(code, options) { + return parser.parse(lexer.tokenize(code, options)); }; exports.run = function(code, options) { var root; diff --git a/lib/lexer.js b/lib/lexer.js index 0d5d3acb..44ad6188 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -605,7 +605,7 @@ MULTI_DENT = /^(?:\n[ \t]*)+/; SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/; JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/; - REGEX = /^\/(?!\s)(?:[^[\/\n\\]+|\\.|\[([^\\\]]+|\\.)*])+\/[imgy]{0,4}(?![A-Za-z])/; + REGEX = /^\/(?!\s)(?:[^[\/\n\\]+|\\[\s\S]|\[([^\]\n\\]+|\\[\s\S])*])+\/[imgy]{0,4}(?![A-Za-z])/; HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?![A-Za-z])/; HEREGEX_OMIT = /\s+(?:#.*)?/g; MULTILINER = /\n/g; diff --git a/lib/nodes.js b/lib/nodes.js index 618cea0c..11815daf 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1382,10 +1382,6 @@ return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); }; Op.prototype.compileNode = function(o) { - var node; - if (node = Value.unfoldSoak(o, this, 'first')) { - return node.compile(o); - } if (this.isChainable() && this.first.unwrap() instanceof Op && this.first.unwrap().isChainable()) { return this.compileChain(o); } diff --git a/lib/rewriter.js b/lib/rewriter.js index 5fa4aa0a..e0e4f73b 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -29,10 +29,10 @@ return true; }; exports.Rewriter.prototype.detectEnd = function(i, condition, action) { - var levels, token; + var levels, token, tokens; + tokens = this.tokens; levels = 0; - while (true) { - token = this.tokens[i]; + while (token = tokens[i]) { if (levels === 0 && condition.call(this, token, i)) { return action.call(this, token, i); } diff --git a/src/coffee-script.coffee b/src/coffee-script.coffee index 923e0aa0..cc03f277 100755 --- a/src/coffee-script.coffee +++ b/src/coffee-script.coffee @@ -33,14 +33,14 @@ exports.compile = compile = (code, options) -> throw err # Tokenize a string of CoffeeScript code, and return the array of tokens. -exports.tokens = (code) -> - lexer.tokenize code +exports.tokens = (code, options) -> + lexer.tokenize code, options # Tokenize and parse a string of CoffeeScript code, and return the AST. You can # then compile it by calling `.compile()` on the root, or traverse it by using # `.traverse()` with a callback. -exports.nodes = (code) -> - parser.parse lexer.tokenize code +exports.nodes = (code, options) -> + parser.parse lexer.tokenize code, options # Compile and execute a string of CoffeeScript (on the server), correctly # setting `__filename`, `__dirname`, and relative `require()`. diff --git a/src/lexer.coffee b/src/lexer.coffee index f7d58afd..a252f76f 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -557,10 +557,10 @@ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/ # Regex-matching-regexes. REGEX = /// ^ - / (?!\s) # disallow leading whitespace - (?: [^ [ / \n \\ ]+ # every other thing - | \\. # anything escaped - | \[ ( [^\\\]]+ | \\. )* ] # character class + / (?!\s) # disallow leading whitespace + (?: [^ [ / \n \\ ]+ # every other thing + | \\[\s\S] # anything escaped + | \[ ( [^ \] \n \\ ]+ | \\[\s\S] )* ] # character class )+ / [imgy]{0,4} (?![A-Za-z]) /// diff --git a/src/nodes.coffee b/src/nodes.coffee index 8315c7c8..db8a59ae 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1201,7 +1201,6 @@ exports.Op = class Op extends Base super(idt, @constructor.name + ' ' + @operator) compileNode: (o) -> - return node.compile o if node = Value.unfoldSoak o, this, 'first' return @compileChain(o) if @isChainable() and @first.unwrap() instanceof Op and @first.unwrap().isChainable() return @compileAssignment(o) if indexOf(@ASSIGNMENT, @operator) >= 0 return @compileUnary(o) if @isUnary() diff --git a/src/rewriter.coffee b/src/rewriter.coffee index d3c18ee8..a3f11202 100644 --- a/src/rewriter.coffee +++ b/src/rewriter.coffee @@ -46,9 +46,9 @@ class exports.Rewriter true detectEnd: (i, condition, action) -> + {tokens} = this levels = 0 - loop - token = @tokens[i] + while token = tokens[i] return action.call this, token, i if levels is 0 and condition.call this, token, i return action.call this, token, i - 1 if not token or levels < 0 if include EXPRESSION_START, token[0] diff --git a/test/test_compilation.coffee b/test/test_compilation.coffee index e5b4ec49..5c78c3b2 100644 --- a/test/test_compilation.coffee +++ b/test/test_compilation.coffee @@ -13,3 +13,10 @@ CoffeeScript.run("resultArray.push i for i of global", {noWrap: on, globals: on, ok 'setInterval' in global.resultArray ok 'passed' is CoffeeScript.eval '"passed"', noWrap: on, globals: on, fileName: 'tests' + +#750 +try + CoffeeScript.nodes 'f(->' + ok no +catch e + eq e.message, 'unclosed CALL_START on line 1' diff --git a/test/test_existence.coffee b/test/test_existence.coffee index 96e19ede..d012361a 100644 --- a/test/test_existence.coffee +++ b/test/test_existence.coffee @@ -92,6 +92,7 @@ ok not value?.property?, 'safely checks existence on soaks' eq nothing?.value, undefined, 'safely calls values off of non-existent variables' +eq !nothing?.value and 1, 1, 'corresponding operators work as expected' # Assign to the result of an exsitential operation with a minus.