Arrow functions with concise bodies cannot return regular expressions
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Oct 2016 02:35:59 +0000 (02:35 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Oct 2016 02:35:59 +0000 (02:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163162

Reviewed by Filip Pizlo.

JSTests:

* ChakraCore/test/Operators/instanceof.baseline-jsc:
* ChakraCore/test/Regex/nul_character.baseline-jsc:
* ChakraCore/test/es5/Lex_u3.baseline-jsc:
* stress/parse-regexp-as-token.js: Added.
(shouldBe):

Source/JavaScriptCore:

When we encounter the RegExp in the parser, we first scan it as / or /=.
And if / or /= is parsed under the primary expression context, we rescan it
as RegExp. However, we did not update the token record information. So the
token record still says "I'm / or /=".

When we parse the string "() => /hello/", the last token becomes "/", which is
the first character of the RegExp, instead of "/hello/". Since the arrow
function parsing utilizes the end offset of the last token, we accidentally
recognize the range of the above arrow function as "() => /".

In this patch, we update the token when rescanning under the RegExp context.
This logic is similar to parsing Tail Template Literal token.

We also refine the error message for regular expression literals. And since
the REGEXP token is now introduced, the other error messages using that token
are improved too.

Currently, unterminated error messages can be seen in Parser.cpp. However,
these messages cannot be shown to users if the lexer has m_error. So these
code is meaningless. I'll move these tokenizing errors to the lexer in the
subsequent patch[1].

[1]: https://bugs.webkit.org/show_bug.cgi?id=163928

* parser/Lexer.cpp:
(JSC::Lexer<T>::fillTokenInfo):
(JSC::Lexer<T>::lex):
(JSC::Lexer<T>::scanRegExp):
(JSC::Lexer<T>::scanTrailingTemplateString):
(JSC::Lexer<T>::skipRegExp): Deleted.
* parser/Lexer.h:
(JSC::Lexer::getToken):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseAssignmentExpression):
* parser/Parser.h:
(JSC::Parser::getToken):
* parser/ParserTokens.h:

LayoutTests:

* fast/regex/dom/non-pattern-characters-expected.txt:
* js/arrowfunction-syntax-errors-expected.txt:
* js/regexp-compile-crash-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.4_Comments/S7.4_A4_T1-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.4_Comments/S7.4_A4_T4-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.2_T2-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.3_T1-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.3_T3-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.5_T1-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.5_T3-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.2_T1-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.3_T1-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.3_T3-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.5_T1-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.5_T3-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207798 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
JSTests/ChakraCore/test/Operators/instanceof.baseline-jsc
JSTests/ChakraCore/test/Regex/nul_character.baseline-jsc
JSTests/ChakraCore/test/es5/Lex_u3.baseline-jsc
JSTests/ChangeLog
JSTests/stress/parse-regexp-as-token.js [new file with mode: 0644]
LayoutTests/ChangeLog
LayoutTests/fast/regex/dom/non-pattern-characters-expected.txt
LayoutTests/js/arrowfunction-syntax-errors-expected.txt
LayoutTests/js/regexp-compile-crash-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.4_Comments/S7.4_A4_T1-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.4_Comments/S7.4_A4_T4-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.2_T2-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.3_T1-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.3_T3-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.5_T1-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.5_T3-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.2_T1-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.3_T1-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.3_T3-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.5_T1-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.5_T3-expected.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/Lexer.cpp
Source/JavaScriptCore/parser/Lexer.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/ParserTokens.h

index 4b47209..2fa2944 100644 (file)
@@ -228,7 +228,7 @@ new Object() instanceof foo : false
  Exception: new Object() instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'new Object() instanceof new Boolean(true)')
  Exception: new Object() instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'new Object() instanceof new Boolean(false)')
  Exception: new Object() instanceof new Date(). new Date() is not a function. (evaluating 'new Object() instanceof new Date()')
- Exception: new Object() instanceof /a+/. / is not a function. (evaluating 'new Object() instanceof /')
+ Exception: new Object() instanceof /a+/. /a+/ is not a function. (evaluating 'new Object() instanceof /a+/')
  Exception: f instanceof new Object(). new Object() is not a function. (evaluating 'f instanceof new Object()')
  Exception: f instanceof f. f is not a function. (evaluating 'f instanceof f')
  Exception: f instanceof b. b is not a function. (evaluating 'f instanceof b')
@@ -249,7 +249,7 @@ f instanceof foo : true
  Exception: f instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'f instanceof new Boolean(true)')
  Exception: f instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'f instanceof new Boolean(false)')
  Exception: f instanceof new Date(). new Date() is not a function. (evaluating 'f instanceof new Date()')
- Exception: f instanceof /a+/. / is not a function. (evaluating 'f instanceof /')
+ Exception: f instanceof /a+/. /a+/ is not a function. (evaluating 'f instanceof /a+/')
  Exception: b instanceof new Object(). new Object() is not a function. (evaluating 'b instanceof new Object()')
  Exception: b instanceof f. f is not a function. (evaluating 'b instanceof f')
  Exception: b instanceof b. b is not a function. (evaluating 'b instanceof b')
@@ -270,7 +270,7 @@ b instanceof foo : false
  Exception: b instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'b instanceof new Boolean(true)')
  Exception: b instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'b instanceof new Boolean(false)')
  Exception: b instanceof new Date(). new Date() is not a function. (evaluating 'b instanceof new Date()')
