From be9e79db1bcd1412861e62a82755109dfb649c42 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 1 Dec 2016 10:24:06 -0800 Subject: [PATCH] Avoid incorrect application of precedence --- spec/integration/compile_grammar_spec.cc | 154 ++++++++++++++++++ .../build_tables/build_parse_table.cc | 2 +- 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/spec/integration/compile_grammar_spec.cc b/spec/integration/compile_grammar_spec.cc index 36f5647e..d41d76e4 100644 --- a/spec/integration/compile_grammar_spec.cc +++ b/spec/integration/compile_grammar_spec.cc @@ -243,6 +243,160 @@ describe("compile_grammar", []() { "(block (expression (identifier)))))))"); }); + it("handles precedence applied to specific rule subsequences (regression)", [&]() { + TSCompileResult result = ts_compile_grammar(R"JSON({ + "name": "precedence_on_subsequence", + + "extras": [ + {"type": "STRING", "value": " "} + ], + + "rules": { + "expression": { + "type": "PREC_LEFT", + "value": 0, + "content": { + "type": "CHOICE", + "members": [ + {"type": "SYMBOL", "name": "function_call"}, + {"type": "SYMBOL", "name": "identifier"}, + {"type": "SYMBOL", "name": "scope_resolution"} + ] + } + }, + + "function_call": { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "identifier"}, + {"type": "SYMBOL", "name": "expression"} + ] + }, + + { + "type": "PREC", + "value": 1, + "content": { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "identifier"}, + {"type": "SYMBOL", "name": "block"} + ] + } + }, + + { + "type": "PREC", + "value": -1, + "content": { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "identifier"}, + {"type": "SYMBOL", "name": "do_block"} + ] + } + }, + + { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "identifier"}, + { + "type": "PREC", + "value": 1, + "content": { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "expression"}, + {"type": "SYMBOL", "name": "block"} + ] + } + } + ] + }, + + { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "identifier"}, + { + "type": "PREC", + "value": -1, + "content": { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "expression"}, + {"type": "SYMBOL", "name": "do_block"} + ] + } + } + ] + } + ] + }, + + "scope_resolution": { + "type": "PREC_LEFT", + "value": 1, + "content": { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + {"type": "SYMBOL", "name": "expression"}, + {"type": "STRING", "value": "::"}, + {"type": "SYMBOL", "name": "expression"} + ] + }, + { + "type": "SEQ", + "members": [ + {"type": "STRING", "value": "::"}, + {"type": "SYMBOL", "name": "expression"}, + ] + } + ] + } + }, + + "block": { + "type": "STRING", + "value": "{}" + }, + + "do_block": { + "type": "STRING", + "value": "do end" + }, + + "identifier": { + "type": "PATTERN", + "value": "[a-zA-Z]+" + } + } + })JSON"); + + auto language = load_compile_result("precedence_on_subsequence", result); + ts_document_set_language(document, language); + + ts_document_set_input_string(document, "a b {}"); + ts_document_parse(document); + assert_root_node("(expression (function_call " + "(identifier) " + "(expression (function_call (identifier) (block)))))"); + + ts_document_set_input_string(document, "a b do end"); + ts_document_parse(document); + assert_root_node("(expression (function_call " + "(identifier) " + "(expression (identifier)) " + "(do_block)))"); + }); + it("does not allow conflicting precedences", [&]() { string grammar_template = R"JSON({ "name": "conflicting_precedence_example", diff --git a/src/compiler/build_tables/build_parse_table.cc b/src/compiler/build_tables/build_parse_table.cc index 2047b4ba..91444310 100644 --- a/src/compiler/build_tables/build_parse_table.cc +++ b/src/compiler/build_tables/build_parse_table.cc @@ -377,7 +377,7 @@ class ParseTableBuilder { LookaheadSet first_set = item_set_builder.get_first_set(item.next_symbol()); if (first_set.contains(lookahead)) { shift_items.insert(item); - shift_precedence.add(item.precedence()); + shift_precedence.add(item.production->at(item.step_index - 1).precedence); } } }