From 34db9e4b298486c71605bb40984c6edf63cd86de Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Mon, 17 Jul 2023 04:52:52 -0400 Subject: [PATCH] fix: rework true top-level items to disallow binary expressions This resolves conflicts with declarations that can be interpreted as binary_expressions --- grammar.js | 59 +++++++++++++-- src/grammar.json | 174 +++++++++++++++++++++++++++++++++++++++++--- src/node-types.json | 56 +++++++++++++- 3 files changed, 273 insertions(+), 16 deletions(-) diff --git a/grammar.js b/grammar.js index 94f1488..294ed16 100644 --- a/grammar.js +++ b/grammar.js @@ -44,7 +44,9 @@ module.exports = grammar({ inline: $ => [ $._statement, + $._block_item, $._top_level_item, + $._top_level_statement, $._type_identifier, $._field_identifier, $._statement_identifier, @@ -57,6 +59,8 @@ module.exports = grammar({ [$._type_specifier, $._declarator, $.macro_type_specifier], [$._type_specifier, $._expression], [$._type_specifier, $._expression, $.macro_type_specifier], + [$._type_specifier, $._expression_not_binary], + [$._type_specifier, $._expression_not_binary, $.macro_type_specifier], [$._type_specifier, $.macro_type_specifier], [$.sized_type_specifier], [$.attributed_statement], @@ -69,7 +73,24 @@ module.exports = grammar({ rules: { translation_unit: $ => repeat($._top_level_item), + // Top level items are block items with the exception of the expression statement _top_level_item: $ => choice( + $.function_definition, + $.linkage_specification, + $.declaration, + $._top_level_statement, + $.attributed_statement, + $.type_definition, + $._empty_declaration, + $.preproc_if, + $.preproc_ifdef, + $.preproc_include, + $.preproc_def, + $.preproc_function_def, + $.preproc_call, + ), + + _block_item: $ => choice( $.function_definition, $.linkage_specification, $.declaration, @@ -123,7 +144,7 @@ module.exports = grammar({ '\n', ), - ...preprocIf('', $ => $._top_level_item), + ...preprocIf('', $ => $._block_item), ...preprocIf('_in_field_declaration_list', $ => $._field_declaration_list_item), preproc_directive: _ => /#[ \t]*[a-zA-Z]\w*/, @@ -307,7 +328,7 @@ module.exports = grammar({ declaration_list: $ => seq( '{', - repeat($._top_level_item), + repeat($._block_item), '}', ), @@ -462,7 +483,7 @@ module.exports = grammar({ compound_statement: $ => seq( '{', - repeat($._top_level_item), + repeat($._block_item), '}', ), @@ -649,12 +670,35 @@ module.exports = grammar({ $.goto_statement, ), + _top_level_statement: $ => choice( + $.case_statement, + $.attributed_statement, + $.labeled_statement, + $.compound_statement, + alias($._top_level_expression_statement, $.expression_statement), + $.if_statement, + $.switch_statement, + $.do_statement, + $.while_statement, + $.for_statement, + $.return_statement, + $.break_statement, + $.continue_statement, + $.goto_statement, + ), + labeled_statement: $ => seq( field('label', $._statement_identifier), ':', $._statement, ), + // This is missing binary expressions, others were kept so that macro code can be parsed better and code examples + _top_level_expression_statement: $ => seq( + $._expression_not_binary, + ';', + ), + expression_statement: $ => seq( optional(choice( $._expression, @@ -741,9 +785,13 @@ module.exports = grammar({ // Expressions _expression: $ => choice( + $._expression_not_binary, + $.binary_expression, + ), + + _expression_not_binary: $ => choice( $.conditional_expression, $.assignment_expression, - $.binary_expression, $.unary_expression, $.update_expression, $.cast_expression, @@ -975,6 +1023,7 @@ module.exports = grammar({ commaSep(field('label', $.identifier)), ), + // The compound_statement is added to parse macros taking statements as arguments, e.g. MYFORLOOP(1, 10, i, { foo(i); bar(i); }) argument_list: $ => seq('(', commaSep(choice($._expression, $.compound_statement)), ')'), field_expression: $ => seq( @@ -1061,7 +1110,7 @@ module.exports = grammar({ concatenated_string: $ => seq( $.string_literal, - repeat1(choice($.string_literal, $.identifier)), + repeat1(choice($.string_literal, $.identifier)), // Identifier is added to parse macros that are strings, like PRIu64 ), string_literal: $ => seq( diff --git a/src/grammar.json b/src/grammar.json index a6d14c9..b328701 100644 --- a/src/grammar.json +++ b/src/grammar.json @@ -10,6 +10,63 @@ } }, "_top_level_item": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "function_definition" + }, + { + "type": "SYMBOL", + "name": "linkage_specification" + }, + { + "type": "SYMBOL", + "name": "declaration" + }, + { + "type": "SYMBOL", + "name": "_top_level_statement" + }, + { + "type": "SYMBOL", + "name": "attributed_statement" + }, + { + "type": "SYMBOL", + "name": "type_definition" + }, + { + "type": "SYMBOL", + "name": "_empty_declaration" + }, + { + "type": "SYMBOL", + "name": "preproc_if" + }, + { + "type": "SYMBOL", + "name": "preproc_ifdef" + }, + { + "type": "SYMBOL", + "name": "preproc_include" + }, + { + "type": "SYMBOL", + "name": "preproc_def" + }, + { + "type": "SYMBOL", + "name": "preproc_function_def" + }, + { + "type": "SYMBOL", + "name": "preproc_call" + } + ] + }, + "_block_item": { "type": "CHOICE", "members": [ { @@ -334,7 +391,7 @@ "type": "REPEAT", "content": { "type": "SYMBOL", - "name": "_top_level_item" + "name": "_block_item" } }, { @@ -411,7 +468,7 @@ "type": "REPEAT", "content": { "type": "SYMBOL", - "name": "_top_level_item" + "name": "_block_item" } }, { @@ -475,7 +532,7 @@ "type": "REPEAT", "content": { "type": "SYMBOL", - "name": "_top_level_item" + "name": "_block_item" } } ] @@ -508,7 +565,7 @@ "type": "REPEAT", "content": { "type": "SYMBOL", - "name": "_top_level_item" + "name": "_block_item" } }, { @@ -2283,7 +2340,7 @@ "type": "REPEAT", "content": { "type": "SYMBOL", - "name": "_top_level_item" + "name": "_block_item" } }, { @@ -3183,7 +3240,7 @@ "type": "REPEAT", "content": { "type": "SYMBOL", - "name": "_top_level_item" + "name": "_block_item" } }, { @@ -4112,6 +4169,72 @@ } ] }, + "_top_level_statement": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "case_statement" + }, + { + "type": "SYMBOL", + "name": "attributed_statement" + }, + { + "type": "SYMBOL", + "name": "labeled_statement" + }, + { + "type": "SYMBOL", + "name": "compound_statement" + }, + { + "type": "ALIAS", + "content": { + "type": "SYMBOL", + "name": "_top_level_expression_statement" + }, + "named": true, + "value": "expression_statement" + }, + { + "type": "SYMBOL", + "name": "if_statement" + }, + { + "type": "SYMBOL", + "name": "switch_statement" + }, + { + "type": "SYMBOL", + "name": "do_statement" + }, + { + "type": "SYMBOL", + "name": "while_statement" + }, + { + "type": "SYMBOL", + "name": "for_statement" + }, + { + "type": "SYMBOL", + "name": "return_statement" + }, + { + "type": "SYMBOL", + "name": "break_statement" + }, + { + "type": "SYMBOL", + "name": "continue_statement" + }, + { + "type": "SYMBOL", + "name": "goto_statement" + } + ] + }, "labeled_statement": { "type": "SEQ", "members": [ @@ -4133,6 +4256,19 @@ } ] }, + "_top_level_expression_statement": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "_expression_not_binary" + }, + { + "type": "STRING", + "value": ";" + } + ] + }, "expression_statement": { "type": "SEQ", "members": [ @@ -4575,15 +4711,24 @@ "members": [ { "type": "SYMBOL", - "name": "conditional_expression" + "name": "_expression_not_binary" }, { "type": "SYMBOL", - "name": "assignment_expression" + "name": "binary_expression" + } + ] + }, + "_expression_not_binary": { + "type": "CHOICE", + "members": [ + { + "type": "SYMBOL", + "name": "conditional_expression" }, { "type": "SYMBOL", - "name": "binary_expression" + "name": "assignment_expression" }, { "type": "SYMBOL", @@ -7477,6 +7622,15 @@ "_expression", "macro_type_specifier" ], + [ + "_type_specifier", + "_expression_not_binary" + ], + [ + "_type_specifier", + "_expression_not_binary", + "macro_type_specifier" + ], [ "_type_specifier", "macro_type_specifier" @@ -7499,7 +7653,9 @@ "externals": [], "inline": [ "_statement", + "_block_item", "_top_level_item", + "_top_level_statement", "_type_identifier", "_field_identifier", "_statement_identifier", diff --git a/src/node-types.json b/src/node-types.json index e59c92c..2f57df5 100644 --- a/src/node-types.json +++ b/src/node-types.json @@ -3289,21 +3289,61 @@ "required": false, "types": [ { - "type": "_statement", + "type": "_type_specifier", "named": true }, { - "type": "_type_specifier", + "type": "attributed_statement", + "named": true + }, + { + "type": "break_statement", + "named": true + }, + { + "type": "case_statement", + "named": true + }, + { + "type": "compound_statement", + "named": true + }, + { + "type": "continue_statement", "named": true }, { "type": "declaration", "named": true }, + { + "type": "do_statement", + "named": true + }, + { + "type": "expression_statement", + "named": true + }, + { + "type": "for_statement", + "named": true + }, { "type": "function_definition", "named": true }, + { + "type": "goto_statement", + "named": true + }, + { + "type": "if_statement", + "named": true + }, + { + "type": "labeled_statement", + "named": true + }, { "type": "linkage_specification", "named": true @@ -3332,9 +3372,21 @@ "type": "preproc_include", "named": true }, + { + "type": "return_statement", + "named": true + }, + { + "type": "switch_statement", + "named": true + }, { "type": "type_definition", "named": true + }, + { + "type": "while_statement", + "named": true } ] }