- Exception: b instanceof /a+/. / is not a function. (evaluating 'b instanceof /')
+ Exception: b instanceof /a+/. /a+/ is not a function. (evaluating 'b instanceof /a+/')
  Exception: foo instanceof new Object(). new Object() is not a function. (evaluating 'foo instanceof new Object()')
  Exception: foo instanceof f. f is not a function. (evaluating 'foo instanceof f')
  Exception: foo instanceof b. b is not a function. (evaluating 'foo instanceof b')
@@ -291,7 +291,7 @@ foo instanceof foo : false
  Exception: foo instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'foo instanceof new Boolean(true)')
  Exception: foo instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'foo instanceof new Boolean(false)')
  Exception: foo instanceof new Date(). new Date() is not a function. (evaluating 'foo instanceof new Date()')
- Exception: foo instanceof /a+/. / is not a function. (evaluating 'foo instanceof /')
+ Exception: foo instanceof /a+/. /a+/ is not a function. (evaluating 'foo instanceof /a+/')
  Exception: String.fromCharCode instanceof new Object(). new Object() is not a function. (evaluating 'String.fromCharCode instanceof new Object()')
  Exception: String.fromCharCode instanceof f. f is not a function. (evaluating 'String.fromCharCode instanceof f')
  Exception: String.fromCharCode instanceof b. b is not a function. (evaluating 'String.fromCharCode instanceof b')
@@ -312,7 +312,7 @@ String.fromCharCode instanceof foo : false
  Exception: String.fromCharCode instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'String.fromCharCode instanceof new Boolean(true)')
  Exception: String.fromCharCode instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'String.fromCharCode instanceof new Boolean(false)')
  Exception: String.fromCharCode instanceof new Date(). new Date() is not a function. (evaluating 'String.fromCharCode instanceof new Date()')
- Exception: String.fromCharCode instanceof /a+/. / is not a function. (evaluating 'String.fromCharCode instanceof /')
+ Exception: String.fromCharCode instanceof /a+/. /a+/ is not a function. (evaluating 'String.fromCharCode instanceof /a+/')
  Exception: Array.prototype.concat instanceof new Object(). new Object() is not a function. (evaluating 'Array.prototype.concat instanceof new Object()')
  Exception: Array.prototype.concat instanceof f. f is not a function. (evaluating 'Array.prototype.concat instanceof f')
  Exception: Array.prototype.concat instanceof b. b is not a function. (evaluating 'Array.prototype.concat instanceof b')
@@ -333,7 +333,7 @@ Array.prototype.concat instanceof foo : false
  Exception: Array.prototype.concat instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'Array.prototype.concat instanceof new Boolean(true)')
  Exception: Array.prototype.concat instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'Array.prototype.concat instanceof new Boolean(false)')
  Exception: Array.prototype.concat instanceof new Date(). new Date() is not a function. (evaluating 'Array.prototype.concat instanceof new Date()')
- Exception: Array.prototype.concat instanceof /a+/. / is not a function. (evaluating 'Array.prototype.concat instanceof /')
+ Exception: Array.prototype.concat instanceof /a+/. /a+/ is not a function. (evaluating 'Array.prototype.concat instanceof /a+/')
  Exception: [1,2,3] instanceof new Object(). new Object() is not a function. (evaluating '[1,2,3] instanceof new Object()')
  Exception: [1,2,3] instanceof f. f is not a function. (evaluating '[1,2,3] instanceof f')
  Exception: [1,2,3] instanceof b. b is not a function. (evaluating '[1,2,3] instanceof b')
@@ -354,7 +354,7 @@ Array.prototype.concat instanceof foo : false
  Exception: [1,2,3] instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating '[1,2,3] instanceof new Boolean(true)')
  Exception: [1,2,3] instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating '[1,2,3] instanceof new Boolean(false)')
  Exception: [1,2,3] instanceof new Date(). new Date() is not a function. (evaluating '[1,2,3] instanceof new Date()')
- Exception: [1,2,3] instanceof /a+/. / is not a function. (evaluating '[1,2,3] instanceof /')
+ Exception: [1,2,3] instanceof /a+/. /a+/ is not a function. (evaluating '[1,2,3] instanceof /a+/')
  Exception: new Array() instanceof new Object(). new Object() is not a function. (evaluating 'new Array() instanceof new Object()')
  Exception: new Array() instanceof f. f is not a function. (evaluating 'new Array() instanceof f')
  Exception: new Array() instanceof b. b is not a function. (evaluating 'new Array() instanceof b')
@@ -375,7 +375,7 @@ new Array() instanceof foo : false
  Exception: new Array() instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'new Array() instanceof new Boolean(true)')
  Exception: new Array() instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'new Array() instanceof new Boolean(false)')
  Exception: new Array() instanceof new Date(). new Date() is not a function. (evaluating 'new Array() instanceof new Date()')
- Exception: new Array() instanceof /a+/. / is not a function. (evaluating 'new Array() instanceof /')
+ Exception: new Array() instanceof /a+/. /a+/ is not a function. (evaluating 'new Array() instanceof /a+/')
  Exception: fncs instanceof new Object(). new Object() is not a function. (evaluating 'fncs instanceof new Object()')
  Exception: fncs instanceof f. f is not a function. (evaluating 'fncs instanceof f')
  Exception: fncs instanceof b. b is not a function. (evaluating 'fncs instanceof b')
@@ -396,7 +396,7 @@ fncs instanceof foo : false
  Exception: fncs instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'fncs instanceof new Boolean(true)')
  Exception: fncs instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'fncs instanceof new Boolean(false)')
  Exception: fncs instanceof new Date(). new Date() is not a function. (evaluating 'fncs instanceof new Date()')
