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