diff --git a/src/scanner.c b/src/scanner.c index d429fcba..57d2af8f 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -47,7 +47,18 @@ static bool scan_template_chars(TSLexer *lexer) { } } -static bool scan_whitespace_and_comments(TSLexer *lexer, bool *scanned_comment) { +typedef enum { + REJECT, // Semicolon is illegal, ie a syntax error occurred + NO_NEWLINE, // Unclear if semicolon will be legal, continue + ACCEPT, // Semicolon is legal, assuming a comment was encountered +} WhitespaceResult; + +/** + * @param consume If false, only consume enough to check if comment indicates semicolon-legality + */ +static WhitespaceResult scan_whitespace_and_comments(TSLexer *lexer, bool *scanned_comment, bool consume) { + bool saw_block_newline = false; + for (;;) { while (iswspace(lexer->lookahead)) { skip(lexer); @@ -71,17 +82,25 @@ static bool scan_whitespace_and_comments(TSLexer *lexer, bool *scanned_comment) if (lexer->lookahead == '/') { skip(lexer); *scanned_comment = true; + + if (lexer->lookahead != '/' && !consume) { + return saw_block_newline ? ACCEPT : NO_NEWLINE; + } + break; } + } else if (lexer->lookahead == '\n' || lexer->lookahead == 0x2028 || lexer->lookahead == 0x2029) { + saw_block_newline = true; + skip(lexer); } else { skip(lexer); } } } else { - return false; + return REJECT; } } else { - return true; + return ACCEPT; } } } @@ -96,10 +115,12 @@ static bool scan_automatic_semicolon(TSLexer *lexer, bool comment_condition, boo } if (lexer->lookahead == '/') { - if (!scan_whitespace_and_comments(lexer, scanned_comment)) { + WhitespaceResult result = scan_whitespace_and_comments(lexer, scanned_comment, false); + if (result == REJECT) { return false; } - if (comment_condition && lexer->lookahead != ',' && lexer->lookahead != '=') { + + if (result == ACCEPT && comment_condition && lexer->lookahead != ',' && lexer->lookahead != '=') { return true; } } @@ -125,7 +146,7 @@ static bool scan_automatic_semicolon(TSLexer *lexer, bool comment_condition, boo skip(lexer); - if (!scan_whitespace_and_comments(lexer, scanned_comment)) { + if (scan_whitespace_and_comments(lexer, scanned_comment, true) == REJECT) { return false; } diff --git a/test/corpus/semicolon_insertion.txt b/test/corpus/semicolon_insertion.txt index d47e3386..75cca226 100644 --- a/test/corpus/semicolon_insertion.txt +++ b/test/corpus/semicolon_insertion.txt @@ -272,6 +272,16 @@ let b /* comment between declarators */, c let d +let e +/* back to back *//* comments */ + +class C { + method/*comment*/() {} +} + +b +/* interleaved non-semi-insertion */ + .c --- (program @@ -286,4 +296,14 @@ let d (comment) (comment) (comment) - (lexical_declaration (variable_declarator (identifier)))) + (lexical_declaration (variable_declarator (identifier))) + (lexical_declaration (variable_declarator (identifier))) + (comment) + (comment) + (class_declaration (identifier) (class_body (method_definition + (property_identifier) + (comment) + (formal_parameters) + (statement_block)))) + (expression_statement + (member_expression (identifier) (comment) (property_identifier))))