- Exception: fncs instanceof /a+/. / is not a function. (evaluating 'fncs instanceof /')
+ Exception: fncs instanceof /a+/. /a+/ is not a function. (evaluating 'fncs instanceof /a+/')
  Exception: 'hello' instanceof new Object(). new Object() is not a function. (evaluating ''hello' instanceof new Object()')
  Exception: 'hello' instanceof f. f is not a function. (evaluating ''hello' instanceof f')
  Exception: 'hello' instanceof b. b is not a function. (evaluating ''hello' instanceof b')
@@ -417,7 +417,7 @@ fncs instanceof foo : false
  Exception: 'hello' instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating ''hello' instanceof new Boolean(true)')
  Exception: 'hello' instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating ''hello' instanceof new Boolean(false)')
  Exception: 'hello' instanceof new Date(). new Date() is not a function. (evaluating ''hello' instanceof new Date()')
- Exception: 'hello' instanceof /a+/. / is not a function. (evaluating ''hello' instanceof /')
+ Exception: 'hello' instanceof /a+/. /a+/ is not a function. (evaluating ''hello' instanceof /a+/')
  Exception: new String('world') instanceof new Object(). new Object() is not a function. (evaluating 'new String('world') instanceof new Object()')
  Exception: new String('world') instanceof f. f is not a function. (evaluating 'new String('world') instanceof f')
  Exception: new String('world') instanceof b. b is not a function. (evaluating 'new String('world') instanceof b')
@@ -438,7 +438,7 @@ new String('world') instanceof foo : false
  Exception: new String('world') instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'new String('world') instanceof new Boolean(true)')
  Exception: new String('world') instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'new String('world') instanceof new Boolean(false)')
  Exception: new String('world') instanceof new Date(). new Date() is not a function. (evaluating 'new String('world') instanceof new Date()')
- Exception: new String('world') instanceof /a+/. / is not a function. (evaluating 'new String('world') instanceof /')
+ Exception: new String('world') instanceof /a+/. /a+/ is not a function. (evaluating 'new String('world') instanceof /a+/')
  Exception: 10 instanceof new Object(). new Object() is not a function. (evaluating '10 instanceof new Object()')
  Exception: 10 instanceof f. f is not a function. (evaluating '10 instanceof f')
  Exception: 10 instanceof b. b is not a function. (evaluating '10 instanceof b')
@@ -459,7 +459,7 @@ new String('world') instanceof foo : false
  Exception: 10 instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating '10 instanceof new Boolean(true)')
  Exception: 10 instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating '10 instanceof new Boolean(false)')
  Exception: 10 instanceof new Date(). new Date() is not a function. (evaluating '10 instanceof new Date()')
- Exception: 10 instanceof /a+/. / is not a function. (evaluating '10 instanceof /')
+ Exception: 10 instanceof /a+/. /a+/ is not a function. (evaluating '10 instanceof /a+/')
  Exception: 10.2 instanceof new Object(). new Object() is not a function. (evaluating '10.2 instanceof new Object()')
  Exception: 10.2 instanceof f. f is not a function. (evaluating '10.2 instanceof f')
  Exception: 10.2 instanceof b. b is not a function. (evaluating '10.2 instanceof b')
@@ -480,7 +480,7 @@ new String('world') instanceof foo : false
  Exception: 10.2 instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating '10.2 instanceof new Boolean(true)')
  Exception: 10.2 instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating '10.2 instanceof new Boolean(false)')
  Exception: 10.2 instanceof new Date(). new Date() is not a function. (evaluating '10.2 instanceof new Date()')
- Exception: 10.2 instanceof /a+/. / is not a function. (evaluating '10.2 instanceof /')
+ Exception: 10.2 instanceof /a+/. /a+/ is not a function. (evaluating '10.2 instanceof /a+/')
  Exception: NaN instanceof new Object(). new Object() is not a function. (evaluating 'NaN instanceof new Object()')
  Exception: NaN instanceof f. f is not a function. (evaluating 'NaN instanceof f')
  Exception: NaN instanceof b. b is not a function. (evaluating 'NaN instanceof b')
@@ -501,7 +501,7 @@ NaN instanceof Array.prototype.concat : false
  Exception: NaN instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'NaN instanceof new Boolean(true)')
  Exception: NaN instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'NaN instanceof new Boolean(false)')
  Exception: NaN instanceof new Date(). new Date() is not a function. (evaluating 'NaN instanceof new Date()')
- Exception: NaN instanceof /a+/. / is not a function. (evaluating 'NaN instanceof /')
+ Exception: NaN instanceof /a+/. /a+/ is not a function. (evaluating 'NaN instanceof /a+/')
  Exception: new Number(3) instanceof new Object(). new Object() is not a function. (evaluating 'new Number(3) instanceof new Object()')
  Exception: new Number(3) instanceof f. f is not a function. (evaluating 'new Number(3) instanceof f')
  Exception: new Number(3) instanceof b. b is not a function. (evaluating 'new Number(3) instanceof b')
@@ -522,7 +522,7 @@ new Number(3) instanceof foo : false
  Exception: new Number(3) instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'new Number(3) instanceof new Boolean(true)')
  Exception: new Number(3) instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'new Number(3) instanceof new Boolean(false)')
  Exception: new Number(3) instanceof new Date(). new Date() is not a function. (evaluating 'new Number(3) instanceof new Date()')
- Exception: new Number(3) instanceof /a+/. / is not a function. (evaluating 'new Number(3) instanceof /')
+ Exception: new Number(3) instanceof /a+/. /a+/ is not a function. (evaluating 'new Number(3) instanceof /a+/')
  Exception: true instanceof new Object(). new Object() is not a function. (evaluating 'true instanceof new Object()')
  Exception: true instanceof f. f is not a function. (evaluating 'true instanceof f')
  Exception: true instanceof b. b is not a function. (evaluating 'true instanceof b')
