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