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