@@ -543,7 +543,7 @@ true instanceof Array.prototype.concat : false
  Exception: true instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'true instanceof new Boolean(true)')
  Exception: true instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'true instanceof new Boolean(false)')
  Exception: true instanceof new Date(). new Date() is not a function. (evaluating 'true instanceof new Date()')
- Exception: true instanceof /a+/. / is not a function. (evaluating 'true instanceof /')
+ Exception: true instanceof /a+/. /a+/ is not a function. (evaluating 'true instanceof /a+/')
  Exception: false instanceof new Object(). new Object() is not a function. (evaluating 'false instanceof new Object()')
  Exception: false instanceof f. f is not a function. (evaluating 'false instanceof f')
  Exception: false instanceof b. b is not a function. (evaluating 'false instanceof b')
@@ -564,7 +564,7 @@ false instanceof Array.prototype.concat : false
  Exception: false instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'false instanceof new Boolean(true)')
  Exception: false instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'false instanceof new Boolean(false)')
  Exception: false instanceof new Date(). new Date() is not a function. (evaluating 'false instanceof new Date()')
- Exception: false instanceof /a+/. / is not a function. (evaluating 'false instanceof /')
+ Exception: false instanceof /a+/. /a+/ is not a function. (evaluating 'false instanceof /a+/')
  Exception: new Boolean(true) instanceof new Object(). new Object() is not a function. (evaluating 'new Boolean(true) instanceof new Object()')
  Exception: new Boolean(true) instanceof f. f is not a function. (evaluating 'new Boolean(true) instanceof f')
  Exception: new Boolean(true) instanceof b. b is not a function. (evaluating 'new Boolean(true) instanceof b')
@@ -585,7 +585,7 @@ new Boolean(true) instanceof foo : false
  Exception: new Boolean(true) instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'new Boolean(true) instanceof new Boolean(true)')
  Exception: new Boolean(true) instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'new Boolean(true) instanceof new Boolean(false)')
  Exception: new Boolean(true) instanceof new Date(). new Date() is not a function. (evaluating 'new Boolean(true) instanceof new Date()')
- Exception: new Boolean(true) instanceof /a+/. / is not a function. (evaluating 'new Boolean(true) instanceof /')
+ Exception: new Boolean(true) instanceof /a+/. /a+/ is not a function. (evaluating 'new Boolean(true) instanceof /a+/')
  Exception: new Boolean(false) instanceof new Object(). new Object() is not a function. (evaluating 'new Boolean(false) instanceof new Object()')
  Exception: new Boolean(false) instanceof f. f is not a function. (evaluating 'new Boolean(false) instanceof f')
  Exception: new Boolean(false) instanceof b. b is not a function. (evaluating 'new Boolean(false) instanceof b')
@@ -606,7 +606,7 @@ new Boolean(false) instanceof foo : false
  Exception: new Boolean(false) instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'new Boolean(false) instanceof new Boolean(true)')
  Exception: new Boolean(false) instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'new Boolean(false) instanceof new Boolean(false)')
  Exception: new Boolean(false) instanceof new Date(). new Date() is not a function. (evaluating 'new Boolean(false) instanceof new Date()')
- Exception: new Boolean(false) instanceof /a+/. / is not a function. (evaluating 'new Boolean(false) instanceof /')
+ Exception: new Boolean(false) instanceof /a+/. /a+/ is not a function. (evaluating 'new Boolean(false) instanceof /a+/')
  Exception: new Date() instanceof new Object(). new Object() is not a function. (evaluating 'new Date() instanceof new Object()')
  Exception: new Date() instanceof f. f is not a function. (evaluating 'new Date() instanceof f')
  Exception: new Date() instanceof b. b is not a function. (evaluating 'new Date() instanceof b')
@@ -627,7 +627,7 @@ new Date() instanceof foo : false
  Exception: new Date() instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating 'new Date() instanceof new Boolean(true)')
  Exception: new Date() instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating 'new Date() instanceof new Boolean(false)')
  Exception: new Date() instanceof new Date(). new Date() is not a function. (evaluating 'new Date() instanceof new Date()')
- Exception: new Date() instanceof /a+/. / is not a function. (evaluating 'new Date() instanceof /')
+ Exception: new Date() instanceof /a+/. /a+/ is not a function. (evaluating 'new Date() instanceof /a+/')
  Exception: /a+/ instanceof new Object(). new Object() is not a function. (evaluating '/a+/ instanceof new Object()')
  Exception: /a+/ instanceof f. f is not a function. (evaluating '/a+/ instanceof f')
  Exception: /a+/ instanceof b. b is not a function. (evaluating '/a+/ instanceof b')
@@ -648,4 +648,4 @@ new Date() instanceof foo : false
  Exception: /a+/ instanceof new Boolean(true). new Boolean(true) is not a function. (evaluating '/a+/ instanceof new Boolean(true)')
  Exception: /a+/ instanceof new Boolean(false). new Boolean(false) is not a function. (evaluating '/a+/ instanceof new Boolean(false)')
  Exception: /a+/ instanceof new Date(). new Date() is not a function. (evaluating '/a+/ instanceof new Date()')
