Merge "Do not return null when no RPC is registered"
[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         try {
807             if (!Strings.isNullOrEmpty(nodeParameter)) {
808                 String[] splittedName = nodeParameter.split(":");
809                 if (splittedName.length == 2) {
810                     qname = new QName(null, null, splittedName[0], splittedName[1]);
811                 } else {
812                     qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
813                 }
814             } else {
815                 qname = nodeType;
816             }
817         } catch (IllegalArgumentException e) {
818             qname = nodeType;
819             
820         }
821         addNodeToPath(qname);
822         SchemaPath path = createActualSchemaPath(actualPath.peek());
823
824         UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
825         builder.setNodeType(nodeType);
826         builder.setNodeParameter(nodeParameter);
827
828
829         parseSchemaNodeArgs(ctx, builder);
830         moduleBuilder.enterNode(builder);
831     }
832
833     @Override
834     public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
835         moduleBuilder.exitNode();
836         exitLog("unknown-node", removeNodeFromPath());
837     }
838
839     @Override
840     public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {
841         final int line = ctx.getStart().getLine();
842         final String rpcName = stringFromNode(ctx);
843         enterLog("rpc", rpcName, line);
844
845         QName rpcQName = new QName(namespace, revision, yangModelPrefix, rpcName);
846         addNodeToPath(rpcQName);
847         SchemaPath path = createActualSchemaPath(actualPath.peek());
848
849         RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path);
850         moduleBuilder.enterNode(rpcBuilder);
851
852
853         parseSchemaNodeArgs(ctx, rpcBuilder);
854     }
855
856     @Override
857     public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {
858         moduleBuilder.exitNode();
859         exitLog("rpc", removeNodeFromPath());
860     }
861
862     @Override
863     public void enterInput_stmt(YangParser.Input_stmtContext ctx) {
864         final int line = ctx.getStart().getLine();
865         final String input = "input";
866         enterLog(input, input, line);
867
868         QName rpcQName = new QName(namespace, revision, yangModelPrefix, input);
869         addNodeToPath(rpcQName);
870         SchemaPath path = createActualSchemaPath(actualPath.peek());
871
872         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
873         moduleBuilder.enterNode(builder);
874
875         parseSchemaNodeArgs(ctx, builder);
876         parseConstraints(ctx, builder.getConstraints());
877     }
878
879     @Override
880     public void exitInput_stmt(YangParser.Input_stmtContext ctx) {
881         moduleBuilder.exitNode();
882         exitLog("input", removeNodeFromPath());
883     }
884
885     @Override
886     public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {
887         final int line = ctx.getStart().getLine();
888         final String output = "output";
889         enterLog(output, output, line);
890
891         QName rpcQName = new QName(namespace, revision, yangModelPrefix, output);
892         addNodeToPath(rpcQName);
893         SchemaPath path = createActualSchemaPath(actualPath.peek());
894
895         ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
896         moduleBuilder.enterNode(builder);
897
898         parseSchemaNodeArgs(ctx, builder);
899         parseConstraints(ctx, builder.getConstraints());
900     }
901
902     @Override
903     public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {
904         moduleBuilder.exitNode();
905         exitLog("output", removeNodeFromPath());
906     }
907
908     @Override
909     public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {
910         final int line = ctx.getStart().getLine();
911         final String featureName = stringFromNode(ctx);
912         enterLog("feature", featureName, line);
913
914         QName featureQName = new QName(namespace, revision, yangModelPrefix, featureName);
915         addNodeToPath(featureQName);
916         SchemaPath path = createActualSchemaPath(actualPath.peek());
917
918         FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path);
919         moduleBuilder.enterNode(featureBuilder);
920
921         parseSchemaNodeArgs(ctx, featureBuilder);
922     }
923
924     @Override
925     public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {
926         moduleBuilder.exitNode();
927         exitLog("feature", removeNodeFromPath());
928     }
929
930     @Override
931     public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
932         final int line = ctx.getStart().getLine();
933         final String targetPath = stringFromNode(ctx);
934         enterLog("deviation", targetPath, line);
935
936         String reference = null;
937         String deviate = null;
938         DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
939         moduleBuilder.enterNode(builder);
940
941         for (int i = 0; i < ctx.getChildCount(); i++) {
942             ParseTree child = ctx.getChild(i);
943             if (child instanceof Reference_stmtContext) {
944                 reference = stringFromNode(child);
945             } else if (child instanceof Deviate_not_supported_stmtContext) {
946                 deviate = stringFromNode(child);
947             } else if (child instanceof Deviate_add_stmtContext) {
948                 deviate = stringFromNode(child);
949             } else if (child instanceof Deviate_replace_stmtContext) {
950                 deviate = stringFromNode(child);
951             } else if (child instanceof Deviate_delete_stmtContext) {
952                 deviate = stringFromNode(child);
953             }
954         }
955         builder.setReference(reference);
956         builder.setDeviate(deviate);
957     }
958
959     @Override
960     public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
961         moduleBuilder.exitNode();
962         exitLog("deviation", "");
963     }
964
965     @Override
966     public void enterIdentity_stmt(YangParser.Identity_stmtContext ctx) {
967         final int line = ctx.getStart().getLine();
968         final String identityName = stringFromNode(ctx);
969         enterLog("identity", identityName, line);
970
971         final QName identityQName = new QName(namespace, revision, yangModelPrefix, identityName);
972         addNodeToPath(identityQName);
973         SchemaPath path = createActualSchemaPath(actualPath.peek());
974
975         IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path);
976         moduleBuilder.enterNode(builder);
977
978
979         parseSchemaNodeArgs(ctx, builder);
980
981         for (int i = 0; i < ctx.getChildCount(); i++) {
982             ParseTree child = ctx.getChild(i);
983             if (child instanceof Base_stmtContext) {
984                 String baseIdentityName = stringFromNode(child);
985                 builder.setBaseIdentityName(baseIdentityName);
986             }
987         }
988     }
989
990     @Override
991     public void exitIdentity_stmt(YangParser.Identity_stmtContext ctx) {
992         moduleBuilder.exitNode();
993         exitLog("identity", removeNodeFromPath());
994     }
995
996     public ModuleBuilder getModuleBuilder() {
997         return moduleBuilder;
998     }
999
1000     private void enterLog(String p1, String p2, int line) {
1001         LOGGER.trace("entering {} {} ({})", p1, p2, line);
1002     }
1003
1004     private void exitLog(String p1, String p2) {
1005         LOGGER.trace("exiting {} {}", p1, p2);
1006     }
1007
1008     private void exitLog(String p1, QName p2) {
1009         LOGGER.trace("exiting {} {}", p1, p2.getLocalName());
1010     }
1011
1012     private void setLog(String p1, String p2) {
1013         LOGGER.trace("setting {} {}", p1, p2);
1014     }
1015
1016 }