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