- Exception: /a+/ instanceof /a+/. / is not a function. (evaluating '/a+/ instanceof /')
+ Exception: /a+/ instanceof /a+/. /a+/ is not a function. (evaluating '/a+/ instanceof /a+/')
index cbdb7e2..67c1082 100644 (file)
@@ -1,23 +1,23 @@
 --- 1 ---
 5
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
+SyntaxError: Unterminated regular expression literal '/'
+SyntaxError: Unterminated regular expression literal '/'
 --- 2 ---
 4
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
+SyntaxError: Unterminated regular expression literal '/\'
+SyntaxError: Unterminated regular expression literal '/\'
+SyntaxError: Unterminated regular expression literal '/\'
+SyntaxError: Unterminated regular expression literal '/\'
+SyntaxError: Unterminated regular expression literal '/\'
 4
 5
 --- 3 ---
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
-SyntaxError: Unexpected token '/'. Invalid regular expression.
+SyntaxError: Unterminated regular expression literal '/['
+SyntaxError: Unterminated regular expression literal '/['
+SyntaxError: Unterminated regular expression literal '/['
+SyntaxError: Unterminated regular expression literal '/['
 5
-SyntaxError: Unexpected token '/'. Invalid regular expression.
+SyntaxError: Unterminated regular expression literal '/['
 SyntaxError: Invalid regular expression: unmatched parentheses
 --- 4 ---
 9
index 8cc18d8..48aefc6 100644 (file)
@@ -3,7 +3,7 @@ undefined
 str const Left 
  str const right
 LS in string -  compile failure in ES5: expected.SyntaxError: Unexpected EOF
-LS in regex literal -  compile failure in ES5: expected.SyntaxError: Unexpected token '/'. Invalid regular expression.
+LS in regex literal -  compile failure in ES5: expected.SyntaxError: Unterminated regular expression literal '/str const regex '
 LS%20in%20escape%20sequence%20string%20literal%20%20%3Amore%20string
 BOM is WS :  91
 ZVNJ is id part :  aa%u200Cbb
index ad60031..6fc5c04 100644 (file)
@@ -1,3 +1,16 @@
+2016-10-24  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Arrow functions with concise bodies cannot return regular expressions
+        https://bugs.webkit.org/show_bug.cgi?id=163162
+
+        Reviewed by Filip Pizlo.
+
+        * ChakraCore/test/Operators/instanceof.baseline-jsc:
+        * ChakraCore/test/Regex/nul_character.baseline-jsc:
+        * ChakraCore/test/es5/Lex_u3.baseline-jsc:
+        * stress/parse-regexp-as-token.js: Added.
+        (shouldBe):
+
 2016-10-24  Keith Miller  <keith_miller@apple.com>
 
         Wasm should support floating point operations.
diff --git a/JSTests/stress/parse-regexp-as-token.js b/JSTests/stress/parse-regexp-as-token.js
new file mode 100644 (file)
index 0000000..ebbfaeb
--- /dev/null
@@ -0,0 +1,7 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+var arrow = () => /Cocoa/;
+shouldBe(arrow.toString(), `() => /Cocoa/`);
index 2de706b..89328d8 100644 (file)
@@ -1,3 +1,26 @@
+2016-10-24  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Arrow functions with concise bodies cannot return regular expressions
+        https://bugs.webkit.org/show_bug.cgi?id=163162
+
+        Reviewed by Filip Pizlo.
+
+        * fast/regex/dom/non-pattern-characters-expected.txt:
+        * js/arrowfunction-syntax-errors-expected.txt:
+        * js/regexp-compile-crash-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.4_Comments/S7.4_A4_T1-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.4_Comments/S7.4_A4_T4-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.2_T2-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.3_T1-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.3_T3-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.5_T1-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A1.5_T3-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.2_T1-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.3_T1-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.3_T3-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.5_T1-expected.txt:
+        * sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A2.5_T3-expected.txt:
+
 2016-10-24  Chris Dumez  <cdumez@apple.com>
 
         event.(dataTransfer|clipboardData).getData('text/html') (onpaste, ondrop)
index 996d9b7..e2ef3e2 100644 (file)
@@ -33,8 +33,8 @@ Testing regexp: /a\_/
 PASS regexp.test('a_') is true
 
 Testing regexp: [invalid \ variations]
-PASS /\/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
-PASS /a\/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
+PASS /\/ threw exception SyntaxError: Unterminated regular expression literal '/\/'.
+PASS /a\/ threw exception SyntaxError: Unterminated regular expression literal '/a\/'.
 
 Testing regexp: /./
 PASS regexp.test('a') is true
