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