diff --git a/src/language/__tests__/lexer-test.ts b/src/language/__tests__/lexer-test.ts index 8ec91df52f..f781e57207 100644 --- a/src/language/__tests__/lexer-test.ts +++ b/src/language/__tests__/lexer-test.ts @@ -165,6 +165,13 @@ describe('Lexer', () => { }); }); + it('reports unexpected characters', () => { + expectSyntaxError('.').to.deep.equal({ + message: 'Syntax Error: Unexpected character: ".".', + locations: [{ line: 1, column: 1 }], + }); + }); + it('errors respect whitespace', () => { let caughtError; try { @@ -852,7 +859,8 @@ describe('Lexer', () => { }); expectSyntaxError('.123').to.deep.equal({ - message: 'Syntax Error: Unexpected character: ".".', + message: + 'Syntax Error: Invalid number, expected digit before ".", did you mean "0.123"?', locations: [{ line: 1, column: 1 }], }); @@ -1030,7 +1038,7 @@ describe('Lexer', () => { it('lex reports useful unknown character error', () => { expectSyntaxError('..').to.deep.equal({ - message: 'Syntax Error: Unexpected character: ".".', + message: 'Syntax Error: Unexpected "..", did you mean "..."?', locations: [{ line: 1, column: 1 }], }); diff --git a/src/language/lexer.ts b/src/language/lexer.ts index c20c879700..6b6a5e90dc 100644 --- a/src/language/lexer.ts +++ b/src/language/lexer.ts @@ -258,14 +258,31 @@ function readNextToken(lexer: Lexer, start: number): Token { return createToken(lexer, TokenKind.PAREN_L, position, position + 1); case 0x0029: // ) return createToken(lexer, TokenKind.PAREN_R, position, position + 1); - case 0x002e: // . - if ( - body.charCodeAt(position + 1) === 0x002e && - body.charCodeAt(position + 2) === 0x002e - ) { + case 0x002e: { + // . + const nextCode = body.charCodeAt(position + 1); + if (nextCode === 0x002e && body.charCodeAt(position + 2) === 0x002e) { return createToken(lexer, TokenKind.SPREAD, position, position + 3); } + if (nextCode === 0x002e) { + throw syntaxError( + lexer.source, + position, + 'Unexpected "..", did you mean "..."?', + ); + } else if (isDigit(nextCode)) { + const digits = lexer.source.body.slice( + position + 1, + readDigits(lexer, position + 1, nextCode), + ); + throw syntaxError( + lexer.source, + position, + `Invalid number, expected digit before ".", did you mean "0.${digits}"?`, + ); + } break; + } case 0x003a: // : return createToken(lexer, TokenKind.COLON, position, position + 1); case 0x003d: // =