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