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