f186860c63ee51c5aa7c6277793dc966f5f033e4
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangParserListenerImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.impl;
9
10 import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.*;
11
12 import java.net.URI;
13 import java.text.*;
14 import java.util.*;
15
16 import org.antlr.v4.runtime.tree.ParseTree;
17 import org.opendaylight.yangtools.antlrv4.code.gen.*;
18 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
19 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
20 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Contact_stmtContext;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Container_stmtContext;
22 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Description_stmtContext;
24 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
26 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_not_supported_stmtContext;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_replace_stmtContext;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.List_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Organization_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Presence_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Reference_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Units_stmtContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.When_stmtContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
48 import org.opendaylight.yangtools.yang.common.QName;
49 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
50 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
51 import org.opendaylight.yangtools.yang.model.util.BaseTypes;
52 import org.opendaylight.yangtools.yang.model.util.YangTypesConverter;
53 import org.opendaylight.yangtools.yang.parser.builder.api.*;
54 import org.opendaylight.yangtools.yang.parser.builder.impl.*;
55 import org.opendaylight.yangtools.yang.parser.util.RefineHolder;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 import com.google.common.base.Strings;
60
61 public final class YangParserListenerImpl extends YangParserBaseListener {
62     private static final Logger LOGGER = LoggerFactory.getLogger(YangParserListenerImpl.class);
63     private static final String AUGMENT_STR = "augment";
64
65     private final String sourcePath;
66     private ModuleBuilder moduleBuilder;
67     private String moduleName;
68     private URI namespace;
69     private String yangModelPrefix;
70     private Date revision = new Date(0L);
71
72     private final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
73     private final Stack<Stack<QName>> actualPath = new Stack<>();
74
75     private void addNodeToPath(QName name) {
76         actualPath.peek().push(name);
77     }
78
79     private QName removeNodeFromPath() {
80         return actualPath.peek().pop();
81     }
82
83     public YangParserListenerImpl(String sourcePath) {
84         this.sourcePath = sourcePath;
85     }
86
87     @Override
88     public void enterModule_stmt(YangParser.Module_stmtContext ctx) {
89         moduleName = stringFromNode(ctx);
90         LOGGER.debug("entering module " + moduleName);
91         enterLog("module", moduleName, 0);
92         actualPath.push(new Stack<QName>());
93
94         moduleBuilder = new ModuleBuilder(moduleName, sourcePath);
95
96         String description = null;
97         String reference = null;
98         for (int i = 0; i < ctx.getChildCount(); i++) {
99             ParseTree child = ctx.getChild(i);
100             if (child instanceof Description_stmtContext) {
101                 description = stringFromNode(child);
102             } else if (child instanceof Reference_stmtContext) {
103                 reference = stringFromNode(child);
104             } else {
105                 if (description != null && reference != null) {
106                     break;
107                 }
108             }
109         }
110         moduleBuilder.setDescription(description);
111         moduleBuilder.setReference(reference);
112     }
113
114     @Override
115     public void exitModule_stmt(YangParser.Module_stmtContext ctx) {
116         exitLog("module", "");
117         actualPath.pop();
118     }
119
120     @Override public void enterSubmodule_stmt(YangParser.Submodule_stmtContext ctx) {
121         moduleName = stringFromNode(ctx);
122         LOGGER.debug("entering submodule " + moduleName);
123         enterLog("submodule", moduleName, 0);
124         actualPath.push(new Stack<QName>());
125
126         moduleBuilder = new ModuleBuilder(moduleName, true, sourcePath);
127
128         String description = null;
129         String reference = null;
130         for (int i = 0; i < ctx.getChildCount(); i++) {
131             ParseTree child = ctx.getChild(i);
132             if (child instanceof Description_stmtContext) {
133                 description = stringFromNode(child);
134             } else if (child instanceof Reference_stmtContext) {
135                 reference = stringFromNode(child);
136             } else {
137                 if (description != null && reference != null) {
138                     break;
139                 }
140             }
141         }
142         moduleBuilder.setDescription(description);
143         moduleBuilder.setReference(reference);
144     }
145
146     @Override public void exitSubmodule_stmt(YangParser.Submodule_stmtContext ctx) {
147         exitLog("submodule", "");
148         actualPath.pop();
149     }
150
151     @Override public void enterBelongs_to_stmt(YangParser.Belongs_to_stmtContext ctx) {
152         moduleBuilder.setBelongsTo(stringFromNode(ctx));
153     }
154
155     @Override
156     public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
157         enterLog("module_header", "", ctx.getStart().getLine());
158         String yangVersion = null;
159         for (int i = 0; i < ctx.getChildCount(); ++i) {
160             final ParseTree treeNode = ctx.getChild(i);
161             if (treeNode instanceof Namespace_stmtContext) {
162                 final String namespaceStr = stringFromNode(treeNode);
163                 namespace = URI.create(namespaceStr);
164                 moduleBuilder.setNamespace(namespace);
165                 setLog("namespace", namespaceStr);
166             } else if (treeNode instanceof Prefix_stmtContext) {
167                 yangModelPrefix = stringFromNode(treeNode);
168                 moduleBuilder.setPrefix(yangModelPrefix);
169                 setLog("prefix", yangModelPrefix);
170             } else if (treeNode instanceof Yang_version_stmtContext) {
171                 yangVersion = stringFromNode(treeNode);
172                 setLog("yang-version", yangVersion);
173             }
174         }
175
176         if (yangVersion == null) {
177             yangVersion = "1";
178         }
179         moduleBuilder.setYangVersion(yangVersion);
180     }
181
182     @Override
183     public void exitModule_header_stmts(Module_header_stmtsContext ctx) {
184         exitLog("module_header", "");
185     }
186
187     @Override
188     public void enterMeta_stmts(YangParser.Meta_stmtsContext ctx) {
189         enterLog("meta_stmt", "", ctx.getStart().getLine());
190         for (int i = 0; i < ctx.getChildCount(); i++) {
191             ParseTree child = ctx.getChild(i);
192             if (child instanceof Organization_stmtContext) {
193                 final String organization = stringFromNode(child);
194                 moduleBuilder.setOrganization(organization);
195                 setLog("organization", organization);
196             } else if (child instanceof Contact_stmtContext) {
197                 final String contact = stringFromNode(child);
198                 moduleBuilder.setContact(contact);
199                 setLog("contact", contact);
200             } else if (child instanceof Description_stmtContext) {
201                 final String description = stringFromNode(child);
202                 moduleBuilder.setDescription(description);
203                 setLog("description", description);
204             } else if (child instanceof Reference_stmtContext) {
205                 final String reference = stringFromNode(child);
206                 moduleBuilder.setReference(reference);
207                 setLog("reference", reference);
208             }
209         }
210     }
211
212     @Override
213     public void exitMeta_stmts(YangParser.Meta_stmtsContext ctx) {
214         exitLog("meta_stmt", "");
215     }
216
217     @Override
218     public void enterRevision_stmts(Revision_stmtsContext ctx) {
219         enterLog("revisions", "", ctx.getStart().getLine());
220         for (int i = 0; i < ctx.getChildCount(); ++i) {
221             final ParseTree treeNode = ctx.getChild(i);
222             if (treeNode instanceof Revision_stmtContext) {
223                 updateRevisionForRevisionStatement(treeNode);
224             }
225         }
226     }
227
228     @Override
229     public void exitRevision_stmts(Revision_stmtsContext ctx) {
230         exitLog("revisions", "");
231     }
232
233     private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
234         final String revisionDateStr = stringFromNode(treeNode);
235         try {
236             final Date revisionDate = SIMPLE_DATE_FORMAT.parse(revisionDateStr);
237             if ((revisionDate != null) && (this.revision.compareTo(revisionDate) < 0)) {
238                 this.revision = revisionDate;
239                 moduleBuilder.setRevision(this.revision);
240                 setLog("revision", this.revision.toString());
241                 for (int i = 0; i < treeNode.getChildCount(); ++i) {
242                     ParseTree child = treeNode.getChild(i);
243                     if (child instanceof Reference_stmtContext) {
244                         moduleBuilder.setReference(stringFromNode(child));
245                     }
246                 }
247             }
248         } catch (ParseException e) {
249             final String message = "Failed to parse revision string: " + revisionDateStr;
250             LOGGER.warn(message);
251         }
252     }
253
254     @Override
255     public void enterImport_stmt(Import_stmtContext ctx) {
256         final int line = ctx.getStart().getLine();
257         final String importName = stringFromNode(ctx);
258         enterLog("import", importName, line);
259
260         String importPrefix = null;
261         Date importRevision = null;
262
263         for (int i = 0; i < ctx.getChildCount(); ++i) {
264             final ParseTree treeNode = ctx.getChild(i);
265             if (treeNode instanceof Prefix_stmtContext) {
266                 importPrefix = stringFromNode(treeNode);
267             }
268             if (treeNode instanceof Revision_date_stmtContext) {
269                 String importRevisionStr = stringFromNode(treeNode);
270                 try {
271                     importRevision = SIMPLE_DATE_FORMAT.parse(importRevisionStr);
272                 } catch (ParseException e) {
273                     LOGGER.warn("Failed to parse import revision-date at line " + line + ": " + importRevisionStr);
274                 }
275             }
276         }
277         moduleBuilder.addModuleImport(importName, importRevision, importPrefix);
278         setLog("import", "(" + importName + "; " + importRevision + "; " + importPrefix + ")");
279     }
280
281     @Override
282     public void exitImport_stmt(Import_stmtContext ctx) {
283         exitLog("import", "");
284     }
285
286     @Override
287     public void enterAugment_stmt(YangParser.Augment_stmtContext ctx) {
288         final int line = ctx.getStart().getLine();
289         final String augmentPath = stringFromNode(ctx);
290         enterLog(AUGMENT_STR, augmentPath, line);
291         actualPath.push(new Stack<QName>());
292
293         AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath);
294
295         for (int i = 0; i < ctx.getChildCount(); i++) {
296             ParseTree child = ctx.getChild(i);
297             if (child instanceof Description_stmtContext) {
298                 builder.setDescription(stringFromNode(child));
299             } else if (child instanceof Reference_stmtContext) {
300                 builder.setReference(stringFromNode(child));
301             } else if (child instanceof Status_stmtContext) {
302                 builder.setStatus(parseStatus((Status_stmtContext) child));
303             } else if (child instanceof When_stmtContext) {
304                 builder.addWhenCondition(stringFromNode(child));
305             }
306         }
307
308         moduleBuilder.enterNode(builder);
309     }
310
311     @Override
312     public void exitAugment_stmt(YangParser.Augment_stmtContext ctx) {
313         moduleBuilder.exitNode();
314         exitLog(AUGMENT_STR, "");
315         actualPath.pop();
316     }
317
318     @Override
319     public void enterExtension_stmt(YangParser.Extension_stmtContext ctx) {
320         final int line = ctx.getStart().getLine();
321         final String extName = stringFromNode(ctx);
322         enterLog("extension", extName, line);
323         QName qname = new QName(namespace, revision, yangModelPrefix, extName);
324         addNodeToPath(qname);
325         SchemaPath path = createActualSchemaPath(actualPath.peek());
326
327         ExtensionBuilder builder = moduleBuilder.addExtension(qname, line, path);
328         parseSchemaNodeArgs(ctx, builder);
329
330         String argument = null;
331         boolean yin = false;
332         for (int i = 0; i < ctx.getChildCount(); i++) {
333             ParseTree child = ctx.getChild(i);
334             if (child instanceof Argument_stmtContext) {
335                 argument = stringFromNode(child);
336                 yin = parseYinValue((Argument_stmtContext) child);
337                 break;
338             }
339         }
340         builder.setArgument(argument);
341         builder.setYinElement(yin);
342
343         moduleBuilder.enterNode(builder);
344     }
345
346     @Override
347     public void exitExtension_stmt(YangParser.Extension_stmtContext ctx) {
348         moduleBuilder.exitNode();
349         exitLog("extension", removeNodeFromPath());
350     }
351
352     @Override
353     public void enterTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
354         final int line = ctx.getStart().getLine();
355         final String typedefName = stringFromNode(ctx);
356         enterLog("typedef", typedefName, line);
357         QName typedefQName = new QName(namespace, revision, yangModelPrefix, typedefName);
358         addNodeToPath(typedefQName);
359         SchemaPath path = createActualSchemaPath(actualPath.peek());
360
361         TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName, path);
362         parseSchemaNodeArgs(ctx, builder);
363         builder.setUnits(parseUnits(ctx));
364         builder.setDefaultValue(parseDefault(ctx));
365
366         moduleBuilder.enterNode(builder);
367     }
368
369     @Override
370     public void exitTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
371         moduleBuilder.exitNode();
372         exitLog("typedef", removeNodeFromPath());
373     }
374
375     @Override
376     public void enterType_stmt(YangParser.Type_stmtContext ctx) {
377         final int line = ctx.getStart().getLine();
378         final String typeName = stringFromNode(ctx);
379         enterLog("type", typeName, line);
380
381         final QName typeQName = parseQName(typeName);
382
383         TypeDefinition<?> type = null;
384         Type_body_stmtsContext typeBody = null;
385         for (int i = 0; i < ctx.getChildCount(); i++) {
386             if (ctx.getChild(i) instanceof Type_body_stmtsContext) {
387                 typeBody = (Type_body_stmtsContext) ctx.getChild(i);
388                 break;
389             }
390         }
391
392         // if this is base yang type...
393         if (YangTypesConverter.isBaseYangType(typeName)) {
394             if (typeBody == null) {
395                 // check for types which must have body
396                 checkMissingBody(typeName, moduleName, line);
397                 // if there are no constraints, just grab default base yang type
398                 type = YangTypesConverter.javaTypeForBaseYangType(typeName);
399                 addNodeToPath(type.getQName());
400                 moduleBuilder.setType(type);
401             } else {
402                 QName qname;
403                 switch (typeName) {
404                     case "union":
405                         qname = BaseTypes.constructQName("union");
406                         addNodeToPath(qname);
407                         UnionTypeBuilder unionBuilder = moduleBuilder.addUnionType(line, namespace, revision);
408                         Builder parent = moduleBuilder.getActualNode();
409                         unionBuilder.setParent(parent);
410                         moduleBuilder.enterNode(unionBuilder);
411                         break;
412                     case "identityref":
413                         qname = BaseTypes.constructQName("identityref");
414                         addNodeToPath(qname);
415                         SchemaPath path = createActualSchemaPath(actualPath.peek());
416                         moduleBuilder.addIdentityrefType(line, path, getIdentityrefBase(typeBody));
417                         break;
418                     default:
419                         type = parseTypeWithBody(typeName, typeBody, actualPath.peek(), namespace, revision,
420                                 yangModelPrefix, moduleBuilder.getActualNode());
421                         moduleBuilder.setType(type);
422                         addNodeToPath(type.getQName());
423                 }
424             }
425         } else {
426             type = parseUnknownTypeWithBody(typeQName, typeBody, actualPath.peek(), namespace, revision,
427                     yangModelPrefix, moduleBuilder.getActualNode());
428             // add parent node of this type statement to dirty nodes
429             moduleBuilder.markActualNodeDirty();
430             moduleBuilder.setType(type);
431             addNodeToPath(type.getQName());
432         }
433
434     }
435
436     private QName parseQName(String typeName) {
437         QName typeQName;
438         if (typeName.contains(":")) {
439             String[] splittedName = typeName.split(":");
440             String prefix = splittedName[0];
441             String name = splittedName[1];
442             if (prefix.equals(yangModelPrefix)) {
443                 typeQName = new QName(namespace, revision, prefix, name);
444             } else {
445                 typeQName = new QName(null, null, prefix, name);
446             }
447         } else {
448             typeQName = new QName(namespace, revision, yangModelPrefix, typeName);
449         }
450         return typeQName;
451     }
452
453     @Override
454     public void exitType_stmt(YangParser.Type_stmtContext ctx) {
455         final String typeName = stringFromNode(ctx);
456         if ("union".equals(typeName)) {
457             moduleBuilder.exitNode();
458         }
459         exitLog("type", removeNodeFromPath());
460     }
461
462     @Override
463     public void enterGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
464         final int line = ctx.getStart().getLine();
465         final String groupName = stringFromNode(ctx);
466         enterLog("grouping", groupName, line);
467         QName groupQName = new QName(namespace, revision, yangModelPrefix, groupName);
468         addNodeToPath(groupQName);
469         SchemaPath path = createActualSchemaPath(actualPath.peek());
470
471         GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName, path);
472         parseSchemaNodeArgs(ctx, builder);
473
474         moduleBuilder.enterNode(builder);
475     }
476
477     @Override
478     public void exitGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
479         moduleBuilder.exitNode();
480         exitLog("grouping", removeNodeFromPath());
481     }
482
483     @Override
484     public void enterContainer_stmt(Container_stmtContext ctx) {
485         final int line = ctx.getStart().getLine();
486         final String containerName = stringFromNode(ctx);
487         enterLog("container", containerName, line);
488
489         QName containerQName = new QName(namespace, revision, yangModelPrefix, containerName);
490         addNodeToPath(containerQName);
491         SchemaPath path = createActualSchemaPath(actualPath.peek());
492
493         ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(line, containerQName, path);
494         parseSchemaNodeArgs(ctx, builder);
495         parseConstraints(ctx, builder.getConstraints());
496         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
497
498         for (int i = 0; i < ctx.getChildCount(); ++i) {
499             final ParseTree childNode = ctx.getChild(i);
500             if (childNode instanceof Presence_stmtContext) {
501                 builder.setPresence(true);
502                 break;
503             }
504         }
505
506         moduleBuilder.enterNode(builder);
507     }
508
509     @Override
510     public void exitContainer_stmt(Container_stmtContext ctx) {
511         moduleBuilder.exitNode();
512         exitLog("container", removeNodeFromPath());
513     }
514
515     @Override
516     public void enterLeaf_stmt(Leaf_stmtContext ctx) {
517         final int line = ctx.getStart().getLine();
518         final String leafName = stringFromNode(ctx);
519         enterLog("leaf", leafName, line);
520
521         QName leafQName = new QName(namespace, revision, yangModelPrefix, leafName);
522         addNodeToPath(leafQName);
523         SchemaPath path = createActualSchemaPath(actualPath.peek());
524
525         LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(line, leafQName, path);
526         parseSchemaNodeArgs(ctx, builder);
527         parseConstraints(ctx, builder.getConstraints());
528         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
529
530         String defaultStr = null;
531         String unitsStr = null;
532         for (int i = 0; i < ctx.getChildCount(); i++) {
533             ParseTree child = ctx.getChild(i);
534             if (child instanceof Default_stmtContext) {
535                 defaultStr = stringFromNode(child);
536             } else if (child instanceof Units_stmtContext) {
537                 unitsStr = stringFromNode(child);
538             }
539         }
540         builder.setDefaultStr(defaultStr);
541         builder.setUnits(unitsStr);
542
543         moduleBuilder.enterNode(builder);
544     }
545
546     @Override
547     public void exitLeaf_stmt(YangParser.Leaf_stmtContext ctx) {
548         moduleBuilder.exitNode();
549         exitLog("leaf", removeNodeFromPath());
550     }
551
552     @Override
553     public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {
554         final int line = ctx.getStart().getLine();
555         final String groupingPathStr = stringFromNode(ctx);
556         enterLog("uses", groupingPathStr, line);
557
558         UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPathStr);
559
560         moduleBuilder.enterNode(builder);
561     }
562
563     @Override
564     public void exitUses_stmt(YangParser.Uses_stmtContext ctx) {
565         moduleBuilder.exitNode();
566         exitLog("uses", "");
567     }
568
569     @Override
570     public void enterUses_augment_stmt(YangParser.Uses_augment_stmtContext ctx) {
571         actualPath.push(new Stack<QName>());
572         final int line = ctx.getStart().getLine();
573         final String augmentPath = stringFromNode(ctx);
574         enterLog(AUGMENT_STR, augmentPath, line);
575
576         AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath);
577
578         for (int i = 0; i < ctx.getChildCount(); i++) {
579             ParseTree child = ctx.getChild(i);
580             if (child instanceof Description_stmtContext) {
581                 builder.setDescription(stringFromNode(child));
582             } else if (child instanceof Reference_stmtContext) {
583                 builder.setReference(stringFromNode(child));
584             } else if (child instanceof Status_stmtContext) {
585                 builder.setStatus(parseStatus((Status_stmtContext) child));
586             } else if (child instanceof When_stmtContext) {
587                 builder.addWhenCondition(stringFromNode(child));
588             }
589         }
590
591         moduleBuilder.enterNode(builder);
592     }
593
594     @Override
595     public void exitUses_augment_stmt(YangParser.Uses_augment_stmtContext ctx) {
596         moduleBuilder.exitNode();
597         exitLog(AUGMENT_STR, "");
598         actualPath.pop();
599     }
600
601     @Override
602     public void enterRefine_stmt(YangParser.Refine_stmtContext ctx) {
603         final String refineString = stringFromNode(ctx);
604         enterLog("refine", refineString, ctx.getStart().getLine());
605
606         RefineHolder refine = parseRefine(ctx, moduleName);
607         moduleBuilder.addRefine(refine);
608         moduleBuilder.enterNode(refine);
609     }
610
611     @Override
612     public void exitRefine_stmt(YangParser.Refine_stmtContext ctx) {
613         moduleBuilder.exitNode();
614         exitLog("refine", "");
615     }
616
617     @Override
618     public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
619         final int line = ctx.getStart().getLine();
620         final String leafListName = stringFromNode(ctx);
621         enterLog("leaf-list", leafListName, line);
622         QName leafListQName = new QName(namespace, revision, yangModelPrefix, leafListName);
623         addNodeToPath(leafListQName);
624         SchemaPath path = createActualSchemaPath(actualPath.peek());
625
626         LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, path);
627         moduleBuilder.enterNode(builder);
628
629         parseSchemaNodeArgs(ctx, builder);
630         parseConstraints(ctx, builder.getConstraints());
631         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
632
633         for (int i = 0; i < ctx.getChildCount(); ++i) {
634             final ParseTree childNode = ctx.getChild(i);
635             if (childNode instanceof Ordered_by_stmtContext) {
636                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
637                 final boolean userOrdered = parseUserOrdered(orderedBy);
638                 builder.setUserOrdered(userOrdered);
639                 break;
640             }
641         }
642     }
643
644     @Override
645     public void exitLeaf_list_stmt(YangParser.Leaf_list_stmtContext ctx) {
646         moduleBuilder.exitNode();
647         exitLog("leaf-list", removeNodeFromPath());
648     }
649
650     @Override
651     public void enterList_stmt(List_stmtContext ctx) {
652         final int line = ctx.getStart().getLine();
653         final String listName = stringFromNode(ctx);
654         enterLog("list", listName, line);
655
656         QName listQName = new QName(namespace, revision, yangModelPrefix, listName);
657         addNodeToPath(listQName);
658         SchemaPath path = createActualSchemaPath(actualPath.peek());
659
660         ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, path);
661         moduleBuilder.enterNode(builder);
662
663         parseSchemaNodeArgs(ctx, builder);
664         parseConstraints(ctx, builder.getConstraints());
665         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
666
667         for (int i = 0; i < ctx.getChildCount(); ++i) {
668             ParseTree childNode = ctx.getChild(i);
669             if (childNode instanceof Ordered_by_stmtContext) {
670                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
671                 final boolean userOrdered = parseUserOrdered(orderedBy);
672                 builder.setUserOrdered(userOrdered);
673             } else if (childNode instanceof Key_stmtContext) {
674                 List<String> key = createListKey((Key_stmtContext) childNode);
675                 builder.setKeys(key);
676             }
677         }
678     }
679
680     @Override
681     public void exitList_stmt(List_stmtContext ctx) {
682         moduleBuilder.exitNode();
683         exitLog("list", removeNodeFromPath());
684     }
685
686     @Override
687     public void enterAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
688         final int line = ctx.getStart().getLine();
689         final String anyXmlName = stringFromNode(ctx);
690         enterLog("anyxml", anyXmlName, line);
691
692         QName anyXmlQName = new QName(namespace, revision, yangModelPrefix, anyXmlName);
693         addNodeToPath(anyXmlQName);
694         SchemaPath path = createActualSchemaPath(actualPath.peek());
695
696         AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, path);
697         moduleBuilder.enterNode(builder);
698
699         parseSchemaNodeArgs(ctx, builder);
700         parseConstraints(ctx, builder.getConstraints());
701         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
702     }
703
704     @Override
705     public void exitAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
706         moduleBuilder.exitNode();
707         exitLog("anyxml", removeNodeFromPath());
708     }
709
710     @Override
711     public void enterChoice_stmt(YangParser.Choice_stmtContext ctx) {
712         final int line = ctx.getStart().getLine();
713         final String choiceName = stringFromNode(ctx);
714         enterLog("choice", choiceName, line);
715
716         QName choiceQName = new QName(namespace, revision, yangModelPrefix, choiceName);
717         addNodeToPath(choiceQName);
718         SchemaPath path = createActualSchemaPath(actualPath.peek());
719
720         ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName, path);
721         moduleBuilder.enterNode(builder);
722
723         parseSchemaNodeArgs(ctx, builder);
724         parseConstraints(ctx, builder.getConstraints());
725         builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
726
727         // set 'default' case
728         for (int i = 0; i < ctx.getChildCount(); i++) {
729             ParseTree child = ctx.getChild(i);
730             if (child instanceof Default_stmtContext) {
731                 String defaultCase = stringFromNode(child);
732                 builder.setDefaultCase(defaultCase);
733                 break;
734             }
735         }
736     }
737
738     @Override
739     public void exitChoice_stmt(YangParser.Choice_stmtContext ctx) {
740         moduleBuilder.exitNode();
741         exitLog("choice", removeNodeFromPath());
742     }
743
744     @Override
745     public void enterCase_stmt(YangParser.Case_stmtContext ctx) {
746         final int line = ctx.getStart().getLine();
747         final String caseName = stringFromNode(ctx);
748         enterLog("case", caseName, line);
749
750         QName caseQName = new QName(namespace, revision, yangModelPrefix, caseName);
751         addNodeToPath(caseQName);
752         SchemaPath path = createActualSchemaPath(actualPath.peek());
753
754         ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName, path);
755         moduleBuilder.enterNode(builder);
756
757         parseSchemaNodeArgs(ctx, builder);
758         parseConstraints(ctx, builder.getConstraints());
759     }
760
761     @Override
762     public void exitCase_stmt(YangParser.Case_stmtContext ctx) {
763         moduleBuilder.exitNode();
764         exitLog("case", removeNodeFromPath());
765     }
766
767     @Override
768     public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {
769         final int line = ctx.getStart().getLine();
770         final String notificationName = stringFromNode(ctx);
771         enterLog("notification", notificationName, line);
772
773         QName notificationQName = new QName(namespace, revision, yangModelPrefix, notificationName);
774         addNodeToPath(notificationQName);
775         SchemaPath path = createActualSchemaPath(actualPath.peek());
776
777         NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName, path);
778         moduleBuilder.enterNode(builder);
779
780         parseSchemaNodeArgs(ctx, builder);
781     }
782
783     @Override
784     public void exitNotification_stmt(YangParser.Notification_stmtContext ctx) {
785         moduleBuilder.exitNode();
786         exitLog("notification", removeNodeFromPath());
787     }
788
789     // Unknown nodes
790     @Override
791     public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
792         final int line = ctx.getStart().getLine();
793         final String nodeParameter = stringFromNode(ctx);
794         enterLog("unknown-node", nodeParameter, line);
795
796         QName nodeType;
797         final String nodeTypeStr = ctx.getChild(0).getText();
798         final String[] splittedElement = nodeTypeStr.split(":");
799         if (splittedElement.length == 1) {
800             nodeType = new QName(namespace, revision, yangModelPrefix, splittedElement[0]);
801         } else {
802             nodeType = new QName(namespace, revision, splittedElement[0], splittedElement[1]);
803         }
804
805         QName qname = null;
806         if (!Strings.isNullOrEmpty(nodeParameter)) {
807             String[] splittedName = nodeParameter.split(":");
808             if (splittedName.length == 2) {
809                 qname = new QName(null, null, splittedName[0], splittedName[1]);
810             } else {
811                 qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
812             }
813         } else {
814             qname = nodeType;
815         }
816         addNodeToPath(qname);
817         SchemaPath path = createActualSchemaPath(actualPath.peek());
818
819         UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
820         builder.setNodeType(nodeType);
821         builder.setNodeParameter(nodeParameter);
822
823
824         parseSchemaNodeArgs(ctx, builder);
825         moduleBuilder.enterNode(builder);
826     }
827
828     @Override
829     public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
830         moduleBuilder.exitNode();
831         exitLog("unknown-node", removeNodeFromPath());
832     }
833
834     @Override
835     public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {
836         final int line = ctx.getStart().getLine();
837         final String rpcName = stringFromNode(ctx);
838         enterLog("rpc", rpcName, line);
839
840         QName rpcQName = new QName(namespace, revision, yangModelPrefix, rpcName);
841         addNodeToPath(rpcQName);
842         SchemaPath path = createActualSchemaPath(actualPath.peek());
843
844         RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path);
845         moduleBuilder.enterNode(rpcBuilder);
846
847
848         parseSchemaNodeArgs(ctx, rpcBuilder);
849     }
850
851     @Override
852     public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {
853         moduleBuilder.exitNode();
854         exitLog("rpc", removeNodeFromPath());
855     }
856
857     @Override
858     public void enterInput_stmt(YangParser.Input_stmtContext ctx) {
859         final int line = ctx.getStart().getLine();
860         final String input = "input";
861         enterLog(input, input, line);
862
863         QName rpcQName = new QName(namespace, revision, yangModelPrefix, input);
864         addNodeToPath(rpcQName);
865         SchemaPath path = createActualSchemaPath(actualPath.peek());
866
867         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
868         moduleBuilder.enterNode(builder);
869
870         parseSchemaNodeArgs(ctx, builder);
871         parseConstraints(ctx, builder.getConstraints());
872     }
873
874     @Override
875     public void exitInput_stmt(YangParser.Input_stmtContext ctx) {
876         moduleBuilder.exitNode();
877         exitLog("input", removeNodeFromPath());
878     }
879
880     @Override
881     public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {
882         final int line = ctx.getStart().getLine();
883         final String output = "output";
884         enterLog(output, output, line);
885
886         QName rpcQName = new QName(namespace, revision, yangModelPrefix, output);
887         addNodeToPath(rpcQName);
888         SchemaPath path = createActualSchemaPath(actualPath.peek());
889
890         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
891         moduleBuilder.enterNode(builder);
892
893         parseSchemaNodeArgs(ctx, builder);
894         parseConstraints(ctx, builder.getConstraints());
895     }
896
897     @Override
898     public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {
899         moduleBuilder.exitNode();
900         exitLog("output", removeNodeFromPath());
901     }
902
903     @Override
904     public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {
905         final int line = ctx.getStart().getLine();
906         final String featureName = stringFromNode(ctx);
907         enterLog("feature", featureName, line);
908
909         QName featureQName = new QName(namespace, revision, yangModelPrefix, featureName);
910         addNodeToPath(featureQName);
911         SchemaPath path = createActualSchemaPath(actualPath.peek());
912
913         FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path);
914         moduleBuilder.enterNode(featureBuilder);
915
916         parseSchemaNodeArgs(ctx, featureBuilder);
917     }
918
919     @Override
920     public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {
921         moduleBuilder.exitNode();
922         exitLog("feature", removeNodeFromPath());
923     }
924
925     @Override
926     public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
927         final int line = ctx.getStart().getLine();
928         final String targetPath = stringFromNode(ctx);
929         enterLog("deviation", targetPath, line);
930
931         String reference = null;
932         String deviate = null;
933         DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
934         moduleBuilder.enterNode(builder);
935
936         for (int i = 0; i < ctx.getChildCount(); i++) {
937             ParseTree child = ctx.getChild(i);
938             if (child instanceof Reference_stmtContext) {
939                 reference = stringFromNode(child);
940             } else if (child instanceof Deviate_not_supported_stmtContext) {
941                 deviate = stringFromNode(child);
942             } else if (child instanceof Deviate_add_stmtContext) {
943                 deviate = stringFromNode(child);
944             } else if (child instanceof Deviate_replace_stmtContext) {
945                 deviate = stringFromNode(child);
946             } else if (child instanceof Deviate_delete_stmtContext) {
947                 deviate = stringFromNode(child);
948             }
949         }
950         builder.setReference(reference);
951         builder.setDeviate(deviate);
952     }
953
954     @Override
955     public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
956         moduleBuilder.exitNode();
957         exitLog("deviation", "");
958     }
959
960     @Override
961     public void enterIdentity_stmt(YangParser.Identity_stmtContext ctx) {
962         final int line = ctx.getStart().getLine();
963         final String identityName = stringFromNode(ctx);
964         enterLog("identity", identityName, line);
965
966         final QName identityQName = new QName(namespace, revision, yangModelPrefix, identityName);
967         addNodeToPath(identityQName);
968         SchemaPath path = createActualSchemaPath(actualPath.peek());
969
970         IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path);
971         moduleBuilder.enterNode(builder);
972
973
974         parseSchemaNodeArgs(ctx, builder);
975
976         for (int i = 0; i < ctx.getChildCount(); i++) {
977             ParseTree child = ctx.getChild(i);
978             if (child instanceof Base_stmtContext) {
979                 String baseIdentityName = stringFromNode(child);
980                 builder.setBaseIdentityName(baseIdentityName);
981             }
982         }
983     }
984
985     @Override
986     public void exitIdentity_stmt(YangParser.Identity_stmtContext ctx) {
987         moduleBuilder.exitNode();
988         exitLog("identity", removeNodeFromPath());
989     }
990
991     public ModuleBuilder getModuleBuilder() {
992         return moduleBuilder;
993     }
994
995     private void enterLog(String p1, String p2, int line) {
996         LOGGER.trace("entering {} {} ({})", p1, p2, line);
997     }
998
999     private void exitLog(String p1, String p2) {
1000         LOGGER.trace("exiting {} {}", p1, p2);
1001     }
1002
1003     private void exitLog(String p1, QName p2) {
1004         LOGGER.trace("exiting {} {}", p1, p2.getLocalName());
1005     }
1006
1007     private void setLog(String p1, String p2) {
1008         LOGGER.trace("setting {} {}", p1, p2);
1009     }
1010
1011 }