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