4cebb06cef2da7b0ad9fa4e4cf0a730a472835bb
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / internal / ctf / core / event / metadata / tsdl / variant / VariantParser.java
1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9 package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.variant;
10
11 import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
12
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
16
17 import org.antlr.runtime.tree.CommonTree;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
20 import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
21 import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
22 import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
23 import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
24 import org.eclipse.tracecompass.ctf.parser.CTFParser;
25 import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
26 import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
27
28 /**
29 *
30 * A CTF variant is a selection between different types. A CTF variant must
31 * always be defined within the scope of a structure or within fields contained
32 * within a structure (defined recursively). A _tag_ enumeration field must
33 * appear in either the same static scope, prior to the variant field (in field
34 * declaration order), in an upper static scope, or in an upper dynamic scope
35 * (see [Static and dynamic scopes](#spec7.3.2)). The type selection is
36 * indicated by the mapping from the enumeration value to the string used as
37 * variant type selector. The field to use as tag is specified by the
38 * `tag_field`, specified between `< >` after the `variant` keyword for unnamed
39 * variants, and after _variant name_ for named variants. It is not required
40 * that each enumeration mapping appears as variant type tag field. It is also
41 * not required that each variant type tag appears as enumeration mapping.
42 * However, it is required that any enumeration mapping encountered within a
43 * stream has a matching variant type tag field. <br>
44 * The alignment of the variant is the alignment of the type as selected by the
45 * tag value for the specific instance of the variant. The size of the variant
46 * is the size as selected by the tag value for the specific instance of the
47 * variant. <br>
48 * The alignment of the type containing the variant is independent of the
49 * variant alignment. For instance, if a structure contains two fields, a 32-bit
50 * integer, aligned on 32 bits, and a variant, which contains two choices:
51 * either a 32-bit field, aligned on 32 bits, or a 64-bit field, aligned on 64
52 * bits, the alignment of the outmost structure will be 32-bit (the alignment of
53 * its largest field, disregarding the alignment of the variant). The alignment
54 * of the variant will depend on the selector: if the variant's 32-bit field is
55 * selected, its alignment will be 32-bit, or 64-bit otherwise. It is important
56 * to note that variants are specifically tailored for compactness in a stream.
57 * Therefore, the relative offsets of compound type fields can vary depending on
58 * the offset at which the compound type starts if it contains a variant that
59 * itself contains a type with alignment larger than the largest field contained
60 * within the compound type. This is caused by the fact that the compound type
61 * may contain the enumeration that select the variant's choice, and therefore
62 * the alignment to be applied to the compound type cannot be determined before
63 * encountering the enumeration. <br>
64 * Each variant type selector possess a field name, which is a unique identifier
65 * within the variant. The identifier is not allowed to use any [reserved
66 * keyword](#C.1.2). Replacing reserved keywords with underscore-prefixed field
67 * names is recommended. Fields starting with an underscore should have their
68 * leading underscore removed by the CTF trace readers. <br>
69 * A named variant declaration followed by its definition within a structure
70 * declaration: <br>
71 *
72 * <pre>
73 variant name {
74 field_type sel1;
75 field_type sel2;
76 field_type sel3;
77 // ...
78 };
79
80 struct {
81 enum : integer_type { sel1, sel2, sel3, <em>more</em> } tag_field;
82 // ...
83 variant name <tag_field> v;
84 }
85 * </pre>
86 *
87 * An unnamed variant definition within a structure is expressed by the
88 * following TSDL metadata: <br>
89 *
90 * <pre>
91 struct {
92 enum : integer_type { sel1, sel2, sel3, <em>more</em> } tag_field;
93 // ...
94 variant <tag_field> {
95 field_type sel1;
96 field_type sel2;
97 field_type sel3;
98 // ...
99 } v;
100 }
101 * </pre>
102 *
103 * Example of a named variant within a sequence that refers to a single tag
104 * field: <br>
105 *
106 * <pre>
107 variant example {
108 uint32_t a;
109 uint64_t b;
110 short c;
111 };
112
113 struct {
114 enum : uint2_t { a, b, c } choice;
115 unsigned int seqlen;
116 variant example <choice> v[seqlen];
117 }
118 * </pre>
119 *
120 * Example of an unnamed variant: <br>
121 *
122 * <pre>
123 struct {
124 enum : uint2_t { a, b, c, d } choice;
125
126 // Unrelated fields can be added between the variant and its tag
127 int32_t somevalue;
128 variant <choice> {
129 uint32_t a;
130 uint64_t b;
131 short c;
132 struct {
133 unsigned int field1;
134 uint64_t field2;
135 } d;
136 } s;
137 }
138 * </pre>
139 *
140 * Example of an unnamed variant within an array: <br>
141 *
142 * <pre>
143 struct {
144 enum : uint2_t { a, b, c } choice;
145 variant <choice> {
146 uint32_t a;
147 uint64_t b;
148 short c;
149 } v[10];
150 }
151 * </pre>
152 *
153 * <br>
154 * Example of a variant type definition within a structure, where the defined
155 * type is then declared within an array of structures. This variant refers to a
156 * tag located in an upper static scope. This example clearly shows that a
157 * variant type definition referring to the tag `x` uses the closest preceding
158 * field from the static scope of the type definition. <br>
159 *
160 * <pre>
161 struct {
162 enum : uint2_t { a, b, c, d } x;
163
164 // "x" refers to the preceding "x" enumeration in the
165 // static scope of the type definition.
166
167 typedef variant <x> {
168 uint32_t a;
169 uint64_t b;
170 short c;
171 } example_variant;
172
173 struct {
174 enum : int { x, y, z } x; // This enumeration is not used by "v".
175
176 // "v" uses the "enum : uint2_t { a, b, c, d }" tag.
177 example_variant v;
178 } a[10];
179 }
180 * </pre>
181 *
182 * @author Matthew Khouzam
183 * @author Efficios - Javadoc preamble
184 *
185 *
186 */
187 public final class VariantParser extends AbstractScopedCommonTreeParser {
188
189 /**
190 * Parameter object with a trace and current scope
191 *
192 * @author Matthew Khouzam
193 *
194 */
195 @NonNullByDefault
196 public static final class Param implements ICommonTreeParserParameter {
197 private final DeclarationScope fDeclarationScope;
198 private final CTFTrace fTrace;
199
200 /**
201 * Constructor
202 *
203 * @param trace
204 * the trace
205 * @param scope
206 * the current scope
207 */
208 public Param(CTFTrace trace, DeclarationScope scope) {
209 fTrace = trace;
210 fDeclarationScope = scope;
211 }
212 }
213
214 /**
215 * The instance
216 */
217 public final static VariantParser INSTANCE = new VariantParser();
218
219 private VariantParser() {
220 }
221
222 /**
223 * Parse the variant
224 *
225 * @param variant
226 * the variant AST node
227 * @param param
228 * the {@link Param} parameter object
229 * @return a populated {@link VariantDeclaration}
230 * @throws ParseException
231 * the AST is malformed
232 */
233 @Override
234 public VariantDeclaration parse(CommonTree variant, ICommonTreeParserParameter param) throws ParseException {
235 if (!(param instanceof Param)) {
236 throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
237 }
238 final DeclarationScope scope = ((Param) param).fDeclarationScope;
239
240 List<CommonTree> children = variant.getChildren();
241 VariantDeclaration variantDeclaration = null;
242
243 boolean hasName = false;
244 String variantName = null;
245
246 boolean hasBody = false;
247 CommonTree variantBody = null;
248
249 boolean hasTag = false;
250 String variantTag = null;
251
252 for (CommonTree child : children) {
253 switch (child.getType()) {
254 case CTFParser.VARIANT_NAME:
255
256 hasName = true;
257
258 CommonTree variantNameIdentifier = (CommonTree) child.getChild(0);
259
260 variantName = variantNameIdentifier.getText();
261
262 break;
263 case CTFParser.VARIANT_TAG:
264
265 hasTag = true;
266
267 CommonTree variantTagIdentifier = (CommonTree) child.getChild(0);
268
269 variantTag = variantTagIdentifier.getText();
270
271 break;
272 case CTFParser.VARIANT_BODY:
273
274 hasBody = true;
275
276 variantBody = child;
277
278 break;
279 default:
280 throw childTypeError(child);
281 }
282 }
283
284 if (hasBody) {
285 /*
286 * If variant has a name, check if already defined in the current
287 * scope.
288 */
289 if (hasName
290 && (scope.lookupVariant(variantName) != null)) {
291 throw new ParseException("variant " + variantName //$NON-NLS-1$
292 + " already defined."); //$NON-NLS-1$
293 }
294
295 /* Create the declaration */
296 variantDeclaration = new VariantDeclaration();
297
298 CTFTrace trace = ((Param) param).fTrace;
299 /* Parse the body */
300 VariantBodyParser.INSTANCE.parse(variantBody, new VariantBodyParser.Param(variantDeclaration, trace, variantName, scope));
301
302 /* If variant has name, add it to the current scope. */
303 if (hasName) {
304 scope.registerVariant(variantName, variantDeclaration);
305 }
306 } else /* !hasBody */ {
307 if (hasName) {
308 /* Name and !body */
309
310 /* Lookup the name in the current scope. */
311 variantDeclaration = scope.lookupVariantRecursive(variantName);
312
313 /*
314 * If not found, it means that a struct with such name has not
315 * been defined
316 */
317 if (variantDeclaration == null) {
318 throw new ParseException("variant " + variantName //$NON-NLS-1$
319 + " is not defined"); //$NON-NLS-1$
320 }
321 } else {
322 /* !Name and !body */
323
324 /* We can't do anything with that. */
325 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
326 }
327 }
328
329 if (hasTag) {
330 variantDeclaration.setTag(variantTag);
331
332 IDeclaration decl = scope.lookupIdentifierRecursive(variantTag);
333 if (decl == null) {
334 throw new ParseException("Variant tag not found: " + variantTag); //$NON-NLS-1$
335 }
336 if (!(decl instanceof EnumDeclaration)) {
337 throw new ParseException("Variant tag must be an enum: " + variantTag); //$NON-NLS-1$
338 }
339 EnumDeclaration tagDecl = (EnumDeclaration) decl;
340 Set<String> intersection = new HashSet<>(tagDecl.getLabels());
341 intersection.retainAll(variantDeclaration.getFields().keySet());
342 if (intersection.isEmpty()) {
343 throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName); //$NON-NLS-1$
344 }
345 }
346
347 return variantDeclaration;
348 }
349
350 }
This page took 0.038435 seconds and 4 git commands to generate.