Unify, simplify and fixup assignment errors
- Show the same type of error message for compound assignment as for `=` assignment when the LHS is invalid. - Show the same type of error message when trying to assign to a CoffeeScript keyword as when trying to assign to a JavaScript keyword. - Now longer treat `&& =` as `&&=`. The same goes for `and=`, `||=` and `or=`. - Unify the error message to: `<optional type> '<value>' can't be assigned`.
This commit is contained in:
parent
585932cf5b
commit
4d8cd03298
|
@ -1,7 +1,8 @@
|
||||||
// Generated by CoffeeScript 1.10.0
|
// Generated by CoffeeScript 1.10.0
|
||||||
(function() {
|
(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, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, 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, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, 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; };
|
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;
|
||||||
|
|
||||||
ref = require('./rewriter'), Rewriter = ref.Rewriter, INVERSES = ref.INVERSES;
|
ref = require('./rewriter'), Rewriter = ref.Rewriter, INVERSES = ref.INVERSES;
|
||||||
|
|
||||||
|
@ -495,7 +496,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
Lexer.prototype.literalToken = function() {
|
Lexer.prototype.literalToken = function() {
|
||||||
var match, prev, ref2, ref3, ref4, ref5, ref6, tag, token, value;
|
var match, message, origin, prev, ref2, ref3, ref4, ref5, ref6, skipToken, tag, token, value;
|
||||||
if (match = OPERATOR.exec(this.chunk)) {
|
if (match = OPERATOR.exec(this.chunk)) {
|
||||||
value = match[0];
|
value = match[0];
|
||||||
if (CODE.test(value)) {
|
if (CODE.test(value)) {
|
||||||
|
@ -506,16 +507,22 @@
|
||||||
}
|
}
|
||||||
tag = value;
|
tag = value;
|
||||||
ref2 = this.tokens, prev = ref2[ref2.length - 1];
|
ref2 = this.tokens, prev = ref2[ref2.length - 1];
|
||||||
if (value === '=' && prev) {
|
if (prev && indexOf.call(['='].concat(slice.call(COMPOUND_ASSIGN)), value) >= 0) {
|
||||||
if (prev.variable && (ref3 = prev[1], indexOf.call(JS_FORBIDDEN, ref3) >= 0)) {
|
skipToken = false;
|
||||||
if (prev.origin) {
|
if (value === '=' && ((ref3 = prev[1]) === '||' || ref3 === '&&') && !prev.spaced) {
|
||||||
prev = prev.origin;
|
|
||||||
}
|
|
||||||
this.error("reserved word '" + prev[1] + "' can't be assigned", prev[2]);
|
|
||||||
}
|
|
||||||
if ((ref4 = prev[1]) === '||' || ref4 === '&&') {
|
|
||||||
prev[0] = 'COMPOUND_ASSIGN';
|
prev[0] = 'COMPOUND_ASSIGN';
|
||||||
prev[1] += '=';
|
prev[1] += '=';
|
||||||
|
prev = this.tokens[this.tokens.length - 2];
|
||||||
|
skipToken = true;
|
||||||
|
}
|
||||||
|
if (prev && prev.variable) {
|
||||||
|
origin = (ref4 = prev.origin) != null ? ref4 : prev;
|
||||||
|
message = isUnassignable(prev[1], origin[1]);
|
||||||
|
if (message) {
|
||||||
|
this.error(message, origin[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (skipToken) {
|
||||||
return value.length;
|
return value.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -886,6 +893,24 @@
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
isUnassignable = function(name, displayName) {
|
||||||
|
if (displayName == null) {
|
||||||
|
displayName = name;
|
||||||
|
}
|
||||||
|
switch (false) {
|
||||||
|
case indexOf.call(slice.call(JS_KEYWORDS).concat(slice.call(COFFEE_KEYWORDS)), name) < 0:
|
||||||
|
return "keyword '" + displayName + "' can't be assigned";
|
||||||
|
case indexOf.call(STRICT_PROSCRIBED, name) < 0:
|
||||||
|
return "'" + displayName + "' can't be assigned";
|
||||||
|
case indexOf.call(RESERVED, name) < 0:
|
||||||
|
return "reserved word '" + displayName + "' can't be assigned";
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.isUnassignable = isUnassignable;
|
||||||
|
|
||||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'yield', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'yield', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
||||||
|
|
||||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
|
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
|
||||||
|
@ -915,15 +940,11 @@
|
||||||
|
|
||||||
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static'];
|
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static'];
|
||||||
|
|
||||||
STRICT_PROSCRIBED = ['arguments', 'eval', 'yield*'];
|
STRICT_PROSCRIBED = ['arguments', 'eval'];
|
||||||
|
|
||||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED);
|
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED);
|
||||||
|
|
||||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED);
|
exports.JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED);
|
||||||
|
|
||||||
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED;
|
|
||||||
|
|
||||||
exports.JS_FORBIDDEN = JS_FORBIDDEN;
|
|
||||||
|
|
||||||
BOM = 65279;
|
BOM = 65279;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Generated by CoffeeScript 1.10.0
|
// Generated by CoffeeScript 1.10.0
|
||||||
(function() {
|
(function() {
|
||||||
var Access, Arr, Assign, Base, Block, BooleanLiteral, Call, Class, Code, CodeFragment, Comment, Existence, Expansion, Extends, For, IdentifierLiteral, If, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, NEGATE, NO, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, RESERVED, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, SuperCall, Switch, TAB, THIS, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isComplexOrAssignable, isLiteralArguments, isLiteralThis, locationDataToString, merge, multident, ref1, ref2, some, starts, throwSyntaxError, unfoldSoak, utility,
|
var Access, Arr, Assign, Base, Block, BooleanLiteral, Call, Class, Code, CodeFragment, Comment, Existence, Expansion, Extends, For, IdentifierLiteral, If, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, NEGATE, NO, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, SuperCall, Switch, TAB, THIS, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isComplexOrAssignable, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, multident, ref1, ref2, some, starts, throwSyntaxError, unfoldSoak, utility,
|
||||||
extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||||
hasProp = {}.hasOwnProperty,
|
hasProp = {}.hasOwnProperty,
|
||||||
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; },
|
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; },
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
Scope = require('./scope').Scope;
|
Scope = require('./scope').Scope;
|
||||||
|
|
||||||
ref1 = require('./lexer'), RESERVED = ref1.RESERVED, STRICT_PROSCRIBED = ref1.STRICT_PROSCRIBED, JS_FORBIDDEN = ref1.JS_FORBIDDEN;
|
ref1 = require('./lexer'), isUnassignable = ref1.isUnassignable, JS_FORBIDDEN = ref1.JS_FORBIDDEN;
|
||||||
|
|
||||||
ref2 = require('./helpers'), compact = ref2.compact, flatten = ref2.flatten, extend = ref2.extend, merge = ref2.merge, del = ref2.del, starts = ref2.starts, ends = ref2.ends, some = ref2.some, addLocationDataFn = ref2.addLocationDataFn, locationDataToString = ref2.locationDataToString, throwSyntaxError = ref2.throwSyntaxError;
|
ref2 = require('./helpers'), compact = ref2.compact, flatten = ref2.flatten, extend = ref2.extend, merge = ref2.merge, del = ref2.del, starts = ref2.starts, ends = ref2.ends, some = ref2.some, addLocationDataFn = ref2.addLocationDataFn, locationDataToString = ref2.locationDataToString, throwSyntaxError = ref2.throwSyntaxError;
|
||||||
|
|
||||||
|
@ -608,10 +608,7 @@
|
||||||
return IdentifierLiteral.__super__.constructor.apply(this, arguments);
|
return IdentifierLiteral.__super__.constructor.apply(this, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentifierLiteral.prototype.isAssignable = function() {
|
IdentifierLiteral.prototype.isAssignable = YES;
|
||||||
var ref3;
|
|
||||||
return ref3 = this.value, indexOf.call(RESERVED, ref3) < 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
return IdentifierLiteral;
|
return IdentifierLiteral;
|
||||||
|
|
||||||
|
@ -1580,7 +1577,7 @@
|
||||||
Class.prototype.defaultClassVariableName = '_Class';
|
Class.prototype.defaultClassVariableName = '_Class';
|
||||||
|
|
||||||
Class.prototype.determineName = function() {
|
Class.prototype.determineName = function() {
|
||||||
var name, node, ref3, tail;
|
var message, name, node, ref3, tail;
|
||||||
if (!this.variable) {
|
if (!this.variable) {
|
||||||
return this.defaultClassVariableName;
|
return this.defaultClassVariableName;
|
||||||
}
|
}
|
||||||
|
@ -1590,6 +1587,12 @@
|
||||||
return this.defaultClassVariableName;
|
return this.defaultClassVariableName;
|
||||||
}
|
}
|
||||||
name = node.value;
|
name = node.value;
|
||||||
|
if (!tail) {
|
||||||
|
message = isUnassignable(name);
|
||||||
|
if (message) {
|
||||||
|
this.variable.error(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (indexOf.call(JS_FORBIDDEN, name) >= 0) {
|
if (indexOf.call(JS_FORBIDDEN, name) >= 0) {
|
||||||
return "_" + name;
|
return "_" + name;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1762,7 +1765,6 @@
|
||||||
extend1(Assign, superClass1);
|
extend1(Assign, superClass1);
|
||||||
|
|
||||||
function Assign(variable1, value1, context, options) {
|
function Assign(variable1, value1, context, options) {
|
||||||
var forbidden, name, ref3;
|
|
||||||
this.variable = variable1;
|
this.variable = variable1;
|
||||||
this.value = value1;
|
this.value = value1;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -1770,10 +1772,6 @@
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
this.param = options.param, this.subpattern = options.subpattern, this.operatorToken = options.operatorToken;
|
this.param = options.param, this.subpattern = options.subpattern, this.operatorToken = options.operatorToken;
|
||||||
forbidden = (ref3 = (name = this.variable.unwrapAll().value), indexOf.call(STRICT_PROSCRIBED, ref3) >= 0);
|
|
||||||
if (forbidden && this.context !== 'object') {
|
|
||||||
this.variable.error("variable name may not be \"" + name + "\"");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Assign.prototype.children = ['variable', 'value'];
|
Assign.prototype.children = ['variable', 'value'];
|
||||||
|
@ -1823,7 +1821,7 @@
|
||||||
if (!this.context) {
|
if (!this.context) {
|
||||||
varBase = this.variable.unwrapAll();
|
varBase = this.variable.unwrapAll();
|
||||||
if (!varBase.isAssignable()) {
|
if (!varBase.isAssignable()) {
|
||||||
this.variable.error("\"" + (this.variable.compile(o)) + "\" cannot be assigned");
|
this.variable.error("'" + (this.variable.compile(o)) + "' can't be assigned");
|
||||||
}
|
}
|
||||||
if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) {
|
if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) {
|
||||||
if (this.param) {
|
if (this.param) {
|
||||||
|
@ -1854,7 +1852,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
Assign.prototype.compilePatternMatch = function(o) {
|
Assign.prototype.compilePatternMatch = function(o) {
|
||||||
var acc, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, name, obj, objects, olen, ref, ref3, ref4, ref5, ref6, ref7, rest, top, val, value, vvar, vvarText;
|
var acc, assigns, code, defaultValue, expandedIdx, fragments, i, idx, isObject, ivar, j, len1, message, name, obj, objects, olen, ref, ref3, ref4, ref5, ref6, rest, top, val, value, vvar, vvarText;
|
||||||
top = o.level === LEVEL_TOP;
|
top = o.level === LEVEL_TOP;
|
||||||
value = this.value;
|
value = this.value;
|
||||||
objects = this.variable.base.objects;
|
objects = this.variable.base.objects;
|
||||||
|
@ -1889,8 +1887,9 @@
|
||||||
acc = idx.unwrap() instanceof IdentifierLiteral;
|
acc = idx.unwrap() instanceof IdentifierLiteral;
|
||||||
value = new Value(value);
|
value = new Value(value);
|
||||||
value.properties.push(new (acc ? Access : Index)(idx));
|
value.properties.push(new (acc ? Access : Index)(idx));
|
||||||
if (ref5 = obj.unwrap().value, indexOf.call(RESERVED, ref5) >= 0) {
|
message = isUnassignable(obj.unwrap().value);
|
||||||
obj.error("assignment to a reserved word: " + (obj.compile(o)));
|
if (message) {
|
||||||
|
obj.error(message);
|
||||||
}
|
}
|
||||||
if (defaultValue) {
|
if (defaultValue) {
|
||||||
value = new Op('?', value, defaultValue);
|
value = new Op('?', value, defaultValue);
|
||||||
|
@ -1945,7 +1944,7 @@
|
||||||
}
|
}
|
||||||
defaultValue = null;
|
defaultValue = null;
|
||||||
if (obj instanceof Assign && obj.context === 'object') {
|
if (obj instanceof Assign && obj.context === 'object') {
|
||||||
ref6 = obj, (ref7 = ref6.variable, idx = ref7.base), obj = ref6.value;
|
ref5 = obj, (ref6 = ref5.variable, idx = ref6.base), obj = ref5.value;
|
||||||
if (obj instanceof Assign) {
|
if (obj instanceof Assign) {
|
||||||
defaultValue = obj.value;
|
defaultValue = obj.value;
|
||||||
obj = obj.variable;
|
obj = obj.variable;
|
||||||
|
@ -1964,8 +1963,11 @@
|
||||||
val = new Op('?', val, defaultValue);
|
val = new Op('?', val, defaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((name != null) && indexOf.call(RESERVED, name) >= 0) {
|
if (name != null) {
|
||||||
obj.error("assignment to a reserved word: " + (obj.compile(o)));
|
message = isUnassignable(name);
|
||||||
|
if (message) {
|
||||||
|
obj.error(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assigns.push(new Assign(obj, val, null, {
|
assigns.push(new Assign(obj, val, null, {
|
||||||
param: this.param,
|
param: this.param,
|
||||||
|
@ -2223,12 +2225,13 @@
|
||||||
extend1(Param, superClass1);
|
extend1(Param, superClass1);
|
||||||
|
|
||||||
function Param(name1, value1, splat) {
|
function Param(name1, value1, splat) {
|
||||||
var name, ref3, token;
|
var message, token;
|
||||||
this.name = name1;
|
this.name = name1;
|
||||||
this.value = value1;
|
this.value = value1;
|
||||||
this.splat = splat;
|
this.splat = splat;
|
||||||
if (ref3 = (name = this.name.unwrapAll().value), indexOf.call(STRICT_PROSCRIBED, ref3) >= 0) {
|
message = isUnassignable(this.name.unwrapAll().value);
|
||||||
this.name.error("parameter name \"" + name + "\" is not allowed");
|
if (message) {
|
||||||
|
this.name.error(message);
|
||||||
}
|
}
|
||||||
if (this.name instanceof Obj && this.name.generated) {
|
if (this.name instanceof Obj && this.name.generated) {
|
||||||
token = this.name.objects[0].operatorToken;
|
token = this.name.objects[0].operatorToken;
|
||||||
|
@ -2611,7 +2614,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
Op.prototype.compileNode = function(o) {
|
Op.prototype.compileNode = function(o) {
|
||||||
var answer, isChain, lhs, ref3, ref4, rhs;
|
var answer, isChain, lhs, message, ref3, rhs;
|
||||||
isChain = this.isChainable() && this.first.isChainable();
|
isChain = this.isChainable() && this.first.isChainable();
|
||||||
if (!isChain) {
|
if (!isChain) {
|
||||||
this.first.front = this.front;
|
this.first.front = this.front;
|
||||||
|
@ -2619,8 +2622,11 @@
|
||||||
if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) {
|
if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) {
|
||||||
this.error('delete operand may not be argument or var');
|
this.error('delete operand may not be argument or var');
|
||||||
}
|
}
|
||||||
if (((ref3 = this.operator) === '--' || ref3 === '++') && (ref4 = this.first.unwrapAll().value, indexOf.call(STRICT_PROSCRIBED, ref4) >= 0)) {
|
if ((ref3 = this.operator) === '--' || ref3 === '++') {
|
||||||
this.error("cannot increment/decrement \"" + (this.first.unwrapAll().value) + "\"");
|
message = isUnassignable(this.first.unwrapAll().value);
|
||||||
|
if (message) {
|
||||||
|
this.first.error(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.isYield()) {
|
if (this.isYield()) {
|
||||||
return this.compileYield(o);
|
return this.compileYield(o);
|
||||||
|
@ -2858,12 +2864,12 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
Try.prototype.compileNode = function(o) {
|
Try.prototype.compileNode = function(o) {
|
||||||
var catchPart, ensurePart, generatedErrorVariableName, placeholder, tryPart;
|
var catchPart, ensurePart, generatedErrorVariableName, message, placeholder, tryPart;
|
||||||
o.indent += TAB;
|
o.indent += TAB;
|
||||||
tryPart = this.attempt.compileToFragments(o, LEVEL_TOP);
|
tryPart = this.attempt.compileToFragments(o, LEVEL_TOP);
|
||||||
catchPart = this.recovery ? (generatedErrorVariableName = o.scope.freeVariable('error', {
|
catchPart = this.recovery ? (generatedErrorVariableName = o.scope.freeVariable('error', {
|
||||||
reserve: false
|
reserve: false
|
||||||
}), placeholder = new IdentifierLiteral(generatedErrorVariableName), this.errorVariable ? this.recovery.unshift(new Assign(this.errorVariable, placeholder)) : void 0, [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}"))) : !(this.ensure || this.recovery) ? (generatedErrorVariableName = o.scope.freeVariable('error', {
|
}), placeholder = new IdentifierLiteral(generatedErrorVariableName), this.errorVariable ? (message = isUnassignable(this.errorVariable.unwrapAll().value), message ? this.errorVariable.error(message) : void 0, this.recovery.unshift(new Assign(this.errorVariable, placeholder))) : void 0, [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}"))) : !(this.ensure || this.recovery) ? (generatedErrorVariableName = o.scope.freeVariable('error', {
|
||||||
reserve: false
|
reserve: false
|
||||||
}), [this.makeCode(" catch (" + generatedErrorVariableName + ") {}")]) : [];
|
}), [this.makeCode(" catch (" + generatedErrorVariableName + ") {}")]) : [];
|
||||||
ensurePart = this.ensure ? [].concat(this.makeCode(" finally {\n"), this.ensure.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}")) : [];
|
ensurePart = this.ensure ? [].concat(this.makeCode(" finally {\n"), this.ensure.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}")) : [];
|
||||||
|
|
|
@ -411,14 +411,20 @@ exports.Lexer = class Lexer
|
||||||
value = @chunk.charAt 0
|
value = @chunk.charAt 0
|
||||||
tag = value
|
tag = value
|
||||||
[..., prev] = @tokens
|
[..., prev] = @tokens
|
||||||
if value is '=' and prev
|
|
||||||
if prev.variable and prev[1] in JS_FORBIDDEN
|
if prev and value in ['=', COMPOUND_ASSIGN...]
|
||||||
prev = prev.origin if prev.origin
|
skipToken = false
|
||||||
@error "reserved word '#{prev[1]}' can't be assigned", prev[2]
|
if value is '=' and prev[1] in ['||', '&&'] and not prev.spaced
|
||||||
if prev[1] in ['||', '&&']
|
|
||||||
prev[0] = 'COMPOUND_ASSIGN'
|
prev[0] = 'COMPOUND_ASSIGN'
|
||||||
prev[1] += '='
|
prev[1] += '='
|
||||||
return value.length
|
prev = @tokens[@tokens.length - 2]
|
||||||
|
skipToken = true
|
||||||
|
if prev and prev.variable
|
||||||
|
origin = prev.origin ? prev
|
||||||
|
message = isUnassignable prev[1], origin[1]
|
||||||
|
@error message, origin[2] if message
|
||||||
|
return value.length if skipToken
|
||||||
|
|
||||||
if value is ';'
|
if value is ';'
|
||||||
@seenFor = no
|
@seenFor = no
|
||||||
tag = 'TERMINATOR'
|
tag = 'TERMINATOR'
|
||||||
|
@ -744,6 +750,21 @@ exports.Lexer = class Lexer
|
||||||
{first_line, first_column, last_column: first_column + (options.length ? 1) - 1}
|
{first_line, first_column, last_column: first_column + (options.length ? 1) - 1}
|
||||||
throwSyntaxError message, location
|
throwSyntaxError message, location
|
||||||
|
|
||||||
|
# Helper functions
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
isUnassignable = (name, displayName = name) -> switch
|
||||||
|
when name in [JS_KEYWORDS..., COFFEE_KEYWORDS...]
|
||||||
|
"keyword '#{displayName}' can't be assigned"
|
||||||
|
when name in STRICT_PROSCRIBED
|
||||||
|
"'#{displayName}' can't be assigned"
|
||||||
|
when name in RESERVED
|
||||||
|
"reserved word '#{displayName}' can't be assigned"
|
||||||
|
else
|
||||||
|
false
|
||||||
|
|
||||||
|
exports.isUnassignable = isUnassignable
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
# ---------
|
# ---------
|
||||||
|
|
||||||
|
@ -782,15 +803,12 @@ RESERVED = [
|
||||||
'protected', 'public', 'static'
|
'protected', 'public', 'static'
|
||||||
]
|
]
|
||||||
|
|
||||||
STRICT_PROSCRIBED = ['arguments', 'eval', 'yield*']
|
STRICT_PROSCRIBED = ['arguments', 'eval']
|
||||||
|
|
||||||
# The superset of both JavaScript keywords and reserved words, none of which may
|
# The superset of both JavaScript keywords and reserved words, none of which may
|
||||||
# be used as identifiers or properties.
|
# be used as identifiers or properties.
|
||||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
|
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
|
||||||
|
exports.JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
|
||||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED)
|
|
||||||
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED
|
|
||||||
exports.JS_FORBIDDEN = JS_FORBIDDEN
|
|
||||||
|
|
||||||
# The character code of the nasty Microsoft madness otherwise known as the BOM.
|
# The character code of the nasty Microsoft madness otherwise known as the BOM.
|
||||||
BOM = 65279
|
BOM = 65279
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Error.stackTraceLimit = Infinity
|
Error.stackTraceLimit = Infinity
|
||||||
|
|
||||||
{Scope} = require './scope'
|
{Scope} = require './scope'
|
||||||
{RESERVED, STRICT_PROSCRIBED, JS_FORBIDDEN} = require './lexer'
|
{isUnassignable, JS_FORBIDDEN} = require './lexer'
|
||||||
|
|
||||||
# Import the helpers we plan to use.
|
# Import the helpers we plan to use.
|
||||||
{compact, flatten, extend, merge, del, starts, ends, some,
|
{compact, flatten, extend, merge, del, starts, ends, some,
|
||||||
|
@ -411,7 +411,7 @@ exports.RegexLiteral = class RegexLiteral extends Literal
|
||||||
exports.PassthroughLiteral = class PassthroughLiteral extends Literal
|
exports.PassthroughLiteral = class PassthroughLiteral extends Literal
|
||||||
|
|
||||||
exports.IdentifierLiteral = class IdentifierLiteral extends Literal
|
exports.IdentifierLiteral = class IdentifierLiteral extends Literal
|
||||||
isAssignable: -> @value not in RESERVED
|
isAssignable: YES
|
||||||
|
|
||||||
exports.StatementLiteral = class StatementLiteral extends Literal
|
exports.StatementLiteral = class StatementLiteral extends Literal
|
||||||
isStatement: YES
|
isStatement: YES
|
||||||
|
@ -1081,6 +1081,9 @@ exports.Class = class Class extends Base
|
||||||
@variable.base
|
@variable.base
|
||||||
return @defaultClassVariableName unless node instanceof IdentifierLiteral
|
return @defaultClassVariableName unless node instanceof IdentifierLiteral
|
||||||
name = node.value
|
name = node.value
|
||||||
|
unless tail
|
||||||
|
message = isUnassignable name
|
||||||
|
@variable.error message if message
|
||||||
if name in JS_FORBIDDEN then "_#{name}" else name
|
if name in JS_FORBIDDEN then "_#{name}" else name
|
||||||
|
|
||||||
# For all `this`-references and bound functions in the class definition,
|
# For all `this`-references and bound functions in the class definition,
|
||||||
|
@ -1215,9 +1218,6 @@ exports.Class = class Class extends Base
|
||||||
exports.Assign = class Assign extends Base
|
exports.Assign = class Assign extends Base
|
||||||
constructor: (@variable, @value, @context, options = {}) ->
|
constructor: (@variable, @value, @context, options = {}) ->
|
||||||
{@param, @subpattern, @operatorToken} = options
|
{@param, @subpattern, @operatorToken} = options
|
||||||
forbidden = (name = @variable.unwrapAll().value) in STRICT_PROSCRIBED
|
|
||||||
if forbidden and @context isnt 'object'
|
|
||||||
@variable.error "variable name may not be \"#{name}\""
|
|
||||||
|
|
||||||
children: ['variable', 'value']
|
children: ['variable', 'value']
|
||||||
|
|
||||||
|
@ -1254,7 +1254,7 @@ exports.Assign = class Assign extends Base
|
||||||
unless @context
|
unless @context
|
||||||
varBase = @variable.unwrapAll()
|
varBase = @variable.unwrapAll()
|
||||||
unless varBase.isAssignable()
|
unless varBase.isAssignable()
|
||||||
@variable.error "\"#{@variable.compile o}\" cannot be assigned"
|
@variable.error "'#{@variable.compile o}' can't be assigned"
|
||||||
unless varBase.hasProperties?()
|
unless varBase.hasProperties?()
|
||||||
if @param
|
if @param
|
||||||
o.scope.add varBase.value, 'var'
|
o.scope.add varBase.value, 'var'
|
||||||
|
@ -1309,8 +1309,8 @@ exports.Assign = class Assign extends Base
|
||||||
acc = idx.unwrap() instanceof IdentifierLiteral
|
acc = idx.unwrap() instanceof IdentifierLiteral
|
||||||
value = new Value value
|
value = new Value value
|
||||||
value.properties.push new (if acc then Access else Index) idx
|
value.properties.push new (if acc then Access else Index) idx
|
||||||
if obj.unwrap().value in RESERVED
|
message = isUnassignable obj.unwrap().value
|
||||||
obj.error "assignment to a reserved word: #{obj.compile o}"
|
obj.error message if message
|
||||||
value = new Op '?', value, defaultValue if defaultValue
|
value = new Op '?', value, defaultValue if defaultValue
|
||||||
return new Assign(obj, value, null, param: @param).compileToFragments o, LEVEL_TOP
|
return new Assign(obj, value, null, param: @param).compileToFragments o, LEVEL_TOP
|
||||||
vvar = value.compileToFragments o, LEVEL_LIST
|
vvar = value.compileToFragments o, LEVEL_LIST
|
||||||
|
@ -1369,8 +1369,9 @@ exports.Assign = class Assign extends Base
|
||||||
acc = idx.unwrap() instanceof IdentifierLiteral
|
acc = idx.unwrap() instanceof IdentifierLiteral
|
||||||
val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
|
val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
|
||||||
val = new Op '?', val, defaultValue if defaultValue
|
val = new Op '?', val, defaultValue if defaultValue
|
||||||
if name? and name in RESERVED
|
if name?
|
||||||
obj.error "assignment to a reserved word: #{obj.compile o}"
|
message = isUnassignable name
|
||||||
|
obj.error message if message
|
||||||
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
|
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
|
||||||
assigns.push vvar unless top or @subpattern
|
assigns.push vvar unless top or @subpattern
|
||||||
fragments = @joinFragmentArrays assigns, ', '
|
fragments = @joinFragmentArrays assigns, ', '
|
||||||
|
@ -1527,8 +1528,8 @@ exports.Code = class Code extends Base
|
||||||
# as well as be a splat, gathering up a group of parameters into an array.
|
# as well as be a splat, gathering up a group of parameters into an array.
|
||||||
exports.Param = class Param extends Base
|
exports.Param = class Param extends Base
|
||||||
constructor: (@name, @value, @splat) ->
|
constructor: (@name, @value, @splat) ->
|
||||||
if (name = @name.unwrapAll().value) in STRICT_PROSCRIBED
|
message = isUnassignable @name.unwrapAll().value
|
||||||
@name.error "parameter name \"#{name}\" is not allowed"
|
@name.error message if message
|
||||||
if @name instanceof Obj and @name.generated
|
if @name instanceof Obj and @name.generated
|
||||||
token = @name.objects[0].operatorToken
|
token = @name.objects[0].operatorToken
|
||||||
token.error "unexpected #{token.value}"
|
token.error "unexpected #{token.value}"
|
||||||
|
@ -1817,8 +1818,9 @@ exports.Op = class Op extends Base
|
||||||
@first.front = @front unless isChain
|
@first.front = @front unless isChain
|
||||||
if @operator is 'delete' and o.scope.check(@first.unwrapAll().value)
|
if @operator is 'delete' and o.scope.check(@first.unwrapAll().value)
|
||||||
@error 'delete operand may not be argument or var'
|
@error 'delete operand may not be argument or var'
|
||||||
if @operator in ['--', '++'] and @first.unwrapAll().value in STRICT_PROSCRIBED
|
if @operator in ['--', '++']
|
||||||
@error "cannot increment/decrement \"#{@first.unwrapAll().value}\""
|
message = isUnassignable @first.unwrapAll().value
|
||||||
|
@first.error message if message
|
||||||
return @compileYield o if @isYield()
|
return @compileYield o if @isYield()
|
||||||
return @compileUnary o if @isUnary()
|
return @compileUnary o if @isUnary()
|
||||||
return @compileChain o if isChain
|
return @compileChain o if isChain
|
||||||
|
@ -1969,7 +1971,10 @@ exports.Try = class Try extends Base
|
||||||
catchPart = if @recovery
|
catchPart = if @recovery
|
||||||
generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
|
generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
|
||||||
placeholder = new IdentifierLiteral generatedErrorVariableName
|
placeholder = new IdentifierLiteral generatedErrorVariableName
|
||||||
@recovery.unshift new Assign @errorVariable, placeholder if @errorVariable
|
if @errorVariable
|
||||||
|
message = isUnassignable @errorVariable.unwrapAll().value
|
||||||
|
@errorVariable.error message if message
|
||||||
|
@recovery.unshift new Assign @errorVariable, placeholder
|
||||||
[].concat @makeCode(" catch ("), placeholder.compileToFragments(o), @makeCode(") {\n"),
|
[].concat @makeCode(" catch ("), placeholder.compileToFragments(o), @makeCode(") {\n"),
|
||||||
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
|
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
|
||||||
else unless @ensure or @recovery
|
else unless @ensure or @recovery
|
||||||
|
|
|
@ -36,7 +36,7 @@ test "compiler error formatting", ->
|
||||||
evil = (foo, eval, bar) ->
|
evil = (foo, eval, bar) ->
|
||||||
''',
|
''',
|
||||||
'''
|
'''
|
||||||
[stdin]:1:14: error: parameter name "eval" is not allowed
|
[stdin]:1:14: error: 'eval' can't be assigned
|
||||||
evil = (foo, eval, bar) ->
|
evil = (foo, eval, bar) ->
|
||||||
^^^^
|
^^^^
|
||||||
'''
|
'''
|
||||||
|
@ -656,22 +656,88 @@ test "reserved words", ->
|
||||||
case
|
case
|
||||||
^^^^
|
^^^^
|
||||||
'''
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
case = 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:1: error: reserved word 'case'
|
||||||
|
case = 1
|
||||||
|
^^^^
|
||||||
|
'''
|
||||||
assertErrorFormat '''
|
assertErrorFormat '''
|
||||||
for = 1
|
for = 1
|
||||||
''', '''
|
''', '''
|
||||||
[stdin]:1:1: error: reserved word 'for' can't be assigned
|
[stdin]:1:1: error: keyword 'for' can't be assigned
|
||||||
for = 1
|
for = 1
|
||||||
^^^
|
^^^
|
||||||
'''
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
unless = 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:1: error: keyword 'unless' can't be assigned
|
||||||
|
unless = 1
|
||||||
|
^^^^^^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
for += 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:1: error: keyword 'for' can't be assigned
|
||||||
|
for += 1
|
||||||
|
^^^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
for &&= 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:1: error: keyword 'for' can't be assigned
|
||||||
|
for &&= 1
|
||||||
|
^^^
|
||||||
|
'''
|
||||||
|
# Make sure token look-behind doesn't go out of range.
|
||||||
|
assertErrorFormat '''
|
||||||
|
&&= 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:1: error: unexpected &&=
|
||||||
|
&&= 1
|
||||||
|
^^^
|
||||||
|
'''
|
||||||
# #2306: Show unaliased name in error messages.
|
# #2306: Show unaliased name in error messages.
|
||||||
assertErrorFormat '''
|
assertErrorFormat '''
|
||||||
on = 1
|
on = 1
|
||||||
''', '''
|
''', '''
|
||||||
[stdin]:1:1: error: reserved word 'on' can't be assigned
|
[stdin]:1:1: error: keyword 'on' can't be assigned
|
||||||
on = 1
|
on = 1
|
||||||
^^
|
^^
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
test "strict mode errors", ->
|
||||||
|
assertErrorFormat '''
|
||||||
|
eval = 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:1: error: 'eval' can't be assigned
|
||||||
|
eval = 1
|
||||||
|
^^^^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
class eval
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:7: error: 'eval' can't be assigned
|
||||||
|
class eval
|
||||||
|
^^^^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
arguments++
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:1: error: 'arguments' can't be assigned
|
||||||
|
arguments++
|
||||||
|
^^^^^^^^^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
--arguments
|
||||||
|
''', '''
|
||||||
|
[stdin]:1:3: error: 'arguments' can't be assigned
|
||||||
|
--arguments
|
||||||
|
^^^^^^^^^
|
||||||
|
'''
|
||||||
|
|
||||||
test "invalid numbers", ->
|
test "invalid numbers", ->
|
||||||
assertErrorFormat '''
|
assertErrorFormat '''
|
||||||
0X0
|
0X0
|
||||||
|
@ -832,35 +898,35 @@ test "#4130: unassignable in destructured param", ->
|
||||||
}) ->
|
}) ->
|
||||||
console.log "Oh hello!"
|
console.log "Oh hello!"
|
||||||
''', '''
|
''', '''
|
||||||
[stdin]:2:12: error: assignment to a reserved word: null
|
[stdin]:2:12: error: keyword 'null' can't be assigned
|
||||||
@param : null
|
@param : null
|
||||||
^^^^
|
^^^^
|
||||||
'''
|
'''
|
||||||
assertErrorFormat '''
|
assertErrorFormat '''
|
||||||
({a: null}) ->
|
({a: null}) ->
|
||||||
''', '''
|
''', '''
|
||||||
[stdin]:1:6: error: assignment to a reserved word: null
|
[stdin]:1:6: error: keyword 'null' can't be assigned
|
||||||
({a: null}) ->
|
({a: null}) ->
|
||||||
^^^^
|
^^^^
|
||||||
'''
|
'''
|
||||||
assertErrorFormat '''
|
assertErrorFormat '''
|
||||||
({a: 1}) ->
|
({a: 1}) ->
|
||||||
''', '''
|
''', '''
|
||||||
[stdin]:1:6: error: "1" cannot be assigned
|
[stdin]:1:6: error: '1' can't be assigned
|
||||||
({a: 1}) ->
|
({a: 1}) ->
|
||||||
^
|
^
|
||||||
'''
|
'''
|
||||||
assertErrorFormat '''
|
assertErrorFormat '''
|
||||||
({1}) ->
|
({1}) ->
|
||||||
''', '''
|
''', '''
|
||||||
[stdin]:1:3: error: "1" cannot be assigned
|
[stdin]:1:3: error: '1' can't be assigned
|
||||||
({1}) ->
|
({1}) ->
|
||||||
^
|
^
|
||||||
'''
|
'''
|
||||||
assertErrorFormat '''
|
assertErrorFormat '''
|
||||||
({a: true = 1}) ->
|
({a: true = 1}) ->
|
||||||
''', '''
|
''', '''
|
||||||
[stdin]:1:6: error: reserved word 'true' can't be assigned
|
[stdin]:1:6: error: keyword 'true' can't be assigned
|
||||||
({a: true = 1}) ->
|
({a: true = 1}) ->
|
||||||
^^^^
|
^^^^
|
||||||
'''
|
'''
|
||||||
|
@ -889,3 +955,37 @@ test "#4097: `yield return` as an expression", ->
|
||||||
-> (yield return)
|
-> (yield return)
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
test "`&&=` and `||=` with a space in-between", ->
|
||||||
|
assertErrorFormat '''
|
||||||
|
a = 0
|
||||||
|
a && = 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:2:6: error: unexpected =
|
||||||
|
a && = 1
|
||||||
|
^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
a = 0
|
||||||
|
a and = 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:2:7: error: unexpected =
|
||||||
|
a and = 1
|
||||||
|
^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
a = 0
|
||||||
|
a || = 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:2:6: error: unexpected =
|
||||||
|
a || = 1
|
||||||
|
^
|
||||||
|
'''
|
||||||
|
assertErrorFormat '''
|
||||||
|
a = 0
|
||||||
|
a or = 1
|
||||||
|
''', '''
|
||||||
|
[stdin]:2:6: error: unexpected =
|
||||||
|
a or = 1
|
||||||
|
^
|
||||||
|
'''
|
||||||
|
|
Loading…
Reference in New Issue