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