diff --git a/pyang/statements.py b/pyang/statements.py index 44cfa9c0..80249eaa 100644 --- a/pyang/statements.py +++ b/pyang/statements.py @@ -155,6 +155,7 @@ class Abort(Exception): # second expansion: expand augmentations into i_children 'expand_2', + 'expand_3', # unique name check phase: 'unique_name', @@ -216,6 +217,7 @@ class Abort(Exception): lambda ctx, s: v_inherit_properties(ctx, s), ('expand_2', 'augment'):lambda ctx, s: v_expand_2_augment(ctx, s), + ('expand_3', 'augment'):lambda ctx, s: v_expand_3_augment(ctx, s), ('unique_name', 'module'): \ lambda ctx, s: v_unique_name_defintions(ctx, s), @@ -252,10 +254,11 @@ class Abort(Exception): _v_i_children = { 'unique_name':True, 'expand_2':True, + 'expand_3':True, 'reference_1':True, 'reference_2':True, } -"""Phases in this dict are run over the stmts which has i_children. +"""Phases in this dict are run over the stmts that have i_children. Note that the tests are not run in grouping definitions.""" _v_i_children_keywords = { @@ -1464,6 +1467,8 @@ def v_expand_1_children(ctx, stmt): v_inherit_properties(ctx, stmt) for a in s.search('augment'): v_expand_2_augment(ctx, a) + for a in s.search('augment'): + v_expand_3_augment(ctx, a) elif s.keyword in data_keywords and hasattr(stmt, 'i_children'): stmt.i_children.append(s) @@ -1726,18 +1731,19 @@ def walk(s, config_value, allow_explicit): def v_expand_2_augment(ctx, stmt): """ - One-pass augment expansion algorithm: First observation: since we - validate each imported module, all nodes that are augmented by - other modules already exist. For each node in the path to the - target node, if it does not exist, it might get created by an - augment later in this module. This only applies to nodes defined - in our namespace (since all other modules already are validated). - For each such node, we add a temporary Statement instance, and - store a pointer to it. If we find such a temporary node in the - nodes we add, we replace it with our real node, and delete it from - the list of temporary nodes created. When we're done with all - augment statements, the list of temporary nodes should be empty, - otherwise it is an error. + First pass of two-pass augment expansion algorithm. + + First observation: since we validate each imported module, all + nodes that are augmented by other modules already exist. For each + node in the path to the target node, if it does not exist, it + might get created by an augment later in this module. This only + applies to nodes defined in our namespace (since all other modules + already are validated). For each such node, we add a temporary + Statement instance, and store a pointer to it. If we find such a + temporary node in the nodes we add, we replace it with our real + node, and delete it from the list of temporary nodes created. + When we're done with all augment statements, the list of temporary + nodes should be empty, otherwise it is an error. """ if hasattr(stmt, 'i_target_node'): # already expanded @@ -1868,6 +1874,15 @@ def is_expected_keyword(parent, child): stmt.i_target_node.substmts.append(s) s.parent = stmt.i_target_node +def v_expand_3_augment(ctx, stmt): + """ + Second pass of two-pass augment expansion algorithm. + + Find the (possibly expanded) target nodes again. The reason for + this is that stmt.i_target_node may point to a __tmp_augment__ node. + """ + stmt.i_target_node = find_target_node(ctx, stmt, is_augment=True) + def create_new_case(ctx, choice, child, expand=True): new_case = new_statement(child.top, choice, child.pos, 'case', child.arg) v_init_stmt(ctx, new_case) diff --git a/test/test_issues/test_i650/Makefile b/test/test_issues/test_i650/Makefile new file mode 100644 index 00000000..6ff2b0a2 --- /dev/null +++ b/test/test_issues/test_i650/Makefile @@ -0,0 +1,4 @@ +test: test1 + +test1: + $(PYANG) -Werror a.yang diff --git a/test/test_issues/test_i650/a.yang b/test/test_issues/test_i650/a.yang new file mode 100644 index 00000000..e8c1ac51 --- /dev/null +++ b/test/test_issues/test_i650/a.yang @@ -0,0 +1,64 @@ +module a { + yang-version 1.1; + namespace "urn:a"; + + prefix ex; + + container interfaces { + + list interface { + key "name"; + + leaf name { + type string; + } + + leaf type { + type string; + mandatory true; + } + + } + + } + + + augment '/ex:interfaces/ex:interface/ex:frame-processing/ex:inline-frame-processingx/ex:inline-frame-processing/ex:ingress-rule/ex:rule/ex:flexible-match' { + + when + "../../../../ex:type = 'value'"; + + } + + augment '/ex:interfaces/ex:interface' { + + choice frame-processing { + + case inline-frame-processingx { + + container inline-frame-processing { + + container ingress-rule { + + list rule { + key "name"; + + leaf name { + type string; + } + + container flexible-match { + } + } + } + } + } + } + } + + + + + + +}