@@ -159,9 +159,168 @@ void Parser::OutOfMemory()
159
159
throw ParseExceptionObject(ERRnoMemory);
160
160
}
161
161
162
- void Parser::Error(HRESULT hr)
162
+ LPCWSTR Parser::GetTokenString(tokens token)
163
+ {
164
+ switch (token)
165
+ {
166
+ case tkNone : return _u("");
167
+ case tkEOF : return _u("end of script");
168
+ case tkIntCon : return _u("integer literal");
169
+ case tkFltCon : return _u("float literal");
170
+ case tkStrCon : return _u("string literal");
171
+ case tkRegExp : return _u("regular expression literal");
172
+
173
+ // keywords
174
+ case tkABSTRACT : return _u("abstract");
175
+ case tkASSERT : return _u("assert");
176
+ case tkAWAIT : return _u("await");
177
+ case tkBOOLEAN : return _u("boolean");
178
+ case tkBREAK : return _u("break");
179
+ case tkBYTE : return _u("byte");
180
+ case tkCASE : return _u("case");
181
+ case tkCATCH : return _u("catch");
182
+ case tkCHAR : return _u("char");
183
+ case tkCONTINUE : return _u("continue");
184
+ case tkDEBUGGER : return _u("debugger");
185
+ case tkDECIMAL : return _u("decimal");
186
+ case tkDEFAULT : return _u("default");
187
+ case tkDELETE : return _u("delete");
188
+ case tkDO : return _u("do");
189
+ case tkDOUBLE : return _u("double");
190
+ case tkELSE : return _u("else");
191
+ case tkENSURE : return _u("ensure");
192
+ case tkEVENT : return _u("event");
193
+ case tkFALSE : return _u("false");
194
+ case tkFINAL : return _u("final");
195
+ case tkFINALLY : return _u("finally");
196
+ case tkFLOAT : return _u("float");
197
+ case tkFOR : return _u("for");
198
+ case tkFUNCTION : return _u("function");
199
+ case tkGET : return _u("get");
200
+ case tkGOTO : return _u("goto");
201
+ case tkIF : return _u("if");
202
+ case tkIN : return _u("in");
203
+ case tkINSTANCEOF : return _u("instanceof");
204
+ case tkINT : return _u("int");
205
+ case tkINTERNAL : return _u("internal");
206
+ case tkINVARIANT : return _u("invariant");
207
+ case tkLONG : return _u("long");
208
+ case tkNAMESPACE : return _u("namespace");
209
+ case tkNATIVE : return _u("native");
210
+ case tkNEW : return _u("new");
211
+ case tkNULL : return _u("null");
212
+ case tkREQUIRE : return _u("require");
213
+ case tkRETURN : return _u("return");
214
+ case tkSBYTE : return _u("sbyte");
215
+ case tkSET : return _u("set");
216
+ case tkSHORT : return _u("short");
217
+ case tkSWITCH : return _u("switch");
218
+ case tkSYNCHRONIZED : return _u("synchronized");
219
+ case tkTHIS : return _u("this");
220
+ case tkTHROW : return _u("throw");
221
+ case tkTHROWS : return _u("throws");
222
+ case tkTRANSIENT : return _u("transient");
223
+ case tkTRUE : return _u("true");
224
+ case tkTRY : return _u("try");
225
+ case tkTYPEOF : return _u("typeof");
226
+ case tkUINT : return _u("uint");
227
+ case tkULONG : return _u("ulong");
228
+ case tkUSE : return _u("use");
229
+ case tkUSHORT : return _u("ushort");
230
+ case tkVAR : return _u("var");
231
+ case tkVOID : return _u("void");
232
+ case tkVOLATILE : return _u("volatile");
233
+ case tkWHILE : return _u("while");
234
+ case tkWITH : return _u("with");
235
+
236
+ // Future reserved words that become keywords in ES6
237
+ case tkCLASS : return _u("class");
238
+ case tkCONST : return _u("const");
239
+ case tkEXPORT : return _u("export");
240
+ case tkEXTENDS : return _u("extends");
241
+ case tkIMPORT : return _u("import");
242
+ case tkLET : return _u("let");
243
+ case tkSUPER : return _u("super");
244
+ case tkYIELD : return _u("yield");
245
+
246
+ // Future reserved words in strict and non-strict modes
247
+ case tkENUM : return _u("enum");
248
+
249
+ // Additional future reserved words in strict mode
250
+ case tkIMPLEMENTS : return _u("implements");
251
+ case tkINTERFACE : return _u("interface");
252
+ case tkPACKAGE : return _u("package");
253
+ case tkPRIVATE : return _u("private");
254
+ case tkPROTECTED : return _u("protected");
255
+ case tkPUBLIC : return _u("public");
256
+ case tkSTATIC : return _u("static");
257
+
258
+ case tkID: return _u("identifier");
259
+
260
+ // Non-operator non-identifier tokens
261
+ case tkSColon: return _u(";");
262
+ case tkRParen: return _u(")");
263
+ case tkRBrack: return _u("]");
264
+ case tkLCurly: return _u("{");
265
+ case tkRCurly: return _u("}");
266
+
267
+ // Operator non-identifier tokens
268
+ case tkComma: return _u(",");
269
+ case tkDArrow: return _u("=>");
270
+ case tkAsg: return _u("=");
271
+ case tkAsgAdd: return _u("+=");
272
+ case tkAsgSub: return _u("-=");
273
+ case tkAsgMul: return _u("*=");
274
+ case tkAsgDiv: return _u("/=");
275
+ case tkAsgExpo: return _u("**=");
276
+ case tkAsgMod: return _u("%=");
277
+ case tkAsgAnd: return _u("&=");
278
+ case tkAsgXor: return _u("^=");
279
+ case tkAsgOr: return _u("|=");
280
+ case tkAsgLsh: return _u("<<=");
281
+ case tkAsgRsh: return _u(">>=");
282
+ case tkAsgRs2: return _u(">>>=");
283
+ case tkQMark: return _u("?");
284
+ case tkColon: return _u(":");
285
+ case tkLogOr: return _u("||");
286
+ case tkLogAnd: return _u("&&");
287
+ case tkOr: return _u("|");
288
+ case tkXor: return _u("^");
289
+ case tkAnd: return _u("&");
290
+ case tkEQ: return _u("==");
291
+ case tkNE: return _u("!=");
292
+ case tkEqv: return _u("===");
293
+ case tkNEqv: return _u("!==");
294
+ case tkLT: return _u("<");
295
+ case tkLE: return _u("<=");
296
+ case tkGT: return _u(">");
297
+ case tkGE: return _u(">=");
298
+ case tkLsh: return _u("<<");
299
+ case tkRsh: return _u(">>");
300
+ case tkRs2: return _u(">>>");
301
+ case tkAdd: return _u("+");
302
+ case tkSub: return _u("-");
303
+ case tkExpo: return _u("**");
304
+ case tkStar: return _u("*");
305
+ case tkDiv: return _u("/");
306
+ case tkPct: return _u("%");
307
+ case tkTilde: return _u("~");
308
+ case tkBang: return _u("!");
309
+ case tkInc: return _u("++");
310
+ case tkDec: return _u("--");
311
+ case tkEllipsis: return _u("...");
312
+ case tkLParen: return _u("(");
313
+ case tkLBrack: return _u("[");
314
+ case tkDot: return _u(".");
315
+
316
+ default:
317
+ return _u("unknown token");
318
+ }
319
+ }
320
+
321
+ void Parser::Error(HRESULT hr, LPCWSTR stringOne, LPCWSTR stringTwo)
163
322
{
164
- throw ParseExceptionObject(hr);
323
+ throw ParseExceptionObject(hr, stringOne, stringTwo );
165
324
}
166
325
167
326
void Parser::Error(HRESULT hr, ParseNodePtr pnode)
@@ -226,6 +385,7 @@ HRESULT Parser::ValidateSyntax(LPCUTF8 pszSrc, size_t encodedCharCount, bool isG
226
385
227
386
HRESULT hr;
228
387
SmartFPUControl smartFpuControl;
388
+ bool handled = false;
229
389
230
390
BOOL fDeferSave = m_deferringAST;
231
391
try
@@ -287,9 +447,11 @@ HRESULT Parser::ValidateSyntax(LPCUTF8 pszSrc, size_t encodedCharCount, bool isG
287
447
{
288
448
m_deferringAST = fDeferSave;
289
449
hr = e.GetError();
450
+ hr = pse->ProcessError(this->GetScanner(), hr, /* pnodeBase */ NULL, e.GetStringOne(), e.GetStringTwo());
451
+ handled = true;
290
452
}
291
453
292
- if (nullptr != pse && FAILED(hr))
454
+ if (handled == false && nullptr != pse && FAILED(hr))
293
455
{
294
456
hr = pse->ProcessError(this->GetScanner(), hr, /* pnodeBase */ NULL);
295
457
}
@@ -326,6 +488,7 @@ HRESULT Parser::ParseSourceInternal(
326
488
ParseNodeProg * pnodeBase = NULL;
327
489
HRESULT hr;
328
490
SmartFPUControl smartFpuControl;
491
+ bool handled = false;
329
492
330
493
try
331
494
{
@@ -364,13 +527,15 @@ HRESULT Parser::ParseSourceInternal(
364
527
catch (ParseExceptionObject& e)
365
528
{
366
529
hr = e.GetError();
530
+ hr = pse->ProcessError(this->GetScanner(), hr, pnodeBase, e.GetStringOne(), e.GetStringTwo());
531
+ handled = true;
367
532
}
368
533
catch (Js::AsmJsParseException&)
369
534
{
370
535
hr = JSERR_AsmJsCompileError;
371
536
}
372
537
373
- if (FAILED(hr))
538
+ if (handled == false && FAILED(hr))
374
539
{
375
540
hr = pse->ProcessError(this->GetScanner(), hr, pnodeBase);
376
541
}
@@ -2153,7 +2318,7 @@ IdentPtr Parser::ParseMetaProperty(tokens metaParentKeyword, charcount_t ichMin,
2153
2318
}
2154
2319
else
2155
2320
{
2156
- Error(ERRsyntax );
2321
+ Error(ERRValidIfFollowedBy, _u("'new.'"), _u("'target'") );
2157
2322
}
2158
2323
}
2159
2324
@@ -2442,7 +2607,7 @@ void Parser::ParseImportClause(ModuleImportOrExportEntryList* importEntryList, b
2442
2607
// There cannot be a namespace import or named imports list on the left of the comma in a module import clause.
2443
2608
if (parsingAfterComma || parsedNamespaceOrNamedImport)
2444
2609
{
2445
- Error(ERRsyntax );
2610
+ Error(ERRTokenAfter, _u(","), GetTokenString(this->GetScanner()->GetPrevious()) );
2446
2611
}
2447
2612
2448
2613
this->GetScanner()->Scan();
@@ -2498,7 +2663,7 @@ ParseNodePtr Parser::ParseImport()
2498
2663
{
2499
2664
if (!m_scriptContext->GetConfig()->IsESDynamicImportEnabled())
2500
2665
{
2501
- Error(ERRsyntax );
2666
+ Error(ERRExperimental );
2502
2667
}
2503
2668
2504
2669
ParseNodePtr pnode = ParseImportCall<buildAST>();
@@ -3109,7 +3274,7 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
3109
3274
// If the token after the right paren is not => or if there was a newline between () and => this is a syntax error
3110
3275
if (!IsDoingFastScan() && (m_token.tk != tkDArrow || this->GetScanner()->FHadNewLine()))
3111
3276
{
3112
- Error(ERRsyntax );
3277
+ Error(ERRValidIfFollowedBy, _u("Lambda parameter list"), _u("'=>' on the same line") );
3113
3278
}
3114
3279
3115
3280
if (buildAST)
@@ -3423,7 +3588,18 @@ ParseNodePtr Parser::ParseTerm(BOOL fAllowCall,
3423
3588
3424
3589
default:
3425
3590
LUnknown:
3426
- Error(ERRsyntax);
3591
+ if (m_token.tk == tkNone)
3592
+ {
3593
+ Error(ERRInvalidIdentifier, m_token.GetIdentifier(this->GetHashTbl())->Psz(), GetTokenString(GetScanner()->GetPrevious()));
3594
+ }
3595
+ else if (m_token.IsKeyword())
3596
+ {
3597
+ Error(ERRKeywordAfter, GetTokenString(m_token.tk), GetTokenString(GetScanner()->GetPrevious()));
3598
+ }
3599
+ else
3600
+ {
3601
+ Error(ERRTokenAfter, GetTokenString(m_token.tk), GetTokenString(GetScanner()->GetPrevious()));
3602
+ }
3427
3603
break;
3428
3604
}
3429
3605
@@ -5607,7 +5783,7 @@ void Parser::ParseFncDeclHelper(ParseNodeFnc * pnodeFnc, LPCOLESTR pNameHint, us
5607
5783
// this after verifying there was a => token. Otherwise we would throw the wrong error.
5608
5784
if (hadNewLine)
5609
5785
{
5610
- Error(ERRsyntax );
5786
+ Error(ERRValidIfFollowedBy, _u("Lambda parameter list"), _u("'=>' on the same line") );
5611
5787
}
5612
5788
}
5613
5789
@@ -11893,6 +12069,7 @@ HRESULT Parser::ParseFunctionInBackground(ParseNodeFnc * pnodeFnc, ParseContext
11893
12069
ParseNodeBlock * pnodeBlock = StartParseBlock<true>(PnodeBlockType::Function, ScopeType_FunctionBody);
11894
12070
pnodeFnc->pnodeScopes = pnodeBlock;
11895
12071
m_ppnodeScope = &pnodeBlock->pnodeScopes;
12072
+ bool handled = false;
11896
12073
11897
12074
uint uDeferSave = m_grfscr & (fscrCanDeferFncParse | fscrWillDeferFncParse);
11898
12075
@@ -11943,9 +12120,11 @@ HRESULT Parser::ParseFunctionInBackground(ParseNodeFnc * pnodeFnc, ParseContext
11943
12120
catch (ParseExceptionObject& e)
11944
12121
{
11945
12122
hr = e.GetError();
12123
+ hr = pse->ProcessError(this->GetScanner(), hr, nullptr, e.GetStringOne(), e.GetStringTwo());
12124
+ handled = true;
11946
12125
}
11947
12126
11948
- if (FAILED(hr))
12127
+ if (handled == false && FAILED(hr))
11949
12128
{
11950
12129
hr = pse->ProcessError(this->GetScanner(), hr, nullptr);
11951
12130
}
0 commit comments