From f7e4da26743c441749c41a8602054b1b552818a1 Mon Sep 17 00:00:00 2001 From: Pete Cordell Date: Mon, 11 Jul 2016 13:19:45 +0100 Subject: [PATCH] Prioritised groupings over type-choices within object, array & group --- abnf/jcr-abnf.txt | 10 ++++++---- lib/jcr/parser.rb | 14 ++++++++------ spec/parser_spec.rb | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/abnf/jcr-abnf.txt b/abnf/jcr-abnf.txt index 842e8f0..5601fa9 100644 --- a/abnf/jcr-abnf.txt +++ b/abnf/jcr-abnf.txt @@ -54,6 +54,7 @@ member-name-spec = regex / q-string type-rule = value-rule / type-choice / target-rule-name type-choice = annotations "(" type-choice-items *( choice-combiner type-choice-items ) ")" +explicit-type-choice = type-designator type-choice type-choice-items = *sp-cmt ( type-choice / type-rule ) *sp-cmt annotations = *( "@{" *sp-cmt annotation-set *sp-cmt "}" *sp-cmt ) @@ -120,21 +121,21 @@ object-rule = annotations "{" *sp-cmt [ object-items *sp-cmt ] "}" object-items = object-item (*( sequence-combiner object-item ) / *( choice-combiner object-item ) ) object-item = object-item-types *sp-cmt [ repetition ] -object-item-types = member-rule / target-rule-name / object-group +object-item-types = object-group / member-rule / target-rule-name object-group = "(" *sp-cmt [ object-items *sp-cmt ] ")" array-rule = annotations "[" *sp-cmt [ array-items *sp-cmt ] "]" array-items = array-item (*( sequence-combiner array-item ) / *( choice-combiner array-item ) ) array-item = array-item-types *sp-cmt [ repetition ] -array-item-types = type-rule / array-group +array-item-types = array-group / type-rule / explicit-type-choice array-group = "(" *sp-cmt [ array-items *sp-cmt ] ")" group-rule = annotations "(" *sp-cmt [ group-items *sp-cmt ] ")" group-items = group-item (*( sequence-combiner group-item ) / *( choice-combiner group-item ) ) group-item = group-item-types *sp-cmt [ repetition ] -group-item-types = member-rule / type-rule / group-group +group-item-types = group-group / member-rule / type-rule / explicit-type-choice group-group = group-rule sequence-combiner = *sp-cmt "," *sp-cmt @@ -146,13 +147,14 @@ repetition = "@" *sp-cmt ( optional / one-or-more / min-max-repetition / optional = "?" one-or-more = "+" zero-or-more = "*" -min-max-repetition = min-repeat ".." max-repeat +min-max-repetition = min-repeat ".." max-repeat ?repetition-step min-repetition = min-repeat ".." max-repetition = ".." max-repeat min-repeat = non-neg-integer max-repeat = non-neg-integer specific-repetition = non-neg-integer +repetition-step = "%" non-neg-integer integer = "0" / ["-"] pos-integer non-neg-integer = "0" / pos-integer pos-integer = digit1-9 *DIGIT diff --git a/lib/jcr/parser.rb b/lib/jcr/parser.rb index ce9d6ac..5951959 100644 --- a/lib/jcr/parser.rb +++ b/lib/jcr/parser.rb @@ -126,6 +126,8 @@ class Parser < Parslet::Parser rule(:type_choice) { ( annotations >> str('(') >> type_choice_items >> ( choice_combiner >> type_choice_items ).repeat >> str(')') ).as(:group_rule) } #! type_choice = annotations "(" type_choice_items #! *( choice_combiner type_choice_items ) ")" + rule(:explicit_type_choice) { type_designator >> type_choice } + #! explicit_type_choice = type_designator type_choice rule(:type_choice_items) { spcCmnt? >> (type_choice | type_rule) >> spcCmnt? } #! type_choice_items = spcCmnt? ( type_choice / type_rule ) spcCmnt? #! @@ -291,8 +293,8 @@ class Parser < Parslet::Parser #! *( choice_combiner object_item ) ) rule(:object_item ) { object_item_types >> spcCmnt? >> repetition.maybe } #! object_item = object_item_types spcCmnt? [ repetition ] - rule(:object_item_types) { member_rule | target_rule_name | object_group } - #! object_item_types = member_rule / target_rule_name / object_group + rule(:object_item_types) { object_group | member_rule | target_rule_name } + #! object_item_types = object_group / member_rule / target_rule_name rule(:object_group) { ( str('(') >> spcCmnt? >> object_items.maybe >> spcCmnt? >> str(')') ).as(:group_rule) } #! object_group = "(" spcCmnt? [ object_items spcCmnt? ] ")" #! @@ -306,8 +308,8 @@ class Parser < Parslet::Parser #! *( choice_combiner array_item ) ) rule(:array_item) { array_item_types >> spcCmnt? >> repetition.maybe } #! array_item = array_item_types spcCmnt? [ repetition ] - rule(:array_item_types) { type_rule | array_group } - #! array_item_types = type_rule / array_group + rule(:array_item_types) { array_group | type_rule | explicit_type_choice } + #! array_item_types = array_group / type_rule / explicit_type_choice rule(:array_group) { ( str('(') >> spcCmnt? >> array_items.maybe >> spcCmnt? >> str(')') ).as(:group_rule) } #! array_group = "(" spcCmnt? [ array_items spcCmnt? ] ")" #! @@ -320,8 +322,8 @@ class Parser < Parslet::Parser #! *( choice_combiner group_item ) ) rule(:group_item) { group_item_types >> spcCmnt? >> repetition.maybe } #! group_item = group_item_types spcCmnt? [ repetition ] - rule(:group_item_types) { member_rule | type_rule | group_group } - #! group_item_types = member_rule / type_rule / group_group + rule(:group_item_types) { group_group | member_rule | type_rule | explicit_type_choice } + #! group_item_types = group_group / member_rule / type_rule / explicit_type_choice rule(:group_group) { group_rule } #! group_group = group_rule #! diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 33d654a..505e51f 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -774,6 +774,42 @@ expect(tree[0][:rule][:rule_name]).to eq("trule") end + it 'should parse an array rule with an choice array group' do + tree = JCR.parse( '$trule = :[ ($my_rule1| $my_rule2 )@+]' ) + expect(tree[0][:rule][:rule_name]).to eq("trule") + expect(tree[0][:rule][:array_rule][:group_rule][0][:target_rule_name][:rule_name]).to eq("my_rule1") + expect(tree[0][:rule][:array_rule][:group_rule][1][:target_rule_name][:rule_name]).to eq("my_rule2") + end + + it 'should parse an array rule with an sequence array group' do + tree = JCR.parse( '$trule = :[ ($my_rule1, $my_rule2 )@+]' ) + expect(tree[0][:rule][:rule_name]).to eq("trule") + expect(tree[0][:rule][:array_rule][:group_rule][0][:target_rule_name][:rule_name]).to eq("my_rule1") + expect(tree[0][:rule][:array_rule][:group_rule][1][:target_rule_name][:rule_name]).to eq("my_rule2") + end + + it 'should parse an array rule with an explicit type choice' do + tree = JCR.parse( '$trule = :[ :($my_rule1| $my_rule2 )@+]' ) + expect(tree[0][:rule][:rule_name]).to eq("trule") + expect(tree[0][:rule][:array_rule][:group_rule][0][:target_rule_name][:rule_name]).to eq("my_rule1") + expect(tree[0][:rule][:array_rule][:group_rule][1][:target_rule_name][:rule_name]).to eq("my_rule2") + end + + it 'should parse an array rule with an explicit type choice' do + tree = JCR.parse( '$trule = :[ type ($my_rule1| $my_rule2 )@+]' ) + expect(tree[0][:rule][:rule_name]).to eq("trule") + expect(tree[0][:rule][:array_rule][:group_rule][0][:target_rule_name][:rule_name]).to eq("my_rule1") + expect(tree[0][:rule][:array_rule][:group_rule][1][:target_rule_name][:rule_name]).to eq("my_rule2") + end + + it 'should NOT parse an array rule with an invalid explicit type choice' do + expect{ tree = JCR.parse( '$trule = :[ :($my_rule1, $my_rule2 )@+]' ) }.to raise_error Parslet::ParseFailed + end + + it 'should NOT parse an array rule with an invalid explicit type choice' do + expect{ tree = JCR.parse( '$trule = :[ type ($my_rule1, $my_rule2 )@+]' ) }.to raise_error Parslet::ParseFailed + end + it 'should parse an array rule with a rulename and a group rule' do tree = JCR.parse( '$trule = :[ $my_rule1 | ( integer | { $my_rule2 } ) ]' ) expect(tree[0][:rule][:rule_name]).to eq("trule")