Restrict indented return arg to object (#4605)

* throw multiline implicit object [Fixes #3199]

* only return

* fix from code review

* test error on non-object

* test error on call indented non-object

* unique test names
This commit is contained in:
Julian Rosse
2017-07-09 12:29:47 -05:00
committed by Geoffrey Booth
parent e4bf1631e1
commit 799bc6e81c
7 changed files with 227 additions and 167 deletions

View File

@@ -143,6 +143,8 @@
Return: [
o('RETURN Expression', function() {
return new Return($2);
}), o('RETURN INDENT Object OUTDENT', function() {
return new Return(new Value($3));
}), o('RETURN', function() {
return new Return;
})

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 1.12.6
(function() {
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError,
var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, UNFINISHED, UNICODE_CODE_POINT_ESCAPE, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
slice = [].slice;
@@ -450,7 +450,7 @@
return indent.length;
}
if (size > this.indent) {
if (noNewlines || this.tag() === 'RETURN') {
if (noNewlines) {
this.indebt = size - this.indent;
this.suppressNewlines();
return indent.length;
@@ -874,7 +874,7 @@
Lexer.prototype.unfinished = function() {
var ref2;
return LINE_CONTINUER.test(this.chunk) || ((ref2 = this.tag()) === '\\' || ref2 === '.' || ref2 === '?.' || ref2 === '?::' || ref2 === 'UNARY' || ref2 === 'MATH' || ref2 === 'UNARY_MATH' || ref2 === '+' || ref2 === '-' || ref2 === '**' || ref2 === 'SHIFT' || ref2 === 'RELATION' || ref2 === 'COMPARE' || ref2 === '&' || ref2 === '^' || ref2 === '|' || ref2 === '&&' || ref2 === '||' || ref2 === 'BIN?' || ref2 === 'THROW' || ref2 === 'EXTENDS' || ref2 === 'DEFAULT');
return LINE_CONTINUER.test(this.chunk) || (ref2 = this.tag(), indexOf.call(UNFINISHED, ref2) >= 0);
};
Lexer.prototype.formatString = function(str, options) {
@@ -1161,4 +1161,6 @@
INDENTABLE_CLOSERS = [')', '}', ']'];
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', '**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||', 'BIN?', 'THROW', 'EXTENDS', 'DEFAULT'];
}).call(this);

File diff suppressed because one or more lines are too long

View File

@@ -211,6 +211,7 @@ grammar =
# A return statement from a function body.
Return: [
o 'RETURN Expression', -> new Return $2
o 'RETURN INDENT Object OUTDENT', -> new Return new Value $3
o 'RETURN', -> new Return
]

View File

@@ -378,7 +378,7 @@ exports.Lexer = class Lexer
return indent.length
if size > @indent
if noNewlines or @tag() is 'RETURN'
if noNewlines
@indebt = size - @indent
@suppressNewlines()
return indent.length
@@ -759,9 +759,7 @@ exports.Lexer = class Lexer
# Are we in the midst of an unfinished expression?
unfinished: ->
LINE_CONTINUER.test(@chunk) or
@tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
'**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||',
'BIN?', 'THROW', 'EXTENDS', 'DEFAULT']
@tag() in UNFINISHED
formatString: (str, options) ->
@replaceUnicodeCodePointEscapes str.replace(STRING_OMIT, '$1'), options
@@ -1094,3 +1092,8 @@ LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR']
# Additional indent in front of these is ignored.
INDENTABLE_CLOSERS = [')', '}', ']']
# Tokens that, when appearing at the end of a line, suppress a following TERMINATOR/INDENT token
UNFINISHED = ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
'**', 'SHIFT', 'RELATION', 'COMPARE', '&', '^', '|', '&&', '||',
'BIN?', 'THROW', 'EXTENDS', 'DEFAULT']

View File

@@ -1328,3 +1328,45 @@ test "#4283: error message for implicit call", ->
console.log {search, users, contacts users_to_display}
^^^^^^^^
'''
test "#3199: error message for call indented non-object", ->
assertErrorFormat '''
fn = ->
fn
1
''', '''
[stdin]:3:1: error: unexpected indentation
1
^^
'''
test "#3199: error message for call indented comprehension", ->
assertErrorFormat '''
fn = ->
fn
x for x in [1, 2, 3]
''', '''
[stdin]:3:1: error: unexpected indentation
x for x in [1, 2, 3]
^^
'''
test "#3199: error message for return indented non-object", ->
assertErrorFormat '''
return
1
''', '''
[stdin]:2:3: error: unexpected number
1
^
'''
test "#3199: error message for return indented comprehension", ->
assertErrorFormat '''
return
x for x in [1, 2, 3]
''', '''
[stdin]:2:3: error: unexpected identifier
x for x in [1, 2, 3]
^
'''

View File

@@ -298,3 +298,10 @@ test "#1275: allow indentation before closing brackets", ->
a = 1
)
eq 1, a
test "#3199: return multiline implicit object", ->
y = do ->
if no then return
type: 'a'
msg: 'b'
eq undefined, y