2 * Copyright (c) 2020 PANTHEON.tech, 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.ir;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.ImmutableList;
14 import java.util.Iterator;
15 import java.util.List;
16 import org.eclipse.jdt.annotation.NonNull;
19 * An argument to a YANG statement, as defined by section 6.1.3 of both
20 * <a href="https://tools.ietf.org/html/rfc6020#section-6.1.3">RFC6020</a> and
21 * <a href="https://tools.ietf.org/html/rfc7950#section-6.1.3">RFC7950</a>. An argument is effectively any old string,
22 * except it can be defined in a number of ways:
24 * <li>it can be a simple unquoted string, or</li>
25 * <li>it can be a single-quoted string, with its contents being completely preserved, or</li>
26 * <li>it can be a double-quoted string, which defines some escaping and whitespace-stripping rules, or</li>
27 * <li>it can be a concatenation of any number of single- or double-quoted strings</li>
31 * The first three cases as covered by {@link Single} subclass, which exposes appropriate methods to infer how its
32 * string literal is to be interpreted. The last case is handled by {@link Concatenation} subclass, which exposes
33 * the constituent parts as {@link Single} items.
36 * Please note that parser implementations producing these argument representations are <b>NOT</b> required to retain
37 * the format of the original definition. They are free to perform quoting and concatenation transformations as long as
38 * they maintain semantic equivalence. As a matter of example, these transformations are explicitly allowed:
40 * <li>elimination of unneeded quotes, for example turning {@code "foo"} into {@code foo}</li>
41 * <li>transformation of quotes, for example turning {@code "foo\nbar"} into {@code 'foo
bar'}</li>
42 * <li>concatenation processing, for example turning {@code 'foo' + 'bar'} into {@code foobar}</li>
46 public abstract class IRArgument extends AbstractIRObject {
48 * An argument composed of multiple concatenated parts.
50 public static final class Concatenation extends IRArgument {
51 private final @NonNull ImmutableList<Single> parts;
53 Concatenation(final List<Single> parts) {
54 this.parts = ImmutableList.copyOf(parts);
58 * Return the argument parts that need to be concatenated.
60 * @return Argument parts.
62 public @NonNull List<? extends Single> parts() {
67 StringBuilder toYangFragment(final StringBuilder sb) {
68 final Iterator<Single> it = parts.iterator();
69 it.next().toYangFragment(sb);
70 while (it.hasNext()) {
71 it.next().toYangFragment(sb.append(" + "));
78 * An argument composed of a single string. This string may need further validation and processing, as it may not
79 * actually conform to the specification as requested by {@code yang-version}.
82 * This is the public footprint which is served by three final subclasses: DoublyQuoted, SingleQuoted, Unquoted.
83 * Those classes must never be exposed, as they are a manifestation of current implementation in StatementFactory.
84 * As noted in the interface contract of IRArgument, we have very much free reign on syntactic transformations,
85 * StatementFactory is just not taking advantage of those at this point.
87 * The subclasses may very much change, in terms of both naming and function, to support whatever StatementFactory
90 public abstract static class Single extends IRArgument {
91 private final @NonNull String string;
93 Single(final String string) {
94 this.string = requireNonNull(string);
98 * Significant portion of this argument. For unquoted and single-quoted strings this is the unquoted string
99 * literal. For double-quoted strings this is the unquoted string, after whitespace trimming as defined by
100 * RFC6020/RFC7950 section 6.1.3, but before escape substitution.
102 * @return Significant portion of this argument.
104 public final @NonNull String string() {
109 * Imprecise check if this argument needs further unescape operation (which is version-specific) to arrive at
110 * the literal string value. This is false for unquoted and single-quoted strings, which do not support any sort
111 * of escaping. This may be true for double-quoted strings, as they <b>may</b> need to be further processed in
112 * version-dependent ways to arrive at the correct literal value.
115 * This method is allowed to err on the false-positive side -- i.e. it may report any double-quoted string as
116 * needing further processing, even when the actual content could be determined to not need further processing.
118 * @return False if the value of {@link #string} can be used as-is.
120 public final boolean needUnescape() {
121 return this instanceof DoubleQuoted;
125 * Imprecise check if this argument needs an additional content check for compliance. This is false if the
126 * string was explicitly quoted and therefore cannot contain stray single- or double-quotes, or if the content
127 * has already been checked to not contain them.
130 * The content check is needed to ascertain RFC7950 compliance, because RFC6020 allows constructs like
131 * <pre>abc"def</pre> in unquoted strings, while RFC7950 explicitly forbids them.
134 * This method is allowed to err on the false-positive side -- i.e. it may report any unquoted string as
135 * needing this check, even when the actual content could be determined to not contain quotes.
137 * @return True if this argument requires a version-specific check for quote content.
139 public final boolean needQuoteCheck() {
140 return this instanceof Unquoted;
144 * Imprecise check if this argument complies with the {@code identifier} YANG specification.
147 * This method is allowed to err on the false-negative side -- i.e. it may report any string as not being
148 * compliant with {@code identifier}, even when the actual content could be determined to be compliant.
150 * @return True if this argument is known to be directly usable in contexts where YANG requires the use of
152 public final boolean isValidIdentifier() {
153 return this instanceof Identifier;
157 StringBuilder toYangFragment(final StringBuilder sb) {
158 return sb.append(string);
162 static final class DoubleQuoted extends Single {
163 DoubleQuoted(final String string) {
168 StringBuilder toYangFragment(final StringBuilder sb) {
169 // Note this is just an approximation. We do not have enough state knowledge to restore any whitespace we
171 return super.toYangFragment(sb.append('"')).append('"');
175 static final class SingleQuoted extends Single {
176 static final @NonNull SingleQuoted EMPTY = new SingleQuoted("");
178 SingleQuoted(final String string) {
183 StringBuilder toYangFragment(final StringBuilder sb) {
184 return super.toYangFragment(sb.append('\'')).append('\'');
188 static final class Identifier extends Single {
189 Identifier(final String string) {
194 static final class Unquoted extends Single {
195 Unquoted(final String string) {