ctf: make dynamic scopes work with definitions [bug 470846]
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / internal / ctf / core / event / metadata / IOStructGen.java
CommitLineData
866e5b51 1/*******************************************************************************
3ba65808 2 * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others
866e5b51
FC
3 *
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
4311ac8b
MAL
9 * Contributors:
10 * Matthew Khouzam - Initial Design and Grammar
11 * Francis Giraldeau - Initial API and implementation
12 * Simon Marchi - Initial API and implementation
866e5b51
FC
13 *******************************************************************************/
14
f357bcd4 15package org.eclipse.tracecompass.internal.ctf.core.event.metadata;
866e5b51 16
4311ac8b 17import java.math.BigInteger;
866e5b51
FC
18import java.nio.ByteOrder;
19import java.util.ArrayList;
20import java.util.Collections;
816fde81 21import java.util.HashSet;
866e5b51
FC
22import java.util.LinkedList;
23import java.util.List;
816fde81 24import java.util.Set;
866e5b51
FC
25import java.util.UUID;
26
27import org.antlr.runtime.tree.CommonTree;
4311ac8b 28import org.eclipse.core.runtime.IStatus;
a4fa4e36 29import org.eclipse.jdt.annotation.NonNull;
3ba65808 30import org.eclipse.jdt.annotation.Nullable;
8d90cd62 31import org.eclipse.tracecompass.ctf.core.CTFStrings;
f357bcd4 32import org.eclipse.tracecompass.ctf.core.event.CTFClock;
c8891db9 33import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
f357bcd4
AM
34import org.eclipse.tracecompass.ctf.core.event.types.Encoding;
35import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
36import org.eclipse.tracecompass.ctf.core.event.types.FloatDeclaration;
37import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
38import org.eclipse.tracecompass.ctf.core.event.types.IEventHeaderDeclaration;
39import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration;
40import org.eclipse.tracecompass.ctf.core.event.types.StringDeclaration;
41import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
42import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
43import org.eclipse.tracecompass.ctf.core.trace.CTFStream;
44import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
45import org.eclipse.tracecompass.ctf.parser.CTFParser;
46import org.eclipse.tracecompass.internal.ctf.core.Activator;
47import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration;
48import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
49import org.eclipse.tracecompass.internal.ctf.core.event.types.ArrayDeclaration;
50import org.eclipse.tracecompass.internal.ctf.core.event.types.SequenceDeclaration;
51import org.eclipse.tracecompass.internal.ctf.core.event.types.StructDeclarationFlattener;
52import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderCompactDeclaration;
53import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderLargeDeclaration;
866e5b51 54
52f81ef7
MK
55import com.google.common.collect.Iterables;
56
866e5b51 57/**
251274dd 58 * IOStructGen
866e5b51 59 */
866e5b51
FC
60public class IOStructGen {
61
62 // ------------------------------------------------------------------------
63 // Attributes
64 // ------------------------------------------------------------------------
65
62c21477
MK
66 private static final @NonNull String MAP = "map"; //$NON-NLS-1$
67 private static final @NonNull String ENCODING = "encoding"; //$NON-NLS-1$
68 private static final @NonNull String BASE = "base"; //$NON-NLS-1$
69 private static final @NonNull String SIZE = "size"; //$NON-NLS-1$
70 private static final @NonNull String SIGNED = "signed"; //$NON-NLS-1$
71 private static final @NonNull String LINE = "line"; //$NON-NLS-1$
72 private static final @NonNull String FILE = "file"; //$NON-NLS-1$
73 private static final @NonNull String IP = "ip"; //$NON-NLS-1$
74 private static final @NonNull String FUNC = "func"; //$NON-NLS-1$
75 private static final @NonNull String NAME = "name"; //$NON-NLS-1$
76 private static final @NonNull String EMPTY_STRING = ""; //$NON-NLS-1$
466f6d95
MK
77 private static final int INTEGER_BASE_16 = 16;
78 private static final int INTEGER_BASE_10 = 10;
79 private static final int INTEGER_BASE_8 = 8;
80 private static final int INTEGER_BASE_2 = 2;
b4685f09 81 private static final long DEFAULT_ALIGNMENT = 1;
466f6d95
MK
82 private static final int DEFAULT_FLOAT_EXPONENT = 8;
83 private static final int DEFAULT_FLOAT_MANTISSA = 24;
84 private static final int DEFAULT_INT_BASE = 10;
866e5b51
FC
85 /**
86 * The trace
87 */
9226cfc5
MK
88 private final CTFTrace fTrace;
89 private CommonTree fTree;
866e5b51
FC
90
91 /**
92 * The current declaration scope.
93 */
3ba65808
MK
94 private final DeclarationScope fRoot;
95 private DeclarationScope fScope;
866e5b51 96
58129ff7
MK
97 /**
98 * Data helpers needed for streaming
99 */
100
101 private boolean fHasBeenParsed = false;
102
866e5b51
FC
103 // ------------------------------------------------------------------------
104 // Constructor
105 // ------------------------------------------------------------------------
106
9ac2eb62 107 /**
ecb12461 108 * Constructor
be6df2d8
AM
109 *
110 * @param tree
111 * the tree (ANTLR generated) with the parsed TSDL data.
112 * @param trace
113 * the trace containing the places to put all the read metadata
9ac2eb62 114 */
866e5b51 115 public IOStructGen(CommonTree tree, CTFTrace trace) {
9226cfc5
MK
116 fTrace = trace;
117 fTree = tree;
8d90cd62 118 fRoot = trace.getScope();
3ba65808 119 fScope = fRoot;
866e5b51
FC
120 }
121
9ac2eb62
MK
122 /**
123 * Parse the tree and populate the trace defined in the constructor.
be6df2d8 124 *
9ac2eb62 125 * @throws ParseException
be6df2d8 126 * If there was a problem parsing the metadata
9ac2eb62 127 */
866e5b51 128 public void generate() throws ParseException {
9226cfc5 129 parseRoot(fTree);
866e5b51
FC
130 }
131
58129ff7
MK
132 /**
133 * Parse a partial tree and populate the trace defined in the constructor.
134 * Does not check for a "trace" block as there is only one in the trace and
135 * thus
136 *
137 * @throws ParseException
138 * If there was a problem parsing the metadata
139 */
140 public void generateFragment() throws ParseException {
9226cfc5 141 parseIncompleteRoot(fTree);
58129ff7
MK
142 }
143
866e5b51
FC
144 // ------------------------------------------------------------------------
145 // Operations
146 // ------------------------------------------------------------------------
147
58129ff7
MK
148 /**
149 * Sets a new tree to parse
150 *
151 * @param newTree
152 * the new tree to parse
153 */
154 public void setTree(CommonTree newTree) {
9226cfc5 155 fTree = newTree;
58129ff7
MK
156 }
157
866e5b51
FC
158 /**
159 * Parse the root node.
160 *
161 * @param root
162 * A ROOT node.
163 * @throws ParseException
164 */
165 private void parseRoot(CommonTree root) throws ParseException {
866e5b51
FC
166
167 List<CommonTree> children = root.getChildren();
866e5b51
FC
168
169 CommonTree traceNode = null;
52f81ef7 170 boolean hasStreams = false;
3de23137 171 List<CommonTree> events = new ArrayList<>();
3ba65808 172 resetScope();
466f6d95
MK
173 for (CommonTree child : children) {
174 final int type = child.getType();
175 switch (type) {
176 case CTFParser.DECLARATION:
52f81ef7 177 parseRootDeclaration(child);
466f6d95
MK
178 break;
179 case CTFParser.TRACE:
180 if (traceNode != null) {
181 throw new ParseException("Only one trace block is allowed"); //$NON-NLS-1$
866e5b51 182 }
466f6d95 183 traceNode = child;
52f81ef7 184 parseTrace(traceNode);
466f6d95
MK
185 break;
186 case CTFParser.STREAM:
52f81ef7
MK
187 parseStream(child);
188 hasStreams = true;
466f6d95
MK
189 break;
190 case CTFParser.EVENT:
191 events.add(child);
192 break;
193 case CTFParser.CLOCK:
52f81ef7 194 parseClock(child);
466f6d95
MK
195 break;
196 case CTFParser.ENV:
52f81ef7 197 parseEnvironment(child);
466f6d95
MK
198 break;
199 case CTFParser.CALLSITE:
52f81ef7 200 parseCallsite(child);
466f6d95
MK
201 break;
202 default:
4ed7d9c1 203 throw childTypeError(child);
866e5b51 204 }
466f6d95 205 }
466f6d95
MK
206 if (traceNode == null) {
207 throw new ParseException("Missing trace block"); //$NON-NLS-1$
208 }
52f81ef7
MK
209 parseEvents(events, hasStreams);
210 popScope();
211 fHasBeenParsed = true;
212 }
866e5b51 213
52f81ef7
MK
214 private void parseEvents(List<CommonTree> events, boolean hasStreams) throws ParseException {
215 if (!hasStreams && !events.isEmpty()) {
466f6d95
MK
216 /* Add an empty stream that will have a null id */
217 fTrace.addStream(new CTFStream(fTrace));
218 }
466f6d95
MK
219 for (CommonTree event : events) {
220 parseEvent(event);
866e5b51 221 }
58129ff7
MK
222 }
223
224 private void parseIncompleteRoot(CommonTree root) throws ParseException {
466f6d95 225 if (!fHasBeenParsed) {
58129ff7
MK
226 throw new ParseException("You need to run generate first"); //$NON-NLS-1$
227 }
52f81ef7 228 List<CommonTree> children = root.getChildren();
58129ff7 229 List<CommonTree> events = new ArrayList<>();
3ba65808 230 resetScope();
58129ff7
MK
231 for (CommonTree child : children) {
232 final int type = child.getType();
233 switch (type) {
234 case CTFParser.DECLARATION:
52f81ef7 235 parseRootDeclaration(child);
58129ff7
MK
236 break;
237 case CTFParser.TRACE:
238 throw new ParseException("Trace block defined here, please use generate and not generateFragment to parse this fragment"); //$NON-NLS-1$
239 case CTFParser.STREAM:
52f81ef7 240 parseStream(child);
58129ff7
MK
241 break;
242 case CTFParser.EVENT:
243 events.add(child);
244 break;
245 case CTFParser.CLOCK:
52f81ef7 246 parseClock(child);
58129ff7
MK
247 break;
248 case CTFParser.ENV:
52f81ef7 249 parseEnvironment(child);
58129ff7
MK
250 break;
251 case CTFParser.CALLSITE:
52f81ef7 252 parseCallsite(child);
58129ff7
MK
253 break;
254 default:
4ed7d9c1 255 throw childTypeError(child);
58129ff7
MK
256 }
257 }
52f81ef7 258 parseEvents(events, !Iterables.isEmpty(fTrace.getStreams()));
58129ff7 259 popScope();
866e5b51
FC
260 }
261
3ba65808
MK
262 private void resetScope() {
263 fScope = fRoot;
264 }
265
4c9d2941
MK
266 private void parseCallsite(CommonTree callsite) {
267
268 List<CommonTree> children = callsite.getChildren();
269 String name = null;
0594c61c
AM
270 String funcName = null;
271 long lineNumber = -1;
4c9d2941 272 long ip = -1;
0594c61c 273 String fileName = null;
4c9d2941
MK
274
275 for (CommonTree child : children) {
276 String left;
ecb12461 277 /* this is a regex to find the leading and trailing quotes */
4c9d2941 278 final String regex = "^\"|\"$"; //$NON-NLS-1$
2c053b6e
MK
279 /*
280 * this is to replace the previous quotes with nothing...
281 * effectively deleting them
282 */
62c21477 283 final String nullString = EMPTY_STRING;
4c9d2941 284 left = child.getChild(0).getChild(0).getChild(0).getText();
62c21477 285 if (left.equals(NAME)) {
4c9d2941 286 name = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString);
62c21477 287 } else if (left.equals(FUNC)) {
0594c61c 288 funcName = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString);
62c21477 289 } else if (left.equals(IP)) {
c30da2fa 290 ip = Long.decode(child.getChild(1).getChild(0).getChild(0).getText());
62c21477 291 } else if (left.equals(FILE)) {
0594c61c 292 fileName = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString);
62c21477 293 } else if (left.equals(LINE)) {
0594c61c 294 lineNumber = Long.parseLong(child.getChild(1).getChild(0).getChild(0).getText());
4c9d2941
MK
295 }
296 }
9226cfc5 297 fTrace.addCallsite(name, funcName, ip, fileName, lineNumber);
4c9d2941
MK
298 }
299
866e5b51
FC
300 private void parseEnvironment(CommonTree environment) {
301 List<CommonTree> children = environment.getChildren();
302 for (CommonTree child : children) {
303 String left;
304 String right;
305 left = child.getChild(0).getChild(0).getChild(0).getText();
306 right = child.getChild(1).getChild(0).getChild(0).getText();
9226cfc5 307 fTrace.addEnvironmentVar(left, right);
866e5b51
FC
308 }
309 }
310
466f6d95 311 private void parseClock(CommonTree clock) throws ParseException {
866e5b51
FC
312 List<CommonTree> children = clock.getChildren();
313 CTFClock ctfClock = new CTFClock();
314 for (CommonTree child : children) {
72dbc4ac 315 final String key = child.getChild(0).getChild(0).getChild(0).getText();
866e5b51
FC
316 final CommonTree value = (CommonTree) child.getChild(1).getChild(0).getChild(0);
317 final int type = value.getType();
d0b5ef0d 318 final String text = value.getText();
866e5b51
FC
319 switch (type) {
320 case CTFParser.INTEGER:
321 case CTFParser.DECIMAL_LITERAL:
284fdee8 322 /*
32ede2ec
MK
323 * Not a pretty hack, this is to make sure that there is no
324 * number overflow due to 63 bit integers. The offset should
325 * only really be an issue in the year 2262. the tracer in C/ASM
326 * can write an offset in an unsigned 64 bit long. In java, the
327 * last bit, being set to 1 will be read as a negative number,
328 * but since it is too big a positive it will throw an
329 * exception. this will happen in 2^63 ns from 1970. Therefore
330 * 293 years from 1970
284fdee8 331 */
866e5b51 332 Long numValue;
32ede2ec 333 try {
d0b5ef0d
MK
334 numValue = Long.parseLong(text);
335 } catch (NumberFormatException e) {
336 throw new ParseException("Number conversion issue with " + text, e); //$NON-NLS-1$
866e5b51
FC
337 }
338 ctfClock.addAttribute(key, numValue);
339 break;
340 default:
d0b5ef0d 341 ctfClock.addAttribute(key, text);
866e5b51
FC
342 }
343
344 }
0594c61c 345 String nameValue = ctfClock.getName();
9226cfc5 346 fTrace.addClock(nameValue, ctfClock);
866e5b51
FC
347 }
348
349 private void parseTrace(CommonTree traceNode) throws ParseException {
866e5b51
FC
350
351 List<CommonTree> children = traceNode.getChildren();
352 if (children == null) {
353 throw new ParseException("Trace block is empty"); //$NON-NLS-1$
354 }
355
8d90cd62 356 resetScope();
866e5b51
FC
357
358 for (CommonTree child : children) {
359 switch (child.getType()) {
360 case CTFParser.TYPEALIAS:
361 parseTypealias(child);
362 break;
363 case CTFParser.TYPEDEF:
364 parseTypedef(child);
365 break;
366 case CTFParser.CTF_EXPRESSION_TYPE:
367 case CTFParser.CTF_EXPRESSION_VAL:
368 parseTraceDeclaration(child);
369 break;
370 default:
4ed7d9c1 371 throw childTypeError(child);
866e5b51
FC
372 }
373 }
374
375 /*
376 * If trace byte order was not specified and not using packet based
377 * metadata
378 */
9226cfc5 379 if (fTrace.getByteOrder() == null) {
866e5b51
FC
380 throw new ParseException("Trace byte order not set"); //$NON-NLS-1$
381 }
866e5b51
FC
382 }
383
384 private void parseTraceDeclaration(CommonTree traceDecl)
385 throws ParseException {
866e5b51
FC
386
387 /* There should be a left and right */
866e5b51
FC
388
389 CommonTree leftNode = (CommonTree) traceDecl.getChild(0);
866e5b51 390 CommonTree rightNode = (CommonTree) traceDecl.getChild(1);
866e5b51
FC
391
392 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51 393
4311ac8b 394 if (!isAnyUnaryString(leftStrings.get(0))) {
2c053b6e 395 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
866e5b51
FC
396 }
397
398 String left = concatenateUnaryStrings(leftStrings);
399
fafc36a7 400 if (left.equals(MetadataStrings.MAJOR)) {
9226cfc5 401 if (fTrace.majorIsSet()) {
866e5b51
FC
402 throw new ParseException("major is already set"); //$NON-NLS-1$
403 }
404
9226cfc5 405 fTrace.setMajor(getMajorOrMinor(rightNode));
fafc36a7 406 } else if (left.equals(MetadataStrings.MINOR)) {
9226cfc5 407 if (fTrace.minorIsSet()) {
866e5b51
FC
408 throw new ParseException("minor is already set"); //$NON-NLS-1$
409 }
410
9226cfc5 411 fTrace.setMinor(getMajorOrMinor(rightNode));
fafc36a7 412 } else if (left.equals(MetadataStrings.UUID_STRING)) {
866e5b51
FC
413 UUID uuid = getUUID(rightNode);
414
415 /*
416 * If uuid was already set by a metadata packet, compare it to see
417 * if it matches
418 */
9226cfc5
MK
419 if (fTrace.uuidIsSet()) {
420 if (fTrace.getUUID().compareTo(uuid) != 0) {
866e5b51 421 throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
9226cfc5 422 + fTrace.getUUID() + " but metadata says " + uuid); //$NON-NLS-1$
866e5b51
FC
423 }
424 } else {
9226cfc5 425 fTrace.setUUID(uuid);
866e5b51
FC
426 }
427
fafc36a7 428 } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
866e5b51
FC
429 ByteOrder byteOrder = getByteOrder(rightNode);
430
431 /*
432 * If byte order was already set by a metadata packet, compare it to
433 * see if it matches
434 */
9226cfc5
MK
435 if (fTrace.getByteOrder() != null) {
436 if (fTrace.getByteOrder() != byteOrder) {
866e5b51
FC
437 throw new ParseException(
438 "Endianness mismatch. Magic number says " //$NON-NLS-1$
9226cfc5 439 + fTrace.getByteOrder()
866e5b51
FC
440 + " but metadata says " + byteOrder); //$NON-NLS-1$
441 }
442 } else {
9226cfc5 443 fTrace.setByteOrder(byteOrder);
72dbc4ac 444
8d90cd62
MK
445 final DeclarationScope currentScope = getCurrentScope();
446 for (String type : currentScope.getTypeNames()) {
447 IDeclaration d = currentScope.lookupType(type);
72dbc4ac 448 if (d instanceof IntegerDeclaration) {
8d90cd62 449 addByteOrder(byteOrder, currentScope, type, (IntegerDeclaration) d);
72dbc4ac 450 } else if (d instanceof StructDeclaration) {
8d90cd62 451 setAlign(currentScope, (StructDeclaration) d, byteOrder);
72dbc4ac
MK
452 }
453 }
866e5b51 454 }
fafc36a7 455 } else if (left.equals(MetadataStrings.PACKET_HEADER)) {
9226cfc5 456 if (fTrace.packetHeaderIsSet()) {
866e5b51
FC
457 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
458 }
459
460 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
461
462 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
2c053b6e 463 throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
866e5b51
FC
464 }
465
94c255ef 466 IDeclaration packetHeaderDecl = parseTypeSpecifierList(typeSpecifier);
866e5b51
FC
467
468 if (!(packetHeaderDecl instanceof StructDeclaration)) {
469 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
470 }
471
9226cfc5 472 fTrace.setPacketHeader((StructDeclaration) packetHeaderDecl);
866e5b51 473 } else {
4311ac8b 474 Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownTraceAttributeWarning + " " + left); //$NON-NLS-1$
866e5b51
FC
475 }
476 }
477
72dbc4ac
MK
478 private static void addByteOrder(ByteOrder byteOrder,
479 final DeclarationScope parentScope, String name,
480 IntegerDeclaration decl) throws ParseException {
481
a4fa4e36 482 if (decl.getByteOrder() != byteOrder) {
72dbc4ac 483 IntegerDeclaration newI;
a4fa4e36 484 newI = IntegerDeclaration.createDeclaration(decl.getLength(), decl.isSigned(),
72dbc4ac
MK
485 decl.getBase(), byteOrder, decl.getEncoding(),
486 decl.getClock(), decl.getAlignment());
487 parentScope.replaceType(name, newI);
488 }
489 }
490
491 private void setAlign(DeclarationScope parentScope, StructDeclaration sd,
492 ByteOrder byteOrder) throws ParseException {
493
494 for (String s : sd.getFieldsList()) {
2db699c2 495 IDeclaration d = sd.getField(s);
72dbc4ac
MK
496
497 if (d instanceof StructDeclaration) {
498 setAlign(parentScope, (StructDeclaration) d, byteOrder);
499
500 } else if (d instanceof VariantDeclaration) {
501 setAlign(parentScope, (VariantDeclaration) d, byteOrder);
72dbc4ac
MK
502 } else if (d instanceof IntegerDeclaration) {
503 IntegerDeclaration decl = (IntegerDeclaration) d;
a4fa4e36 504 if (decl.getByteOrder() != byteOrder) {
72dbc4ac 505 IntegerDeclaration newI;
a4fa4e36 506 newI = IntegerDeclaration.createDeclaration(decl.getLength(),
72dbc4ac
MK
507 decl.isSigned(), decl.getBase(), byteOrder,
508 decl.getEncoding(), decl.getClock(),
509 decl.getAlignment());
510 sd.getFields().put(s, newI);
511 }
512 }
513 }
514 }
515
516 private void setAlign(DeclarationScope parentScope, VariantDeclaration vd,
517 ByteOrder byteOrder) throws ParseException {
518
519 for (String s : vd.getFields().keySet()) {
520 IDeclaration d = vd.getFields().get(s);
521
522 if (d instanceof StructDeclaration) {
523 setAlign(parentScope, (StructDeclaration) d, byteOrder);
524
525 } else if (d instanceof IntegerDeclaration) {
526 IntegerDeclaration decl = (IntegerDeclaration) d;
527 IntegerDeclaration newI;
a4fa4e36 528 newI = IntegerDeclaration.createDeclaration(decl.getLength(),
72dbc4ac
MK
529 decl.isSigned(), decl.getBase(), byteOrder,
530 decl.getEncoding(), decl.getClock(),
531 decl.getAlignment());
532 vd.getFields().put(s, newI);
533 }
534 }
535 }
536
866e5b51 537 private void parseStream(CommonTree streamNode) throws ParseException {
866e5b51 538
d84419e1 539 CTFStream stream = new CTFStream(fTrace);
866e5b51
FC
540
541 List<CommonTree> children = streamNode.getChildren();
542 if (children == null) {
543 throw new ParseException("Empty stream block"); //$NON-NLS-1$
544 }
545
3ba65808 546 pushScope(MetadataStrings.STREAM);
866e5b51
FC
547
548 for (CommonTree child : children) {
549 switch (child.getType()) {
550 case CTFParser.TYPEALIAS:
551 parseTypealias(child);
552 break;
553 case CTFParser.TYPEDEF:
554 parseTypedef(child);
555 break;
556 case CTFParser.CTF_EXPRESSION_TYPE:
557 case CTFParser.CTF_EXPRESSION_VAL:
558 parseStreamDeclaration(child, stream);
559 break;
560 default:
4ed7d9c1 561 throw childTypeError(child);
866e5b51
FC
562 }
563 }
564
466f6d95
MK
565 if (stream.isIdSet() &&
566 (!fTrace.packetHeaderIsSet() || !fTrace.getPacketHeader().hasField(MetadataStrings.STREAM_ID))) {
567 throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
866e5b51
FC
568 }
569
9226cfc5 570 fTrace.addStream(stream);
866e5b51
FC
571
572 popScope();
573 }
574
d84419e1 575 private void parseStreamDeclaration(CommonTree streamDecl, CTFStream stream)
866e5b51 576 throws ParseException {
866e5b51
FC
577
578 /* There should be a left and right */
866e5b51
FC
579
580 CommonTree leftNode = (CommonTree) streamDecl.getChild(0);
866e5b51 581 CommonTree rightNode = (CommonTree) streamDecl.getChild(1);
866e5b51
FC
582
583 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51 584
4311ac8b 585 if (!isAnyUnaryString(leftStrings.get(0))) {
2c053b6e 586 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
866e5b51
FC
587 }
588
589 String left = concatenateUnaryStrings(leftStrings);
590
fafc36a7 591 if (left.equals(MetadataStrings.ID)) {
9ac2eb62 592 if (stream.isIdSet()) {
866e5b51
FC
593 throw new ParseException("stream id already defined"); //$NON-NLS-1$
594 }
595
596 long streamID = getStreamID(rightNode);
597
598 stream.setId(streamID);
fafc36a7 599 } else if (left.equals(MetadataStrings.EVENT_HEADER)) {
9ac2eb62 600 if (stream.isEventHeaderSet()) {
866e5b51
FC
601 throw new ParseException("event.header already defined"); //$NON-NLS-1$
602 }
603
604 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
605
606 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
2c053b6e 607 throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$
866e5b51
FC
608 }
609
94c255ef 610 IDeclaration eventHeaderDecl = parseTypeSpecifierList(typeSpecifier);
8d90cd62
MK
611 DeclarationScope scope = getCurrentScope();
612 DeclarationScope eventHeaderScope = scope.lookupChildRecursive(MetadataStrings.STRUCT);
613 if (eventHeaderScope == null) {
614 throw new ParseException("event.header scope not found"); //$NON-NLS-1$
615 }
616 pushScope(MetadataStrings.EVENT);
617 getCurrentScope().addChild(eventHeaderScope);
618 eventHeaderScope.setName(CTFStrings.HEADER);
619 popScope();
6c7592e1
MK
620 if (eventHeaderDecl instanceof StructDeclaration) {
621 stream.setEventHeader((StructDeclaration) eventHeaderDecl);
622 } else if (eventHeaderDecl instanceof IEventHeaderDeclaration) {
623 stream.setEventHeader((IEventHeaderDeclaration) eventHeaderDecl);
624 } else {
866e5b51
FC
625 throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
626 }
627
fafc36a7 628 } else if (left.equals(MetadataStrings.EVENT_CONTEXT)) {
9ac2eb62 629 if (stream.isEventContextSet()) {
866e5b51
FC
630 throw new ParseException("event.context already defined"); //$NON-NLS-1$
631 }
632
633 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
634
635 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
2c053b6e 636 throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$
866e5b51
FC
637 }
638
94c255ef 639 IDeclaration eventContextDecl = parseTypeSpecifierList(typeSpecifier);
866e5b51
FC
640
641 if (!(eventContextDecl instanceof StructDeclaration)) {
642 throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
643 }
644
645 stream.setEventContext((StructDeclaration) eventContextDecl);
fafc36a7 646 } else if (left.equals(MetadataStrings.PACKET_CONTEXT)) {
9ac2eb62 647 if (stream.isPacketContextSet()) {
866e5b51
FC
648 throw new ParseException("packet.context already defined"); //$NON-NLS-1$
649 }
650
651 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
652
653 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
2c053b6e 654 throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$
866e5b51
FC
655 }
656
94c255ef 657 IDeclaration packetContextDecl = parseTypeSpecifierList(typeSpecifier);
866e5b51
FC
658
659 if (!(packetContextDecl instanceof StructDeclaration)) {
660 throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
661 }
662
663 stream.setPacketContext((StructDeclaration) packetContextDecl);
664 } else {
4311ac8b 665 Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownStreamAttributeWarning + " " + left); //$NON-NLS-1$
866e5b51
FC
666 }
667 }
668
669 private void parseEvent(CommonTree eventNode) throws ParseException {
866e5b51
FC
670
671 List<CommonTree> children = eventNode.getChildren();
672 if (children == null) {
673 throw new ParseException("Empty event block"); //$NON-NLS-1$
674 }
675
676 EventDeclaration event = new EventDeclaration();
677
3ba65808 678 pushScope(MetadataStrings.EVENT);
866e5b51
FC
679
680 for (CommonTree child : children) {
681 switch (child.getType()) {
682 case CTFParser.TYPEALIAS:
683 parseTypealias(child);
684 break;
685 case CTFParser.TYPEDEF:
686 parseTypedef(child);
687 break;
688 case CTFParser.CTF_EXPRESSION_TYPE:
689 case CTFParser.CTF_EXPRESSION_VAL:
690 parseEventDeclaration(child, event);
691 break;
692 default:
4ed7d9c1 693 throw childTypeError(child);
866e5b51
FC
694 }
695 }
696
697 if (!event.nameIsSet()) {
698 throw new ParseException("Event name not set"); //$NON-NLS-1$
699 }
700
701 /*
702 * If the event did not specify a stream, then the trace must be single
703 * stream
704 */
705 if (!event.streamIsSet()) {
9226cfc5 706 if (fTrace.nbStreams() > 1) {
2c053b6e 707 throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$
866e5b51
FC
708 }
709
710 /*
711 * If the event did not specify a stream, the only existing stream
712 * must not have an id. Note: That behavior could be changed, it
713 * could be possible to just get the only existing stream, whatever
714 * is its id.
715 */
d84419e1 716 CTFStream stream = fTrace.getStream(null);
866e5b51
FC
717
718 if (stream != null) {
719 event.setStream(stream);
720 } else {
2c053b6e 721 throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
866e5b51
FC
722 }
723 }
724
725 /*
726 * Add the event to the stream.
727 */
728 event.getStream().addEvent(event);
729
730 popScope();
731 }
732
733 private void parseEventDeclaration(CommonTree eventDecl,
734 EventDeclaration event) throws ParseException {
866e5b51
FC
735
736 /* There should be a left and right */
866e5b51
FC
737
738 CommonTree leftNode = (CommonTree) eventDecl.getChild(0);
866e5b51 739 CommonTree rightNode = (CommonTree) eventDecl.getChild(1);
866e5b51
FC
740
741 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51 742
4311ac8b 743 if (!isAnyUnaryString(leftStrings.get(0))) {
2c053b6e 744 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
866e5b51
FC
745 }
746
747 String left = concatenateUnaryStrings(leftStrings);
748
fafc36a7 749 if (left.equals(MetadataStrings.NAME2)) {
866e5b51
FC
750 if (event.nameIsSet()) {
751 throw new ParseException("name already defined"); //$NON-NLS-1$
752 }
753
754 String name = getEventName(rightNode);
755
756 event.setName(name);
fafc36a7 757 } else if (left.equals(MetadataStrings.ID)) {
866e5b51
FC
758 if (event.idIsSet()) {
759 throw new ParseException("id already defined"); //$NON-NLS-1$
760 }
761
762 long id = getEventID(rightNode);
6c7592e1
MK
763 if (id > Integer.MAX_VALUE) {
764 throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id); //$NON-NLS-1$
765 }
766 if (id < 0) {
767 throw new ParseException("negative id, unsupported. id : " + id); //$NON-NLS-1$
768 }
769 event.setId((int) id);
fafc36a7 770 } else if (left.equals(MetadataStrings.STREAM_ID)) {
866e5b51
FC
771 if (event.streamIsSet()) {
772 throw new ParseException("stream id already defined"); //$NON-NLS-1$
773 }
774
775 long streamId = getStreamID(rightNode);
776
d84419e1 777 CTFStream stream = fTrace.getStream(streamId);
866e5b51
FC
778
779 if (stream == null) {
780 throw new ParseException("Stream " + streamId + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
781 }
782
783 event.setStream(stream);
fafc36a7 784 } else if (left.equals(MetadataStrings.CONTEXT)) {
866e5b51
FC
785 if (event.contextIsSet()) {
786 throw new ParseException("context already defined"); //$NON-NLS-1$
787 }
788
789 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
790
791 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
792 throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
793 }
794
94c255ef 795 IDeclaration contextDecl = parseTypeSpecifierList(typeSpecifier);
866e5b51
FC
796
797 if (!(contextDecl instanceof StructDeclaration)) {
798 throw new ParseException("context expects a struct"); //$NON-NLS-1$
799 }
800
801 event.setContext((StructDeclaration) contextDecl);
fafc36a7 802 } else if (left.equals(MetadataStrings.FIELDS_STRING)) {
866e5b51
FC
803 if (event.fieldsIsSet()) {
804 throw new ParseException("fields already defined"); //$NON-NLS-1$
805 }
806
807 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
808
809 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
810 throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
811 }
812
13be1a8f 813 IDeclaration fieldsDecl;
94c255ef 814 fieldsDecl = parseTypeSpecifierList(typeSpecifier);
866e5b51
FC
815
816 if (!(fieldsDecl instanceof StructDeclaration)) {
817 throw new ParseException("fields expects a struct"); //$NON-NLS-1$
818 }
819 /*
32ede2ec
MK
820 * The underscores in the event names. These underscores were added
821 * by the LTTng tracer.
866e5b51 822 */
91847dfc 823 final StructDeclaration fields = (StructDeclaration) fieldsDecl;
866e5b51 824 event.setFields(fields);
fafc36a7 825 } else if (left.equals(MetadataStrings.LOGLEVEL2)) {
32ede2ec 826 long logLevel = parseUnaryInteger((CommonTree) rightNode.getChild(0));
53047a66 827 event.setLogLevel(logLevel);
866e5b51 828 } else {
8e964be1
MK
829 /* Custom event attribute, we'll add it to the attributes map */
830 String right = parseUnaryString((CommonTree) rightNode.getChild(0));
831 event.setCustomAttribute(left, right);
866e5b51
FC
832 }
833 }
834
835 /**
836 * Parses a declaration at the root level.
837 *
838 * @param declaration
839 * The declaration subtree.
840 * @throws ParseException
841 */
842 private void parseRootDeclaration(CommonTree declaration)
843 throws ParseException {
866e5b51
FC
844
845 List<CommonTree> children = declaration.getChildren();
866e5b51
FC
846
847 for (CommonTree child : children) {
848 switch (child.getType()) {
849 case CTFParser.TYPEDEF:
850 parseTypedef(child);
851 break;
852 case CTFParser.TYPEALIAS:
853 parseTypealias(child);
854 break;
855 case CTFParser.TYPE_SPECIFIER_LIST:
94c255ef 856 parseTypeSpecifierList(child);
866e5b51
FC
857 break;
858 default:
4ed7d9c1 859 throw childTypeError(child);
866e5b51
FC
860 }
861 }
862 }
863
864 /**
865 * Parses a typealias node. It parses the target, the alias, and registers
866 * the type in the current scope.
867 *
868 * @param typealias
869 * A TYPEALIAS node.
870 * @throws ParseException
871 */
872 private void parseTypealias(CommonTree typealias) throws ParseException {
866e5b51
FC
873
874 List<CommonTree> children = typealias.getChildren();
866e5b51
FC
875
876 CommonTree target = null;
877 CommonTree alias = null;
878
879 for (CommonTree child : children) {
880 switch (child.getType()) {
881 case CTFParser.TYPEALIAS_TARGET:
866e5b51
FC
882 target = child;
883 break;
884 case CTFParser.TYPEALIAS_ALIAS:
866e5b51
FC
885 alias = child;
886 break;
887 default:
4ed7d9c1 888 throw childTypeError(child);
866e5b51
FC
889 }
890 }
891
866e5b51
FC
892 IDeclaration targetDeclaration = parseTypealiasTarget(target);
893
0594c61c
AM
894 if ((targetDeclaration instanceof VariantDeclaration)
895 && ((VariantDeclaration) targetDeclaration).isTagged()) {
896 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
866e5b51
FC
897 }
898
899 String aliasString = parseTypealiasAlias(alias);
900
901 getCurrentScope().registerType(aliasString, targetDeclaration);
902 }
903
904 /**
905 * Parses the target part of a typealias and gets the corresponding
906 * declaration.
907 *
908 * @param target
909 * A TYPEALIAS_TARGET node.
910 * @return The corresponding declaration.
911 * @throws ParseException
912 */
913 private IDeclaration parseTypealiasTarget(CommonTree target)
914 throws ParseException {
866e5b51
FC
915
916 List<CommonTree> children = target.getChildren();
866e5b51
FC
917
918 CommonTree typeSpecifierList = null;
919 CommonTree typeDeclaratorList = null;
920 CommonTree typeDeclarator = null;
921 StringBuilder identifierSB = new StringBuilder();
922
923 for (CommonTree child : children) {
924 switch (child.getType()) {
925 case CTFParser.TYPE_SPECIFIER_LIST:
866e5b51
FC
926 typeSpecifierList = child;
927 break;
928 case CTFParser.TYPE_DECLARATOR_LIST:
866e5b51
FC
929 typeDeclaratorList = child;
930 break;
931 default:
4ed7d9c1 932 throw childTypeError(child);
866e5b51
FC
933 }
934 }
935
866e5b51
FC
936 if (typeDeclaratorList != null) {
937 /*
938 * Only allow one declarator
939 *
940 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
941 * otherwise the new type puint8_t would maps to two different
942 * types.
943 */
944 if (typeDeclaratorList.getChildCount() != 1) {
2c053b6e 945 throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
866e5b51
FC
946 }
947
948 typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
949 }
950
951 /* Parse the target type and get the declaration */
952 IDeclaration targetDeclaration = parseTypeDeclarator(typeDeclarator,
953 typeSpecifierList, identifierSB);
954
955 /*
956 * We don't allow identifier in the target
957 *
958 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
959 * permitted
960 */
961 if (identifierSB.length() > 0) {
962 throw new ParseException("Identifier (" + identifierSB.toString() //$NON-NLS-1$
963 + ") not expected in the typealias target"); //$NON-NLS-1$
964 }
965
966 return targetDeclaration;
967 }
968
969 /**
970 * Parses the alias part of a typealias. It parses the underlying specifier
971 * list and declarator and creates the string representation that will be
972 * used to register the type.
973 *
974 * @param alias
975 * A TYPEALIAS_ALIAS node.
976 * @return The string representation of the alias.
977 * @throws ParseException
978 */
979 private static String parseTypealiasAlias(CommonTree alias)
980 throws ParseException {
866e5b51
FC
981
982 List<CommonTree> children = alias.getChildren();
866e5b51
FC
983
984 CommonTree typeSpecifierList = null;
985 CommonTree typeDeclaratorList = null;
986 CommonTree typeDeclarator = null;
3de23137 987 List<CommonTree> pointers = new LinkedList<>();
866e5b51
FC
988
989 for (CommonTree child : children) {
990 switch (child.getType()) {
991 case CTFParser.TYPE_SPECIFIER_LIST:
866e5b51
FC
992 typeSpecifierList = child;
993 break;
994 case CTFParser.TYPE_DECLARATOR_LIST:
866e5b51
FC
995 typeDeclaratorList = child;
996 break;
997 default:
4ed7d9c1 998 throw childTypeError(child);
866e5b51
FC
999 }
1000 }
1001
1002 /* If there is a type declarator list, extract the pointers */
1003 if (typeDeclaratorList != null) {
1004 /*
1005 * Only allow one declarator
1006 *
1007 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
1008 */
1009 if (typeDeclaratorList.getChildCount() != 1) {
2c053b6e 1010 throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
866e5b51
FC
1011 }
1012
1013 typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
1014
72dbc4ac 1015 List<CommonTree> typeDeclaratorChildren = typeDeclarator.getChildren();
866e5b51
FC
1016
1017 for (CommonTree child : typeDeclaratorChildren) {
1018 switch (child.getType()) {
1019 case CTFParser.POINTER:
1020 pointers.add(child);
1021 break;
1022 case CTFParser.IDENTIFIER:
1023 throw new ParseException("Identifier (" + child.getText() //$NON-NLS-1$
1024 + ") not expected in the typealias target"); //$NON-NLS-1$
866e5b51 1025 default:
4ed7d9c1 1026 throw childTypeError(child);
866e5b51
FC
1027 }
1028 }
1029 }
1030
1031 return createTypeDeclarationString(typeSpecifierList, pointers);
1032 }
1033
1034 /**
1035 * Parses a typedef node. This creates and registers a new declaration for
1036 * each declarator found in the typedef.
1037 *
1038 * @param typedef
1039 * A TYPEDEF node.
1040 * @throws ParseException
1041 * If there is an error creating the declaration.
1042 */
1043 private void parseTypedef(CommonTree typedef) throws ParseException {
866e5b51 1044
72dbc4ac 1045 CommonTree typeDeclaratorListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
866e5b51 1046
72dbc4ac 1047 CommonTree typeSpecifierListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
866e5b51 1048
72dbc4ac 1049 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
866e5b51
FC
1050
1051 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
1052 StringBuilder identifierSB = new StringBuilder();
1053
0594c61c 1054 IDeclaration typeDeclaration = parseTypeDeclarator(
866e5b51
FC
1055 typeDeclaratorNode, typeSpecifierListNode, identifierSB);
1056
0594c61c 1057 if ((typeDeclaration instanceof VariantDeclaration)
2c053b6e
MK
1058 && ((VariantDeclaration) typeDeclaration).isTagged()) {
1059 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
866e5b51
FC
1060 }
1061
1062 getCurrentScope().registerType(identifierSB.toString(),
0594c61c 1063 typeDeclaration);
866e5b51
FC
1064 }
1065 }
1066
1067 /**
1068 * Parses a pair type declarator / type specifier list and returns the
1069 * corresponding declaration. If it is present, it also writes the
1070 * identifier of the declarator in the given {@link StringBuilder}.
1071 *
1072 * @param typeDeclarator
1073 * A TYPE_DECLARATOR node.
1074 * @param typeSpecifierList
1075 * A TYPE_SPECIFIER_LIST node.
1076 * @param identifierSB
1077 * A StringBuilder that will receive the identifier found in the
1078 * declarator.
1079 * @return The corresponding declaration.
1080 * @throws ParseException
1081 * If there is an error finding or creating the declaration.
1082 */
1083 private IDeclaration parseTypeDeclarator(CommonTree typeDeclarator,
1084 CommonTree typeSpecifierList, StringBuilder identifierSB)
3ba65808 1085 throws ParseException {
866e5b51
FC
1086
1087 IDeclaration declaration = null;
1088 List<CommonTree> children = null;
3de23137
AM
1089 List<CommonTree> pointers = new LinkedList<>();
1090 List<CommonTree> lengths = new LinkedList<>();
866e5b51
FC
1091 CommonTree identifier = null;
1092
1093 /* Separate the tokens by type */
1094 if (typeDeclarator != null) {
1095 children = typeDeclarator.getChildren();
866e5b51
FC
1096 for (CommonTree child : children) {
1097
1098 switch (child.getType()) {
1099 case CTFParser.POINTER:
1100 pointers.add(child);
1101 break;
1102 case CTFParser.IDENTIFIER:
866e5b51
FC
1103 identifier = child;
1104 break;
1105 case CTFParser.LENGTH:
1106 lengths.add(child);
1107 break;
1108 default:
4ed7d9c1 1109 throw childTypeError(child);
866e5b51
FC
1110 }
1111 }
1112
1113 }
1114
1115 /*
1116 * Parse the type specifier list, which is the "base" type. For example,
1117 * it would be int in int a[3][len].
1118 */
94c255ef 1119 declaration = parseTypeSpecifierList(typeSpecifierList, pointers, identifier);
866e5b51
FC
1120
1121 /*
1122 * Each length subscript means that we must create a nested array or
1123 * sequence. For example, int a[3][len] means that we have an array of 3
1124 * (sequences of length 'len' of (int)).
1125 */
62c21477 1126 if (!lengths.isEmpty()) {
866e5b51
FC
1127 /* We begin at the end */
1128 Collections.reverse(lengths);
1129
1130 for (CommonTree length : lengths) {
1131 /*
1132 * By looking at the first expression, we can determine whether
1133 * it is an array or a sequence.
1134 */
1135 List<CommonTree> lengthChildren = length.getChildren();
866e5b51
FC
1136
1137 CommonTree first = lengthChildren.get(0);
1138 if (isUnaryInteger(first)) {
1139 /* Array */
1140 int arrayLength = (int) parseUnaryInteger(first);
1141
1142 if (arrayLength < 1) {
1143 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1144 }
1145
1146 /* Create the array declaration. */
1147 declaration = new ArrayDeclaration(arrayLength, declaration);
4311ac8b 1148 } else if (isAnyUnaryString(first)) {
866e5b51
FC
1149 /* Sequence */
1150 String lengthName = concatenateUnaryStrings(lengthChildren);
1151
8d90cd62
MK
1152 /* check that lengthName was declared */
1153 if (isSignedIntegerField(lengthName)) {
1154 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1155 }
1156 /* Create the sequence declaration. */
1157 declaration = new SequenceDeclaration(lengthName,
1158 declaration);
1159 } else if (isTrace(first)) {
1160 /* Sequence */
1161 String lengthName = parseTraceScope(lengthChildren);
1162
1163 /* check that lengthName was declared */
1164 if (isSignedIntegerField(lengthName)) {
1165 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1166 }
1167 /* Create the sequence declaration. */
1168 declaration = new SequenceDeclaration(lengthName,
1169 declaration);
1170
1171 } else if (isStream(first)) {
1172 /* Sequence */
1173 String lengthName = parseStreamScope(lengthChildren);
1174
1175 /* check that lengthName was declared */
1176 if (isSignedIntegerField(lengthName)) {
1177 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1178 }
1179 /* Create the sequence declaration. */
1180 declaration = new SequenceDeclaration(lengthName,
1181 declaration);
1182 } else if (isEvent(first)) {
1183 /* Sequence */
1184 String lengthName = parseEventScope(lengthChildren);
1185
2c053b6e
MK
1186 /* check that lengthName was declared */
1187 if (isSignedIntegerField(lengthName)) {
1188 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1189 }
866e5b51
FC
1190 /* Create the sequence declaration. */
1191 declaration = new SequenceDeclaration(lengthName,
1192 declaration);
1193 } else {
4ed7d9c1 1194 throw childTypeError(first);
866e5b51
FC
1195 }
1196 }
1197 }
1198
1199 if (identifier != null) {
8d90cd62
MK
1200 final String text = identifier.getText();
1201 identifierSB.append(text);
1202 registerType(declaration, text);
866e5b51
FC
1203 }
1204
1205 return declaration;
1206 }
1207
8d90cd62
MK
1208 private void registerType(IDeclaration declaration, String identifier) throws ParseException {
1209 final DeclarationScope currentScope = getCurrentScope();
94c255ef 1210 if (declaration instanceof EnumDeclaration) {
8d90cd62
MK
1211 currentScope.registerEnum(identifier, (EnumDeclaration) declaration);
1212 } else if (declaration instanceof VariantDeclaration) {
1213 currentScope.registerVariant(identifier, (VariantDeclaration) declaration);
1214 }
1215 }
1216
1217 private static String parseStreamScope(List<CommonTree> lengthChildren) throws ParseException {
1218 List<CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size());
1219
1220 CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
1221 String lengthName = null;
1222 if (isUnaryString(nextElem)) {
1223 lengthName = parseUnaryString(nextElem);
1224 }
1225
1226 int type = nextElem.getType();
1227 if ((CTFParser.tokenNames[CTFParser.EVENT]).equals(lengthName)) {
1228 type = CTFParser.EVENT;
1229 }
1230 switch (type) {
1231 case CTFParser.IDENTIFIER:
1232 lengthName = concatenateUnaryStrings(sublist);
1233 break;
1234 case CTFParser.EVENT:
1235 lengthName = parseEventScope(sublist);
1236 break;
1237 default:
1238 if (lengthName == null) {
1239 throw new ParseException("Unsupported scope stream." + nextElem); //$NON-NLS-1$
1240 }
1241 }
1242 return MetadataStrings.STREAM + '.' + lengthName;
1243 }
1244
1245 private static String parseEventScope(List<CommonTree> lengthChildren) throws ParseException {
1246 CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
1247 String lengthName;
1248 switch (nextElem.getType()) {
1249 case CTFParser.UNARY_EXPRESSION_STRING:
1250 case CTFParser.IDENTIFIER:
1251 List<CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size());
1252 lengthName = MetadataStrings.EVENT + '.' + concatenateUnaryStrings(sublist);
1253 break;
1254 default:
1255 throw new ParseException("Unsupported scope event." + nextElem); //$NON-NLS-1$
1256 }
1257 return lengthName;
1258 }
1259
1260 private static String parseTraceScope(List<CommonTree> lengthChildren) throws ParseException {
1261 CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
1262 String lengthName;
1263 switch (nextElem.getType()) {
1264 case CTFParser.IDENTIFIER:
1265 lengthName = concatenateUnaryStrings(lengthChildren.subList(1, lengthChildren.size()));
1266 break;
1267 case CTFParser.STREAM:
1268 return parseStreamScope(lengthChildren.subList(1, lengthChildren.size()));
1269 default:
1270 throw new ParseException("Unsupported scope trace." + nextElem); //$NON-NLS-1$
1271 }
1272 return lengthName;
1273 }
1274
1275 private static boolean isEvent(CommonTree first) {
1276 return first.getType() == CTFParser.EVENT;
1277 }
1278
1279 private static boolean isStream(CommonTree first) {
1280 return first.getType() == CTFParser.STREAM;
1281 }
1282
1283 private static boolean isTrace(CommonTree first) {
1284 return first.getType() == CTFParser.TRACE;
1285 }
1286
2c053b6e
MK
1287 private boolean isSignedIntegerField(String lengthName) throws ParseException {
1288 IDeclaration decl = getCurrentScope().lookupIdentifierRecursive(lengthName);
1289 if (decl instanceof IntegerDeclaration) {
1290 return ((IntegerDeclaration) decl).isSigned();
1291 }
1292 throw new ParseException("Is not an integer: " + lengthName); //$NON-NLS-1$
1293
1294 }
1295
94c255ef
MK
1296 private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList) throws ParseException {
1297 return parseTypeSpecifierList(typeSpecifierList, null, null);
1298 }
1299
866e5b51
FC
1300 /**
1301 * Parses a type specifier list and returns the corresponding declaration.
1302 *
1303 * @param typeSpecifierList
1304 * A TYPE_SPECIFIER_LIST node.
1305 * @param pointerList
1306 * A list of POINTER nodes that apply to the specified type.
1307 * @return The corresponding declaration.
1308 * @throws ParseException
1309 * If the type has not been defined or if there is an error
1310 * creating the declaration.
1311 */
1312 private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList,
94c255ef 1313 List<CommonTree> pointerList, CommonTree identifier) throws ParseException {
866e5b51
FC
1314 IDeclaration declaration = null;
1315
1316 /*
1317 * By looking at the first element of the type specifier list, we can
1318 * determine which type it belongs to.
1319 */
1320 CommonTree firstChild = (CommonTree) typeSpecifierList.getChild(0);
866e5b51
FC
1321
1322 switch (firstChild.getType()) {
1323 case CTFParser.FLOATING_POINT:
53047a66 1324 declaration = parseFloat(firstChild);
866e5b51
FC
1325 break;
1326 case CTFParser.INTEGER:
1327 declaration = parseInteger(firstChild);
1328 break;
1329 case CTFParser.STRING:
1330 declaration = parseString(firstChild);
1331 break;
1332 case CTFParser.STRUCT:
94c255ef 1333 declaration = parseStruct(firstChild, identifier);
6c7592e1
MK
1334 StructDeclaration structDeclaration = (StructDeclaration) declaration;
1335 IDeclaration idEnumDecl = structDeclaration.getFields().get("id"); //$NON-NLS-1$
66aa25f0
MK
1336 if (idEnumDecl instanceof EnumDeclaration) {
1337 EnumDeclaration enumDeclaration = (EnumDeclaration) idEnumDecl;
1338 ByteOrder bo = enumDeclaration.getContainerType().getByteOrder();
1339 if (EventHeaderCompactDeclaration.getEventHeader(bo).isCompactEventHeader(structDeclaration)) {
1340 declaration = EventHeaderCompactDeclaration.getEventHeader(bo);
1341 } else if (EventHeaderLargeDeclaration.getEventHeader(bo).isLargeEventHeader(structDeclaration)) {
1342 declaration = EventHeaderLargeDeclaration.getEventHeader(bo);
1343 }
6c7592e1 1344 }
866e5b51
FC
1345 break;
1346 case CTFParser.VARIANT:
1347 declaration = parseVariant(firstChild);
1348 break;
1349 case CTFParser.ENUM:
1350 declaration = parseEnum(firstChild);
1351 break;
1352 case CTFParser.IDENTIFIER:
1353 case CTFParser.FLOATTOK:
1354 case CTFParser.INTTOK:
1355 case CTFParser.LONGTOK:
1356 case CTFParser.SHORTTOK:
1357 case CTFParser.SIGNEDTOK:
1358 case CTFParser.UNSIGNEDTOK:
1359 case CTFParser.CHARTOK:
1360 case CTFParser.DOUBLETOK:
1361 case CTFParser.VOIDTOK:
1362 case CTFParser.BOOLTOK:
1363 case CTFParser.COMPLEXTOK:
1364 case CTFParser.IMAGINARYTOK:
1365 declaration = parseTypeDeclaration(typeSpecifierList, pointerList);
1366 break;
1367 default:
4ed7d9c1 1368 throw childTypeError(firstChild);
866e5b51
FC
1369 }
1370
866e5b51
FC
1371 return declaration;
1372 }
1373
32ede2ec
MK
1374 private IDeclaration parseFloat(CommonTree floatingPoint)
1375 throws ParseException {
53047a66
MK
1376
1377 List<CommonTree> children = floatingPoint.getChildren();
1378
1379 /*
1380 * If the integer has no attributes, then it is missing the size
1381 * attribute which is required
1382 */
1383 if (children == null) {
1384 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1385 }
1386
1387 /* The return value */
1388 FloatDeclaration floatDeclaration = null;
9226cfc5 1389 ByteOrder byteOrder = fTrace.getByteOrder();
53047a66 1390 long alignment = 0;
466f6d95
MK
1391
1392 int exponent = DEFAULT_FLOAT_EXPONENT;
1393 int mantissa = DEFAULT_FLOAT_MANTISSA;
53047a66 1394
53047a66
MK
1395 /* Iterate on all integer children */
1396 for (CommonTree child : children) {
1397 switch (child.getType()) {
1398 case CTFParser.CTF_EXPRESSION_VAL:
1399 /*
1400 * An assignment expression must have 2 children, left and right
1401 */
53047a66
MK
1402
1403 CommonTree leftNode = (CommonTree) child.getChild(0);
53047a66 1404 CommonTree rightNode = (CommonTree) child.getChild(1);
53047a66
MK
1405
1406 List<CommonTree> leftStrings = leftNode.getChildren();
53047a66 1407
4311ac8b 1408 if (!isAnyUnaryString(leftStrings.get(0))) {
2c053b6e 1409 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
53047a66
MK
1410 }
1411 String left = concatenateUnaryStrings(leftStrings);
1412
fafc36a7 1413 if (left.equals(MetadataStrings.EXP_DIG)) {
53047a66 1414 exponent = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
fafc36a7 1415 } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
53047a66 1416 byteOrder = getByteOrder(rightNode);
fafc36a7 1417 } else if (left.equals(MetadataStrings.MANT_DIG)) {
53047a66 1418 mantissa = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
fafc36a7 1419 } else if (left.equals(MetadataStrings.ALIGN)) {
53047a66
MK
1420 alignment = getAlignment(rightNode);
1421 } else {
1422 throw new ParseException("Float: unknown attribute " + left); //$NON-NLS-1$
1423 }
1424
1425 break;
1426 default:
4ed7d9c1 1427 throw childTypeError(child);
53047a66
MK
1428 }
1429 }
1430 int size = mantissa + exponent;
1431 if (size == 0) {
1432 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1433 }
1434
1435 if (alignment == 0) {
466f6d95 1436 alignment = ((size % DEFAULT_ALIGNMENT) == 0) ? 1 : DEFAULT_ALIGNMENT;
53047a66
MK
1437 }
1438
07002e0a 1439 floatDeclaration = new FloatDeclaration(exponent, mantissa, byteOrder, alignment);
53047a66 1440
53047a66
MK
1441 return floatDeclaration;
1442
1443 }
1444
866e5b51
FC
1445 /**
1446 * Parses a type specifier list as a user-declared type.
1447 *
1448 * @param typeSpecifierList
1449 * A TYPE_SPECIFIER_LIST node containing a user-declared type.
1450 * @param pointerList
1451 * A list of POINTER nodes that apply to the type specified in
1452 * typeSpecifierList.
1453 * @return The corresponding declaration.
1454 * @throws ParseException
1455 * If the type does not exist (has not been found).
1456 */
1457 private IDeclaration parseTypeDeclaration(CommonTree typeSpecifierList,
1458 List<CommonTree> pointerList) throws ParseException {
1459 /* Create the string representation of the type declaration */
1460 String typeStringRepresentation = createTypeDeclarationString(
1461 typeSpecifierList, pointerList);
1462
3ba65808
MK
1463 /*
1464 * Use the string representation to search the type in the current scope
1465 */
2c053b6e 1466 IDeclaration decl = getCurrentScope().lookupTypeRecursive(
866e5b51
FC
1467 typeStringRepresentation);
1468
1469 if (decl == null) {
1470 throw new ParseException("Type " + typeStringRepresentation //$NON-NLS-1$
1471 + " has not been defined."); //$NON-NLS-1$
1472 }
1473
1474 return decl;
1475 }
1476
1477 /**
1478 * Parses an integer declaration node.
1479 *
1480 * @param integer
1481 * An INTEGER node.
1482 * @return The corresponding integer declaration.
1483 * @throws ParseException
1484 */
1485 private IntegerDeclaration parseInteger(CommonTree integer)
1486 throws ParseException {
866e5b51
FC
1487
1488 List<CommonTree> children = integer.getChildren();
1489
1490 /*
1491 * If the integer has no attributes, then it is missing the size
1492 * attribute which is required
1493 */
1494 if (children == null) {
1495 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1496 }
1497
1498 /* The return value */
1499 IntegerDeclaration integerDeclaration = null;
1500 boolean signed = false;
9226cfc5 1501 ByteOrder byteOrder = fTrace.getByteOrder();
866e5b51
FC
1502 long size = 0;
1503 long alignment = 0;
466f6d95 1504 int base = DEFAULT_INT_BASE;
a4fa4e36 1505 @NonNull
62c21477 1506 String clock = EMPTY_STRING;
866e5b51
FC
1507
1508 Encoding encoding = Encoding.NONE;
1509
1510 /* Iterate on all integer children */
1511 for (CommonTree child : children) {
1512 switch (child.getType()) {
1513 case CTFParser.CTF_EXPRESSION_VAL:
1514 /*
1515 * An assignment expression must have 2 children, left and right
1516 */
866e5b51
FC
1517
1518 CommonTree leftNode = (CommonTree) child.getChild(0);
866e5b51 1519 CommonTree rightNode = (CommonTree) child.getChild(1);
866e5b51
FC
1520
1521 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51 1522
4311ac8b 1523 if (!isAnyUnaryString(leftStrings.get(0))) {
2c053b6e 1524 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
866e5b51
FC
1525 }
1526 String left = concatenateUnaryStrings(leftStrings);
1527
62c21477 1528 if (left.equals(SIGNED)) {
866e5b51 1529 signed = getSigned(rightNode);
fafc36a7 1530 } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
866e5b51 1531 byteOrder = getByteOrder(rightNode);
62c21477 1532 } else if (left.equals(SIZE)) {
866e5b51 1533 size = getSize(rightNode);
fafc36a7 1534 } else if (left.equals(MetadataStrings.ALIGN)) {
866e5b51 1535 alignment = getAlignment(rightNode);
62c21477 1536 } else if (left.equals(BASE)) {
866e5b51 1537 base = getBase(rightNode);
62c21477 1538 } else if (left.equals(ENCODING)) {
866e5b51 1539 encoding = getEncoding(rightNode);
62c21477 1540 } else if (left.equals(MAP)) {
866e5b51
FC
1541 clock = getClock(rightNode);
1542 } else {
4311ac8b 1543 Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownIntegerAttributeWarning + " " + left); //$NON-NLS-1$
866e5b51
FC
1544 }
1545
1546 break;
1547 default:
4ed7d9c1 1548 throw childTypeError(child);
866e5b51
FC
1549 }
1550 }
1551
6fbc2ff7
AM
1552 if (size <= 0) {
1553 throw new ParseException("Invalid size attribute in Integer: " + size); //$NON-NLS-1$
866e5b51
FC
1554 }
1555
1556 if (alignment == 0) {
466f6d95 1557 alignment = ((size % DEFAULT_ALIGNMENT) == 0) ? 1 : DEFAULT_ALIGNMENT;
866e5b51
FC
1558 }
1559
a4fa4e36 1560 integerDeclaration = IntegerDeclaration.createDeclaration((int) size, signed, base,
fd74e6c1 1561 byteOrder, encoding, clock, alignment);
866e5b51 1562
866e5b51
FC
1563 return integerDeclaration;
1564 }
1565
a4fa4e36 1566 @NonNull
284fdee8 1567 private static String getClock(CommonTree rightNode) {
a4fa4e36 1568 String clock = rightNode.getChild(1).getChild(0).getChild(0).getText();
62c21477 1569 return clock == null ? EMPTY_STRING : clock;
866e5b51
FC
1570 }
1571
1572 private static StringDeclaration parseString(CommonTree string)
1573 throws ParseException {
866e5b51
FC
1574
1575 List<CommonTree> children = string.getChildren();
1576 StringDeclaration stringDeclaration = null;
1577
1578 if (children == null) {
d890ec37 1579 stringDeclaration = StringDeclaration.getStringDeclaration(Encoding.UTF8);
866e5b51
FC
1580 } else {
1581 Encoding encoding = Encoding.UTF8;
1582 for (CommonTree child : children) {
1583 switch (child.getType()) {
1584 case CTFParser.CTF_EXPRESSION_VAL:
1585 /*
1586 * An assignment expression must have 2 children, left and
1587 * right
1588 */
866e5b51
FC
1589
1590 CommonTree leftNode = (CommonTree) child.getChild(0);
866e5b51 1591 CommonTree rightNode = (CommonTree) child.getChild(1);
866e5b51
FC
1592
1593 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51 1594
4311ac8b 1595 if (!isAnyUnaryString(leftStrings.get(0))) {
2c053b6e 1596 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
866e5b51
FC
1597 }
1598 String left = concatenateUnaryStrings(leftStrings);
1599
62c21477 1600 if (left.equals(ENCODING)) {
866e5b51
FC
1601 encoding = getEncoding(rightNode);
1602 } else {
1603 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1604 + left);
1605 }
1606
1607 break;
1608 default:
4ed7d9c1 1609 throw childTypeError(child);
866e5b51
FC
1610 }
1611 }
1612
d890ec37 1613 stringDeclaration = StringDeclaration.getStringDeclaration(encoding);
866e5b51
FC
1614 }
1615
1616 return stringDeclaration;
1617 }
1618
1619 /**
1620 * Parses a struct declaration and returns the corresponding declaration.
1621 *
1622 * @param struct
1623 * An STRUCT node.
1624 * @return The corresponding struct declaration.
1625 * @throws ParseException
1626 */
94c255ef 1627 private StructDeclaration parseStruct(CommonTree struct, CommonTree identifier)
866e5b51 1628 throws ParseException {
866e5b51
FC
1629
1630 List<CommonTree> children = struct.getChildren();
866e5b51
FC
1631
1632 /* The return value */
1633 StructDeclaration structDeclaration = null;
1634
1635 /* Name */
1636 String structName = null;
1637 boolean hasName = false;
1638
1639 /* Body */
1640 CommonTree structBody = null;
1641 boolean hasBody = false;
1642
1643 /* Align */
1644 long structAlign = 0;
1645
1646 /* Loop on all children and identify what we have to work with. */
1647 for (CommonTree child : children) {
1648 switch (child.getType()) {
1649 case CTFParser.STRUCT_NAME: {
1650 hasName = true;
72dbc4ac 1651 CommonTree structNameIdentifier = (CommonTree) child.getChild(0);
866e5b51 1652 structName = structNameIdentifier.getText();
866e5b51
FC
1653 break;
1654 }
1655 case CTFParser.STRUCT_BODY: {
1656 hasBody = true;
1657
1658 structBody = child;
866e5b51
FC
1659 break;
1660 }
1661 case CTFParser.ALIGN: {
72dbc4ac 1662 CommonTree structAlignExpression = (CommonTree) child.getChild(0);
866e5b51
FC
1663
1664 structAlign = getAlignment(structAlignExpression);
866e5b51
FC
1665 break;
1666 }
1667 default:
4ed7d9c1 1668 throw childTypeError(child);
866e5b51
FC
1669 }
1670 }
1671
94c255ef
MK
1672 if (!hasName && identifier != null) {
1673 structName = identifier.getText();
1674 hasName = true;
1675 }
1676
866e5b51
FC
1677 /*
1678 * If a struct has just a body and no name (just like the song,
1679 * "A Struct With No Name" by America (sorry for that...)), it's a
1680 * definition of a new type, so we create the type declaration and
1681 * return it. We can't add it to the declaration scope since there is no
1682 * name, but that's what we want because it won't be possible to use it
1683 * again to declare another field.
1684 *
1685 * If it has just a name, we look it up in the declaration scope and
1686 * return the associated declaration. If it is not found in the
1687 * declaration scope, it means that a struct with that name has not been
1688 * declared, which is an error.
1689 *
1690 * If it has both, then we create the type declaration and register it
1691 * to the current scope.
1692 *
1693 * If it has none, then what are we doing here ?
1694 */
1695 if (hasBody) {
1696 /*
1697 * If struct has a name, check if already defined in the current
1698 * scope.
1699 */
1700 if (hasName && (getCurrentScope().lookupStruct(structName) != null)) {
1701 throw new ParseException("struct " + structName //$NON-NLS-1$
1702 + " already defined."); //$NON-NLS-1$
1703 }
866e5b51
FC
1704 /* Create the declaration */
1705 structDeclaration = new StructDeclaration(structAlign);
1706
1707 /* Parse the body */
3ba65808 1708 parseStructBody(structBody, structDeclaration, structName);
866e5b51
FC
1709
1710 /* If struct has name, add it to the current scope. */
1711 if (hasName) {
1712 getCurrentScope().registerStruct(structName, structDeclaration);
1713 }
3ba65808 1714 } else /* !hasBody */ {
866e5b51
FC
1715 if (hasName) {
1716 /* Name and !body */
1717
1718 /* Lookup the name in the current scope. */
2c053b6e 1719 structDeclaration = getCurrentScope().lookupStructRecursive(structName);
866e5b51
FC
1720
1721 /*
1722 * If not found, it means that a struct with such name has not
1723 * been defined
1724 */
1725 if (structDeclaration == null) {
1726 throw new ParseException("struct " + structName //$NON-NLS-1$
1727 + " is not defined"); //$NON-NLS-1$
1728 }
1729 } else {
1730 /* !Name and !body */
1731
1732 /* We can't do anything with that. */
1733 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1734 }
1735 }
8fa270f6 1736 return StructDeclarationFlattener.tryFlattenStruct(structDeclaration);
866e5b51
FC
1737 }
1738
1739 /**
1740 * Parses a struct body, adding the fields to specified structure
1741 * declaration.
1742 *
1743 * @param structBody
1744 * A STRUCT_BODY node.
1745 * @param structDeclaration
1746 * The struct declaration.
1747 * @throws ParseException
1748 */
1749 private void parseStructBody(CommonTree structBody,
3ba65808 1750 StructDeclaration structDeclaration, @Nullable String structName) throws ParseException {
866e5b51 1751 List<CommonTree> structDeclarations = structBody.getChildren();
3ba65808
MK
1752 if (structDeclarations == null) {
1753 structDeclarations = Collections.emptyList();
1754 }
866e5b51
FC
1755
1756 /*
1757 * If structDeclaration is null, structBody has no children and the
1758 * struct body is empty.
1759 */
3ba65808 1760 pushNamedScope(structName, MetadataStrings.STRUCT);
866e5b51 1761
3ba65808
MK
1762 for (CommonTree declarationNode : structDeclarations) {
1763 switch (declarationNode.getType()) {
1764 case CTFParser.TYPEALIAS:
1765 parseTypealias(declarationNode);
1766 break;
1767 case CTFParser.TYPEDEF:
1768 parseTypedef(declarationNode);
94c255ef 1769 parseStructDeclaration(declarationNode, structDeclaration);
3ba65808
MK
1770 break;
1771 case CTFParser.SV_DECLARATION:
1772 parseStructDeclaration(declarationNode, structDeclaration);
1773 break;
1774 default:
1775 throw childTypeError(declarationNode);
866e5b51 1776 }
866e5b51 1777 }
3ba65808 1778 popScope();
866e5b51
FC
1779 }
1780
1781 /**
1782 * Parses a declaration found in a struct.
1783 *
1784 * @param declaration
1785 * A SV_DECLARATION node.
1786 * @param struct
1787 * A struct declaration. (I know, little name clash here...)
1788 * @throws ParseException
1789 */
1790 private void parseStructDeclaration(CommonTree declaration,
1791 StructDeclaration struct) throws ParseException {
866e5b51 1792
866e5b51 1793 /* Get the type specifier list node */
72dbc4ac 1794 CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
866e5b51
FC
1795
1796 /* Get the type declarator list node */
72dbc4ac 1797 CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
866e5b51
FC
1798
1799 /* Get the type declarator list */
72dbc4ac 1800 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
866e5b51
FC
1801
1802 /*
1803 * For each type declarator, parse the declaration and add a field to
1804 * the struct
1805 */
1806 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
866e5b51
FC
1807
1808 StringBuilder identifierSB = new StringBuilder();
1809
1810 IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
1811 typeSpecifierListNode, identifierSB);
1812 String fieldName = identifierSB.toString();
2c053b6e 1813 getCurrentScope().registerIdentifier(fieldName, decl);
866e5b51
FC
1814
1815 if (struct.hasField(fieldName)) {
1816 throw new ParseException("struct: duplicate field " //$NON-NLS-1$
1817 + fieldName);
1818 }
1819
1820 struct.addField(fieldName, decl);
1821
1822 }
1823 }
1824
1825 /**
1826 * Parses an enum declaration and returns the corresponding declaration.
1827 *
0594c61c 1828 * @param theEnum
866e5b51
FC
1829 * An ENUM node.
1830 * @return The corresponding enum declaration.
1831 * @throws ParseException
1832 */
0594c61c 1833 private EnumDeclaration parseEnum(CommonTree theEnum) throws ParseException {
866e5b51 1834
0594c61c 1835 List<CommonTree> children = theEnum.getChildren();
866e5b51
FC
1836
1837 /* The return value */
1838 EnumDeclaration enumDeclaration = null;
1839
1840 /* Name */
1841 String enumName = null;
1842
1843 /* Body */
1844 CommonTree enumBody = null;
1845
1846 /* Container type */
1847 IntegerDeclaration containerTypeDeclaration = null;
1848
1849 /* Loop on all children and identify what we have to work with. */
1850 for (CommonTree child : children) {
1851 switch (child.getType()) {
1852 case CTFParser.ENUM_NAME: {
866e5b51 1853 CommonTree enumNameIdentifier = (CommonTree) child.getChild(0);
866e5b51 1854 enumName = enumNameIdentifier.getText();
866e5b51
FC
1855 break;
1856 }
1857 case CTFParser.ENUM_BODY: {
866e5b51 1858 enumBody = child;
866e5b51
FC
1859 break;
1860 }
1861 case CTFParser.ENUM_CONTAINER_TYPE: {
866e5b51 1862 containerTypeDeclaration = parseEnumContainerType(child);
866e5b51
FC
1863 break;
1864 }
1865 default:
4ed7d9c1 1866 throw childTypeError(child);
866e5b51
FC
1867 }
1868 }
1869
1870 /*
1871 * If the container type has not been defined explicitly, we assume it
1872 * is "int".
1873 */
1874 if (containerTypeDeclaration == null) {
32ede2ec
MK
1875 IDeclaration enumDecl;
1876 /*
1877 * it could be because the enum was already declared.
1878 */
1879 if (enumName != null) {
3ba65808 1880 getCurrentScope().setName(enumName);
2c053b6e 1881 enumDecl = getCurrentScope().lookupEnumRecursive(enumName);
32ede2ec
MK
1882 if (enumDecl != null) {
1883 return (EnumDeclaration) enumDecl;
1884 }
1885 }
1886
2c053b6e 1887 IDeclaration decl = getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$
866e5b51
FC
1888
1889 if (decl == null) {
2c053b6e 1890 throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$
866e5b51 1891 } else if (!(decl instanceof IntegerDeclaration)) {
2c053b6e 1892 throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$
866e5b51
FC
1893 }
1894
1895 containerTypeDeclaration = (IntegerDeclaration) decl;
1896 }
1897
1898 /*
1899 * If it has a body, it's a new declaration, otherwise it's a reference
1900 * to an existing declaration. Same logic as struct.
1901 */
1902 if (enumBody != null) {
1903 /*
1904 * If enum has a name, check if already defined in the current
1905 * scope.
1906 */
1907 if ((enumName != null)
1908 && (getCurrentScope().lookupEnum(enumName) != null)) {
1909 throw new ParseException("enum " + enumName //$NON-NLS-1$
1910 + " already defined"); //$NON-NLS-1$
1911 }
1912
1913 /* Create the declaration */
1914 enumDeclaration = new EnumDeclaration(containerTypeDeclaration);
1915
1916 /* Parse the body */
3ba65808 1917 parseEnumBody(enumBody, enumDeclaration, enumName);
866e5b51
FC
1918
1919 /* If the enum has name, add it to the current scope. */
1920 if (enumName != null) {
1921 getCurrentScope().registerEnum(enumName, enumDeclaration);
1922 }
1923 } else {
1924 if (enumName != null) {
1925 /* Name and !body */
1926
1927 /* Lookup the name in the current scope. */
2c053b6e 1928 enumDeclaration = getCurrentScope().lookupEnumRecursive(enumName);
866e5b51
FC
1929
1930 /*
1931 * If not found, it means that an enum with such name has not
1932 * been defined
1933 */
1934 if (enumDeclaration == null) {
1935 throw new ParseException("enum " + enumName //$NON-NLS-1$
1936 + " is not defined"); //$NON-NLS-1$
1937 }
1938 } else {
1939 /* !Name and !body */
1940 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1941 }
1942 }
1943
1944 return enumDeclaration;
1945
1946 }
1947
1948 /**
1949 * Parses an enum body, adding the enumerators to the specified enum
1950 * declaration.
1951 *
1952 * @param enumBody
1953 * An ENUM_BODY node.
1954 * @param enumDeclaration
1955 * The enum declaration.
1956 * @throws ParseException
1957 */
1958 private void parseEnumBody(CommonTree enumBody,
3ba65808 1959 EnumDeclaration enumDeclaration, @Nullable String enumName) throws ParseException {
866e5b51
FC
1960
1961 List<CommonTree> enumerators = enumBody.getChildren();
1962 /* enum body can't be empty (unlike struct). */
866e5b51 1963
3ba65808 1964 pushNamedScope(enumName, MetadataStrings.ENUM);
866e5b51
FC
1965
1966 /*
1967 * Start at -1, so that if the first enumrator has no explicit value, it
1968 * will choose 0
1969 */
1970 long lastHigh = -1;
1971
1972 for (CommonTree enumerator : enumerators) {
1973 lastHigh = parseEnumEnumerator(enumerator, enumDeclaration,
1974 lastHigh);
1975 }
1976
1977 popScope();
1978
1979 }
1980
1981 /**
1982 * Parses an enumerator node and adds an enumerator declaration to an
1983 * enumeration declaration.
1984 *
1985 * The high value of the range of the last enumerator is needed in case the
1986 * current enumerator does not specify its value.
1987 *
1988 * @param enumerator
1989 * An ENUM_ENUMERATOR node.
1990 * @param enumDeclaration
1991 * en enumeration declaration to which will be added the
1992 * enumerator.
1993 * @param lastHigh
1994 * The high value of the range of the last enumerator
1995 * @return The high value of the value range of the current enumerator.
1996 * @throws ParseException
1997 */
1998 private static long parseEnumEnumerator(CommonTree enumerator,
1999 EnumDeclaration enumDeclaration, long lastHigh)
3ba65808 2000 throws ParseException {
866e5b51
FC
2001
2002 List<CommonTree> children = enumerator.getChildren();
866e5b51
FC
2003
2004 long low = 0, high = 0;
2005 boolean valueSpecified = false;
2006 String label = null;
2007
2008 for (CommonTree child : children) {
4311ac8b 2009 if (isAnyUnaryString(child)) {
866e5b51
FC
2010 label = parseUnaryString(child);
2011 } else if (child.getType() == CTFParser.ENUM_VALUE) {
866e5b51
FC
2012
2013 valueSpecified = true;
2014
2015 low = parseUnaryInteger((CommonTree) child.getChild(0));
2016 high = low;
2017 } else if (child.getType() == CTFParser.ENUM_VALUE_RANGE) {
866e5b51
FC
2018
2019 valueSpecified = true;
2020
2021 low = parseUnaryInteger((CommonTree) child.getChild(0));
2022 high = parseUnaryInteger((CommonTree) child.getChild(1));
2023 } else {
4ed7d9c1 2024 throw childTypeError(child);
866e5b51
FC
2025 }
2026 }
2027
866e5b51
FC
2028 if (!valueSpecified) {
2029 low = lastHigh + 1;
2030 high = low;
2031 }
2032
2033 if (low > high) {
2034 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
2035 }
2036
2037 if (!enumDeclaration.add(low, high, label)) {
2038 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
2039 }
2040
4311ac8b
MAL
2041 if (valueSpecified && (BigInteger.valueOf(low).compareTo(enumDeclaration.getContainerType().getMinValue()) == -1 ||
2042 BigInteger.valueOf(high).compareTo(enumDeclaration.getContainerType().getMaxValue()) == 1)) {
2043 throw new ParseException("enum value is not in range"); //$NON-NLS-1$
2044 }
2045
866e5b51
FC
2046 return high;
2047 }
2048
2049 /**
2050 * Parses an enum container type node and returns the corresponding integer
2051 * type.
2052 *
2053 * @param enumContainerType
2054 * An ENUM_CONTAINER_TYPE node.
2055 * @return An integer declaration corresponding to the container type.
2056 * @throws ParseException
2057 * If the type does not parse correctly or if it is not an
2058 * integer type.
2059 */
2060 private IntegerDeclaration parseEnumContainerType(
2061 CommonTree enumContainerType) throws ParseException {
866e5b51
FC
2062
2063 /* Get the child, which should be a type specifier list */
72dbc4ac 2064 CommonTree typeSpecifierList = (CommonTree) enumContainerType.getChild(0);
866e5b51
FC
2065
2066 /* Parse it and get the corresponding declaration */
94c255ef 2067 IDeclaration decl = parseTypeSpecifierList(typeSpecifierList);
866e5b51
FC
2068
2069 /* If is is an integer, return it, else throw an error */
2070 if (decl instanceof IntegerDeclaration) {
2071 return (IntegerDeclaration) decl;
2072 }
2073 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
2074 }
2075
2076 private VariantDeclaration parseVariant(CommonTree variant)
2077 throws ParseException {
866e5b51
FC
2078
2079 List<CommonTree> children = variant.getChildren();
2080 VariantDeclaration variantDeclaration = null;
2081
2082 boolean hasName = false;
2083 String variantName = null;
2084
2085 boolean hasBody = false;
2086 CommonTree variantBody = null;
2087
2088 boolean hasTag = false;
2089 String variantTag = null;
2090
2091 for (CommonTree child : children) {
2092 switch (child.getType()) {
2093 case CTFParser.VARIANT_NAME:
866e5b51
FC
2094
2095 hasName = true;
2096
72dbc4ac 2097 CommonTree variantNameIdentifier = (CommonTree) child.getChild(0);
866e5b51 2098
866e5b51
FC
2099 variantName = variantNameIdentifier.getText();
2100
2101 break;
2102 case CTFParser.VARIANT_TAG:
866e5b51
FC
2103
2104 hasTag = true;
2105
72dbc4ac 2106 CommonTree variantTagIdentifier = (CommonTree) child.getChild(0);
866e5b51 2107
866e5b51
FC
2108 variantTag = variantTagIdentifier.getText();
2109
2110 break;
2111 case CTFParser.VARIANT_BODY:
866e5b51
FC
2112
2113 hasBody = true;
2114
2115 variantBody = child;
2116
2117 break;
2118 default:
4ed7d9c1 2119 throw childTypeError(child);
866e5b51
FC
2120 }
2121 }
2122
2123 if (hasBody) {
2124 /*
2125 * If variant has a name, check if already defined in the current
2126 * scope.
2127 */
2128 if (hasName
2129 && (getCurrentScope().lookupVariant(variantName) != null)) {
2130 throw new ParseException("variant " + variantName //$NON-NLS-1$
2131 + " already defined."); //$NON-NLS-1$
2132 }
2133
2134 /* Create the declaration */
2135 variantDeclaration = new VariantDeclaration();
2136
2137 /* Parse the body */
3ba65808 2138 parseVariantBody(variantBody, variantDeclaration, variantName);
866e5b51
FC
2139
2140 /* If variant has name, add it to the current scope. */
2141 if (hasName) {
2142 getCurrentScope().registerVariant(variantName,
2143 variantDeclaration);
2144 }
3ba65808 2145 } else /* !hasBody */ {
866e5b51
FC
2146 if (hasName) {
2147 /* Name and !body */
2148
2149 /* Lookup the name in the current scope. */
2c053b6e 2150 variantDeclaration = getCurrentScope().lookupVariantRecursive(
866e5b51
FC
2151 variantName);
2152
2153 /*
2154 * If not found, it means that a struct with such name has not
2155 * been defined
2156 */
2157 if (variantDeclaration == null) {
2158 throw new ParseException("variant " + variantName //$NON-NLS-1$
2159 + " is not defined"); //$NON-NLS-1$
2160 }
2161 } else {
2162 /* !Name and !body */
2163
2164 /* We can't do anything with that. */
2165 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2166 }
2167 }
2168
2169 if (hasTag) {
2170 variantDeclaration.setTag(variantTag);
816fde81
MK
2171
2172 IDeclaration decl = getCurrentScope().lookupIdentifierRecursive(variantTag);
2173 if (decl == null) {
2174 throw new ParseException("Variant tag not found: " + variantTag); //$NON-NLS-1$
2175 }
2176 if (!(decl instanceof EnumDeclaration)) {
2177 throw new ParseException("Variant tag must be an enum: " + variantTag); //$NON-NLS-1$
2178 }
2179 EnumDeclaration tagDecl = (EnumDeclaration) decl;
3de23137 2180 Set<String> intersection = new HashSet<>(tagDecl.getLabels());
816fde81
MK
2181 intersection.retainAll(variantDeclaration.getFields().keySet());
2182 if (intersection.isEmpty()) {
2183 throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName); //$NON-NLS-1$
2184 }
866e5b51
FC
2185 }
2186
866e5b51
FC
2187 return variantDeclaration;
2188 }
2189
2190 private void parseVariantBody(CommonTree variantBody,
3ba65808 2191 VariantDeclaration variantDeclaration, @Nullable String variantName) throws ParseException {
866e5b51
FC
2192
2193 List<CommonTree> variantDeclarations = variantBody.getChildren();
866e5b51 2194
3ba65808 2195 pushNamedScope(variantName, MetadataStrings.VARIANT);
866e5b51
FC
2196
2197 for (CommonTree declarationNode : variantDeclarations) {
2198 switch (declarationNode.getType()) {
2199 case CTFParser.TYPEALIAS:
2200 parseTypealias(declarationNode);
2201 break;
2202 case CTFParser.TYPEDEF:
2203 parseTypedef(declarationNode);
2204 break;
2205 case CTFParser.SV_DECLARATION:
2206 parseVariantDeclaration(declarationNode, variantDeclaration);
2207 break;
2208 default:
4ed7d9c1 2209 throw childTypeError(declarationNode);
866e5b51
FC
2210 }
2211 }
2212
2213 popScope();
2214 }
2215
2216 private void parseVariantDeclaration(CommonTree declaration,
2217 VariantDeclaration variant) throws ParseException {
866e5b51 2218
866e5b51 2219 /* Get the type specifier list node */
72dbc4ac 2220 CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
866e5b51
FC
2221
2222 /* Get the type declarator list node */
72dbc4ac 2223 CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
866e5b51
FC
2224
2225 /* Get the type declarator list */
72dbc4ac 2226 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
866e5b51
FC
2227
2228 /*
2229 * For each type declarator, parse the declaration and add a field to
2230 * the variant
2231 */
2232 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
866e5b51
FC
2233
2234 StringBuilder identifierSB = new StringBuilder();
2235
2236 IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
2237 typeSpecifierListNode, identifierSB);
2238
2c053b6e
MK
2239 String name = identifierSB.toString();
2240
2241 if (variant.hasField(name)) {
866e5b51 2242 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2c053b6e 2243 + name);
866e5b51
FC
2244 }
2245
2c053b6e
MK
2246 getCurrentScope().registerIdentifier(name, decl);
2247
2248 variant.addField(name, decl);
866e5b51
FC
2249 }
2250 }
2251
2252 /**
2253 * Creates the string representation of a type declaration (type specifier
2254 * list + pointers).
2255 *
2256 * @param typeSpecifierList
2257 * A TYPE_SPECIFIER_LIST node.
2258 * @param pointers
2259 * A list of POINTER nodes.
2260 * @return The string representation.
2261 * @throws ParseException
2262 */
2263 private static String createTypeDeclarationString(
2264 CommonTree typeSpecifierList, List<CommonTree> pointers)
3ba65808 2265 throws ParseException {
866e5b51
FC
2266 StringBuilder sb = new StringBuilder();
2267
2268 createTypeSpecifierListString(typeSpecifierList, sb);
2269 createPointerListString(pointers, sb);
2270
2271 return sb.toString();
2272 }
2273
2274 /**
2275 * Creates the string representation of a list of type specifiers.
2276 *
2277 * @param typeSpecifierList
2278 * A TYPE_SPECIFIER_LIST node.
2279 * @param sb
2280 * A StringBuilder to which will be appended the string.
2281 * @throws ParseException
2282 */
2283 private static void createTypeSpecifierListString(
2284 CommonTree typeSpecifierList, StringBuilder sb)
3ba65808 2285 throws ParseException {
866e5b51
FC
2286
2287 List<CommonTree> children = typeSpecifierList.getChildren();
866e5b51
FC
2288
2289 boolean firstItem = true;
2290
2291 for (CommonTree child : children) {
2292 if (!firstItem) {
2293 sb.append(' ');
2294
2295 }
2296
2297 firstItem = false;
2298
2299 /* Append the string that represents this type specifier. */
2300 createTypeSpecifierString(child, sb);
2301 }
2302 }
2303
2304 /**
2305 * Creates the string representation of a type specifier.
2306 *
2307 * @param typeSpecifier
2308 * A TYPE_SPECIFIER node.
2309 * @param sb
2310 * A StringBuilder to which will be appended the string.
2311 * @throws ParseException
2312 */
2313 private static void createTypeSpecifierString(CommonTree typeSpecifier,
2314 StringBuilder sb) throws ParseException {
2315 switch (typeSpecifier.getType()) {
2316 case CTFParser.FLOATTOK:
2317 case CTFParser.INTTOK:
2318 case CTFParser.LONGTOK:
2319 case CTFParser.SHORTTOK:
2320 case CTFParser.SIGNEDTOK:
2321 case CTFParser.UNSIGNEDTOK:
2322 case CTFParser.CHARTOK:
2323 case CTFParser.DOUBLETOK:
2324 case CTFParser.VOIDTOK:
2325 case CTFParser.BOOLTOK:
2326 case CTFParser.COMPLEXTOK:
2327 case CTFParser.IMAGINARYTOK:
2328 case CTFParser.CONSTTOK:
2329 case CTFParser.IDENTIFIER:
2330 sb.append(typeSpecifier.getText());
2331 break;
2332 case CTFParser.STRUCT: {
72dbc4ac 2333 CommonTree structName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.STRUCT_NAME);
866e5b51 2334 if (structName == null) {
2c053b6e 2335 throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
866e5b51 2336 }
866e5b51 2337
72dbc4ac 2338 CommonTree structNameIdentifier = (CommonTree) structName.getChild(0);
866e5b51
FC
2339
2340 sb.append(structNameIdentifier.getText());
2341 break;
2342 }
2343 case CTFParser.VARIANT: {
72dbc4ac 2344 CommonTree variantName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.VARIANT_NAME);
866e5b51 2345 if (variantName == null) {
2c053b6e 2346 throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
866e5b51 2347 }
866e5b51 2348
72dbc4ac 2349 CommonTree variantNameIdentifier = (CommonTree) variantName.getChild(0);
866e5b51
FC
2350
2351 sb.append(variantNameIdentifier.getText());
2352 break;
2353 }
2354 case CTFParser.ENUM: {
72dbc4ac 2355 CommonTree enumName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.ENUM_NAME);
866e5b51 2356 if (enumName == null) {
2c053b6e 2357 throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
866e5b51 2358 }
866e5b51
FC
2359
2360 CommonTree enumNameIdentifier = (CommonTree) enumName.getChild(0);
866e5b51
FC
2361
2362 sb.append(enumNameIdentifier.getText());
2363 break;
2364 }
2365 case CTFParser.FLOATING_POINT:
2366 case CTFParser.INTEGER:
2367 case CTFParser.STRING:
2c053b6e 2368 throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
866e5b51 2369 default:
4ed7d9c1 2370 throw childTypeError(typeSpecifier);
866e5b51
FC
2371 }
2372 }
2373
2374 /**
2375 * Creates the string representation of a list of pointers.
2376 *
2377 * @param pointerList
2378 * A list of pointer nodes. If pointerList is null, this function
2379 * does nothing.
2380 * @param sb
2381 * A stringbuilder to which will be appended the string.
2382 */
2383 private static void createPointerListString(List<CommonTree> pointerList,
2384 StringBuilder sb) {
2385 if (pointerList == null) {
2386 return;
2387 }
2388
2389 for (CommonTree pointer : pointerList) {
866e5b51
FC
2390
2391 sb.append(" *"); //$NON-NLS-1$
2392 if (pointer.getChildCount() > 0) {
866e5b51
FC
2393
2394 sb.append(" const"); //$NON-NLS-1$
2395 }
2396 }
2397 }
2398
866e5b51
FC
2399 /**
2400 * @param node
2401 * The node to check.
2402 * @return True if the given node is an unary string.
2403 */
2404 private static boolean isUnaryString(CommonTree node) {
4311ac8b
MAL
2405 return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING));
2406 }
2407
2408 /**
2409 * @param node
2410 * The node to check.
2c053b6e
MK
2411 * @return True if the given node is any type of unary string (no quotes,
2412 * quotes, etc).
4311ac8b
MAL
2413 */
2414 private static boolean isAnyUnaryString(CommonTree node) {
2c053b6e 2415 return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING) || (node.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES));
866e5b51
FC
2416 }
2417
2418 /**
2419 * @param node
2420 * The node to check.
2421 * @return True if the given node is an unary integer.
2422 */
2423 private static boolean isUnaryInteger(CommonTree node) {
72dbc4ac 2424 return ((node.getType() == CTFParser.UNARY_EXPRESSION_DEC) ||
2c053b6e 2425 (node.getType() == CTFParser.UNARY_EXPRESSION_HEX) || (node.getType() == CTFParser.UNARY_EXPRESSION_OCT));
866e5b51
FC
2426 }
2427
2428 /**
2429 * Parses a unary string node and return the string value.
2430 *
2431 * @param unaryString
2432 * The unary string node to parse (type UNARY_EXPRESSION_STRING
2433 * or UNARY_EXPRESSION_STRING_QUOTES).
2434 * @return The string value.
2435 */
2436 /*
2437 * It would be really nice to remove the quotes earlier, such as in the
2438 * parser.
2439 */
2440 private static String parseUnaryString(CommonTree unaryString) {
866e5b51 2441
866e5b51 2442 CommonTree value = (CommonTree) unaryString.getChild(0);
8d90cd62
MK
2443 if (value.getType() == CTFParser.UNARY_EXPRESSION_STRING) {
2444 value = (CommonTree) value.getChild(0);
2445 }
866e5b51
FC
2446 String strval = value.getText();
2447
2448 /* Remove quotes */
2449 if (unaryString.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES) {
2450 strval = strval.substring(1, strval.length() - 1);
2451 }
2452
2453 return strval;
2454 }
2455
2456 /**
2457 * Parses an unary integer (dec, hex or oct).
2458 *
2459 * @param unaryInteger
2460 * An unary integer node.
2461 * @return The integer value.
58129ff7
MK
2462 * @throws ParseException
2463 * on an invalid integer format ("bob" for example)
866e5b51 2464 */
a94410d9 2465 private static long parseUnaryInteger(CommonTree unaryInteger) throws ParseException {
866e5b51
FC
2466
2467 List<CommonTree> children = unaryInteger.getChildren();
2468 CommonTree value = children.get(0);
2469 String strval = value.getText();
2470
2471 long intval;
a94410d9 2472 try {
ab98db9a 2473 intval = Long.decode(strval);
a94410d9 2474 } catch (NumberFormatException e) {
466f6d95 2475 throw new ParseException("Invalid integer format: " + strval, e); //$NON-NLS-1$
866e5b51 2476 }
4311ac8b 2477
866e5b51
FC
2478 /* The rest of children are sign */
2479 if ((children.size() % 2) == 0) {
2480 return -intval;
2481 }
2482 return intval;
2483 }
2484
2485 private static long getMajorOrMinor(CommonTree rightNode)
2486 throws ParseException {
866e5b51
FC
2487
2488 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2489
2490 if (isUnaryInteger(firstChild)) {
2491 if (rightNode.getChildCount() > 1) {
2492 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2493 }
2494
2495 long m = parseUnaryInteger(firstChild);
2496
2497 if (m < 0) {
2498 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2499 }
2500
2501 return m;
2502 }
2503 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2504 }
2505
2506 private static UUID getUUID(CommonTree rightNode) throws ParseException {
866e5b51
FC
2507
2508 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2509
4311ac8b 2510 if (isAnyUnaryString(firstChild)) {
866e5b51
FC
2511 if (rightNode.getChildCount() > 1) {
2512 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2513 }
2514
2515 String uuidstr = parseUnaryString(firstChild);
2516
2517 try {
0594c61c 2518 return UUID.fromString(uuidstr);
866e5b51 2519 } catch (IllegalArgumentException e) {
466f6d95 2520 throw new ParseException("Invalid format for UUID", e); //$NON-NLS-1$
866e5b51
FC
2521 }
2522 }
2523 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2524 }
2525
2526 /**
2527 * Gets the value of a "signed" integer attribute.
2528 *
2529 * @param rightNode
2530 * A CTF_RIGHT node.
2531 * @return The "signed" value as a boolean.
2532 * @throws ParseException
2533 */
2534 private static boolean getSigned(CommonTree rightNode)
2535 throws ParseException {
866e5b51
FC
2536
2537 boolean ret = false;
2538 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2539
2540 if (isUnaryString(firstChild)) {
2541 String strval = concatenateUnaryStrings(rightNode.getChildren());
2542
fafc36a7
AM
2543 if (strval.equals(MetadataStrings.TRUE)
2544 || strval.equals(MetadataStrings.TRUE2)) {
866e5b51 2545 ret = true;
fafc36a7
AM
2546 } else if (strval.equals(MetadataStrings.FALSE)
2547 || strval.equals(MetadataStrings.FALSE2)) {
866e5b51
FC
2548 ret = false;
2549 } else {
2550 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2551 + firstChild.getChild(0).getText());
2552 }
2553 } else if (isUnaryInteger(firstChild)) {
2554 /* Happens if the value is something like "1234.hello" */
2555 if (rightNode.getChildCount() > 1) {
2556 throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
2557 }
2558
2559 long intval = parseUnaryInteger(firstChild);
2560
2561 if (intval == 1) {
2562 ret = true;
2563 } else if (intval == 0) {
2564 ret = false;
2565 } else {
2566 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2567 + firstChild.getChild(0).getText());
2568 }
2569 } else {
2570 throw new ParseException();
2571 }
2572
2573 return ret;
2574 }
2575
2576 /**
2577 * Gets the value of a "byte_order" integer attribute.
2578 *
2579 * @param rightNode
2580 * A CTF_RIGHT node.
2581 * @return The "byte_order" value.
2582 * @throws ParseException
2583 */
2584 private ByteOrder getByteOrder(CommonTree rightNode) throws ParseException {
866e5b51
FC
2585
2586 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2587
2588 if (isUnaryString(firstChild)) {
2589 String strval = concatenateUnaryStrings(rightNode.getChildren());
2590
fafc36a7 2591 if (strval.equals(MetadataStrings.LE)) {
866e5b51 2592 return ByteOrder.LITTLE_ENDIAN;
fafc36a7
AM
2593 } else if (strval.equals(MetadataStrings.BE)
2594 || strval.equals(MetadataStrings.NETWORK)) {
866e5b51 2595 return ByteOrder.BIG_ENDIAN;
fafc36a7 2596 } else if (strval.equals(MetadataStrings.NATIVE)) {
9226cfc5 2597 return fTrace.getByteOrder();
866e5b51
FC
2598 } else {
2599 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2600 }
2601 }
2602 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2603 }
2604
2605 /**
2606 * Determines if the given value is a valid alignment value.
2607 *
2608 * @param alignment
2609 * The value to check.
2610 * @return True if it is valid.
2611 */
2612 private static boolean isValidAlignment(long alignment) {
2613 return !((alignment <= 0) || ((alignment & (alignment - 1)) != 0));
2614 }
2615
2616 /**
2617 * Gets the value of a "size" integer attribute.
2618 *
2619 * @param rightNode
2620 * A CTF_RIGHT node.
2621 * @return The "size" value.
2622 * @throws ParseException
2623 */
2624 private static long getSize(CommonTree rightNode) throws ParseException {
866e5b51
FC
2625
2626 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2627
2628 if (isUnaryInteger(firstChild)) {
2629 if (rightNode.getChildCount() > 1) {
2630 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2631 }
2632
2633 long size = parseUnaryInteger(firstChild);
2634
2635 if (size < 1) {
2636 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2637 }
2638
2639 return size;
2640 }
2641 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2642 }
2643
2644 /**
2645 * Gets the value of a "align" integer or struct attribute.
2646 *
2647 * @param node
2648 * A CTF_RIGHT node or directly an unary integer.
2649 * @return The align value.
2650 * @throws ParseException
2651 */
2652 private static long getAlignment(CommonTree node) throws ParseException {
866e5b51
FC
2653
2654 /*
2655 * If a CTF_RIGHT node was passed, call getAlignment with the first
2656 * child
2657 */
2658 if (node.getType() == CTFParser.CTF_RIGHT) {
2659 if (node.getChildCount() > 1) {
2660 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2661 }
2662
2663 return getAlignment((CommonTree) node.getChild(0));
2664 } else if (isUnaryInteger(node)) {
2665 long alignment = parseUnaryInteger(node);
2666
2667 if (!isValidAlignment(alignment)) {
2668 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2669 + alignment);
2670 }
2671
2672 return alignment;
2673 }
2674 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2675 }
2676
2677 /**
2678 * Gets the value of a "base" integer attribute.
2679 *
2680 * @param rightNode
2681 * An CTF_RIGHT node.
2682 * @return The "base" value.
2683 * @throws ParseException
2684 */
2685 private static int getBase(CommonTree rightNode) throws ParseException {
866e5b51
FC
2686
2687 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2688
2689 if (isUnaryInteger(firstChild)) {
2690 if (rightNode.getChildCount() > 1) {
2691 throw new ParseException("invalid base value"); //$NON-NLS-1$
2692 }
2693
2694 long intval = parseUnaryInteger(firstChild);
466f6d95
MK
2695 if ((intval == INTEGER_BASE_2) || (intval == INTEGER_BASE_8) || (intval == INTEGER_BASE_10)
2696 || (intval == INTEGER_BASE_16)) {
866e5b51
FC
2697 return (int) intval;
2698 }
2699 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2700 } else if (isUnaryString(firstChild)) {
f068c622
MK
2701 switch (concatenateUnaryStrings(rightNode.getChildren())) {
2702 case MetadataStrings.DECIMAL:
2703 case MetadataStrings.DEC:
2704 case MetadataStrings.DEC_CTE:
2705 case MetadataStrings.INT_MOD:
2706 case MetadataStrings.UNSIGNED_CTE:
466f6d95 2707 return INTEGER_BASE_10;
f068c622
MK
2708 case MetadataStrings.HEXADECIMAL:
2709 case MetadataStrings.HEX:
2710 case MetadataStrings.X:
2711 case MetadataStrings.X2:
2712 case MetadataStrings.POINTER:
466f6d95 2713 return INTEGER_BASE_16;
f068c622
MK
2714 case MetadataStrings.OCT:
2715 case MetadataStrings.OCTAL:
2716 case MetadataStrings.OCTAL_CTE:
466f6d95 2717 return INTEGER_BASE_8;
f068c622
MK
2718 case MetadataStrings.BIN:
2719 case MetadataStrings.BINARY:
466f6d95 2720 return INTEGER_BASE_2;
f068c622 2721 default:
866e5b51
FC
2722 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2723 }
2724 } else {
2725 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2726 }
2727 }
2728
2729 /**
2730 * Gets the value of an "encoding" integer attribute.
2731 *
2732 * @param rightNode
2733 * A CTF_RIGHT node.
2734 * @return The "encoding" value.
2735 * @throws ParseException
2736 */
a4fa4e36 2737 @NonNull
866e5b51
FC
2738 private static Encoding getEncoding(CommonTree rightNode)
2739 throws ParseException {
866e5b51
FC
2740
2741 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2742
2743 if (isUnaryString(firstChild)) {
2744 String strval = concatenateUnaryStrings(rightNode.getChildren());
2745
fafc36a7 2746 if (strval.equals(MetadataStrings.UTF8)) {
866e5b51 2747 return Encoding.UTF8;
fafc36a7 2748 } else if (strval.equals(MetadataStrings.ASCII)) {
866e5b51 2749 return Encoding.ASCII;
fafc36a7 2750 } else if (strval.equals(MetadataStrings.NONE)) {
866e5b51
FC
2751 return Encoding.NONE;
2752 } else {
2753 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2754 }
2755 }
2756 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2757 }
2758
2759 private static long getStreamID(CommonTree rightNode) throws ParseException {
866e5b51
FC
2760
2761 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2762
2763 if (isUnaryInteger(firstChild)) {
2764 if (rightNode.getChildCount() > 1) {
2765 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2766 }
2767
2768 long intval = parseUnaryInteger(firstChild);
2769
2770 return intval;
2771 }
2772 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2773 }
2774
2775 private static String getEventName(CommonTree rightNode)
2776 throws ParseException {
866e5b51
FC
2777
2778 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2779
4311ac8b 2780 if (isAnyUnaryString(firstChild)) {
866e5b51
FC
2781 String str = concatenateUnaryStrings(rightNode.getChildren());
2782
2783 return str;
2784 }
2785 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2786 }
2787
2788 private static long getEventID(CommonTree rightNode) throws ParseException {
866e5b51
FC
2789
2790 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2791
2792 if (isUnaryInteger(firstChild)) {
2793 if (rightNode.getChildCount() > 1) {
2794 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2795 }
2796
2797 long intval = parseUnaryInteger(firstChild);
6c7592e1
MK
2798 if (intval > Integer.MAX_VALUE) {
2799 throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$
2800 }
866e5b51
FC
2801 return intval;
2802 }
2803 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2804 }
2805
2806 /**
2807 * Concatenates a list of unary strings separated by arrows (->) or dots.
2808 *
2809 * @param strings
2810 * A list, first element being an unary string, subsequent
2811 * elements being ARROW or DOT nodes with unary strings as child.
2812 * @return The string representation of the unary string chain.
2813 */
2814 private static String concatenateUnaryStrings(List<CommonTree> strings) {
866e5b51
FC
2815
2816 StringBuilder sb = new StringBuilder();
2817
2818 CommonTree first = strings.get(0);
2819 sb.append(parseUnaryString(first));
2820
2821 boolean isFirst = true;
2822
2823 for (CommonTree ref : strings) {
2824 if (isFirst) {
2825 isFirst = false;
2826 continue;
2827 }
2828
866e5b51
FC
2829 CommonTree id = (CommonTree) ref.getChild(0);
2830
2831 if (ref.getType() == CTFParser.ARROW) {
2832 sb.append("->"); //$NON-NLS-1$
2833 } else { /* DOT */
2834 sb.append('.');
2835 }
2836
2837 sb.append(parseUnaryString(id));
2838 }
2839
2840 return sb.toString();
2841 }
2842
2843 /**
2844 * Throws a ParseException stating that the parent-child relation between
2845 * the given node and its parent is not valid. It means that the shape of
2846 * the AST is unexpected.
2847 *
2848 * @param child
2849 * The invalid child node.
4ed7d9c1 2850 * @return ParseException with details
866e5b51 2851 */
4ed7d9c1 2852 private static ParseException childTypeError(CommonTree child) {
866e5b51
FC
2853 CommonTree parent = (CommonTree) child.getParent();
2854 String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$
2855 + " can't have a child of type " //$NON-NLS-1$
2856 + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$
2857
4ed7d9c1 2858 return new ParseException(error);
866e5b51
FC
2859 }
2860
2861 // ------------------------------------------------------------------------
2862 // Scope management
2863 // ------------------------------------------------------------------------
2864
2865 /**
2866 * Adds a new declaration scope on the top of the scope stack.
2867 */
3ba65808 2868 private void pushScope(String name) {
8d90cd62 2869 fScope = new DeclarationScope(getCurrentScope(), name);
866e5b51
FC
2870 }
2871
2872 /**
2873 * Removes the top declaration scope from the scope stack.
2874 */
2875 private void popScope() {
8d90cd62 2876 fScope = getCurrentScope().getParentScope();
866e5b51
FC
2877 }
2878
3ba65808
MK
2879 private void pushNamedScope(@Nullable String name, String defaultName) {
2880 pushScope(name == null ? defaultName : name);
2881 }
2882
866e5b51
FC
2883 /**
2884 * Returns the current declaration scope.
2885 *
2886 * @return The current declaration scope.
2887 */
2888 private DeclarationScope getCurrentScope() {
9226cfc5 2889 return fScope;
866e5b51
FC
2890 }
2891
2892}
This page took 0.206995 seconds and 5 git commands to generate.