2 * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.rfc7950.repo;
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.base.VerifyException;
14 import java.util.Optional;
15 import org.antlr.v4.runtime.Token;
16 import org.antlr.v4.runtime.tree.ParseTree;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.common.QNameModule;
19 import org.opendaylight.yangtools.yang.common.YangConstants;
20 import org.opendaylight.yangtools.yang.common.YangVersion;
21 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
22 import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser.ArgumentContext;
23 import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser.KeywordContext;
24 import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser.StatementContext;
25 import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
26 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
27 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
28 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
29 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
30 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter.ResumedStatement;
32 class StatementContextVisitor {
33 private final QNameToStatementDefinition stmtDef;
34 private final ArgumentContextUtils utils;
35 private final StatementWriter writer;
36 private final PrefixToModule prefixes;
37 private final String sourceName;
39 StatementContextVisitor(final String sourceName, final StatementWriter writer,
40 final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes, final YangVersion yangVersion) {
41 this.writer = requireNonNull(writer);
42 this.stmtDef = requireNonNull(stmtDef);
43 this.utils = ArgumentContextUtils.forVersion(yangVersion);
44 this.sourceName = sourceName;
45 this.prefixes = prefixes;
48 void visit(final StatementContext context) {
49 processStatement(0, context);
53 * Based on identifier read from source and collections of relevant prefixes and statement definitions mappings
54 * provided for actual phase, method resolves and returns valid QName for declared statement to be written.
55 * This applies to any declared statement, including unknown statements.
57 * @param prefixes collection of all relevant prefix mappings supplied for actual parsing phase
58 * @param stmtDef collection of all relevant statement definition mappings provided for actual parsing phase
59 * @param keyword statement keyword text to parse from source
60 * @param ref Source reference
61 * @return valid QName for declared statement to be written, or null
63 QName getValidStatementDefinition(final KeywordContext keyword, final StatementSourceReference ref) {
64 switch (keyword.getChildCount()) {
66 final StatementDefinition def = stmtDef.get(QName.create(YangConstants.RFC6020_YIN_MODULE,
67 keyword.getChild(0).getText()));
68 return def != null ? def.getStatementName() : null;
70 if (prefixes == null) {
71 // No prefixes to look up from
75 final String prefix = keyword.getChild(0).getText();
76 final QNameModule qNameModule = prefixes.get(prefix);
77 if (qNameModule == null) {
78 // Failed to look the namespace
82 final String localName = keyword.getChild(2).getText();
83 final StatementDefinition foundStmtDef = resolveStatement(qNameModule, localName);
84 return foundStmtDef != null ? foundStmtDef.getStatementName() : null;
86 throw new VerifyException("Unexpected shape of " + keyword);
90 StatementDefinition resolveStatement(final QNameModule module, final String localName) {
91 return stmtDef.get(QName.create(module, localName));
94 // Normal entry point, checks for potential resume
95 private boolean processStatement(final int myOffset, final StatementContext ctx) {
96 final Optional<? extends ResumedStatement> optResumed = writer.resumeStatement(myOffset);
97 if (optResumed.isPresent()) {
98 final ResumedStatement resumed = optResumed.get();
99 return resumed.isFullyDefined() || doProcessStatement(ctx, resumed.getSourceReference());
101 return processNewStatement(myOffset, ctx);
104 // Slow-path allocation of a new statement
105 private boolean processNewStatement(final int myOffset, final StatementContext ctx) {
106 final Token start = ctx.getStart();
107 final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, start.getLine(),
108 start.getCharPositionInLine());
109 final QName def = getValidStatementDefinition(verifyNotNull(ctx.getChild(KeywordContext.class, 0)), ref);
114 final ArgumentContext argumentCtx = ctx.getChild(ArgumentContext.class, 0);
115 final String argument = argumentCtx == null ? null : utils.stringFromStringContext(argumentCtx, ref);
116 writer.startStatement(myOffset, def, argument, ref);
117 return doProcessStatement(ctx, ref);
121 private boolean doProcessStatement(final StatementContext ctx, final StatementSourceReference ref) {
123 boolean fullyDefined = true;
124 if (ctx.children != null) {
125 for (ParseTree s : ctx.children) {
126 if (s instanceof StatementContext && !processStatement(childOffset++, (StatementContext) s)) {
127 fullyDefined = false;
132 writer.storeStatement(childOffset, fullyDefined);
133 writer.endStatement(ref);