@@ -80,8 +80,8 @@ PASS /)/ threw exception SyntaxError: Invalid regular expression: unmatched pare
 PASS /a)/ threw exception SyntaxError: Invalid regular expression: unmatched parentheses.
 
 Testing regexp: [invalid [ variations]
-PASS /[/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
-PASS /a[/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
+PASS /[/ threw exception SyntaxError: Unterminated regular expression literal '/[/'.
+PASS /a[/ threw exception SyntaxError: Unterminated regular expression literal '/a[/'.
 PASS /[b-a]/ threw exception SyntaxError: Invalid regular expression: range out of order in character class.
 PASS /a[b-a]/ threw exception SyntaxError: Invalid regular expression: range out of order in character class.
 
index 31fc0c1..8a5802c 100644 (file)
@@ -6,7 +6,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 PASS =>{} threw exception SyntaxError: Unexpected token '=>'.
 PASS x=> threw exception SyntaxError: Unexpected end of script.
 PASS x=>* threw exception SyntaxError: Unexpected token '*'.
-PASS x=>/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
+PASS x=>/ threw exception SyntaxError: Unterminated regular expression literal '/'.
 PASS x=>% threw exception SyntaxError: Unexpected token '%'.
 PASS x=>+ threw exception SyntaxError: Unexpected end of script.
 PASS x=>- threw exception SyntaxError: Unexpected end of script.
@@ -32,7 +32,7 @@ PASS x=>; threw exception SyntaxError: Unexpected token ';'.
 PASS x=>, threw exception SyntaxError: Unexpected token ','.
 PASS x=>{ threw exception SyntaxError: Unexpected end of script.
 PASS x=>{* threw exception SyntaxError: Unexpected token '*'.
-PASS x=>{/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
+PASS x=>{/ threw exception SyntaxError: Unterminated regular expression literal '/'.
 PASS x=>{% threw exception SyntaxError: Unexpected token '%'.
 PASS x=>{+ threw exception SyntaxError: Unexpected end of script.
 PASS x=>{- threw exception SyntaxError: Unexpected end of script.
@@ -59,7 +59,7 @@ PASS x=>{, threw exception SyntaxError: Unexpected token ','.
 PASS x=>} threw exception SyntaxError: Unexpected token '}'.
 PASS var y = x=> threw exception SyntaxError: Unexpected end of script.
 PASS var y = x=>* threw exception SyntaxError: Unexpected token '*'.
-PASS var y = x=>/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
+PASS var y = x=>/ threw exception SyntaxError: Unterminated regular expression literal '/'.
 PASS var y = x=>% threw exception SyntaxError: Unexpected token '%'.
 PASS var y = x=>+ threw exception SyntaxError: Unexpected end of script.
 PASS var y = x=>- threw exception SyntaxError: Unexpected end of script.
@@ -85,7 +85,7 @@ PASS var y = x=>; threw exception SyntaxError: Unexpected token ';'.
 PASS var y = x=>, threw exception SyntaxError: Unexpected token ','.
 PASS var y = x=>{ threw exception SyntaxError: Unexpected end of script.
 PASS var y = x=>{* threw exception SyntaxError: Unexpected token '*'.
-PASS var y = x=>{/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
+PASS var y = x=>{/ threw exception SyntaxError: Unterminated regular expression literal '/'.
 PASS var y = x=>{% threw exception SyntaxError: Unexpected token '%'.
 PASS var y = x=>{+ threw exception SyntaxError: Unexpected end of script.
 PASS var y = x=>{- threw exception SyntaxError: Unexpected end of script.
index 7fc6ef0..461f3e1 100644 (file)
@@ -4,9 +4,9 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS !!/\)[;s]+/ is true
-PASS /[/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
-PASS /[a/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
-PASS /[-/ threw exception SyntaxError: Unexpected token '/'. Invalid regular expression..
+PASS /[/ threw exception SyntaxError: Unterminated regular expression literal '/[/'.
+PASS /[a/ threw exception SyntaxError: Unterminated regular expression literal '/[a/'.
+PASS /[-/ threw exception SyntaxError: Unterminated regular expression literal '/[-/'.
 PASS !!/(a)\ 1/ is true
 PASS !!/(a)\ 1{1,3}/ is true
 PASS No crashes, yay!
index d602ff8..8dbcad2 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 79: SyntaxError: Unexpected token '/'. Invalid regular expression.
+CONSOLE MESSAGE: line 79: SyntaxError: Unterminated regular expression literal '/'
 S7.4_A4_T1
 
 PASS Expected parsing failure
index a7ed364..935efcd 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 79: SyntaxError: Unexpected token '/'. Invalid regular expression.
+CONSOLE MESSAGE: line 79: SyntaxError: Unterminated regular expression literal '/'
 S7.4_A4_T4
 
 PASS Expected parsing failure
index d0d542c..47244ae 100644 (file)
@@ -1,3 +1,48 @@
+2016-10-24  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Arrow functions with concise bodies cannot return regular expressions
+        https://bugs.webkit.org/show_bug.cgi?id=163162
+
+        Reviewed by Filip Pizlo.
+
+        When we encounter the RegExp in the parser, we first scan it as / or /=.
+        And if / or /= is parsed under the primary expression context, we rescan it
+        as RegExp. However, we did not update the token record information. So the
+        token record still says "I'm / or /=".
+
+        When we parse the string "() => /hello/", the last token becomes "/", which is
+        the first character of the RegExp, instead of "/hello/". Since the arrow
+        function parsing utilizes the end offset of the last token, we accidentally
+        recognize the range of the above arrow function as "() => /".
+
+        In this patch, we update the token when rescanning under the RegExp context.
+        This logic is similar to parsing Tail Template Literal token.
+
+        We also refine the error message for regular expression literals. And since
+        the REGEXP token is now introduced, the other error messages using that token
+        are improved too.
+
+        Currently, unterminated error messages can be seen in Parser.cpp. However,
+        these messages cannot be shown to users if the lexer has m_error. So these
+        code is meaningless. I'll move these tokenizing errors to the lexer in the
+        subsequent patch[1].
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=163928
+
+        * parser/Lexer.cpp:
+        (JSC::Lexer<T>::fillTokenInfo):
+        (JSC::Lexer<T>::lex):
+        (JSC::Lexer<T>::scanRegExp):
+        (JSC::Lexer<T>::scanTrailingTemplateString):
+        (JSC::Lexer<T>::skipRegExp): Deleted.
+        * parser/Lexer.h:
+        (JSC::Lexer::getToken):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseAssignmentExpression):
+        * parser/Parser.h:
+        (JSC::Parser::getToken):
+        * parser/ParserTokens.h:
+
 2016-10-24  Per Arne Vollan  <pvollan@apple.com>
 
         [Win] CMake build type is not set.
index bc76779..5e04e54 100644 (file)
@@ -1783,6 +1783,18 @@ bool Lexer<T>::nextTokenIsColon()
 }
 
 template <typename T>
+void Lexer<T>::fillTokenInfo(JSToken* tokenRecord, JSTokenType token, int lineNumber, int endOffset, int lineStartOffset, JSTextPosition endPosition)
+{
+    JSTokenLocation* tokenLocation = &tokenRecord->m_location;
+    tokenLocation->line = lineNumber;
+    tokenLocation->endOffset = endOffset;
+    tokenLocation->lineStartOffset = lineStartOffset;
+    ASSERT(tokenLocation->endOffset >= tokenLocation->lineStartOffset);
+    tokenRecord->m_endPosition = endPosition;
+    m_lastToken = token;
+}
+
+template <typename T>
 JSTokenType Lexer<T>::lex(JSToken* tokenRecord, unsigned lexerFlags, bool strictMode)
 {
     JSTokenData* tokenData = &tokenRecord->m_data;
@@ -1796,15 +1808,6 @@ JSTokenType Lexer<T>::lex(JSToken* tokenRecord, unsigned lexerFlags, bool strict
     JSTokenType token = ERRORTOK;
     m_terminator = false;
 
-    auto fillTokenInfo = [&] (int lineNumber, int endOffset, int lineStartOffset, JSTextPosition endPosition) {
-        tokenLocation->line = lineNumber;
-        tokenLocation->endOffset = endOffset;
-        tokenLocation->lineStartOffset = lineStartOffset;
-        ASSERT(tokenLocation->endOffset >= tokenLocation->lineStartOffset);
-        tokenRecord->m_endPosition = endPosition;
-        m_lastToken = token;
-    };
-
 start:
     skipWhitespace();
 
@@ -2312,17 +2315,17 @@ inSingleLineComment:
             goto start;
 
         token = SEMICOLON;
-        fillTokenInfo(lineNumber, endOffset, lineStartOffset, endPosition);
+        fillTokenInfo(tokenRecord, token, lineNumber, endOffset, lineStartOffset, endPosition);
         return token;
     }
 
 returnToken:
-    fillTokenInfo(m_lineNumber, currentOffset(), currentLineStartOffset(), currentPosition());
+    fillTokenInfo(tokenRecord, token, m_lineNumber, currentOffset(), currentLineStartOffset(), currentPosition());
     return token;
 
 returnError:
     m_error = true;
-    fillTokenInfo(m_lineNumber, currentOffset(), currentLineStartOffset(), currentPosition());
+    fillTokenInfo(tokenRecord, token, m_lineNumber, currentOffset(), currentLineStartOffset(), currentPosition());
     RELEASE_ASSERT(token & ErrorTokenFlag);
     return token;
 }
@@ -2340,8 +2343,9 @@ inline void orCharacter<UChar>(UChar& orAccumulator, UChar character)
 }
 
 template <typename T>
-bool Lexer<T>::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix)
+JSTokenType Lexer<T>::scanRegExp(JSToken* tokenRecord, UChar patternPrefix)
 {
+    JSTokenData* tokenData = &tokenRecord->m_data;
     ASSERT(m_buffer16.isEmpty());
 
     bool lastWasEscape = false;
@@ -2358,7 +2362,11 @@ bool Lexer<T>::scanRegExp(const Identifier*& pattern, const Identifier*& flags,
     while (true) {
         if (isLineTerminator(m_current) || atEnd()) {
             m_buffer16.shrink(0);
-            return false;
+            JSTokenType token = UNTERMINATED_REGEXP_LITERAL_ERRORTOK;
+            fillTokenInfo(tokenRecord, token, m_lineNumber, currentOffset(), currentLineStartOffset(), currentPosition());
+            m_error = true;
+            m_lexErrorMessage = makeString("Unterminated regular expression literal '", getToken(*tokenRecord), "'");
+            return token;
         }
 
         T prev = m_current;
@@ -2389,7 +2397,7 @@ bool Lexer<T>::scanRegExp(const Identifier*& pattern, const Identifier*& flags,
         }
     }
 
-    pattern = makeRightSizedIdentifier(m_buffer16.data(), m_buffer16.size(), charactersOredTogether);
+    tokenData->pattern = makeRightSizedIdentifier(m_buffer16.data(), m_buffer16.size(), charactersOredTogether);
 
     m_buffer16.shrink(0);
     charactersOredTogether = 0;
@@ -2400,58 +2408,21 @@ bool Lexer<T>::scanRegExp(const Identifier*& pattern, const Identifier*& flags,
         shift();
     }
 
-    flags = makeRightSizedIdentifier(m_buffer16.data(), m_buffer16.size(), charactersOredTogether);
+    tokenData->flags = makeRightSizedIdentifier(m_buffer16.data(), m_buffer16.size(), charactersOredTogether);
     m_buffer16.shrink(0);
 
-    return true;
-}
-
-template <typename T>
-bool Lexer<T>::skipRegExp()
-{
-    bool lastWasEscape = false;
-    bool inBrackets = false;
-
-    while (true) {
-        if (isLineTerminator(m_current) || atEnd())
-            return false;
-
-        T prev = m_current;
-        
-        shift();
-
-        if (prev == '/' && !lastWasEscape && !inBrackets)
-            break;
-
-        if (lastWasEscape) {
-            lastWasEscape = false;
-            continue;
-        }
-
-        switch (prev) {
-        case '[':
-            inBrackets = true;
-            break;
-        case ']':
-            inBrackets = false;
-            break;
-        case '\\':
-            lastWasEscape = true;
-            break;
-        }
-    }
-
-    while (isIdentPart(m_current))
-        shift();
+    // Since RegExp always ends with /, m_atLineStart always becomes false.
+    m_atLineStart = false;
 
-    return true;
+    JSTokenType token = REGEXP;
+    fillTokenInfo(tokenRecord, token, m_lineNumber, currentOffset(), currentLineStartOffset(), currentPosition());
+    return token;
 }
 
 template <typename T>
 JSTokenType Lexer<T>::scanTrailingTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)
 {
     JSTokenData* tokenData = &tokenRecord->m_data;
-    JSTokenLocation* tokenLocation = &tokenRecord->m_location;
     ASSERT(!m_error);
     ASSERT(m_buffer16.isEmpty());
 
@@ -2462,20 +2433,12 @@ JSTokenType Lexer<T>::scanTrailingTemplateString(JSToken* tokenRecord, RawString
     if (UNLIKELY(result != StringParsedSuccessfully)) {
         token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
         m_error = true;
-    } else {
+    } else
         token = TEMPLATE;
-        m_lastToken = token;
-    }
 
     // Since TemplateString always ends with ` or }, m_atLineStart always becomes false.
     m_atLineStart = false;
-
-    // Adjust current tokenLocation data for TemplateString.
-    tokenLocation->line = m_lineNumber;
-    tokenLocation->endOffset = currentOffset();
-    tokenLocation->lineStartOffset = currentLineStartOffset();
-    ASSERT(tokenLocation->endOffset >= tokenLocation->lineStartOffset);
-    tokenRecord->m_endPosition = currentPosition();
+    fillTokenInfo(tokenRecord, token, m_lineNumber, currentOffset(), currentLineStartOffset(), currentPosition());
     return token;
 }
 
index dccf750..e408cc6 100644 (file)
@@ -75,10 +75,9 @@ public:
     void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
     int lastLineNumber() const { return m_lastLineNumber; }
     bool prevTerminator() const { return m_terminator; }
-    bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0);
+    JSTokenType scanRegExp(JSToken*, UChar patternPrefix = 0);
     enum class RawStringsBuildMode { BuildRawStrings, DontBuildRawStrings };
     JSTokenType scanTrailingTemplateString(JSToken*, RawStringsBuildMode);
-    bool skipRegExp();
 
     // Functions for use after parsing.
     bool sawError() const { return m_error; }
@@ -115,6 +114,13 @@ public:
 
     JSTokenType lexExpectIdentifier(JSToken*, unsigned, bool strictMode);
 
+    ALWAYS_INLINE StringView getToken(const JSToken& token)
+    {
+        SourceProvider* sourceProvider = m_source->provider();
+        ASSERT_WITH_MESSAGE(token.m_location.startOffset <= token.m_location.endOffset, "Calling this function with the baked token.");
+        return sourceProvider->getRange(token.m_location.startOffset, token.m_location.endOffset);
+    }
+
 private:
     void record8(int);
     void append8(const T*, size_t);
@@ -181,6 +187,8 @@ private:
     template <unsigned length>
     ALWAYS_INLINE bool consume(const char (&input)[length]);
 
+    void fillTokenInfo(JSToken*, JSTokenType, int lineNumber, int endOffset, int lineStartOffset, JSTextPosition endPosition);
+
     static const size_t initialReadBufferCapacity = 32;
 
     int m_lineNumber;
index 4908841..8974adb 100644 (file)
@@ -4306,13 +4306,14 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpre
     case DIVEQUAL:
     case DIVIDE: {
         /* regexp */
-        const Identifier* pattern;
-        const Identifier* flags;
         if (match(DIVEQUAL))
-            failIfFalse(m_lexer->scanRegExp(pattern, flags, '='), "Invalid regular expression");
+            m_token.m_type = m_lexer->scanRegExp(&m_token, '=');
         else
-            failIfFalse(m_lexer->scanRegExp(pattern, flags), "Invalid regular expression");
-        
+            m_token.m_type = m_lexer->scanRegExp(&m_token);
+        matchOrFail(REGEXP, "Invalid regular expression");
+
+        const Identifier* pattern = m_token.m_data.pattern;
+        const Identifier* flags = m_token.m_data.flags;
         JSTextPosition start = tokenStartPosition();
         JSTokenLocation location(tokenLocation());
         next();
index 8c4474b..ad5d36a 100644 (file)
@@ -1288,9 +1288,9 @@ private:
     }
 
     void printUnexpectedTokenText(WTF::PrintStream&);
-    ALWAYS_INLINE StringView getToken() {
-        SourceProvider* sourceProvider = m_source->provider();
-        return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset);
+    ALWAYS_INLINE StringView getToken()
+    {
+        return m_lexer->getToken(m_token);
     }
     
     ALWAYS_INLINE bool match(JSTokenType expected)
index ac8305e..efc2b8f 100644 (file)
@@ -96,6 +96,7 @@ enum JSTokenType {
     IDENT,
     STRING,
     TEMPLATE,
+    REGEXP,
     SEMICOLON,
     COLON,
     DOT,
@@ -166,7 +167,8 @@ enum JSTokenType {
     UNTERMINATED_HEX_NUMBER_ERRORTOK = 11 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
     UNTERMINATED_BINARY_NUMBER_ERRORTOK = 12 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
     UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK = 13 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
-    INVALID_TEMPLATE_LITERAL_ERRORTOK = 14 | ErrorTokenFlag,
+    UNTERMINATED_REGEXP_LITERAL_ERRORTOK = 14 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+    INVALID_TEMPLATE_LITERAL_ERRORTOK = 15 | ErrorTokenFlag,
 };
 
 struct JSTextPosition {
@@ -199,6 +201,10 @@ union JSTokenData {
         const Identifier* raw;
         bool isTail;
     };
+    struct {
+        const Identifier* pattern;
+        const Identifier* flags;
+    };
 };
 
 struct JSTokenLocation {