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