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