split
(Ljava/lang/String;I)[Ljava/lang/String;
(L1java/lang/String;I)[1L1java/lang/String;
+substring
+ (II)Ljava/lang/String;
+ (II)L1java/lang/String;
toString
()Ljava/lang/String;
()L1java/lang/String;
--- /dev/null
+class java/util/List
+subList
+ (II)Ljava/util/List<TE;>;
+ (II)L1java/util/List<TE;>;
--- /dev/null
+class java/util/UUID
+UUID
+ ([B)V
+ ([1B)V
+digits
+ (JI)Ljava/lang/String;
+ (JI)L1java/lang/String;
+fromString
+ (Ljava/lang/String;)Ljava/util/UUID;
+ (L1java/lang/String;)L1java/util/UUID;
+nameUUIDFromBytes
+ ([B)Ljava/util/UUID;
+ ([1B)L1java/util/UUID;
+randomUUID
+ ()Ljava/util/UUID;
+ ()L1java/util/UUID;
+toString
+ ()Ljava/lang/String;
+ ()L1java/lang/String;
--- /dev/null
+class org/antlr/runtime/tree/BaseTree
+getFirstChildWithType
+ (I)Lorg/antlr/runtime/tree/Tree;
+ (I)L0org/antlr/runtime/tree/Tree;
--- /dev/null
+class org/antlr/runtime/tree/CommonTree
+dupNode
+ ()Lorg/antlr/runtime/tree/Tree;
+ ()L1org/antlr/runtime/tree/Tree;
+getText
+ ()Ljava/lang/String;
+ ()L0java/lang/String;
\ No newline at end of file
import org.eclipse.tracecompass.ctf.core.trace.CTFStreamInput;
import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace;
import org.junit.Before;
import org.eclipse.tracecompass.ctf.core.tests.shared.CtfTestTraceUtils;
import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
import org.eclipse.tracecompass.ctf.core.trace.ICTFStream;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace;
import org.junit.Before;
import org.junit.Test;
+import com.google.common.collect.ImmutableMap;
+
/**
* The class <code>CTFTraceTest</code> contains tests for the class
* <code>{@link CTFTrace}</code>.
@Test
public void testLookupEnvironment_3() {
String key = "test";
- fixture.addEnvironmentVar(key, key);
+ fixture.setEnvironment(ImmutableMap.<String, String> of(key, key));
String result = fixture.getEnvironment().get(key);
assertNotNull(result);
- assertTrue(result.equals(key));
+ assertEquals(key, result);
}
/**
@Test
public void testLookupEnvironment_4() {
String key = "test";
- fixture.addEnvironmentVar(key, "bozo");
- fixture.addEnvironmentVar(key, "the clown");
+ fixture.setEnvironment(ImmutableMap.<String, String> of(key, "bozo"));
String result = fixture.getEnvironment().get(key);
assertNotNull(result);
}
org.eclipse.tracecompass.internal.ctf.core;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
org.eclipse.tracecompass.internal.ctf.core.event;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
org.eclipse.tracecompass.internal.ctf.core.event.metadata;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
- org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.enumeration;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.environment;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.floatingpoint;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.string;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.struct;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
+ org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.variant;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
org.eclipse.tracecompass.internal.ctf.core.event.types;x-friends:="org.eclipse.tracecompass.ctf.core.tests,org.eclipse.tracecompass.tmf.ctf.core,org.eclipse.tracecompass.tmf.ctf.core.tests",
org.eclipse.tracecompass.internal.ctf.core.event.types.composite;x-friends:="org.eclipse.tracecompass.ctf.core.tests",
org.eclipse.tracecompass.internal.ctf.core.trace;x-friends:="org.eclipse.tracecompass.ctf.core.tests"
import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
/**
* <b><u>DeclarationScope</u></b>
fChildren.put(scope.fName, scope);
scope.fParentScope = this;
}
+
+ @Override
+ public String toString() {
+ return "Scope : " + fName + " children: " + fChildren.size() + (fParentScope == null ? "" : (" parent " + fParentScope.fName)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
}
return fTable.add(low, high, label);
}
+ /**
+ * Add a value. Do not overlap, this is <em><strong>not</strong></em> an
+ * interval tree. This could be seen more as a collection of segments.
+ *
+ * @param label
+ * the name of the value.
+ * @return was the value be added? true == success
+ * @since 2.0
+ */
+ public boolean add(@Nullable String label) {
+ fLabels.add(label);
+ return fTable.add(label);
+ }
+
/**
* Check if the label for a value (enum a{day=0,night=1} would return "day"
* for query(0)
public EnumTable() {
}
+ public synchronized boolean add(@Nullable String label) {
+ LabelAndRange lastAdded = ranges.isEmpty() ? new LabelAndRange(-1, -1, "") : ranges.get(ranges.size() - 1); //$NON-NLS-1$
+ return add(lastAdded.low + 1, lastAdded.high + 1, label);
+ }
+
public synchronized boolean add(long low, long high, @Nullable String label) {
LabelAndRange newRange = new LabelAndRange(low, high, label);
import java.util.Set;
import java.util.UUID;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.core.CTFStrings;
import org.eclipse.tracecompass.ctf.core.event.CTFClock;
import org.eclipse.tracecompass.ctf.core.event.types.StructDefinition;
import org.eclipse.tracecompass.internal.ctf.core.SafeMappedByteBuffer;
import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
import org.eclipse.tracecompass.internal.ctf.core.trace.Utils;
+import com.google.common.collect.ImmutableMap;
+
/**
* A CTF trace on the file system.
*
/**
* Collection of environment variables set by the tracer
*/
- private final Map<String, String> fEnvironment = new HashMap<>();
+ private Map<String, String> fEnvironment = new HashMap<>();
/**
* Collection of all the clocks in a system.
return Collections.unmodifiableMap(fEnvironment);
}
- /**
- * Add a variable to the environment variables
- *
- * @param varName
- * the name of the variable
- * @param varValue
- * the value of the variable
- */
- public void addEnvironmentVar(String varName, String varValue) {
- fEnvironment.put(varName, varValue);
- }
-
/**
* Add a clock to the clock list
*
public StructDefinition getPacketHeaderDef() {
return fPacketHeaderDef;
}
+
+ /**
+ * Sets the environment map
+ *
+ * @param parseEnvironment
+ * The environment map
+ * @since 2.0
+ */
+ public void setEnvironment(@NonNull Map<String, String> parseEnvironment) {
+ fEnvironment = ImmutableMap.copyOf(parseEnvironment);
+ }
}
class MetadataFileFilter implements FileFilter {
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.RewriteCardinalityException;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.parser.CTFLexer;
import org.eclipse.tracecompass.ctf.parser.CTFParser;
import org.eclipse.tracecompass.ctf.parser.CTFParser.parse_return;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.CtfAntlrException;
import org.eclipse.tracecompass.internal.ctf.core.event.metadata.IOStructGen;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.CtfAntlrException;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
import org.eclipse.tracecompass.internal.ctf.core.trace.Utils;
/**
try (FileInputStream fis = new FileInputStream(getMetadataPath());
FileChannel metadataFileChannel = fis.getChannel();
/* Check if metadata is packet-based, if not it is text based */
- Reader metadataTextInput =
- (isPacketBased(metadataFileChannel) ?
- readBinaryMetaData(metadataFileChannel) :
- new FileReader(getMetadataPath()));) {
+ Reader metadataTextInput = (isPacketBased(metadataFileChannel) ? readBinaryMetaData(metadataFileChannel) : new FileReader(getMetadataPath()));) {
readMetaDataText(metadataTextInput);
}
/**
- * Executes a weak validation of the metadata. It checks if a file with
- * name metadata exists and if one of the following conditions are met:
- * - For text-only metadata, the file starts with "/* CTF" (without the quotes)
- * - For packet-based metadata, the file starts with correct magic number
+ * Executes a weak validation of the metadata. It checks if a file with name
+ * metadata exists and if one of the following conditions are met:
+ * <ul>
+ * <li>For text-only metadata, the file starts with "/* CTF" (without the
+ * quotes)</li>
+ * <li>For packet-based metadata, the file starts with correct magic number
+ * </li>
+ * </ul>
*
* @param path
* path to CTF trace directory
CommonTree tree = createAST(metadataTextInput);
/* Generate IO structures (declarations) */
- fTreeParser = new IOStructGen(tree, fTrace);
+ fTreeParser = new IOStructGen(tree, NonNullUtils.checkNotNull(fTrace));
fTreeParser.generate();
/* store locally in case of concurrent modification */
ByteOrder detectedByteOrder = getDetectedByteOrder();
*/
private MetadataPacketHeader readMetadataPacket(
FileChannel metadataFileChannel, StringBuffer metadataText)
- throws CTFException {
+ throws CTFException {
/* Allocate a ByteBuffer for the header */
ByteBuffer headerByteBuffer = ByteBuffer.allocate(METADATA_PACKET_HEADER_SIZE);
/**
* Copies the metadata file to a destination directory.
+ *
* @param path
- * the destination directory
+ * the destination directory
* @return the path to the target file
* @throws IOException
* if an error occurred
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
+
+/**
+ * Common tree parser with scopes
+ *
+ * @author Matthew Khouzam
+ *
+ */
+@NonNullByDefault
+public abstract class AbstractScopedCommonTreeParser implements ICommonTreeParser {
+
+ /**
+ * Register a declaration to the current scope
+ *
+ * @param declaration
+ * the declaration to register
+ * @param identifier
+ * the declaration's name
+ * @param scope the scope to register
+ * @throws ParseException
+ * if something already has that name
+ */
+ protected void registerType(IDeclaration declaration, String identifier , DeclarationScope scope) throws ParseException {
+ if (declaration instanceof EnumDeclaration) {
+ if (scope.lookupEnum(identifier) == null) {
+ scope.registerEnum(identifier, (EnumDeclaration) declaration);
+ }
+ } else if (declaration instanceof VariantDeclaration) {
+ scope.registerVariant(identifier, (VariantDeclaration) declaration);
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Montplaisir - Initial API and implementation
+ * Matthew Khouzam - Addition to have more descriptive errors
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata;
+
+import java.lang.reflect.Field;
+
+import org.antlr.runtime.MismatchedTokenException;
+import org.antlr.runtime.RecognitionException;
+import org.eclipse.tracecompass.ctf.core.CTFException;
+import org.eclipse.tracecompass.ctf.parser.CTFLexer;
+
+/**
+ * CTF Reader exception but dealing with Antlr-specific parsing problems.
+ *
+ * It is separated from the main {@link CTFException} - and is not part of the
+ * API - to isolate the Antlr-specific classes and avoid pushing that dependency
+ * to the users of this plugin.
+ *
+ * @author Matthew Khouzam
+ */
+public class CtfAntlrException extends CTFException {
+
+ private static final long serialVersionUID = -7078624493350073777L;
+
+ private final int fErrorLine;
+ private final String fFile;
+ private String fExpectingName = ""; //$NON-NLS-1$
+ private int fExpectedValue = -1;
+ private String fActualName = ""; //$NON-NLS-1$
+ private int fActualValue = -1;
+
+ private final int fCharPositionInLine;
+
+ /**
+ * Re-throw the exception but read its data
+ *
+ * @param e
+ * the previous recognition exception (Antlr specific)
+ */
+ public CtfAntlrException(MismatchedTokenException e) {
+ super(e);
+ fErrorLine = e.line;
+ fCharPositionInLine = e.charPositionInLine;
+ fFile = "metadata"; //$NON-NLS-1$ // we're in CTF, the only thing using antlr is metadata
+ parseMismatchedException(e);
+ }
+
+ /**
+ * Re-throw the exception but read its data
+ *
+ * @param e
+ * the previous recognition exception (Antlr specific)
+ */
+ public CtfAntlrException(RecognitionException e) {
+ super(e);
+ fErrorLine = e.line;
+ fCharPositionInLine = e.charPositionInLine;
+ fFile = "metadata"; //$NON-NLS-1$ // we're in CTF, the only thing using antlr is metadata
+ }
+
+ /**
+ * Re-throw the exception but read its data
+ *
+ * @param e
+ * the previous rewrite exception (Antlr specific)
+ */
+ public CtfAntlrException(Exception e) {
+ super(e);
+ fErrorLine = -1;
+ fCharPositionInLine = -1;
+ fFile = "metadata"; //$NON-NLS-1$ // we're in CTF, the only thing using antlr is metadata
+ }
+
+ private void parseMismatchedException(MismatchedTokenException m) {
+ // Iterate through the tokens that are hidden in the CTFLexer
+ // They are private static final int fields.
+ for (Field f : CTFLexer.class.getDeclaredFields()) {
+ f.setAccessible(true);
+ String name;
+ int value;
+ try {
+ name = f.getName();
+ final boolean isInt = (f.getType().isPrimitive());
+ if (isInt) {
+ value = ((Integer) f.get(null)).intValue();
+ if (value == m.expecting) {
+ this.fExpectingName = name;
+ this.fExpectedValue = value;
+ }
+ if (value == m.c) {
+ this.fActualName = name;
+ this.fActualValue = value;
+ }
+ }
+ } catch (NullPointerException e1) {
+ // Pokemon, gotta catch em all!
+ // actually useful since f may not have a
+ // value
+ } catch (IllegalArgumentException e1) {
+ // Catch these exceptions (reflexion)
+ } catch (IllegalAccessException e1) {
+ // Catch these exceptions (reflexion)
+ }
+ if (!this.fExpectingName.isEmpty() && !this.fActualName.isEmpty()) {
+ return;
+ }
+ }
+ }
+
+ @Override
+ public String getMessage() {
+ final String message = super.getMessage();
+ if (fErrorLine == -1) {
+ return message;
+ }
+ String expected = "" + this.fExpectedValue; //$NON-NLS-1$
+ String actual = "" + this.fActualValue; //$NON-NLS-1$
+ String newMessage = message.replaceAll(expected, this.fExpectingName);
+ newMessage = newMessage.replaceAll(actual, this.fActualName);
+ return newMessage + " at " + fFile + ":" + fErrorLine + ":" + fCharPositionInLine; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Common tree parser interface. Should only have one method
+ * {@link #parse(CommonTree, ICommonTreeParserParameter)}
+ *
+ * It is recommended to add to the javadoc on this inerface as it is not
+ * specific
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public interface ICommonTreeParser {
+
+ /**
+ * Parameter object to avoid passing "Object" as a parameter
+ * @author Matthew Khouzam
+ *
+ */
+ public interface ICommonTreeParserParameter{
+
+ }
+
+ /**
+ * The only parse method of the common tree parser. Caution must be used
+ * handling this as it can return any type and thus care must be used with
+ * the input and output.
+ *
+ *
+ * @param tree
+ * the common tree input
+ * @param param
+ * the parameter to pass (for lookups)
+ * @return the parsed data
+ * @throws ParseException
+ * if the tree or data is wrong
+ */
+ @NonNull
+ Object parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException;
+
+}
package org.eclipse.tracecompass.internal.ctf.core.event.metadata;
-import java.math.BigInteger;
-import java.nio.ByteOrder;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.UUID;
import org.antlr.runtime.tree.CommonTree;
-import org.antlr.runtime.tree.Tree;
-import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.tracecompass.ctf.core.CTFStrings;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.ctf.core.event.CTFClock;
import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
-import org.eclipse.tracecompass.ctf.core.event.types.Encoding;
-import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
-import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration.Pair;
-import org.eclipse.tracecompass.ctf.core.event.types.FloatDeclaration;
-import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
-import org.eclipse.tracecompass.ctf.core.event.types.IEventHeaderDeclaration;
-import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration;
-import org.eclipse.tracecompass.ctf.core.event.types.StringDeclaration;
-import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
-import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
-import org.eclipse.tracecompass.ctf.core.trace.ICTFStream;
import org.eclipse.tracecompass.ctf.parser.CTFParser;
-import org.eclipse.tracecompass.internal.ctf.core.Activator;
-import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
-import org.eclipse.tracecompass.internal.ctf.core.event.types.ArrayDeclaration;
-import org.eclipse.tracecompass.internal.ctf.core.event.types.SequenceDeclaration;
-import org.eclipse.tracecompass.internal.ctf.core.event.types.StructDeclarationFlattener;
-import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderCompactDeclaration;
-import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderLargeDeclaration;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.ClockParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeAliasParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypedefParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.environment.EnvironmentParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event.EventParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream.StreamParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace.TraceDeclarationParser;
import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
import com.google.common.collect.Iterables;
// Attributes
// ------------------------------------------------------------------------
- private static final @NonNull String MAP = "map"; //$NON-NLS-1$
- private static final @NonNull String ENCODING = "encoding"; //$NON-NLS-1$
- private static final @NonNull String BASE = "base"; //$NON-NLS-1$
- private static final @NonNull String SIZE = "size"; //$NON-NLS-1$
- private static final @NonNull String SIGNED = "signed"; //$NON-NLS-1$
- private static final @NonNull String EMPTY_STRING = ""; //$NON-NLS-1$
- private static final int INTEGER_BASE_16 = 16;
- private static final int INTEGER_BASE_10 = 10;
- private static final int INTEGER_BASE_8 = 8;
- private static final int INTEGER_BASE_2 = 2;
- private static final long DEFAULT_ALIGNMENT = 1;
- private static final int DEFAULT_FLOAT_EXPONENT = 8;
- private static final int DEFAULT_FLOAT_MANTISSA = 24;
- private static final int DEFAULT_INT_BASE = 10;
/**
* The trace
*/
- private final CTFTrace fTrace;
+ private final @NonNull CTFTrace fTrace;
private CommonTree fTree;
/**
* The current declaration scope.
*/
- private final DeclarationScope fRoot;
- private DeclarationScope fScope;
+ private final @NonNull DeclarationScope fRoot;
/**
* Data helpers needed for streaming
* @param trace
* the trace containing the places to put all the read metadata
*/
- public IOStructGen(CommonTree tree, CTFTrace trace) {
+ public IOStructGen(CommonTree tree, @NonNull CTFTrace trace) {
fTrace = trace;
fTree = tree;
- fRoot = trace.getScope();
- fScope = fRoot;
+ fRoot = NonNullUtils.checkNotNull(trace.getScope());
}
/**
CommonTree traceNode = null;
boolean hasStreams = false;
List<CommonTree> events = new ArrayList<>();
- resetScope();
for (CommonTree child : children) {
final int type = child.getType();
switch (type) {
parseTrace(traceNode);
break;
case CTFParser.STREAM:
- parseStream(child);
+ StreamParser.INSTANCE.parse(child, new StreamParser.Param(fTrace, fRoot));
hasStreams = true;
break;
case CTFParser.EVENT:
events.add(child);
break;
case CTFParser.CLOCK:
- parseClock(child);
+ CTFClock ctfClock = ClockParser.INSTANCE.parse(child, null);
+ String nameValue = ctfClock.getName();
+ fTrace.addClock(nameValue, ctfClock);
break;
case CTFParser.ENV:
- parseEnvironment(child);
+ fTrace.setEnvironment(EnvironmentParser.INSTANCE.parse(child, null));
break;
default:
throw childTypeError(child);
throw new ParseException("Missing trace block"); //$NON-NLS-1$
}
parseEvents(events, hasStreams);
- popScope();
fHasBeenParsed = true;
}
fTrace.addStream(new CTFStream(fTrace));
}
for (CommonTree event : events) {
- parseEvent(event);
+ EventParser.INSTANCE.parse(event, new EventParser.Param(fTrace, fRoot));
}
}
}
List<CommonTree> children = root.getChildren();
List<CommonTree> events = new ArrayList<>();
- resetScope();
for (CommonTree child : children) {
final int type = child.getType();
switch (type) {
case CTFParser.TRACE:
throw new ParseException("Trace block defined here, please use generate and not generateFragment to parse this fragment"); //$NON-NLS-1$
case CTFParser.STREAM:
- parseStream(child);
+ StreamParser.INSTANCE.parse(child, new StreamParser.Param(fTrace, fRoot));
break;
case CTFParser.EVENT:
events.add(child);
break;
case CTFParser.CLOCK:
- parseClock(child);
+ CTFClock ctfClock = ClockParser.INSTANCE.parse(child, null);
+ String nameValue = ctfClock.getName();
+ fTrace.addClock(nameValue, ctfClock);
break;
case CTFParser.ENV:
- parseEnvironment(child);
+ fTrace.setEnvironment(EnvironmentParser.INSTANCE.parse(child, null));
break;
default:
throw childTypeError(child);
}
}
parseEvents(events, !Iterables.isEmpty(fTrace.getStreams()));
- popScope();
- }
-
- private void resetScope() {
- fScope = fRoot;
- }
-
- private void parseEnvironment(CommonTree environment) {
- List<CommonTree> children = environment.getChildren();
- for (CommonTree child : children) {
- String left;
- String right;
- left = child.getChild(0).getChild(0).getChild(0).getText();
- right = child.getChild(1).getChild(0).getChild(0).getText();
- fTrace.addEnvironmentVar(left, right);
- }
- }
-
- private void parseClock(CommonTree clock) throws ParseException {
- List<CommonTree> children = clock.getChildren();
- CTFClock ctfClock = new CTFClock();
- for (CommonTree child : children) {
- final String key = child.getChild(0).getChild(0).getChild(0).getText();
- final CommonTree value = (CommonTree) child.getChild(1).getChild(0).getChild(0);
- final int type = value.getType();
- final String text = value.getText();
- switch (type) {
- case CTFParser.INTEGER:
- case CTFParser.DECIMAL_LITERAL:
- /*
- * Not a pretty hack, this is to make sure that there is no
- * number overflow due to 63 bit integers. The offset should
- * only really be an issue in the year 2262. the tracer in C/ASM
- * can write an offset in an unsigned 64 bit long. In java, the
- * last bit, being set to 1 will be read as a negative number,
- * but since it is too big a positive it will throw an
- * exception. this will happen in 2^63 ns from 1970. Therefore
- * 293 years from 1970
- */
- Long numValue;
- try {
- numValue = Long.parseLong(text);
- } catch (NumberFormatException e) {
- throw new ParseException("Number conversion issue with " + text, e); //$NON-NLS-1$
- }
- ctfClock.addAttribute(key, numValue);
- break;
- default:
- ctfClock.addAttribute(key, text);
- }
-
- }
- String nameValue = ctfClock.getName();
- fTrace.addClock(nameValue, ctfClock);
}
private void parseTrace(CommonTree traceNode) throws ParseException {
+ CTFTrace trace = fTrace;
List<CommonTree> children = traceNode.getChildren();
if (children == null) {
throw new ParseException("Trace block is empty"); //$NON-NLS-1$
}
- resetScope();
-
for (CommonTree child : children) {
switch (child.getType()) {
case CTFParser.TYPEALIAS:
- parseTypealias(child);
+ TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(trace, fRoot));
break;
case CTFParser.TYPEDEF:
- parseTypedef(child);
+ TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(trace, fRoot));
break;
case CTFParser.CTF_EXPRESSION_TYPE:
case CTFParser.CTF_EXPRESSION_VAL:
- parseTraceDeclaration(child);
+ TraceDeclarationParser.INSTANCE.parse(child, new TraceDeclarationParser.Param(fTrace, fRoot));
break;
default:
throw childTypeError(child);
}
}
- private void parseTraceDeclaration(CommonTree traceDecl)
- throws ParseException {
-
- /* There should be a left and right */
-
- CommonTree leftNode = (CommonTree) traceDecl.getChild(0);
- CommonTree rightNode = (CommonTree) traceDecl.getChild(1);
-
- List<CommonTree> leftStrings = leftNode.getChildren();
-
- if (!isAnyUnaryString(leftStrings.get(0))) {
- throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
- }
-
- String left = concatenateUnaryStrings(leftStrings);
-
- if (left.equals(MetadataStrings.MAJOR)) {
- if (fTrace.majorIsSet()) {
- throw new ParseException("major is already set"); //$NON-NLS-1$
- }
-
- fTrace.setMajor(getMajorOrMinor(rightNode));
- } else if (left.equals(MetadataStrings.MINOR)) {
- if (fTrace.minorIsSet()) {
- throw new ParseException("minor is already set"); //$NON-NLS-1$
- }
-
- fTrace.setMinor(getMajorOrMinor(rightNode));
- } else if (left.equals(MetadataStrings.UUID_STRING)) {
- UUID uuid = getUUID(rightNode);
-
- /*
- * If uuid was already set by a metadata packet, compare it to see
- * if it matches
- */
- if (fTrace.uuidIsSet()) {
- if (fTrace.getUUID().compareTo(uuid) != 0) {
- throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
- + fTrace.getUUID() + " but metadata says " + uuid); //$NON-NLS-1$
- }
- } else {
- fTrace.setUUID(uuid);
- }
-
- } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
- ByteOrder byteOrder = getByteOrder(rightNode);
-
- /*
- * If byte order was already set by a metadata packet, compare it to
- * see if it matches
- */
- if (fTrace.getByteOrder() != null) {
- if (fTrace.getByteOrder() != byteOrder) {
- throw new ParseException(
- "Endianness mismatch. Magic number says " //$NON-NLS-1$
- + fTrace.getByteOrder()
- + " but metadata says " + byteOrder); //$NON-NLS-1$
- }
- } else {
- fTrace.setByteOrder(byteOrder);
-
- final DeclarationScope currentScope = getCurrentScope();
- for (String type : currentScope.getTypeNames()) {
- IDeclaration d = currentScope.lookupType(type);
- if (d instanceof IntegerDeclaration) {
- addByteOrder(byteOrder, currentScope, type, (IntegerDeclaration) d);
- } else if (d instanceof FloatDeclaration) {
- addByteOrder(byteOrder, currentScope, type, (FloatDeclaration) d);
- } else if (d instanceof EnumDeclaration) {
- addByteOrder(byteOrder, currentScope, type, (EnumDeclaration) d);
- } else if (d instanceof StructDeclaration) {
- setAlign(currentScope, (StructDeclaration) d, byteOrder);
- }
- }
- }
- } else if (left.equals(MetadataStrings.PACKET_HEADER)) {
- if (fTrace.packetHeaderIsSet()) {
- throw new ParseException("packet.header already defined"); //$NON-NLS-1$
- }
-
- CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
-
- if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
- throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
- }
-
- IDeclaration packetHeaderDecl = parseTypeSpecifierList(typeSpecifier);
-
- if (!(packetHeaderDecl instanceof StructDeclaration)) {
- throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
- }
-
- fTrace.setPacketHeader((StructDeclaration) packetHeaderDecl);
- } else {
- Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownTraceAttributeWarning + " " + left); //$NON-NLS-1$
- }
- }
-
- private static void addByteOrder(ByteOrder byteOrder,
- final DeclarationScope parentScope, String name,
- IntegerDeclaration decl) throws ParseException {
-
- if (!decl.isByteOrderSet()) {
- IntegerDeclaration newI;
- newI = IntegerDeclaration.createDeclaration(decl.getLength(), decl.isSigned(),
- decl.getBase(), byteOrder, decl.getEncoding(),
- decl.getClock(), decl.getAlignment());
- parentScope.replaceType(name, newI);
- }
- }
-
- private static void addByteOrder(ByteOrder byteOrder, DeclarationScope parentScope, String name, EnumDeclaration decl) throws ParseException {
- final IntegerDeclaration containerType = decl.getContainerType();
- if (!decl.isByteOrderSet()) {
- EnumDeclaration newEnum = new EnumDeclaration(IntegerDeclaration.createDeclaration(containerType.getLength(), containerType.isSigned(),
- containerType.getBase(), byteOrder, containerType.getEncoding(),
- containerType.getClock(), containerType.getAlignment()));
- for (Entry<String, Pair> entry : decl.getEnumTable().entrySet()) {
- newEnum.add(entry.getValue().getFirst(), entry.getValue().getSecond(), entry.getKey());
- }
-
- parentScope.replaceType(name, newEnum);
- }
- }
-
- private static void addByteOrder(ByteOrder byteOrder, DeclarationScope parentScope, String name, FloatDeclaration decl) throws ParseException {
- if (!decl.isByteOrderSet()) {
- FloatDeclaration newFloat = new FloatDeclaration(decl.getExponent(), decl.getMantissa(), byteOrder, decl.getAlignment());
- parentScope.replaceType(name, newFloat);
- }
- }
-
- private void setAlign(DeclarationScope parentScope, StructDeclaration sd,
- ByteOrder byteOrder) throws ParseException {
-
- for (String s : sd.getFieldsList()) {
- IDeclaration d = sd.getField(s);
-
- if (d instanceof StructDeclaration) {
- setAlign(parentScope, (StructDeclaration) d, byteOrder);
-
- } else if (d instanceof VariantDeclaration) {
- setAlign(parentScope, (VariantDeclaration) d, byteOrder);
- } else if (d instanceof IntegerDeclaration) {
- IntegerDeclaration decl = (IntegerDeclaration) d;
- if (decl.getByteOrder() != byteOrder) {
- IntegerDeclaration newI;
- newI = IntegerDeclaration.createDeclaration(decl.getLength(),
- decl.isSigned(), decl.getBase(), byteOrder,
- decl.getEncoding(), decl.getClock(),
- decl.getAlignment());
- sd.getFields().put(s, newI);
- }
- }
- }
- }
-
- private void setAlign(DeclarationScope parentScope, VariantDeclaration vd,
- ByteOrder byteOrder) throws ParseException {
-
- for (String s : vd.getFields().keySet()) {
- IDeclaration d = vd.getFields().get(s);
-
- if (d instanceof StructDeclaration) {
- setAlign(parentScope, (StructDeclaration) d, byteOrder);
-
- } else if (d instanceof IntegerDeclaration) {
- IntegerDeclaration decl = (IntegerDeclaration) d;
- IntegerDeclaration newI;
- newI = IntegerDeclaration.createDeclaration(decl.getLength(),
- decl.isSigned(), decl.getBase(), byteOrder,
- decl.getEncoding(), decl.getClock(),
- decl.getAlignment());
- vd.getFields().put(s, newI);
- }
- }
- }
-
- private void parseStream(CommonTree streamNode) throws ParseException {
-
- CTFStream stream = new CTFStream(fTrace);
-
- List<CommonTree> children = streamNode.getChildren();
- if (children == null) {
- throw new ParseException("Empty stream block"); //$NON-NLS-1$
- }
-
- pushScope(MetadataStrings.STREAM);
-
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.TYPEALIAS:
- parseTypealias(child);
- break;
- case CTFParser.TYPEDEF:
- parseTypedef(child);
- break;
- case CTFParser.CTF_EXPRESSION_TYPE:
- case CTFParser.CTF_EXPRESSION_VAL:
- parseStreamDeclaration(child, stream);
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- if (stream.isIdSet() &&
- (!fTrace.packetHeaderIsSet() || !fTrace.getPacketHeader().hasField(MetadataStrings.STREAM_ID))) {
- throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
- }
-
- fTrace.addStream(stream);
-
- popScope();
- }
-
- private void parseStreamDeclaration(CommonTree streamDecl, CTFStream stream)
- throws ParseException {
-
- /* There should be a left and right */
-
- CommonTree leftNode = (CommonTree) streamDecl.getChild(0);
- CommonTree rightNode = (CommonTree) streamDecl.getChild(1);
-
- List<CommonTree> leftStrings = leftNode.getChildren();
-
- if (!isAnyUnaryString(leftStrings.get(0))) {
- throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
- }
-
- String left = concatenateUnaryStrings(leftStrings);
-
- if (left.equals(MetadataStrings.ID)) {
- if (stream.isIdSet()) {
- throw new ParseException("stream id already defined"); //$NON-NLS-1$
- }
-
- long streamID = getStreamID(rightNode);
-
- stream.setId(streamID);
- } else if (left.equals(MetadataStrings.EVENT_HEADER)) {
- if (stream.isEventHeaderSet()) {
- throw new ParseException("event.header already defined"); //$NON-NLS-1$
- }
-
- CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
-
- if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
- throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$
- }
-
- IDeclaration eventHeaderDecl = parseTypeSpecifierList(typeSpecifier);
- DeclarationScope scope = getCurrentScope();
- DeclarationScope eventHeaderScope = lookupStructName(typeSpecifier, scope);
- if (eventHeaderScope == null) {
- throw new ParseException("event.header scope not found"); //$NON-NLS-1$
- }
- pushScope(MetadataStrings.EVENT);
- getCurrentScope().addChild(eventHeaderScope);
- eventHeaderScope.setName(CTFStrings.HEADER);
- popScope();
- if (eventHeaderDecl instanceof StructDeclaration) {
- stream.setEventHeader((StructDeclaration) eventHeaderDecl);
- } else if (eventHeaderDecl instanceof IEventHeaderDeclaration) {
- stream.setEventHeader((IEventHeaderDeclaration) eventHeaderDecl);
- } else {
- throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
- }
-
- } else if (left.equals(MetadataStrings.EVENT_CONTEXT)) {
- if (stream.isEventContextSet()) {
- throw new ParseException("event.context already defined"); //$NON-NLS-1$
- }
-
- CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
-
- if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
- throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$
- }
-
- IDeclaration eventContextDecl = parseTypeSpecifierList(typeSpecifier);
-
- if (!(eventContextDecl instanceof StructDeclaration)) {
- throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
- }
-
- stream.setEventContext((StructDeclaration) eventContextDecl);
- } else if (left.equals(MetadataStrings.PACKET_CONTEXT)) {
- if (stream.isPacketContextSet()) {
- throw new ParseException("packet.context already defined"); //$NON-NLS-1$
- }
-
- CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
-
- if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
- throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$
- }
-
- IDeclaration packetContextDecl = parseTypeSpecifierList(typeSpecifier);
-
- if (!(packetContextDecl instanceof StructDeclaration)) {
- throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
- }
-
- stream.setPacketContext((StructDeclaration) packetContextDecl);
- } else {
- Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownStreamAttributeWarning + " " + left); //$NON-NLS-1$
- }
- }
-
- private static DeclarationScope lookupStructName(CommonTree typeSpecifier, DeclarationScope scope) {
- /*
- * This needs a struct.struct_name.name to work, luckily, that is 99.99%
- * of traces we receive.
- */
- final Tree potentialStruct = typeSpecifier.getChild(0);
- DeclarationScope eventHeaderScope = null;
- if (potentialStruct.getType() == (CTFParser.STRUCT)) {
- final Tree potentialStructName = potentialStruct.getChild(0);
- if (potentialStructName.getType() == (CTFParser.STRUCT_NAME)) {
- final String name = potentialStructName.getChild(0).getText();
- eventHeaderScope = scope.lookupChildRecursive(name);
- }
- }
- /*
- * If that fails, maybe the struct is anonymous
- */
- if (eventHeaderScope == null) {
- eventHeaderScope = scope.lookupChildRecursive(MetadataStrings.STRUCT);
- }
- /*
- * This can still be null
- */
- return eventHeaderScope;
- }
-
- private void parseEvent(CommonTree eventNode) throws ParseException {
-
- List<CommonTree> children = eventNode.getChildren();
- if (children == null) {
- throw new ParseException("Empty event block"); //$NON-NLS-1$
- }
-
- EventDeclaration event = new EventDeclaration();
-
- pushScope(MetadataStrings.EVENT);
-
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.TYPEALIAS:
- parseTypealias(child);
- break;
- case CTFParser.TYPEDEF:
- parseTypedef(child);
- break;
- case CTFParser.CTF_EXPRESSION_TYPE:
- case CTFParser.CTF_EXPRESSION_VAL:
- parseEventDeclaration(child, event);
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- if (!event.nameIsSet()) {
- throw new ParseException("Event name not set"); //$NON-NLS-1$
- }
-
- /*
- * If the event did not specify a stream, then the trace must be single
- * stream
- */
- if (!event.streamIsSet()) {
- if (fTrace.nbStreams() > 1) {
- throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$
- }
-
- /*
- * If the event did not specify a stream, the only existing stream
- * must not have an id. Note: That behavior could be changed, it
- * could be possible to just get the only existing stream, whatever
- * is its id.
- */
- ICTFStream iStream = fTrace.getStream(null);
- if (iStream instanceof CTFStream) {
-
- CTFStream ctfStream = (CTFStream) iStream;
- event.setStream(ctfStream);
- } else {
- throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
- }
- }
-
- /*
- * Add the event to the stream.
- */
- event.getStream().addEvent(event);
-
- popScope();
-
- }
-
- private void parseEventDeclaration(CommonTree eventDecl,
- EventDeclaration event) throws ParseException {
-
- /* There should be a left and right */
-
- CommonTree leftNode = (CommonTree) eventDecl.getChild(0);
- CommonTree rightNode = (CommonTree) eventDecl.getChild(1);
-
- List<CommonTree> leftStrings = leftNode.getChildren();
-
- if (!isAnyUnaryString(leftStrings.get(0))) {
- throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
- }
-
- String left = concatenateUnaryStrings(leftStrings);
-
- if (left.equals(MetadataStrings.NAME2)) {
- if (event.nameIsSet()) {
- throw new ParseException("name already defined"); //$NON-NLS-1$
- }
-
- String name = getEventName(rightNode);
-
- event.setName(name);
- } else if (left.equals(MetadataStrings.ID)) {
- if (event.idIsSet()) {
- throw new ParseException("id already defined"); //$NON-NLS-1$
- }
-
- long id = getEventID(rightNode);
- if (id > Integer.MAX_VALUE) {
- throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id); //$NON-NLS-1$
- }
- if (id < 0) {
- throw new ParseException("negative id, unsupported. id : " + id); //$NON-NLS-1$
- }
- event.setId((int) id);
- } else if (left.equals(MetadataStrings.STREAM_ID)) {
- if (event.streamIsSet()) {
- throw new ParseException("stream id already defined"); //$NON-NLS-1$
- }
-
- long streamId = getStreamID(rightNode);
-
- ICTFStream iStream = fTrace.getStream(streamId);
-
- if (iStream instanceof CTFStream) {
- CTFStream stream = (CTFStream) iStream;
- event.setStream(stream);
- } else {
- throw new ParseException("Stream " + streamId + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- } else if (left.equals(MetadataStrings.CONTEXT)) {
- if (event.contextIsSet()) {
- throw new ParseException("context already defined"); //$NON-NLS-1$
- }
-
- CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
-
- if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
- throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
- }
-
- IDeclaration contextDecl = parseTypeSpecifierList(typeSpecifier);
-
- if (!(contextDecl instanceof StructDeclaration)) {
- throw new ParseException("context expects a struct"); //$NON-NLS-1$
- }
-
- event.setContext((StructDeclaration) contextDecl);
- } else if (left.equals(MetadataStrings.FIELDS_STRING)) {
- if (event.fieldsIsSet()) {
- throw new ParseException("fields already defined"); //$NON-NLS-1$
- }
-
- CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
-
- if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
- throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
- }
-
- IDeclaration fieldsDecl;
- fieldsDecl = parseTypeSpecifierList(typeSpecifier);
-
- if (!(fieldsDecl instanceof StructDeclaration)) {
- throw new ParseException("fields expects a struct"); //$NON-NLS-1$
- }
- /*
- * The underscores in the event names. These underscores were added
- * by the LTTng tracer.
- */
- final StructDeclaration fields = (StructDeclaration) fieldsDecl;
- event.setFields(fields);
- } else if (left.equals(MetadataStrings.LOGLEVEL2)) {
- long logLevel = parseUnaryInteger((CommonTree) rightNode.getChild(0));
- event.setLogLevel(logLevel);
- } else {
- /* Custom event attribute, we'll add it to the attributes map */
- String right = parseUnaryString((CommonTree) rightNode.getChild(0));
- event.setCustomAttribute(left, right);
- }
- }
-
/**
* Parses a declaration at the root level.
*
for (CommonTree child : children) {
switch (child.getType()) {
case CTFParser.TYPEDEF:
- parseTypedef(child);
+ TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(fTrace, fRoot));
break;
case CTFParser.TYPEALIAS:
- parseTypealias(child);
+ TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(fTrace, fRoot));
break;
case CTFParser.TYPE_SPECIFIER_LIST:
- parseTypeSpecifierList(child);
+ TypeSpecifierListParser.INSTANCE.parse(child, new TypeSpecifierListParser.Param(fTrace, null, null, fRoot));
break;
default:
throw childTypeError(child);
}
/**
- * Parses a typealias node. It parses the target, the alias, and registers
- * the type in the current scope.
+ * Throws a ParseException stating that the parent-child relation between
+ * the given node and its parent is not valid. It means that the shape of
+ * the AST is unexpected.
*
- * @param typealias
- * A TYPEALIAS node.
- * @throws ParseException
+ * @param child
+ * The invalid child node.
+ * @return ParseException with details
*/
- private void parseTypealias(CommonTree typealias) throws ParseException {
-
- List<CommonTree> children = typealias.getChildren();
-
- CommonTree target = null;
- CommonTree alias = null;
-
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.TYPEALIAS_TARGET:
- target = child;
- break;
- case CTFParser.TYPEALIAS_ALIAS:
- alias = child;
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- IDeclaration targetDeclaration = parseTypealiasTarget(target);
-
- if ((targetDeclaration instanceof VariantDeclaration)
- && ((VariantDeclaration) targetDeclaration).isTagged()) {
- throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
- }
-
- String aliasString = parseTypealiasAlias(alias);
-
- getCurrentScope().registerType(aliasString, targetDeclaration);
- }
-
- /**
- * Parses the target part of a typealias and gets the corresponding
- * declaration.
- *
- * @param target
- * A TYPEALIAS_TARGET node.
- * @return The corresponding declaration.
- * @throws ParseException
- */
- private IDeclaration parseTypealiasTarget(CommonTree target)
- throws ParseException {
-
- List<CommonTree> children = target.getChildren();
-
- CommonTree typeSpecifierList = null;
- CommonTree typeDeclaratorList = null;
- CommonTree typeDeclarator = null;
- StringBuilder identifierSB = new StringBuilder();
-
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.TYPE_SPECIFIER_LIST:
- typeSpecifierList = child;
- break;
- case CTFParser.TYPE_DECLARATOR_LIST:
- typeDeclaratorList = child;
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- if (typeDeclaratorList != null) {
- /*
- * Only allow one declarator
- *
- * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
- * otherwise the new type puint8_t would maps to two different
- * types.
- */
- if (typeDeclaratorList.getChildCount() != 1) {
- throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
- }
-
- typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
- }
-
- /* Parse the target type and get the declaration */
- IDeclaration targetDeclaration = parseTypeDeclarator(typeDeclarator,
- typeSpecifierList, identifierSB);
-
- /*
- * We don't allow identifier in the target
- *
- * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
- * permitted
- */
- if (identifierSB.length() > 0) {
- throw new ParseException("Identifier (" + identifierSB.toString() //$NON-NLS-1$
- + ") not expected in the typealias target"); //$NON-NLS-1$
- }
-
- return targetDeclaration;
- }
-
- /**
- * Parses the alias part of a typealias. It parses the underlying specifier
- * list and declarator and creates the string representation that will be
- * used to register the type.
- *
- * @param alias
- * A TYPEALIAS_ALIAS node.
- * @return The string representation of the alias.
- * @throws ParseException
- */
- private static String parseTypealiasAlias(CommonTree alias)
- throws ParseException {
-
- List<CommonTree> children = alias.getChildren();
-
- CommonTree typeSpecifierList = null;
- CommonTree typeDeclaratorList = null;
- CommonTree typeDeclarator = null;
- List<CommonTree> pointers = new LinkedList<>();
-
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.TYPE_SPECIFIER_LIST:
- typeSpecifierList = child;
- break;
- case CTFParser.TYPE_DECLARATOR_LIST:
- typeDeclaratorList = child;
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- /* If there is a type declarator list, extract the pointers */
- if (typeDeclaratorList != null) {
- /*
- * Only allow one declarator
- *
- * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
- */
- if (typeDeclaratorList.getChildCount() != 1) {
- throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
- }
-
- typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
-
- List<CommonTree> typeDeclaratorChildren = typeDeclarator.getChildren();
-
- for (CommonTree child : typeDeclaratorChildren) {
- switch (child.getType()) {
- case CTFParser.POINTER:
- pointers.add(child);
- break;
- case CTFParser.IDENTIFIER:
- throw new ParseException("Identifier (" + child.getText() //$NON-NLS-1$
- + ") not expected in the typealias target"); //$NON-NLS-1$
- default:
- throw childTypeError(child);
- }
- }
- }
-
- return createTypeDeclarationString(typeSpecifierList, pointers);
- }
-
- /**
- * Parses a typedef node. This creates and registers a new declaration for
- * each declarator found in the typedef.
- *
- * @param typedef
- * A TYPEDEF node.
- * @return map of type name to type declaration
- * @throws ParseException
- * If there is an error creating the declaration.
- */
- private Map<String, IDeclaration> parseTypedef(CommonTree typedef) throws ParseException {
-
- CommonTree typeDeclaratorListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
-
- CommonTree typeSpecifierListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
-
- List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
-
- Map<String, IDeclaration> declarations = new HashMap<>();
-
- for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
- StringBuilder identifierSB = new StringBuilder();
-
- IDeclaration typeDeclaration = parseTypeDeclarator(
- typeDeclaratorNode, typeSpecifierListNode, identifierSB);
-
- if ((typeDeclaration instanceof VariantDeclaration)
- && !((VariantDeclaration) typeDeclaration).isTagged()) {
- throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
- }
-
- getCurrentScope().registerType(identifierSB.toString(),
- typeDeclaration);
-
- declarations.put(identifierSB.toString(), typeDeclaration);
- }
- return declarations;
- }
-
- /**
- * Parses a pair type declarator / type specifier list and returns the
- * corresponding declaration. If it is present, it also writes the
- * identifier of the declarator in the given {@link StringBuilder}.
- *
- * @param typeDeclarator
- * A TYPE_DECLARATOR node.
- * @param typeSpecifierList
- * A TYPE_SPECIFIER_LIST node.
- * @param identifierSB
- * A StringBuilder that will receive the identifier found in the
- * declarator.
- * @return The corresponding declaration.
- * @throws ParseException
- * If there is an error finding or creating the declaration.
- */
- private IDeclaration parseTypeDeclarator(CommonTree typeDeclarator,
- CommonTree typeSpecifierList, StringBuilder identifierSB)
- throws ParseException {
-
- IDeclaration declaration = null;
- List<CommonTree> children = null;
- List<CommonTree> pointers = new LinkedList<>();
- List<CommonTree> lengths = new LinkedList<>();
- CommonTree identifier = null;
-
- /* Separate the tokens by type */
- if (typeDeclarator != null) {
- children = typeDeclarator.getChildren();
- for (CommonTree child : children) {
-
- switch (child.getType()) {
- case CTFParser.POINTER:
- pointers.add(child);
- break;
- case CTFParser.IDENTIFIER:
- identifier = child;
- break;
- case CTFParser.LENGTH:
- lengths.add(child);
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- }
-
- /*
- * Parse the type specifier list, which is the "base" type. For example,
- * it would be int in int a[3][len].
- */
- declaration = parseTypeSpecifierList(typeSpecifierList, pointers, identifier);
-
- /*
- * Each length subscript means that we must create a nested array or
- * sequence. For example, int a[3][len] means that we have an array of 3
- * (sequences of length 'len' of (int)).
- */
- if (!lengths.isEmpty()) {
- /* We begin at the end */
- Collections.reverse(lengths);
-
- for (CommonTree length : lengths) {
- /*
- * By looking at the first expression, we can determine whether
- * it is an array or a sequence.
- */
- List<CommonTree> lengthChildren = length.getChildren();
-
- CommonTree first = lengthChildren.get(0);
- if (isUnaryInteger(first)) {
- /* Array */
- int arrayLength = (int) parseUnaryInteger(first);
-
- if (arrayLength < 1) {
- throw new ParseException("Array length is negative"); //$NON-NLS-1$
- }
-
- /* Create the array declaration. */
- declaration = new ArrayDeclaration(arrayLength, declaration);
- } else if (isAnyUnaryString(first)) {
- /* Sequence */
- String lengthName = concatenateUnaryStrings(lengthChildren);
-
- /* check that lengthName was declared */
- if (isSignedIntegerField(lengthName)) {
- throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
- }
- /* Create the sequence declaration. */
- declaration = new SequenceDeclaration(lengthName,
- declaration);
- } else if (isTrace(first)) {
- /* Sequence */
- String lengthName = parseTraceScope(lengthChildren);
-
- /* check that lengthName was declared */
- if (isSignedIntegerField(lengthName)) {
- throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
- }
- /* Create the sequence declaration. */
- declaration = new SequenceDeclaration(lengthName,
- declaration);
-
- } else if (isStream(first)) {
- /* Sequence */
- String lengthName = parseStreamScope(lengthChildren);
-
- /* check that lengthName was declared */
- if (isSignedIntegerField(lengthName)) {
- throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
- }
- /* Create the sequence declaration. */
- declaration = new SequenceDeclaration(lengthName,
- declaration);
- } else if (isEvent(first)) {
- /* Sequence */
- String lengthName = parseEventScope(lengthChildren);
-
- /* check that lengthName was declared */
- if (isSignedIntegerField(lengthName)) {
- throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
- }
- /* Create the sequence declaration. */
- declaration = new SequenceDeclaration(lengthName,
- declaration);
- } else {
- throw childTypeError(first);
- }
- }
- }
-
- if (identifier != null) {
- final String text = identifier.getText();
- identifierSB.append(text);
- registerType(declaration, text);
- }
-
- return declaration;
- }
-
- private void registerType(IDeclaration declaration, String identifier) throws ParseException {
- final DeclarationScope currentScope = getCurrentScope();
- if (declaration instanceof EnumDeclaration) {
- if (currentScope.lookupEnum(identifier) == null) {
- currentScope.registerEnum(identifier, (EnumDeclaration) declaration);
- }
- } else if (declaration instanceof VariantDeclaration) {
- currentScope.registerVariant(identifier, (VariantDeclaration) declaration);
- }
- }
-
- private static String parseStreamScope(List<CommonTree> lengthChildren) throws ParseException {
- List<CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size());
-
- CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
- String lengthName = null;
- if (isUnaryString(nextElem)) {
- lengthName = parseUnaryString(nextElem);
- }
-
- int type = nextElem.getType();
- if ((CTFParser.tokenNames[CTFParser.EVENT]).equals(lengthName)) {
- type = CTFParser.EVENT;
- }
- switch (type) {
- case CTFParser.IDENTIFIER:
- lengthName = concatenateUnaryStrings(sublist);
- break;
- case CTFParser.EVENT:
- lengthName = parseEventScope(sublist);
- break;
- default:
- if (lengthName == null) {
- throw new ParseException("Unsupported scope stream." + nextElem); //$NON-NLS-1$
- }
- }
- return MetadataStrings.STREAM + '.' + lengthName;
- }
-
- private static String parseEventScope(List<CommonTree> lengthChildren) throws ParseException {
- CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
- String lengthName;
- switch (nextElem.getType()) {
- case CTFParser.UNARY_EXPRESSION_STRING:
- case CTFParser.IDENTIFIER:
- List<CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size());
- lengthName = MetadataStrings.EVENT + '.' + concatenateUnaryStrings(sublist);
- break;
- default:
- throw new ParseException("Unsupported scope event." + nextElem); //$NON-NLS-1$
- }
- return lengthName;
- }
-
- private static String parseTraceScope(List<CommonTree> lengthChildren) throws ParseException {
- CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
- String lengthName;
- switch (nextElem.getType()) {
- case CTFParser.IDENTIFIER:
- lengthName = concatenateUnaryStrings(lengthChildren.subList(1, lengthChildren.size()));
- break;
- case CTFParser.STREAM:
- return parseStreamScope(lengthChildren.subList(1, lengthChildren.size()));
- default:
- throw new ParseException("Unsupported scope trace." + nextElem); //$NON-NLS-1$
- }
- return lengthName;
- }
-
- private static boolean isEvent(CommonTree first) {
- return first.getType() == CTFParser.EVENT;
- }
-
- private static boolean isStream(CommonTree first) {
- return first.getType() == CTFParser.STREAM;
- }
-
- private static boolean isTrace(CommonTree first) {
- return first.getType() == CTFParser.TRACE;
- }
-
- private boolean isSignedIntegerField(String lengthName) throws ParseException {
- IDeclaration decl = getCurrentScope().lookupIdentifierRecursive(lengthName);
- if (decl instanceof IntegerDeclaration) {
- return ((IntegerDeclaration) decl).isSigned();
- }
- throw new ParseException("Is not an integer: " + lengthName); //$NON-NLS-1$
-
- }
-
- private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList) throws ParseException {
- return parseTypeSpecifierList(typeSpecifierList, null, null);
- }
-
- /**
- * Parses a type specifier list and returns the corresponding declaration.
- *
- * @param typeSpecifierList
- * A TYPE_SPECIFIER_LIST node.
- * @param pointerList
- * A list of POINTER nodes that apply to the specified type.
- * @return The corresponding declaration.
- * @throws ParseException
- * If the type has not been defined or if there is an error
- * creating the declaration.
- */
- private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList,
- List<CommonTree> pointerList, CommonTree identifier) throws ParseException {
- IDeclaration declaration = null;
-
- /*
- * By looking at the first element of the type specifier list, we can
- * determine which type it belongs to.
- */
- CommonTree firstChild = (CommonTree) typeSpecifierList.getChild(0);
-
- switch (firstChild.getType()) {
- case CTFParser.FLOATING_POINT:
- declaration = parseFloat(firstChild);
- break;
- case CTFParser.INTEGER:
- declaration = parseInteger(firstChild);
- break;
- case CTFParser.STRING:
- declaration = parseString(firstChild);
- break;
- case CTFParser.STRUCT:
- declaration = parseStruct(firstChild, identifier);
- StructDeclaration structDeclaration = (StructDeclaration) declaration;
- IDeclaration idEnumDecl = structDeclaration.getFields().get("id"); //$NON-NLS-1$
- if (idEnumDecl instanceof EnumDeclaration) {
- EnumDeclaration enumDeclaration = (EnumDeclaration) idEnumDecl;
- ByteOrder bo = enumDeclaration.getContainerType().getByteOrder();
- if (EventHeaderCompactDeclaration.getEventHeader(bo).isCompactEventHeader(structDeclaration)) {
- declaration = EventHeaderCompactDeclaration.getEventHeader(bo);
- } else if (EventHeaderLargeDeclaration.getEventHeader(bo).isLargeEventHeader(structDeclaration)) {
- declaration = EventHeaderLargeDeclaration.getEventHeader(bo);
- }
- }
- break;
- case CTFParser.VARIANT:
- declaration = parseVariant(firstChild);
- break;
- case CTFParser.ENUM:
- declaration = parseEnum(firstChild);
- break;
- case CTFParser.IDENTIFIER:
- case CTFParser.FLOATTOK:
- case CTFParser.INTTOK:
- case CTFParser.LONGTOK:
- case CTFParser.SHORTTOK:
- case CTFParser.SIGNEDTOK:
- case CTFParser.UNSIGNEDTOK:
- case CTFParser.CHARTOK:
- case CTFParser.DOUBLETOK:
- case CTFParser.VOIDTOK:
- case CTFParser.BOOLTOK:
- case CTFParser.COMPLEXTOK:
- case CTFParser.IMAGINARYTOK:
- declaration = parseTypeDeclaration(typeSpecifierList, pointerList);
- break;
- default:
- throw childTypeError(firstChild);
- }
-
- return declaration;
- }
-
- private IDeclaration parseFloat(CommonTree floatingPoint)
- throws ParseException {
-
- List<CommonTree> children = floatingPoint.getChildren();
-
- /*
- * If the integer has no attributes, then it is missing the size
- * attribute which is required
- */
- if (children == null) {
- throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
- }
-
- /* The return value */
- FloatDeclaration floatDeclaration = null;
- ByteOrder byteOrder = fTrace.getByteOrder();
- long alignment = 0;
-
- int exponent = DEFAULT_FLOAT_EXPONENT;
- int mantissa = DEFAULT_FLOAT_MANTISSA;
-
- /* Iterate on all integer children */
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.CTF_EXPRESSION_VAL:
- /*
- * An assignment expression must have 2 children, left and right
- */
-
- CommonTree leftNode = (CommonTree) child.getChild(0);
- CommonTree rightNode = (CommonTree) child.getChild(1);
-
- List<CommonTree> leftStrings = leftNode.getChildren();
-
- if (!isAnyUnaryString(leftStrings.get(0))) {
- throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
- }
- String left = concatenateUnaryStrings(leftStrings);
-
- if (left.equals(MetadataStrings.EXP_DIG)) {
- exponent = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
- } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
- byteOrder = getByteOrder(rightNode);
- } else if (left.equals(MetadataStrings.MANT_DIG)) {
- mantissa = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
- } else if (left.equals(MetadataStrings.ALIGN)) {
- alignment = getAlignment(rightNode);
- } else {
- throw new ParseException("Float: unknown attribute " + left); //$NON-NLS-1$
- }
-
- break;
- default:
- throw childTypeError(child);
- }
- }
- int size = mantissa + exponent;
- if (size == 0) {
- throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
- }
-
- if (alignment == 0) {
- alignment = DEFAULT_ALIGNMENT;
- }
-
- floatDeclaration = new FloatDeclaration(exponent, mantissa, byteOrder, alignment);
-
- return floatDeclaration;
-
- }
-
- /**
- * Parses a type specifier list as a user-declared type.
- *
- * @param typeSpecifierList
- * A TYPE_SPECIFIER_LIST node containing a user-declared type.
- * @param pointerList
- * A list of POINTER nodes that apply to the type specified in
- * typeSpecifierList.
- * @return The corresponding declaration.
- * @throws ParseException
- * If the type does not exist (has not been found).
- */
- private IDeclaration parseTypeDeclaration(CommonTree typeSpecifierList,
- List<CommonTree> pointerList) throws ParseException {
- /* Create the string representation of the type declaration */
- String typeStringRepresentation = createTypeDeclarationString(
- typeSpecifierList, pointerList);
-
- /*
- * Use the string representation to search the type in the current scope
- */
- IDeclaration decl = getCurrentScope().lookupTypeRecursive(
- typeStringRepresentation);
-
- if (decl == null) {
- throw new ParseException("Type " + typeStringRepresentation //$NON-NLS-1$
- + " has not been defined."); //$NON-NLS-1$
- }
-
- return decl;
- }
-
- /**
- * Parses an integer declaration node.
- *
- * @param integer
- * An INTEGER node.
- * @return The corresponding integer declaration.
- * @throws ParseException
- */
- private IntegerDeclaration parseInteger(CommonTree integer)
- throws ParseException {
-
- List<CommonTree> children = integer.getChildren();
-
- /*
- * If the integer has no attributes, then it is missing the size
- * attribute which is required
- */
- if (children == null) {
- throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
- }
-
- /* The return value */
- IntegerDeclaration integerDeclaration = null;
- boolean signed = false;
- ByteOrder byteOrder = fTrace.getByteOrder();
- long size = 0;
- long alignment = 0;
- int base = DEFAULT_INT_BASE;
- @NonNull
- String clock = EMPTY_STRING;
-
- Encoding encoding = Encoding.NONE;
-
- /* Iterate on all integer children */
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.CTF_EXPRESSION_VAL:
- /*
- * An assignment expression must have 2 children, left and right
- */
-
- CommonTree leftNode = (CommonTree) child.getChild(0);
- CommonTree rightNode = (CommonTree) child.getChild(1);
-
- List<CommonTree> leftStrings = leftNode.getChildren();
-
- if (!isAnyUnaryString(leftStrings.get(0))) {
- throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
- }
- String left = concatenateUnaryStrings(leftStrings);
-
- if (left.equals(SIGNED)) {
- signed = getSigned(rightNode);
- } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
- byteOrder = getByteOrder(rightNode);
- } else if (left.equals(SIZE)) {
- size = getSize(rightNode);
- } else if (left.equals(MetadataStrings.ALIGN)) {
- alignment = getAlignment(rightNode);
- } else if (left.equals(BASE)) {
- base = getBase(rightNode);
- } else if (left.equals(ENCODING)) {
- encoding = getEncoding(rightNode);
- } else if (left.equals(MAP)) {
- clock = getClock(rightNode);
- } else {
- Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownIntegerAttributeWarning + " " + left); //$NON-NLS-1$
- }
-
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- if (size <= 0) {
- throw new ParseException("Invalid size attribute in Integer: " + size); //$NON-NLS-1$
- }
-
- if (alignment == 0) {
- alignment = DEFAULT_ALIGNMENT;
- }
-
- integerDeclaration = IntegerDeclaration.createDeclaration((int) size, signed, base,
- byteOrder, encoding, clock, alignment);
-
- return integerDeclaration;
- }
-
- @NonNull
- private static String getClock(CommonTree rightNode) {
- String clock = rightNode.getChild(1).getChild(0).getChild(0).getText();
- return clock == null ? EMPTY_STRING : clock;
- }
-
- private static StringDeclaration parseString(CommonTree string)
- throws ParseException {
-
- List<CommonTree> children = string.getChildren();
- StringDeclaration stringDeclaration = null;
-
- if (children == null) {
- stringDeclaration = StringDeclaration.getStringDeclaration(Encoding.UTF8);
- } else {
- Encoding encoding = Encoding.UTF8;
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.CTF_EXPRESSION_VAL:
- /*
- * An assignment expression must have 2 children, left and
- * right
- */
-
- CommonTree leftNode = (CommonTree) child.getChild(0);
- CommonTree rightNode = (CommonTree) child.getChild(1);
-
- List<CommonTree> leftStrings = leftNode.getChildren();
-
- if (!isAnyUnaryString(leftStrings.get(0))) {
- throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
- }
- String left = concatenateUnaryStrings(leftStrings);
-
- if (left.equals(ENCODING)) {
- encoding = getEncoding(rightNode);
- } else {
- throw new ParseException("String: unknown attribute " //$NON-NLS-1$
- + left);
- }
-
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- stringDeclaration = StringDeclaration.getStringDeclaration(encoding);
- }
-
- return stringDeclaration;
- }
-
- /**
- * Parses a struct declaration and returns the corresponding declaration.
- *
- * @param struct
- * An STRUCT node.
- * @return The corresponding struct declaration.
- * @throws ParseException
- */
- private StructDeclaration parseStruct(CommonTree struct, CommonTree identifier)
- throws ParseException {
-
- List<CommonTree> children = struct.getChildren();
-
- /* The return value */
- StructDeclaration structDeclaration = null;
-
- /* Name */
- String structName = null;
- boolean hasName = false;
-
- /* Body */
- CommonTree structBody = null;
- boolean hasBody = false;
-
- /* Align */
- long structAlign = 0;
-
- /* Loop on all children and identify what we have to work with. */
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.STRUCT_NAME: {
- hasName = true;
- CommonTree structNameIdentifier = (CommonTree) child.getChild(0);
- structName = structNameIdentifier.getText();
- break;
- }
- case CTFParser.STRUCT_BODY: {
- hasBody = true;
-
- structBody = child;
- break;
- }
- case CTFParser.ALIGN: {
- CommonTree structAlignExpression = (CommonTree) child.getChild(0);
-
- structAlign = getAlignment(structAlignExpression);
- break;
- }
- default:
- throw childTypeError(child);
- }
- }
-
- if (!hasName && identifier != null) {
- structName = identifier.getText();
- hasName = true;
- }
-
- /*
- * If a struct has just a body and no name (just like the song,
- * "A Struct With No Name" by America (sorry for that...)), it's a
- * definition of a new type, so we create the type declaration and
- * return it. We can't add it to the declaration scope since there is no
- * name, but that's what we want because it won't be possible to use it
- * again to declare another field.
- *
- * If it has just a name, we look it up in the declaration scope and
- * return the associated declaration. If it is not found in the
- * declaration scope, it means that a struct with that name has not been
- * declared, which is an error.
- *
- * If it has both, then we create the type declaration and register it
- * to the current scope.
- *
- * If it has none, then what are we doing here ?
- */
- if (hasBody) {
- /*
- * If struct has a name, check if already defined in the current
- * scope.
- */
- if (hasName && (getCurrentScope().lookupStruct(structName) != null)) {
- throw new ParseException("struct " + structName //$NON-NLS-1$
- + " already defined."); //$NON-NLS-1$
- }
- /* Create the declaration */
- structDeclaration = new StructDeclaration(structAlign);
-
- /* Parse the body */
- parseStructBody(structBody, structDeclaration, structName);
-
- /* If struct has name, add it to the current scope. */
- if (hasName) {
- getCurrentScope().registerStruct(structName, structDeclaration);
- }
- } else /* !hasBody */ {
- if (hasName) {
- /* Name and !body */
-
- /* Lookup the name in the current scope. */
- structDeclaration = getCurrentScope().lookupStructRecursive(structName);
-
- /*
- * If not found, it means that a struct with such name has not
- * been defined
- */
- if (structDeclaration == null) {
- throw new ParseException("struct " + structName //$NON-NLS-1$
- + " is not defined"); //$NON-NLS-1$
- }
- } else {
- /* !Name and !body */
-
- /* We can't do anything with that. */
- throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
- }
- }
- return StructDeclarationFlattener.tryFlattenStruct(structDeclaration);
- }
-
- /**
- * Parses a struct body, adding the fields to specified structure
- * declaration.
- *
- * @param structBody
- * A STRUCT_BODY node.
- * @param structDeclaration
- * The struct declaration.
- * @throws ParseException
- */
- private void parseStructBody(CommonTree structBody,
- StructDeclaration structDeclaration, @Nullable String structName) throws ParseException {
- List<CommonTree> structDeclarations = structBody.getChildren();
- if (structDeclarations == null) {
- structDeclarations = Collections.emptyList();
- }
-
- /*
- * If structDeclaration is null, structBody has no children and the
- * struct body is empty.
- */
- pushNamedScope(structName, MetadataStrings.STRUCT);
-
- for (CommonTree declarationNode : structDeclarations) {
- switch (declarationNode.getType()) {
- case CTFParser.TYPEALIAS:
- parseTypealias(declarationNode);
- break;
- case CTFParser.TYPEDEF:
- parseTypedef(declarationNode);
- parseStructDeclaration(declarationNode, structDeclaration);
- break;
- case CTFParser.SV_DECLARATION:
- parseStructDeclaration(declarationNode, structDeclaration);
- break;
- default:
- throw childTypeError(declarationNode);
- }
- }
- popScope();
- }
-
- /**
- * Parses a declaration found in a struct.
- *
- * @param declaration
- * A SV_DECLARATION node.
- * @param struct
- * A struct declaration. (I know, little name clash here...)
- * @throws ParseException
- */
- private void parseStructDeclaration(CommonTree declaration,
- StructDeclaration struct) throws ParseException {
-
- /* Get the type specifier list node */
- CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
-
- /* Get the type declarator list node */
- CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
-
- /* Get the type declarator list */
- List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
-
- /*
- * For each type declarator, parse the declaration and add a field to
- * the struct
- */
- for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
-
- StringBuilder identifierSB = new StringBuilder();
-
- IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
- typeSpecifierListNode, identifierSB);
- String fieldName = identifierSB.toString();
- getCurrentScope().registerIdentifier(fieldName, decl);
-
- if (struct.hasField(fieldName)) {
- throw new ParseException("struct: duplicate field " //$NON-NLS-1$
- + fieldName);
- }
-
- struct.addField(fieldName, decl);
-
- }
- }
-
- /**
- * Parses an enum declaration and returns the corresponding declaration.
- *
- * @param theEnum
- * An ENUM node.
- * @return The corresponding enum declaration.
- * @throws ParseException
- */
- private EnumDeclaration parseEnum(CommonTree theEnum) throws ParseException {
-
- List<CommonTree> children = theEnum.getChildren();
-
- /* The return value */
- EnumDeclaration enumDeclaration = null;
-
- /* Name */
- String enumName = null;
-
- /* Body */
- CommonTree enumBody = null;
-
- /* Container type */
- IntegerDeclaration containerTypeDeclaration = null;
-
- /* Loop on all children and identify what we have to work with. */
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.ENUM_NAME: {
- CommonTree enumNameIdentifier = (CommonTree) child.getChild(0);
- enumName = enumNameIdentifier.getText();
- break;
- }
- case CTFParser.ENUM_BODY: {
- enumBody = child;
- break;
- }
- case CTFParser.ENUM_CONTAINER_TYPE: {
- containerTypeDeclaration = parseEnumContainerType(child);
- break;
- }
- default:
- throw childTypeError(child);
- }
- }
-
- /*
- * If the container type has not been defined explicitly, we assume it
- * is "int".
- */
- if (containerTypeDeclaration == null) {
- IDeclaration enumDecl;
- /*
- * it could be because the enum was already declared.
- */
- if (enumName != null) {
- getCurrentScope().setName(enumName);
- enumDecl = getCurrentScope().lookupEnumRecursive(enumName);
- if (enumDecl != null) {
- return (EnumDeclaration) enumDecl;
- }
- }
-
- IDeclaration decl = getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$
-
- if (decl == null) {
- throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$
- } else if (!(decl instanceof IntegerDeclaration)) {
- throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$
- }
-
- containerTypeDeclaration = (IntegerDeclaration) decl;
- }
-
- /*
- * If it has a body, it's a new declaration, otherwise it's a reference
- * to an existing declaration. Same logic as struct.
- */
- if (enumBody != null) {
- /*
- * If enum has a name, check if already defined in the current
- * scope.
- */
- if ((enumName != null)
- && (getCurrentScope().lookupEnum(enumName) != null)) {
- throw new ParseException("enum " + enumName //$NON-NLS-1$
- + " already defined"); //$NON-NLS-1$
- }
-
- /* Create the declaration */
- enumDeclaration = new EnumDeclaration(containerTypeDeclaration);
-
- /* Parse the body */
- parseEnumBody(enumBody, enumDeclaration, enumName);
-
- /* If the enum has name, add it to the current scope. */
- if (enumName != null) {
- getCurrentScope().registerEnum(enumName, enumDeclaration);
- }
- } else {
- if (enumName != null) {
- /* Name and !body */
-
- /* Lookup the name in the current scope. */
- enumDeclaration = getCurrentScope().lookupEnumRecursive(enumName);
-
- /*
- * If not found, it means that an enum with such name has not
- * been defined
- */
- if (enumDeclaration == null) {
- throw new ParseException("enum " + enumName //$NON-NLS-1$
- + " is not defined"); //$NON-NLS-1$
- }
- } else {
- /* !Name and !body */
- throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
- }
- }
-
- return enumDeclaration;
-
- }
-
- /**
- * Parses an enum body, adding the enumerators to the specified enum
- * declaration.
- *
- * @param enumBody
- * An ENUM_BODY node.
- * @param enumDeclaration
- * The enum declaration.
- * @throws ParseException
- */
- private void parseEnumBody(CommonTree enumBody,
- EnumDeclaration enumDeclaration, @Nullable String enumName) throws ParseException {
-
- List<CommonTree> enumerators = enumBody.getChildren();
- /* enum body can't be empty (unlike struct). */
-
- pushNamedScope(enumName, MetadataStrings.ENUM);
-
- /*
- * Start at -1, so that if the first enumrator has no explicit value, it
- * will choose 0
- */
- long lastHigh = -1;
-
- for (CommonTree enumerator : enumerators) {
- lastHigh = parseEnumEnumerator(enumerator, enumDeclaration,
- lastHigh);
- }
-
- popScope();
-
- }
-
- /**
- * Parses an enumerator node and adds an enumerator declaration to an
- * enumeration declaration.
- *
- * The high value of the range of the last enumerator is needed in case the
- * current enumerator does not specify its value.
- *
- * @param enumerator
- * An ENUM_ENUMERATOR node.
- * @param enumDeclaration
- * en enumeration declaration to which will be added the
- * enumerator.
- * @param lastHigh
- * The high value of the range of the last enumerator
- * @return The high value of the value range of the current enumerator.
- * @throws ParseException
- */
- private static long parseEnumEnumerator(CommonTree enumerator,
- EnumDeclaration enumDeclaration, long lastHigh)
- throws ParseException {
-
- List<CommonTree> children = enumerator.getChildren();
-
- long low = 0, high = 0;
- boolean valueSpecified = false;
- String label = null;
-
- for (CommonTree child : children) {
- if (isAnyUnaryString(child)) {
- label = parseUnaryString(child);
- } else if (child.getType() == CTFParser.ENUM_VALUE) {
-
- valueSpecified = true;
-
- low = parseUnaryInteger((CommonTree) child.getChild(0));
- high = low;
- } else if (child.getType() == CTFParser.ENUM_VALUE_RANGE) {
-
- valueSpecified = true;
-
- low = parseUnaryInteger((CommonTree) child.getChild(0));
- high = parseUnaryInteger((CommonTree) child.getChild(1));
- } else {
- throw childTypeError(child);
- }
- }
-
- if (!valueSpecified) {
- low = lastHigh + 1;
- high = low;
- }
-
- if (low > high) {
- throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
- }
-
- if (!enumDeclaration.add(low, high, label)) {
- throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
- }
-
- if (valueSpecified && (BigInteger.valueOf(low).compareTo(enumDeclaration.getContainerType().getMinValue()) == -1 ||
- BigInteger.valueOf(high).compareTo(enumDeclaration.getContainerType().getMaxValue()) == 1)) {
- throw new ParseException("enum value is not in range"); //$NON-NLS-1$
- }
-
- return high;
- }
-
- /**
- * Parses an enum container type node and returns the corresponding integer
- * type.
- *
- * @param enumContainerType
- * An ENUM_CONTAINER_TYPE node.
- * @return An integer declaration corresponding to the container type.
- * @throws ParseException
- * If the type does not parse correctly or if it is not an
- * integer type.
- */
- private IntegerDeclaration parseEnumContainerType(
- CommonTree enumContainerType) throws ParseException {
-
- /* Get the child, which should be a type specifier list */
- CommonTree typeSpecifierList = (CommonTree) enumContainerType.getChild(0);
-
- /* Parse it and get the corresponding declaration */
- IDeclaration decl = parseTypeSpecifierList(typeSpecifierList);
-
- /* If is is an integer, return it, else throw an error */
- if (decl instanceof IntegerDeclaration) {
- return (IntegerDeclaration) decl;
- }
- throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
- }
-
- private VariantDeclaration parseVariant(CommonTree variant)
- throws ParseException {
-
- List<CommonTree> children = variant.getChildren();
- VariantDeclaration variantDeclaration = null;
-
- boolean hasName = false;
- String variantName = null;
-
- boolean hasBody = false;
- CommonTree variantBody = null;
-
- boolean hasTag = false;
- String variantTag = null;
-
- for (CommonTree child : children) {
- switch (child.getType()) {
- case CTFParser.VARIANT_NAME:
-
- hasName = true;
-
- CommonTree variantNameIdentifier = (CommonTree) child.getChild(0);
-
- variantName = variantNameIdentifier.getText();
-
- break;
- case CTFParser.VARIANT_TAG:
-
- hasTag = true;
-
- CommonTree variantTagIdentifier = (CommonTree) child.getChild(0);
-
- variantTag = variantTagIdentifier.getText();
-
- break;
- case CTFParser.VARIANT_BODY:
-
- hasBody = true;
-
- variantBody = child;
-
- break;
- default:
- throw childTypeError(child);
- }
- }
-
- if (hasBody) {
- /*
- * If variant has a name, check if already defined in the current
- * scope.
- */
- if (hasName
- && (getCurrentScope().lookupVariant(variantName) != null)) {
- throw new ParseException("variant " + variantName //$NON-NLS-1$
- + " already defined."); //$NON-NLS-1$
- }
-
- /* Create the declaration */
- variantDeclaration = new VariantDeclaration();
-
- /* Parse the body */
- parseVariantBody(variantBody, variantDeclaration, variantName);
-
- /* If variant has name, add it to the current scope. */
- if (hasName) {
- getCurrentScope().registerVariant(variantName,
- variantDeclaration);
- }
- } else /* !hasBody */ {
- if (hasName) {
- /* Name and !body */
-
- /* Lookup the name in the current scope. */
- variantDeclaration = getCurrentScope().lookupVariantRecursive(
- variantName);
-
- /*
- * If not found, it means that a struct with such name has not
- * been defined
- */
- if (variantDeclaration == null) {
- throw new ParseException("variant " + variantName //$NON-NLS-1$
- + " is not defined"); //$NON-NLS-1$
- }
- } else {
- /* !Name and !body */
-
- /* We can't do anything with that. */
- throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
- }
- }
-
- if (hasTag) {
- variantDeclaration.setTag(variantTag);
-
- IDeclaration decl = getCurrentScope().lookupIdentifierRecursive(variantTag);
- if (decl == null) {
- throw new ParseException("Variant tag not found: " + variantTag); //$NON-NLS-1$
- }
- if (!(decl instanceof EnumDeclaration)) {
- throw new ParseException("Variant tag must be an enum: " + variantTag); //$NON-NLS-1$
- }
- EnumDeclaration tagDecl = (EnumDeclaration) decl;
- Set<String> intersection = new HashSet<>(tagDecl.getLabels());
- intersection.retainAll(variantDeclaration.getFields().keySet());
- if (intersection.isEmpty()) {
- throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName); //$NON-NLS-1$
- }
- }
-
- return variantDeclaration;
- }
-
- private void parseVariantBody(CommonTree variantBody,
- VariantDeclaration variantDeclaration, @Nullable String variantName) throws ParseException {
-
- List<CommonTree> variantDeclarations = variantBody.getChildren();
-
- pushNamedScope(variantName, MetadataStrings.VARIANT);
-
- for (CommonTree declarationNode : variantDeclarations) {
- switch (declarationNode.getType()) {
- case CTFParser.TYPEALIAS:
- parseTypealias(declarationNode);
- break;
- case CTFParser.TYPEDEF:
- Map<String, IDeclaration> decs = parseTypedef(declarationNode);
- for (Entry<String, IDeclaration> declarationEntry : decs.entrySet()) {
- variantDeclaration.addField(declarationEntry.getKey(), declarationEntry.getValue());
- }
- break;
- case CTFParser.SV_DECLARATION:
- parseVariantDeclaration(declarationNode, variantDeclaration);
- break;
- default:
- throw childTypeError(declarationNode);
- }
- }
-
- popScope();
- }
-
- private void parseVariantDeclaration(CommonTree declaration,
- VariantDeclaration variant) throws ParseException {
-
- /* Get the type specifier list node */
- CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
-
- /* Get the type declarator list node */
- CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
-
- /* Get the type declarator list */
- List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
-
- /*
- * For each type declarator, parse the declaration and add a field to
- * the variant
- */
- for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
-
- StringBuilder identifierSB = new StringBuilder();
-
- IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
- typeSpecifierListNode, identifierSB);
-
- String name = identifierSB.toString();
-
- if (variant.hasField(name)) {
- throw new ParseException("variant: duplicate field " //$NON-NLS-1$
- + name);
- }
-
- getCurrentScope().registerIdentifier(name, decl);
-
- variant.addField(name, decl);
- }
- }
-
- /**
- * Creates the string representation of a type declaration (type specifier
- * list + pointers).
- *
- * @param typeSpecifierList
- * A TYPE_SPECIFIER_LIST node.
- * @param pointers
- * A list of POINTER nodes.
- * @return The string representation.
- * @throws ParseException
- */
- private static String createTypeDeclarationString(
- CommonTree typeSpecifierList, List<CommonTree> pointers)
- throws ParseException {
- StringBuilder sb = new StringBuilder();
-
- createTypeSpecifierListString(typeSpecifierList, sb);
- createPointerListString(pointers, sb);
-
- return sb.toString();
- }
-
- /**
- * Creates the string representation of a list of type specifiers.
- *
- * @param typeSpecifierList
- * A TYPE_SPECIFIER_LIST node.
- * @param sb
- * A StringBuilder to which will be appended the string.
- * @throws ParseException
- */
- private static void createTypeSpecifierListString(
- CommonTree typeSpecifierList, StringBuilder sb)
- throws ParseException {
-
- List<CommonTree> children = typeSpecifierList.getChildren();
-
- boolean firstItem = true;
-
- for (CommonTree child : children) {
- if (!firstItem) {
- sb.append(' ');
-
- }
-
- firstItem = false;
-
- /* Append the string that represents this type specifier. */
- createTypeSpecifierString(child, sb);
- }
- }
-
- /**
- * Creates the string representation of a type specifier.
- *
- * @param typeSpecifier
- * A TYPE_SPECIFIER node.
- * @param sb
- * A StringBuilder to which will be appended the string.
- * @throws ParseException
- */
- private static void createTypeSpecifierString(CommonTree typeSpecifier,
- StringBuilder sb) throws ParseException {
- switch (typeSpecifier.getType()) {
- case CTFParser.FLOATTOK:
- case CTFParser.INTTOK:
- case CTFParser.LONGTOK:
- case CTFParser.SHORTTOK:
- case CTFParser.SIGNEDTOK:
- case CTFParser.UNSIGNEDTOK:
- case CTFParser.CHARTOK:
- case CTFParser.DOUBLETOK:
- case CTFParser.VOIDTOK:
- case CTFParser.BOOLTOK:
- case CTFParser.COMPLEXTOK:
- case CTFParser.IMAGINARYTOK:
- case CTFParser.CONSTTOK:
- case CTFParser.IDENTIFIER:
- sb.append(typeSpecifier.getText());
- break;
- case CTFParser.STRUCT: {
- CommonTree structName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.STRUCT_NAME);
- if (structName == null) {
- throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
- }
-
- CommonTree structNameIdentifier = (CommonTree) structName.getChild(0);
-
- sb.append(structNameIdentifier.getText());
- break;
- }
- case CTFParser.VARIANT: {
- CommonTree variantName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.VARIANT_NAME);
- if (variantName == null) {
- throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
- }
-
- CommonTree variantNameIdentifier = (CommonTree) variantName.getChild(0);
-
- sb.append(variantNameIdentifier.getText());
- break;
- }
- case CTFParser.ENUM: {
- CommonTree enumName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.ENUM_NAME);
- if (enumName == null) {
- throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
- }
-
- CommonTree enumNameIdentifier = (CommonTree) enumName.getChild(0);
-
- sb.append(enumNameIdentifier.getText());
- break;
- }
- case CTFParser.FLOATING_POINT:
- case CTFParser.INTEGER:
- case CTFParser.STRING:
- throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
- default:
- throw childTypeError(typeSpecifier);
- }
- }
-
- /**
- * Creates the string representation of a list of pointers.
- *
- * @param pointerList
- * A list of pointer nodes. If pointerList is null, this function
- * does nothing.
- * @param sb
- * A stringbuilder to which will be appended the string.
- */
- private static void createPointerListString(List<CommonTree> pointerList,
- StringBuilder sb) {
- if (pointerList == null) {
- return;
- }
-
- for (CommonTree pointer : pointerList) {
-
- sb.append(" *"); //$NON-NLS-1$
- if (pointer.getChildCount() > 0) {
-
- sb.append(" const"); //$NON-NLS-1$
- }
- }
- }
-
- /**
- * @param node
- * The node to check.
- * @return True if the given node is an unary string.
- */
- private static boolean isUnaryString(CommonTree node) {
- return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING));
- }
-
- /**
- * @param node
- * The node to check.
- * @return True if the given node is any type of unary string (no quotes,
- * quotes, etc).
- */
- private static boolean isAnyUnaryString(CommonTree node) {
- return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING) || (node.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES));
- }
-
- /**
- * @param node
- * The node to check.
- * @return True if the given node is an unary integer.
- */
- private static boolean isUnaryInteger(CommonTree node) {
- return ((node.getType() == CTFParser.UNARY_EXPRESSION_DEC) ||
- (node.getType() == CTFParser.UNARY_EXPRESSION_HEX) || (node.getType() == CTFParser.UNARY_EXPRESSION_OCT));
- }
-
- /**
- * Parses a unary string node and return the string value.
- *
- * @param unaryString
- * The unary string node to parse (type UNARY_EXPRESSION_STRING
- * or UNARY_EXPRESSION_STRING_QUOTES).
- * @return The string value.
- */
- /*
- * It would be really nice to remove the quotes earlier, such as in the
- * parser.
- */
- private static String parseUnaryString(CommonTree unaryString) {
-
- CommonTree value = (CommonTree) unaryString.getChild(0);
- if (value.getType() == CTFParser.UNARY_EXPRESSION_STRING) {
- value = (CommonTree) value.getChild(0);
- }
- String strval = value.getText();
-
- /* Remove quotes */
- if (unaryString.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES) {
- strval = strval.substring(1, strval.length() - 1);
- }
-
- return strval;
- }
-
- /**
- * Parses an unary integer (dec, hex or oct).
- *
- * @param unaryInteger
- * An unary integer node.
- * @return The integer value.
- * @throws ParseException
- * on an invalid integer format ("bob" for example)
- */
- private static long parseUnaryInteger(CommonTree unaryInteger) throws ParseException {
-
- List<CommonTree> children = unaryInteger.getChildren();
- CommonTree value = children.get(0);
- String strval = value.getText();
-
- long intval;
- try {
- intval = Long.decode(strval);
- } catch (NumberFormatException e) {
- throw new ParseException("Invalid integer format: " + strval, e); //$NON-NLS-1$
- }
-
- /* The rest of children are sign */
- if ((children.size() % 2) == 0) {
- return -intval;
- }
- return intval;
- }
-
- private static long getMajorOrMinor(CommonTree rightNode)
- throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryInteger(firstChild)) {
- if (rightNode.getChildCount() > 1) {
- throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
- }
-
- long m = parseUnaryInteger(firstChild);
-
- if (m < 0) {
- throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
- }
-
- return m;
- }
- throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
- }
-
- private static UUID getUUID(CommonTree rightNode) throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isAnyUnaryString(firstChild)) {
- if (rightNode.getChildCount() > 1) {
- throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
- }
-
- String uuidstr = parseUnaryString(firstChild);
-
- try {
- return UUID.fromString(uuidstr);
- } catch (IllegalArgumentException e) {
- throw new ParseException("Invalid format for UUID", e); //$NON-NLS-1$
- }
- }
- throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
- }
-
- /**
- * Gets the value of a "signed" integer attribute.
- *
- * @param rightNode
- * A CTF_RIGHT node.
- * @return The "signed" value as a boolean.
- * @throws ParseException
- */
- private static boolean getSigned(CommonTree rightNode)
- throws ParseException {
-
- boolean ret = false;
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryString(firstChild)) {
- String strval = concatenateUnaryStrings(rightNode.getChildren());
-
- if (strval.equals(MetadataStrings.TRUE)
- || strval.equals(MetadataStrings.TRUE2)) {
- ret = true;
- } else if (strval.equals(MetadataStrings.FALSE)
- || strval.equals(MetadataStrings.FALSE2)) {
- ret = false;
- } else {
- throw new ParseException("Invalid boolean value " //$NON-NLS-1$
- + firstChild.getChild(0).getText());
- }
- } else if (isUnaryInteger(firstChild)) {
- /* Happens if the value is something like "1234.hello" */
- if (rightNode.getChildCount() > 1) {
- throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
- }
-
- long intval = parseUnaryInteger(firstChild);
-
- if (intval == 1) {
- ret = true;
- } else if (intval == 0) {
- ret = false;
- } else {
- throw new ParseException("Invalid boolean value " //$NON-NLS-1$
- + firstChild.getChild(0).getText());
- }
- } else {
- throw new ParseException();
- }
-
- return ret;
- }
-
- /**
- * Gets the value of a "byte_order" integer attribute.
- *
- * @param rightNode
- * A CTF_RIGHT node.
- * @return The "byte_order" value.
- * @throws ParseException
- */
- private ByteOrder getByteOrder(CommonTree rightNode) throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryString(firstChild)) {
- String strval = concatenateUnaryStrings(rightNode.getChildren());
-
- if (strval.equals(MetadataStrings.LE)) {
- return ByteOrder.LITTLE_ENDIAN;
- } else if (strval.equals(MetadataStrings.BE)
- || strval.equals(MetadataStrings.NETWORK)) {
- return ByteOrder.BIG_ENDIAN;
- } else if (strval.equals(MetadataStrings.NATIVE)) {
- return fTrace.getByteOrder();
- } else {
- throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
- }
- }
- throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
- }
-
- /**
- * Determines if the given value is a valid alignment value.
- *
- * @param alignment
- * The value to check.
- * @return True if it is valid.
- */
- private static boolean isValidAlignment(long alignment) {
- return !((alignment <= 0) || ((alignment & (alignment - 1)) != 0));
- }
-
- /**
- * Gets the value of a "size" integer attribute.
- *
- * @param rightNode
- * A CTF_RIGHT node.
- * @return The "size" value.
- * @throws ParseException
- */
- private static long getSize(CommonTree rightNode) throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryInteger(firstChild)) {
- if (rightNode.getChildCount() > 1) {
- throw new ParseException("Invalid value for size"); //$NON-NLS-1$
- }
-
- long size = parseUnaryInteger(firstChild);
-
- if (size < 1) {
- throw new ParseException("Invalid value for size"); //$NON-NLS-1$
- }
-
- return size;
- }
- throw new ParseException("Invalid value for size"); //$NON-NLS-1$
- }
-
- /**
- * Gets the value of a "align" integer or struct attribute.
- *
- * @param node
- * A CTF_RIGHT node or directly an unary integer.
- * @return The align value.
- * @throws ParseException
- */
- private static long getAlignment(CommonTree node) throws ParseException {
-
- /*
- * If a CTF_RIGHT node was passed, call getAlignment with the first
- * child
- */
- if (node.getType() == CTFParser.CTF_RIGHT) {
- if (node.getChildCount() > 1) {
- throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
- }
-
- return getAlignment((CommonTree) node.getChild(0));
- } else if (isUnaryInteger(node)) {
- long alignment = parseUnaryInteger(node);
-
- if (!isValidAlignment(alignment)) {
- throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
- + alignment);
- }
-
- return alignment;
- }
- throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
- }
-
- /**
- * Gets the value of a "base" integer attribute.
- *
- * @param rightNode
- * An CTF_RIGHT node.
- * @return The "base" value.
- * @throws ParseException
- */
- private static int getBase(CommonTree rightNode) throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryInteger(firstChild)) {
- if (rightNode.getChildCount() > 1) {
- throw new ParseException("invalid base value"); //$NON-NLS-1$
- }
-
- long intval = parseUnaryInteger(firstChild);
- if ((intval == INTEGER_BASE_2) || (intval == INTEGER_BASE_8) || (intval == INTEGER_BASE_10)
- || (intval == INTEGER_BASE_16)) {
- return (int) intval;
- }
- throw new ParseException("Invalid value for base"); //$NON-NLS-1$
- } else if (isUnaryString(firstChild)) {
- switch (concatenateUnaryStrings(rightNode.getChildren())) {
- case MetadataStrings.DECIMAL:
- case MetadataStrings.DEC:
- case MetadataStrings.DEC_CTE:
- case MetadataStrings.INT_MOD:
- case MetadataStrings.UNSIGNED_CTE:
- return INTEGER_BASE_10;
- case MetadataStrings.HEXADECIMAL:
- case MetadataStrings.HEX:
- case MetadataStrings.X:
- case MetadataStrings.X2:
- case MetadataStrings.POINTER:
- return INTEGER_BASE_16;
- case MetadataStrings.OCT:
- case MetadataStrings.OCTAL:
- case MetadataStrings.OCTAL_CTE:
- return INTEGER_BASE_8;
- case MetadataStrings.BIN:
- case MetadataStrings.BINARY:
- return INTEGER_BASE_2;
- default:
- throw new ParseException("Invalid value for base"); //$NON-NLS-1$
- }
- } else {
- throw new ParseException("invalid value for base"); //$NON-NLS-1$
- }
- }
-
- /**
- * Gets the value of an "encoding" integer attribute.
- *
- * @param rightNode
- * A CTF_RIGHT node.
- * @return The "encoding" value.
- * @throws ParseException
- */
- @NonNull
- private static Encoding getEncoding(CommonTree rightNode)
- throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryString(firstChild)) {
- String strval = concatenateUnaryStrings(rightNode.getChildren());
-
- if (strval.equals(MetadataStrings.UTF8)) {
- return Encoding.UTF8;
- } else if (strval.equals(MetadataStrings.ASCII)) {
- return Encoding.ASCII;
- } else if (strval.equals(MetadataStrings.NONE)) {
- return Encoding.NONE;
- } else {
- throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
- }
- }
- throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
- }
-
- private static long getStreamID(CommonTree rightNode) throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryInteger(firstChild)) {
- if (rightNode.getChildCount() > 1) {
- throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
- }
-
- long intval = parseUnaryInteger(firstChild);
-
- return intval;
- }
- throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
- }
-
- private static String getEventName(CommonTree rightNode)
- throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isAnyUnaryString(firstChild)) {
- String str = concatenateUnaryStrings(rightNode.getChildren());
-
- return str;
- }
- throw new ParseException("invalid value for event name"); //$NON-NLS-1$
- }
-
- private static long getEventID(CommonTree rightNode) throws ParseException {
-
- CommonTree firstChild = (CommonTree) rightNode.getChild(0);
-
- if (isUnaryInteger(firstChild)) {
- if (rightNode.getChildCount() > 1) {
- throw new ParseException("invalid value for event id"); //$NON-NLS-1$
- }
-
- long intval = parseUnaryInteger(firstChild);
- if (intval > Integer.MAX_VALUE) {
- throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$
- }
- return intval;
- }
- throw new ParseException("invalid value for event id"); //$NON-NLS-1$
- }
-
- /**
- * Concatenates a list of unary strings separated by arrows (->) or dots.
- *
- * @param strings
- * A list, first element being an unary string, subsequent
- * elements being ARROW or DOT nodes with unary strings as child.
- * @return The string representation of the unary string chain.
- */
- private static String concatenateUnaryStrings(List<CommonTree> strings) {
-
- StringBuilder sb = new StringBuilder();
-
- CommonTree first = strings.get(0);
- sb.append(parseUnaryString(first));
-
- boolean isFirst = true;
-
- for (CommonTree ref : strings) {
- if (isFirst) {
- isFirst = false;
- continue;
- }
-
- CommonTree id = (CommonTree) ref.getChild(0);
-
- if (ref.getType() == CTFParser.ARROW) {
- sb.append("->"); //$NON-NLS-1$
- } else { /* DOT */
- sb.append('.');
- }
-
- sb.append(parseUnaryString(id));
- }
-
- return sb.toString();
- }
-
- /**
- * Throws a ParseException stating that the parent-child relation between
- * the given node and its parent is not valid. It means that the shape of
- * the AST is unexpected.
- *
- * @param child
- * The invalid child node.
- * @return ParseException with details
- */
- private static ParseException childTypeError(CommonTree child) {
- CommonTree parent = (CommonTree) child.getParent();
- String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$
- + " can't have a child of type " //$NON-NLS-1$
- + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$
+ private static ParseException childTypeError(CommonTree child) {
+ CommonTree parent = (CommonTree) child.getParent();
+ String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$
+ + " can't have a child of type " //$NON-NLS-1$
+ + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$
return new ParseException(error);
}
- // ------------------------------------------------------------------------
- // Scope management
- // ------------------------------------------------------------------------
-
- /**
- * Adds a new declaration scope on the top of the scope stack.
- */
- private void pushScope(String name) {
- fScope = new DeclarationScope(getCurrentScope(), name);
- }
-
- /**
- * Removes the top declaration scope from the scope stack.
- */
- private void popScope() {
- fScope = getCurrentScope().getParentScope();
- }
-
- private void pushNamedScope(@Nullable String name, String defaultName) {
- pushScope(name == null ? defaultName : name);
- }
-
- /**
- * Returns the current declaration scope.
- *
- * @return The current declaration scope.
- */
- private DeclarationScope getCurrentScope() {
- return fScope;
- }
-
}
/*******************************************************************************
- * Copyright (c) 2013, 2014 Ericsson
+ * Copyright (c) 2013, 2015 Ericsson
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
/*******************************************************************************
- * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
+ * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: Matthew Khouzam - Initial API and implementation
+ * Contributors: Simon Marchi - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata;
+
+
+/**
+ * <b><u>ParseException</u></b>
+ */
+public class ParseException extends Exception {
+
+ private static final long serialVersionUID = 7901917601459652080L;
+
+ /**
+ * Empty constructor
+ */
+ public ParseException() {
+ super();
+ }
+
+ /**
+ * Constructor
+ *
+ * @param message to be sent to logs
+ */
+ public ParseException(String message) {
+ super(message);
+ }
+
+ /**
+ * Copy constructor
+ * @param e the exception to throw
+ */
+ public ParseException(Exception e) {
+ super(e);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause. <p>Note that the detail message associated with
+ * {@code cause} is <i>not</i> automatically incorporated in
+ * this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A <tt>null</tt> value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ */
+ public ParseException(String message, Exception cause) {
+ super(message, cause);
+ }
+}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2013, 2014 Ericsson
- *
- * All rights reserved. This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License v1.0 which
- * accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Alexandre Montplaisir - Initial API and implementation
- * Matthew Khouzam - Addition to have more descriptive errors
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions;
-
-import java.lang.reflect.Field;
-
-import org.antlr.runtime.MismatchedTokenException;
-import org.antlr.runtime.RecognitionException;
-import org.eclipse.tracecompass.ctf.core.CTFException;
-import org.eclipse.tracecompass.ctf.parser.CTFLexer;
-
-/**
- * CTF Reader exception but dealing with Antlr-specific parsing problems.
- *
- * It is separated from the main {@link CTFException} - and is not part of the
- * API - to isolate the Antlr-specific classes and avoid pushing that dependency
- * to the users of this plugin.
- *
- * @author Matthew Khouzam
- */
-public class CtfAntlrException extends CTFException {
-
- private static final long serialVersionUID = -7078624493350073777L;
-
- private final int fErrorLine;
- private final String fFile;
- private String fExpectingName = ""; //$NON-NLS-1$
- private int fExpectedValue = -1;
- private String fActualName = ""; //$NON-NLS-1$
- private int fActualValue = -1;
-
- private final int fCharPositionInLine;
-
- /**
- * Re-throw the exception but read its data
- *
- * @param e
- * the previous recognition exception (Antlr specific)
- */
- public CtfAntlrException(MismatchedTokenException e) {
- super(e);
- fErrorLine = e.line;
- fCharPositionInLine = e.charPositionInLine;
- fFile = "metadata"; //$NON-NLS-1$ // we're in CTF, the only thing using antlr is metadata
- parseMismatchedException(e);
- }
-
- /**
- * Re-throw the exception but read its data
- *
- * @param e
- * the previous recognition exception (Antlr specific)
- */
- public CtfAntlrException(RecognitionException e) {
- super(e);
- fErrorLine = e.line;
- fCharPositionInLine = e.charPositionInLine;
- fFile = "metadata"; //$NON-NLS-1$ // we're in CTF, the only thing using antlr is metadata
- }
-
- /**
- * Re-throw the exception but read its data
- *
- * @param e
- * the previous rewrite exception (Antlr specific)
- */
- public CtfAntlrException(Exception e) {
- super(e);
- fErrorLine = -1;
- fCharPositionInLine = -1;
- fFile = "metadata"; //$NON-NLS-1$ // we're in CTF, the only thing using antlr is metadata
- }
-
- private void parseMismatchedException(MismatchedTokenException m) {
- // Iterate through the tokens that are hidden in the CTFLexer
- // They are private static final int fields.
- for (Field f : CTFLexer.class.getDeclaredFields()) {
- f.setAccessible(true);
- String name;
- int value;
- try {
- name = f.getName();
- final boolean isInt = (f.getType().isPrimitive());
- if (isInt) {
- value = ((Integer) f.get(null)).intValue();
- if (value == m.expecting) {
- this.fExpectingName = name;
- this.fExpectedValue = value;
- }
- if (value == m.c) {
- this.fActualName = name;
- this.fActualValue = value;
- }
- }
- } catch (NullPointerException e1) {
- // Pokemon, gotta catch em all!
- // actually useful since f may not have a
- // value
- } catch (IllegalArgumentException e1) {
- // Catch these exceptions (reflexion)
- } catch (IllegalAccessException e1) {
- // Catch these exceptions (reflexion)
- }
- if (!this.fExpectingName.isEmpty() && !this.fActualName.isEmpty()) {
- return;
- }
- }
- }
-
- @Override
- public String getMessage() {
- final String message = super.getMessage();
- if (fErrorLine == -1) {
- return message;
- }
- String expected = "" + this.fExpectedValue; //$NON-NLS-1$
- String actual = "" + this.fActualValue; //$NON-NLS-1$
- String newMessage = message.replaceAll(expected, this.fExpectingName);
- newMessage = newMessage.replaceAll(actual, this.fActualName);
- return newMessage + " at " + fFile + ":" + fErrorLine + ":" + fCharPositionInLine; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
-}
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
- *
- * All rights reserved. This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License v1.0 which
- * accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: Matthew Khouzam - Initial API and implementation
- * Contributors: Simon Marchi - Initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions;
-
-
-/**
- * <b><u>ParseException</u></b>
- */
-public class ParseException extends Exception {
-
- private static final long serialVersionUID = 7901917601459652080L;
-
- /**
- * Empty constructor
- */
- public ParseException() {
- super();
- }
-
- /**
- * Constructor
- *
- * @param message to be sent to logs
- */
- public ParseException(String message) {
- super(message);
- }
-
- /**
- * Copy constructor
- * @param e the exception to throw
- */
- public ParseException(Exception e) {
- super(e);
- }
-
- /**
- * Constructs a new exception with the specified detail message and
- * cause. <p>Note that the detail message associated with
- * {@code cause} is <i>not</i> automatically incorporated in
- * this exception's detail message.
- *
- * @param message the detail message (which is saved for later retrieval
- * by the {@link #getMessage()} method).
- * @param cause the cause (which is saved for later retrieval by the
- * {@link #getCause()} method). (A <tt>null</tt> value is
- * permitted, and indicates that the cause is nonexistent or
- * unknown.)
- */
- public ParseException(String message, Exception cause) {
- super(message, cause);
- }
-}
###############################################################################
-# Copyright (c) 2013, 2014 Ericsson
+# Copyright (c) 2013, 2015 Ericsson
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Alignment parser, we define byte-packed types as aligned on the byte size,
+ * namely 8-bit. We define bit-packed types as following on the next bit, as
+ * defined by the Integers section.
+ *
+ * Each basic type must specify its alignment, in bits. Examples of possible
+ * alignments are: bit-packed (align = 1), byte-packed (align = 8), or
+ * word-aligned (e.g. align = 32 or align = 64). The choice depends on the
+ * architecture preference and compactness vs performance trade-offs of the
+ * implementation. Architectures providing fast unaligned write byte-packed
+ * basic types to save space, aligning each type on byte boundaries (8-bit).
+ * Architectures with slow unaligned writes align types on specific alignment
+ * values. If no specific alignment is declared for a type, it is assumed to be
+ * bit-packed for integers with size not multiple of 8 bits and for gcc
+ * bitfields. All other basic types are byte-packed by default. It is however
+ * recommended to always specify the alignment explicitly. Alignment values must
+ * be power of two. Compound types are aligned as specified in their individual
+ * specification.
+ *
+ * The base offset used for field alignment is the start of the packet
+ * containing the field. For instance, a field aligned on 32-bit needs to be at
+ * an offset multiple of 32-bit from the start of the packet that contains it.
+ *
+ * TSDL metadata attribute representation of a specific alignment:
+ *
+ * @author Matthew Khouzam
+ * @author Efficios (javadoc preamble)
+ *
+ */
+public final class AlignmentParser implements ICommonTreeParser {
+
+ /**
+ * Alignment parser instance
+ */
+ public static final AlignmentParser INSTANCE = new AlignmentParser();
+
+ private static final String INVALID_VALUE_FOR_ALIGNMENT = "Invalid value for alignment"; //$NON-NLS-1$
+
+ private AlignmentParser() {
+ }
+
+ /**
+ * Gets the value of a "align" integer or struct attribute.
+ * @param tree
+ * A CTF_RIGHT node or directly an unary integer.
+ *
+ * @return The align value.
+ * @throws ParseException
+ * Invalid alignment value
+ */
+ @Override
+ public Long parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException {
+ /*
+ * If a CTF_RIGHT node was passed, call getAlignment with the first
+ * child
+ */
+ if (tree.getType() == CTFParser.CTF_RIGHT) {
+ if (tree.getChildCount() > 1) {
+ throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT);
+ }
+
+ return parse((CommonTree) tree.getChild(0), param);
+ } else if (isUnaryInteger(tree)) {
+ long alignment = UnaryIntegerParser.INSTANCE.parse(tree, null);
+
+ if (!isValidAlignment(alignment)) {
+ throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
+ + alignment);
+ }
+
+ return alignment;
+ }
+ throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT); // $NON-NLS-1$
+ }
+
+ /**
+ * Determines if the given value is a valid alignment value.
+ *
+ * @param alignment
+ * The value to check.
+ * @return True if it is valid.
+ */
+ private static boolean isValidAlignment(long alignment) {
+ return !((alignment <= 0) || ((alignment & (alignment - 1)) != 0));
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryString;
+
+import java.nio.ByteOrder;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * By default, byte order of a basic type is the byte order described in the
+ * trace description. It can be overridden by specifying a byte_order attribute
+ * for a basic type. Typical use-case is to specify the network byte order (big
+ * endian: be) to save data captured from the network into the trace without
+ * conversion.
+ *
+ * TSDL metadata representation:
+ *
+ * <pre>
+ * /* network and be are aliases * /
+ * byte_order= /* native OR network OR be OR le * /;
+ * </pre>
+ *
+ * The native keyword selects the byte order described in the trace description.
+ * The network byte order is an alias for big endian.
+ *
+ * Even though the trace description section is not per se a type, for sake of
+ * clarity, it should be noted that native and network byte orders are only
+ * allowed within type declaration. The byte_order specified in the trace
+ * description section only accepts be or le values.
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Javadoc preamble
+ *
+ */
+public final class ByteOrderParser implements ICommonTreeParser {
+
+ /**
+ * Parameter object with a trace
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ public static final class Param implements ICommonTreeParserParameter {
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ */
+ public Param(CTFTrace trace) {
+ fTrace = trace;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public static final ByteOrderParser INSTANCE = new ByteOrderParser();
+
+ private static final String INVALID_VALUE_FOR_BYTE_ORDER = "Invalid value for byte order"; //$NON-NLS-1$
+
+ private ByteOrderParser() {
+ }
+
+ /**
+ * Gets the value of a "byte_order" integer attribute.
+ *
+ * @param byteOrderTree
+ * A CTF_RIGHT node.
+ *
+ * @return The "byte_order" value.
+ * @throws ParseException
+ * if the value is invalid
+ */
+ @Override
+ public final ByteOrder parse(CommonTree byteOrderTree, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ CTFTrace trace = ((Param) param).fTrace;
+ CommonTree firstChild = (CommonTree) byteOrderTree.getChild(0);
+
+ if (isUnaryString(firstChild)) {
+ String strval = concatenateUnaryStrings(byteOrderTree.getChildren());
+
+ if (strval.equals(MetadataStrings.LE)) {
+ return ByteOrder.LITTLE_ENDIAN;
+ } else if (strval.equals(MetadataStrings.BE)
+ || strval.equals(MetadataStrings.NETWORK)) {
+ return ByteOrder.BIG_ENDIAN;
+ } else if (strval.equals(MetadataStrings.NATIVE)) {
+ ByteOrder byteOrder = trace.getByteOrder();
+ return (byteOrder == null) ? ByteOrder.nativeOrder() : byteOrder;
+ } else {
+ throw new ParseException(INVALID_VALUE_FOR_BYTE_ORDER);
+ }
+ }
+ throw new ParseException(INVALID_VALUE_FOR_BYTE_ORDER);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.ctf.core.event.CTFClock;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Clock metadata allows to describe the clock topology of the system, as well
+ * as to detail each clock parameter. In absence of clock description, it is
+ * assumed that all fields named timestamp use the same clock source, which
+ * increments once per nanosecond.
+ * <p>
+ * Describing a clock and how it is used by streams is threefold: first, the
+ * clock and clock topology should be described in a clock description block,
+ * e.g.:
+ *
+ * <pre>
+clock {
+ name = cycle_counter_sync;
+ uuid = "62189bee-96dc-11e0-91a8-cfa3d89f3923";
+ description = "Cycle counter synchronized across CPUs";
+ freq = 1000000000; // frequency, in Hz
+ // precision in seconds is: 1000 * (1/freq)
+ precision = 1000;
+
+ // clock value offset from Epoch is:
+ // offset_s + (offset * (1/freq))
+
+ offset_s = 1326476837;
+ offset = 897235420;
+ absolute = FALSE;
+};
+ * </pre>
+ *
+ * The mandatory name field specifies the name of the clock identifier, which
+ * can later be used as a reference. The optional field uuid is the unique
+ * identifier of the clock. It can be used to correlate different traces that
+ * use the same clock. An optional textual description string can be added with
+ * the description field. The freq field is the initial frequency of the clock,
+ * in Hz. If the freq field is not present, the frequency is assumed to be
+ * 1000000000 (providing clock increment of 1 ns). The optional precision field
+ * details the uncertainty on the clock measurements, in (1/freq) units. The
+ * offset_s and offset fields indicate the offset from POSIX.1 Epoch, 1970-01-01
+ * 00:00:00 +0000 (UTC), to the zero of value of the clock. The offset_s field
+ * is in seconds. The offset field is in (1/freq) units. If any of the offset_s
+ * or offset field is not present, it is assigned the 0 value. The field
+ * absolute is TRUE if the clock is a global reference across different clock
+ * UUID (e.g. NTP time). Otherwise, absolute is FALSE, and the clock can be
+ * considered as synchronized only with other clocks that have the same UUID.
+ * <p>
+ * Secondly, a reference to this clock should be added within an integer type:
+ *
+ * <pre>
+typealias integer {
+ size = 64; align = 1; signed = false;
+ map = clock.cycle_counter_sync.value;
+} := uint64_ccnt_t;
+ * </pre>
+ *
+ * Thirdly, stream declarations can reference the clock they use as a timestamp
+ * source:
+ *
+ * <pre>
+struct packet_context {
+ uint64_ccnt_t ccnt_begin;
+ uint64_ccnt_t ccnt_end;
+ // ...
+};
+
+stream {
+ // ...
+ event.header := struct {
+ uint64_ccnt_t timestamp;
+ // ...
+ };
+ packet.context := struct packet_context;
+};
+ * </pre>
+ *
+ * For a N-bit integer type referring to a clock, if the integer overflows
+ * compared to the N low order bits of the clock prior value found in the same
+ * stream, then it is assumed that one, and only one, overflow occurred. It is
+ * therefore important that events encoding time on a small number of bits
+ * happen frequently enough to detect when more than one N-bit overflow occurs.
+ * <p>
+ * In a packet context, clock field names ending with _begin and _end have a
+ * special meaning: this refers to the timestamps at, respectively, the
+ * beginning and the end of each packet.
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ * @author Efficios (documentation)
+ *
+ */
+public class ClockParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final ClockParser INSTANCE = new ClockParser();
+
+ private ClockParser() {
+ }
+
+ @Override
+ public CTFClock parse(CommonTree clock, ICommonTreeParserParameter unused) throws ParseException {
+ List<CommonTree> children = clock.getChildren();
+ CTFClock ctfClock = new CTFClock();
+ for (CommonTree child : children) {
+ final String key = child.getChild(0).getChild(0).getChild(0).getText();
+ final CommonTree value = (CommonTree) child.getChild(1).getChild(0).getChild(0);
+ final int type = value.getType();
+ final String text = value.getText();
+ switch (type) {
+ case CTFParser.INTEGER:
+ case CTFParser.DECIMAL_LITERAL:
+ /*
+ * Not a pretty hack, this is to make sure that there is no
+ * number overflow due to 63 bit integers. The offset should
+ * only really be an issue in the year 2262. the tracer in C/ASM
+ * can write an offset in an unsigned 64 bit long. In java, the
+ * last bit, being set to 1 will be read as a negative number,
+ * but since it is too big a positive it will throw an
+ * exception. this will happen in 2^63 ns from 1970. Therefore
+ * 293 years from 1970
+ */
+ Long numValue;
+ try {
+ numValue = Long.parseLong(text);
+ } catch (NumberFormatException e) {
+ throw new ParseException("Number conversion issue with " + text, e); //$NON-NLS-1$
+ }
+ ctfClock.addAttribute(key, numValue);
+ break;
+ default:
+ ctfClock.addAttribute(key, text);
+ }
+
+ }
+ return ctfClock;
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+
+/**
+ * A parser of pointer lists... like x.y.z
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ */
+public class PointerListStringParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final PointerListStringParser INSTANCE = new PointerListStringParser();
+
+ private PointerListStringParser() {
+ }
+
+ /**
+ * Creates the string representation of a type specifier.
+ *
+ * @param pointers
+ * A TYPE_SPECIFIER node.
+ * @param param
+ * unused
+ *
+ * @return A StringBuilder to which will be appended the string.
+ */
+ @Override
+ public StringBuilder parse(CommonTree pointers, ICommonTreeParserParameter param) {
+ StringBuilder sb = new StringBuilder();
+ List<CommonTree> pointerList = pointers.getChildren();
+ if (pointers.getChildCount() == 0) {
+ return sb;
+ }
+
+ for (CommonTree pointer : pointerList) {
+
+ sb.append(" *"); //$NON-NLS-1$
+ if (pointer.getChildCount() > 0) {
+ sb.append(" const"); //$NON-NLS-1$
+ }
+ }
+ return sb;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Type size, in bits, for integers and floats is that returned by sizeof() in C
+ * multiplied by CHAR_BIT. We require the size of char and unsigned char types
+ * (CHAR_BIT) to be fixed to 8 bits for cross-endianness compatibility.
+ *
+ * TSDL metadata representation:
+ *
+ * <pre>
+ * size = /* value is in bits * /
+ * </pre>
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - javadoc preamble.
+ */
+public class SizeParser implements ICommonTreeParser {
+ private static final String INVALID_VALUE_FOR_SIZE = "Invalid value for size"; //$NON-NLS-1$
+
+ /**
+ * Instance
+ */
+ public static final SizeParser INSTANCE = new SizeParser();
+
+ private SizeParser() {
+ }
+
+ /**
+ * Gets the value of a "size" integer attribute.
+ *
+ * @param rightNode
+ * A CTF_RIGHT node.
+ * @param param
+ * unused
+ * @return The "size" value. Can be 4 bytes.
+ * @throws ParseException
+ * if the size is not an int or a negative
+ */
+ @Override
+ public Long parse(CommonTree rightNode, ICommonTreeParserParameter param) throws ParseException {
+ CommonTree firstChild = (CommonTree) rightNode.getChild(0);
+ if (isUnaryInteger(firstChild)) {
+ if (rightNode.getChildCount() > 1) {
+ throw new ParseException(INVALID_VALUE_FOR_SIZE);
+ }
+ long size = UnaryIntegerParser.INSTANCE.parse(firstChild, null);
+ if (size < 1) {
+ throw new ParseException(INVALID_VALUE_FOR_SIZE);
+ }
+ return size;
+ }
+ throw new ParseException(INVALID_VALUE_FOR_SIZE);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * TSDL utils, this class provides some simple verifications for a common tree.
+ * These are useful before parsing.
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public final class TsdlUtils {
+
+ private static final UnaryStringParser STRING_PARSER = UnaryStringParser.INSTANCE;
+
+ private TsdlUtils() {
+ }
+
+ /**
+ * Is the tree a unary string
+ *
+ * @param node
+ * The node to check.
+ * @return True if the given node is an unary string.
+ */
+ public static boolean isUnaryString(CommonTree node) {
+ return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING));
+ }
+
+ /**
+ * Is the tree a unary string or a quoted string
+ *
+ * @param node
+ * The node to check.
+ * @return True if the given node is any type of unary string (no quotes,
+ * quotes, etc).
+ */
+ public static boolean isAnyUnaryString(CommonTree node) {
+ return (isUnaryString(node) || (node.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES));
+ }
+
+ /**
+ * Is the tree a unary integer
+ *
+ * @param node
+ * The node to check.
+ * @return True if the given node is an unary integer.
+ */
+ public static boolean isUnaryInteger(CommonTree node) {
+ return ((node.getType() == CTFParser.UNARY_EXPRESSION_DEC) ||
+ (node.getType() == CTFParser.UNARY_EXPRESSION_HEX) || (node.getType() == CTFParser.UNARY_EXPRESSION_OCT));
+ }
+
+ /**
+ * Concatenates a list of unary strings separated by arrows (->) or dots.
+ *
+ * @param strings
+ * A list, first element being an unary string, subsequent
+ * elements being ARROW or DOT nodes with unary strings as child.
+ * @return The string representation of the unary string chain.
+ * @throws ParseException
+ * If the strings list contains a non-string element
+ */
+ public static @NonNull String concatenateUnaryStrings(List<CommonTree> strings) throws ParseException {
+
+ StringBuilder sb = new StringBuilder();
+
+ CommonTree first = strings.get(0);
+ sb.append(STRING_PARSER.parse(first, null));
+
+ boolean isFirst = true;
+
+ for (CommonTree ref : strings) {
+ if (isFirst) {
+ isFirst = false;
+ continue;
+ }
+
+ CommonTree id = (CommonTree) ref.getChild(0);
+
+ if (ref.getType() == CTFParser.ARROW) {
+ sb.append("->"); //$NON-NLS-1$
+ } else { /* DOT */
+ sb.append('.');
+ }
+
+ sb.append(STRING_PARSER.parse(id, null));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Throws a ParseException stating that the parent-child relation between
+ * the given node and its parent is not valid. It means that the shape of
+ * the AST is unexpected.
+ *
+ * @param child
+ * The invalid child node.
+ * @return ParseException with details
+ */
+ public static ParseException childTypeError(CommonTree child) {
+ CommonTree parent = (CommonTree) child.getParent();
+ String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$
+ + " can't have a child of type " //$NON-NLS-1$
+ + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$
+
+ return new ParseException(error);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * The "typealias" declaration can be used to give a name (including pointer
+ * declarator specifier) to a type. It should also be used to map basic C types
+ * (float, int, unsigned long, ...) to a CTF type. Typealias is a superset of
+ * "typedef": it also allows assignment of a simple variable identifier to a
+ * type.
+ *
+ * @author Matthew Khouzam - Inital API and implementation
+ * @author Efficios - Documentation
+ *
+ */
+public class TypeAliasAliasParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final TypeAliasAliasParser INSTANCE = new TypeAliasAliasParser();
+
+ private TypeAliasAliasParser() {
+ }
+
+ /**
+ * Parses the alias part of a typealias. It parses the underlying specifier
+ * list and declarator and creates the string representation that will be
+ * used to register the type. In typealias integer{ blabla } := int, the
+ * alias is the <em>integer{ blabla }</em> part, and the target is the
+ * <em>int</em> part.
+ *
+ * @param typeSpecifier
+ * A TYPEALIAS_ALIAS node.
+ * @param param
+ * unused
+ *
+ * @return The string representation of the alias.
+ * @throws ParseException
+ * if an alias is not allowed here
+ */
+ @Override
+ public String parse(CommonTree typeSpecifier, ICommonTreeParserParameter param) throws ParseException {
+
+ List<CommonTree> children = typeSpecifier.getChildren();
+
+ CommonTree typeSpecifierList = null;
+ CommonTree typeDeclaratorList = null;
+ CommonTree typeDeclarator = null;
+ List<CommonTree> pointers = new LinkedList<>();
+
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.TYPE_SPECIFIER_LIST:
+ typeSpecifierList = child;
+ break;
+ case CTFParser.TYPE_DECLARATOR_LIST:
+ typeDeclaratorList = child;
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ /* If there is a type declarator list, extract the pointers */
+ if (typeDeclaratorList != null) {
+ /*
+ * Only allow one declarator
+ *
+ * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
+ */
+ if (typeDeclaratorList.getChildCount() != 1) {
+ throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
+ }
+
+ typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
+
+ List<CommonTree> typeDeclaratorChildren = typeDeclarator.getChildren();
+
+ for (CommonTree child : typeDeclaratorChildren) {
+ switch (child.getType()) {
+ case CTFParser.POINTER:
+ pointers.add(child);
+ break;
+ case CTFParser.IDENTIFIER:
+ throw new ParseException("Identifier (" + child.getText() //$NON-NLS-1$
+ + ") not expected in the typealias target"); //$NON-NLS-1$
+ default:
+ throw childTypeError(child);
+ }
+ }
+ }
+
+ return TypeDeclarationStringParser.INSTANCE.parse(typeSpecifierList, new TypeDeclarationStringParser.Param(pointers));
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * The "typealias" declaration can be used to give a name (including pointer
+ * declarator specifier) to a type. It should also be used to map basic C types
+ * (float, int, unsigned long, ...) to a CTF type. Typealias is a superset of
+ * "typedef": it also allows assignment of a simple variable identifier to a
+ * type.
+ *
+ * @author Matthew Khouzam - Inital API and implementation
+ * @author Efficios - Documentation
+ *
+ */
+public class TypeAliasParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameters for the typealias parser
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Parameter constructor
+ *
+ * @param trace
+ * the trace
+ * @param scope
+ * the scope
+ */
+ public Param(CTFTrace trace, DeclarationScope scope) {
+ fTrace = trace;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public final static TypeAliasParser INSTANCE = new TypeAliasParser();
+
+ private TypeAliasParser() {
+ }
+
+ @Override
+ public IDeclaration parse(CommonTree typealias, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = ((Param) param).fDeclarationScope;
+
+ List<CommonTree> children = typealias.getChildren();
+
+ CommonTree target = null;
+ CommonTree alias = null;
+
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.TYPEALIAS_TARGET:
+ target = child;
+ break;
+ case CTFParser.TYPEALIAS_ALIAS:
+ alias = child;
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+ CTFTrace trace = ((Param) param).fTrace;
+ IDeclaration targetDeclaration = TypeAliasTargetParser.INSTANCE.parse(target, new TypeAliasTargetParser.Param(trace, scope));
+
+ if ((targetDeclaration instanceof VariantDeclaration)
+ && ((VariantDeclaration) targetDeclaration).isTagged()) {
+ throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
+ }
+
+ String aliasString = TypeAliasAliasParser.INSTANCE.parse(alias, null);
+
+ scope.registerType(aliasString, targetDeclaration);
+ return targetDeclaration;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Type alias targets are the nodes of the declaration of the typealiases.
+ * Typealiases are a superset of typedef defined in TSDL.
+ *
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypeAliasTargetParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * A parameter object with a trace and a scope
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param scope
+ * the current scope
+ */
+ public Param(CTFTrace trace, DeclarationScope scope) {
+ fTrace = trace;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static TypeAliasTargetParser INSTANCE = new TypeAliasTargetParser();
+
+ private TypeAliasTargetParser() {
+ }
+
+ /**
+ * Parses the target part of a typealias and gets the corresponding
+ * declaration. In typealias integer{ blabla } := int, the alias is the
+ * <em>integer{ blabla }</em> part, and the target is the <em>int</em> part.
+ *
+ * Typealiases only allow one declarator.
+ *
+ * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted, otherwise
+ * the new type puint8_t would maps to two different types.
+ *
+ * @param target
+ * A TYPEALIAS_TARGET node.
+ *
+ * @return The corresponding declaration.
+ * @throws ParseException
+ * an invalid child in the tree
+ */
+ @Override
+ public IDeclaration parse(CommonTree target, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = ((Param) param).fDeclarationScope;
+
+ List<CommonTree> children = target.getChildren();
+
+ CommonTree typeSpecifierList = null;
+ CommonTree typeDeclaratorList = null;
+ CommonTree typeDeclarator = null;
+ StringBuilder identifierSB = new StringBuilder();
+
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.TYPE_SPECIFIER_LIST:
+ typeSpecifierList = child;
+ break;
+ case CTFParser.TYPE_DECLARATOR_LIST:
+ typeDeclaratorList = child;
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ if (typeDeclaratorList != null) {
+ /*
+ * Only allow one declarator
+ *
+ * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
+ * otherwise the new type puint8_t would maps to two different
+ * types.
+ */
+ if (typeDeclaratorList.getChildCount() != 1) {
+ throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
+ }
+
+ typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
+ }
+ if (typeSpecifierList == null) {
+ throw new ParseException("Cannot have a typealias with no specifiers"); //$NON-NLS-1$
+ }
+ CTFTrace trace = ((Param) param).fTrace;
+ /* Parse the target type and get the declaration */
+ IDeclaration targetDeclaration = TypeDeclaratorParser.INSTANCE.parse(typeDeclarator,
+ new TypeDeclaratorParser.Param(trace, typeSpecifierList, scope, identifierSB));
+
+ /*
+ * We don't allow identifier in the target
+ *
+ * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
+ * permitted
+ */
+ if (identifierSB.length() > 0) {
+ throw new ParseException("Identifier (" + identifierSB.toString() //$NON-NLS-1$
+ + ") not expected in the typealias target"); //$NON-NLS-1$
+ }
+
+ return targetDeclaration;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Basic parser for all abstract data types
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypeDeclarationParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object with a current scope and a list of pointers
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final @Nullable List<CommonTree> fPointerList;
+
+ /**
+ * Constructor
+ *
+ * @param pointerList
+ * the list of pointers
+ * @param scope
+ * the current scope
+ */
+ public Param(@Nullable List<CommonTree> pointerList, DeclarationScope scope) {
+ fPointerList = pointerList;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public final static TypeDeclarationParser INSTANCE = new TypeDeclarationParser();
+
+ private TypeDeclarationParser() {
+ }
+
+ /**
+ * Parses a type specifier list as a user-declared type.
+ *
+ * @param typeSpecifierList
+ * A TYPE_SPECIFIER_LIST node containing a user-declared type.
+ * @param param
+ * (pointerList, currentscope) A list of POINTER nodes that apply
+ * to the type specified in typeSpecifierList.
+ *
+ * @return The corresponding declaration.
+ * @throws ParseException
+ * If the type does not exist (has not been found).
+ */
+ @Override
+ public IDeclaration parse(CommonTree typeSpecifierList, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = ((Param) param).fDeclarationScope;
+
+ List<CommonTree> pointerList = ((Param) param).fPointerList;
+ /* Create the string representation of the type declaration */
+ String typeStringRepresentation = TypeDeclarationStringParser.INSTANCE.parse(typeSpecifierList, new TypeDeclarationStringParser.Param(pointerList));
+
+ /*
+ * Use the string representation to search the type in the current scope
+ */
+ IDeclaration decl = scope.lookupTypeRecursive(typeStringRepresentation);
+
+ if (decl == null) {
+ throw new ParseException("Type " + typeStringRepresentation //$NON-NLS-1$
+ + " has not been defined."); //$NON-NLS-1$
+ }
+
+ return decl;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Type declaration String parser
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypeDeclarationStringParser implements ICommonTreeParser {
+
+ /**
+ * Parameter Object with a list of common trees
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ public static final class Param implements ICommonTreeParserParameter {
+ private final List<CommonTree> fList;
+
+ /**
+ * Constructor
+ *
+ * @param list
+ * List of trees
+ */
+ public Param(List<CommonTree> list) {
+ fList = list;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public static final TypeDeclarationStringParser INSTANCE = new TypeDeclarationStringParser();
+
+ private TypeDeclarationStringParser() {
+ }
+
+ /**
+ * Creates the string representation of a type specifier.
+ *
+ * @param typeSpecifierList
+ * A TYPE_SPECIFIER node.
+ *
+ * @return A StringBuilder to which will be appended the string.
+ * @throws ParseException
+ * invalid node
+ */
+ @Override
+ public String parse(CommonTree typeSpecifierList, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ List<CommonTree> pointers = ((Param) param).fList;
+ StringBuilder sb = new StringBuilder();
+ sb.append(TypeSpecifierListStringParser.INSTANCE.parse(typeSpecifierList, null));
+ if (pointers != null) {
+ CommonTree temp = new CommonTree();
+ for (CommonTree pointer : pointers) {
+ temp.addChild(pointer);
+ }
+ sb.append(PointerListStringParser.INSTANCE.parse(temp, null));
+ }
+ return sb.toString();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event.EventScopeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream.StreamScopeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace.TraceScopeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.types.ArrayDeclaration;
+import org.eclipse.tracecompass.internal.ctf.core.event.types.SequenceDeclaration;
+
+/**
+ * A type declarator parser
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypeDeclaratorParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * The parameter object for type declarator parsers
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final CommonTree fListNode;
+ private final StringBuilder fBuilder;
+ private final CTFTrace fTrace;
+
+ /**
+ * Parameter constructor
+ *
+ * @param trace
+ * the trace
+ * @param listNode
+ * the listNode
+ * @param scope
+ * the scope
+ * @param builder
+ * the string builder to populate
+ */
+ public Param(CTFTrace trace, CommonTree listNode, DeclarationScope scope, StringBuilder builder) {
+ fTrace = trace;
+ fListNode = listNode;
+ fDeclarationScope = scope;
+ fBuilder = builder;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static TypeDeclaratorParser INSTANCE = new TypeDeclaratorParser();
+
+ private TypeDeclaratorParser() {
+ }
+
+ /**
+ * Parses a pair type declarator / type specifier list and returns the
+ * corresponding declaration. If it is present, it also writes the
+ * identifier of the declarator in the given {@link StringBuilder}.
+ *
+ * @param typeDeclarator
+ * A TYPE_DECLARATOR node.
+ * @param param
+ * the parameter object
+ * @return The corresponding declaration.
+ * @throws ParseException
+ * If there is an error finding or creating the declaration.
+ */
+ @Override
+ public IDeclaration parse(CommonTree typeDeclarator, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = ((Param) param).fDeclarationScope;
+ CTFTrace trace = ((Param) param).fTrace;
+ CommonTree typeSpecifierList = ((Param) param).fListNode;
+
+ IDeclaration declaration = null;
+ List<CommonTree> children = null;
+ List<@NonNull CommonTree> pointers = new LinkedList<>();
+ List<CommonTree> lengths = new LinkedList<>();
+ CommonTree identifier = null;
+
+ /* Separate the tokens by type */
+ if (typeDeclarator != null) {
+ children = typeDeclarator.getChildren();
+ for (CommonTree child : children) {
+
+ switch (child.getType()) {
+ case CTFParser.POINTER:
+ pointers.add(child);
+ break;
+ case CTFParser.IDENTIFIER:
+ identifier = child;
+ break;
+ case CTFParser.LENGTH:
+ lengths.add(child);
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ }
+
+ /*
+ * Parse the type specifier list, which is the "base" type. For example,
+ * it would be int in int a[3][len].
+ */
+ declaration = TypeSpecifierListParser.INSTANCE.parse(typeSpecifierList, new TypeSpecifierListParser.Param(trace, pointers, identifier, scope));
+
+ /*
+ * Each length subscript means that we must create a nested array or
+ * sequence. For example, int a[3][len] means that we have an array of 3
+ * (sequences of length 'len' of (int)).
+ */
+ if (!lengths.isEmpty()) {
+ /* We begin at the end */
+ Collections.reverse(lengths);
+
+ for (CommonTree length : lengths) {
+ /*
+ * By looking at the first expression, we can determine whether
+ * it is an array or a sequence.
+ */
+ List<CommonTree> lengthChildren = length.getChildren();
+
+ CommonTree first = lengthChildren.get(0);
+ if (isUnaryInteger(first)) {
+ /* Array */
+ int arrayLength = UnaryIntegerParser.INSTANCE.parse(first, null).intValue();
+
+ if (arrayLength < 1) {
+ throw new ParseException("Array length is negative"); //$NON-NLS-1$
+ }
+
+ /* Create the array declaration. */
+ declaration = new ArrayDeclaration(arrayLength, declaration);
+ } else if (isAnyUnaryString(first)) {
+ /* Sequence */
+ String lengthName = concatenateUnaryStrings(lengthChildren);
+
+ /* check that lengthName was declared */
+ if (isSignedIntegerField(lengthName, scope)) {
+ throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
+ }
+ /* Create the sequence declaration. */
+ declaration = new SequenceDeclaration(lengthName,
+ declaration);
+ } else if (isTrace(first)) {
+ /* Sequence */
+ String lengthName = TraceScopeParser.INSTANCE.parse(null, new TraceScopeParser.Param(lengthChildren));
+
+ /* check that lengthName was declared */
+ if (isSignedIntegerField(lengthName, scope)) {
+ throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
+ }
+ /* Create the sequence declaration. */
+ declaration = new SequenceDeclaration(lengthName,
+ declaration);
+
+ } else if (isStream(first)) {
+ /* Sequence */
+ String lengthName = StreamScopeParser.INSTANCE.parse(null, new StreamScopeParser.Param(lengthChildren));
+
+ /* check that lengthName was declared */
+ if (isSignedIntegerField(lengthName, scope)) {
+ throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
+ }
+ /* Create the sequence declaration. */
+ declaration = new SequenceDeclaration(lengthName,
+ declaration);
+ } else if (isEvent(first)) {
+ /* Sequence */
+ String lengthName = EventScopeParser.INSTANCE.parse(null, new EventScopeParser.Param(lengthChildren));
+
+ /* check that lengthName was declared */
+ if (isSignedIntegerField(lengthName, scope)) {
+ throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
+ }
+ /* Create the sequence declaration. */
+ declaration = new SequenceDeclaration(lengthName,
+ declaration);
+ } else {
+ throw childTypeError(first);
+ }
+ }
+ }
+
+ if (identifier != null) {
+ final String text = identifier.getText();
+ if (text == null) {
+ throw new ParseException("Cannot have unidentified declarator"); //$NON-NLS-1$
+ }
+ ((Param) param).fBuilder.append(text);
+ registerType(declaration, text, scope);
+ }
+
+ return declaration;
+ }
+
+ private static boolean isSignedIntegerField(String lengthName, DeclarationScope scope) throws ParseException {
+ IDeclaration decl = scope.lookupIdentifierRecursive(lengthName);
+ if (decl instanceof IntegerDeclaration) {
+ return ((IntegerDeclaration) decl).isSigned();
+ }
+ throw new ParseException("Is not an integer: " + lengthName); //$NON-NLS-1$
+
+ }
+
+ private static boolean isEvent(CommonTree first) {
+ return first.getType() == CTFParser.EVENT;
+ }
+
+ private static boolean isStream(CommonTree first) {
+ return first.getType() == CTFParser.STREAM;
+ }
+
+ private static boolean isTrace(CommonTree first) {
+ return first.getType() == CTFParser.TRACE;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Type specifier list name parser (is it a bool? a string... )
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypeSpecifierListNameParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final TypeSpecifierListNameParser INSTANCE = new TypeSpecifierListNameParser();
+
+ private TypeSpecifierListNameParser() {
+ }
+
+ /**
+ * Creates the string representation of a type specifier.
+ *
+ * @param typeSpecifier
+ * A TYPE_SPECIFIER node.
+ *
+ * @return param unused
+ * @throws ParseException
+ * invalid node
+ */
+ @Override
+ public StringBuilder parse(CommonTree typeSpecifier, ICommonTreeParserParameter param) throws ParseException {
+ StringBuilder sb = new StringBuilder();
+ switch (typeSpecifier.getType()) {
+ case CTFParser.FLOATTOK:
+ case CTFParser.INTTOK:
+ case CTFParser.LONGTOK:
+ case CTFParser.SHORTTOK:
+ case CTFParser.SIGNEDTOK:
+ case CTFParser.UNSIGNEDTOK:
+ case CTFParser.CHARTOK:
+ case CTFParser.DOUBLETOK:
+ case CTFParser.VOIDTOK:
+ case CTFParser.BOOLTOK:
+ case CTFParser.COMPLEXTOK:
+ case CTFParser.IMAGINARYTOK:
+ case CTFParser.CONSTTOK:
+ case CTFParser.IDENTIFIER:
+ parseSimple(typeSpecifier, sb);
+ break;
+ case CTFParser.STRUCT: {
+ parseStruct(typeSpecifier, sb);
+ break;
+ }
+ case CTFParser.VARIANT: {
+ parseVariant(typeSpecifier, sb);
+ break;
+ }
+ case CTFParser.ENUM: {
+ parseEnum(typeSpecifier, sb);
+ break;
+ }
+ case CTFParser.FLOATING_POINT:
+ case CTFParser.INTEGER:
+ case CTFParser.STRING:
+ throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
+ default:
+ throw childTypeError(typeSpecifier);
+ }
+ return sb;
+
+ }
+
+ private static void parseEnum(CommonTree typeSpecifier, StringBuilder sb) throws ParseException {
+ CommonTree enumName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.ENUM_NAME);
+ if (enumName == null) {
+ throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
+ }
+
+ CommonTree enumNameIdentifier = (CommonTree) enumName.getChild(0);
+
+ parseSimple(enumNameIdentifier, sb);
+ }
+
+ private static void parseVariant(CommonTree typeSpecifier, StringBuilder sb) throws ParseException {
+ CommonTree variantName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.VARIANT_NAME);
+ if (variantName == null) {
+ throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
+ }
+
+ CommonTree variantNameIdentifier = (CommonTree) variantName.getChild(0);
+
+ parseSimple(variantNameIdentifier, sb);
+ }
+
+ private static void parseSimple(CommonTree typeSpecifier, StringBuilder sb) {
+ sb.append(typeSpecifier.getText());
+ }
+
+ private static void parseStruct(CommonTree typeSpecifier, StringBuilder sb) throws ParseException {
+ CommonTree structName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.STRUCT_NAME);
+ if (structName == null) {
+ throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
+ }
+
+ CommonTree structNameIdentifier = (CommonTree) structName.getChild(0);
+
+ parseSimple(structNameIdentifier, sb);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.nio.ByteOrder;
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.enumeration.EnumParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.floatingpoint.FloatDeclarationParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer.IntegerDeclarationParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.string.StringDeclarationParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.struct.StructParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.variant.VariantParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderCompactDeclaration;
+import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderLargeDeclaration;
+
+/**
+ * Parse the specifiers. Make sure they are known types. This can be seen as a
+ * declaration factory.
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypeSpecifierListParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter Object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final @Nullable List<CommonTree> fListNode;
+ private final CTFTrace fTrace;
+ private final @Nullable CommonTree fIdentifier;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * The trace
+ * @param listNode
+ * A list of POINTER nodes that apply to the specified type.
+ * @param identifier
+ * the identifier node
+ * @param scope
+ * the current scope
+ */
+ public Param(CTFTrace trace, @Nullable List<CommonTree> listNode, @Nullable CommonTree identifier, DeclarationScope scope) {
+ fTrace = trace;
+ fListNode = listNode;
+ fIdentifier = identifier;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static TypeSpecifierListParser INSTANCE = new TypeSpecifierListParser();
+
+ private TypeSpecifierListParser() {
+ }
+
+ /**
+ * Parses a type specifier list and returns the corresponding declaration.
+ *
+ * @param typeSpecifierList
+ * A TYPE_SPECIFIER_LIST node.
+ * @param param
+ * The paramer object
+ *
+ * @return The corresponding declaration.
+ * @throws ParseException
+ * If the type has not been defined or if there is an error
+ * creating the declaration.
+ */
+ @Override
+ public IDeclaration parse(CommonTree typeSpecifierList, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ final DeclarationScope scope = ((Param) param).fDeclarationScope;
+ List<@NonNull CommonTree> pointerList = ((Param) param).fListNode;
+ CTFTrace trace = ((Param) param).fTrace;
+ CommonTree identifier = ((Param) param).fIdentifier;
+ IDeclaration declaration = null;
+
+ /*
+ * By looking at the first element of the type specifier list, we can
+ * determine which type it belongs to.
+ */
+ CommonTree firstChild = (CommonTree) typeSpecifierList.getChild(0);
+
+ switch (firstChild.getType()) {
+ case CTFParser.FLOATING_POINT:
+ declaration = FloatDeclarationParser.INSTANCE.parse(firstChild, new FloatDeclarationParser.Param(trace));
+ break;
+ case CTFParser.INTEGER:
+ declaration = IntegerDeclarationParser.INSTANCE.parse(firstChild, new IntegerDeclarationParser.Param(trace));
+ break;
+ case CTFParser.STRING:
+ declaration = StringDeclarationParser.INSTANCE.parse(firstChild, null);
+ break;
+ case CTFParser.STRUCT:
+ declaration = StructParser.INSTANCE.parse(firstChild, new StructParser.Param(trace, identifier, scope));
+ StructDeclaration structDeclaration = (StructDeclaration) declaration;
+ IDeclaration idEnumDecl = structDeclaration.getFields().get("id"); //$NON-NLS-1$
+ if (idEnumDecl instanceof EnumDeclaration) {
+ EnumDeclaration enumDeclaration = (EnumDeclaration) idEnumDecl;
+ ByteOrder bo = enumDeclaration.getContainerType().getByteOrder();
+ if (EventHeaderCompactDeclaration.getEventHeader(bo).isCompactEventHeader(structDeclaration)) {
+ declaration = EventHeaderCompactDeclaration.getEventHeader(bo);
+ } else if (EventHeaderLargeDeclaration.getEventHeader(bo).isLargeEventHeader(structDeclaration)) {
+ declaration = EventHeaderLargeDeclaration.getEventHeader(bo);
+ }
+ }
+ break;
+ case CTFParser.VARIANT:
+ declaration = VariantParser.INSTANCE.parse(firstChild, new VariantParser.Param(trace, scope));
+ break;
+ case CTFParser.ENUM:
+ declaration = EnumParser.INSTANCE.parse(firstChild, new EnumParser.Param(trace, scope));
+ break;
+ case CTFParser.IDENTIFIER:
+ case CTFParser.FLOATTOK:
+ case CTFParser.INTTOK:
+ case CTFParser.LONGTOK:
+ case CTFParser.SHORTTOK:
+ case CTFParser.SIGNEDTOK:
+ case CTFParser.UNSIGNEDTOK:
+ case CTFParser.CHARTOK:
+ case CTFParser.DOUBLETOK:
+ case CTFParser.VOIDTOK:
+ case CTFParser.BOOLTOK:
+ case CTFParser.COMPLEXTOK:
+ case CTFParser.IMAGINARYTOK:
+ declaration = TypeDeclarationParser.INSTANCE.parse(typeSpecifierList, new TypeDeclarationParser.Param(pointerList, scope));
+ break;
+ default:
+ throw childTypeError(firstChild);
+ }
+
+ return declaration;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Type specifier list string parser, parses a list of names
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypeSpecifierListStringParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final TypeSpecifierListStringParser INSTANCE = new TypeSpecifierListStringParser();
+
+ private TypeSpecifierListStringParser() {
+ }
+
+ /**
+ * Creates the string representation of a type specifier.
+ *
+ * @param typeSpecifierList
+ * A TYPE_SPECIFIER node.
+ * @param param
+ * unused
+ *
+ * @return A StringBuilder to which will be appended the string.
+ * @throws ParseException
+ * invalid node
+ */
+ @Override
+ public StringBuilder parse(CommonTree typeSpecifierList, ICommonTreeParserParameter param) throws ParseException {
+ StringBuilder sb = new StringBuilder();
+ List<CommonTree> children = typeSpecifierList.getChildren();
+
+ boolean firstItem = true;
+
+ for (CommonTree child : children) {
+ if (!firstItem) {
+ sb.append(' ');
+
+ }
+
+ firstItem = false;
+
+ /* Append the string that represents this type specifier. */
+ sb.append(TypeSpecifierListNameParser.INSTANCE.parse(child, null));
+ }
+ return sb;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * C typedef parser
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TypedefParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object with a trace and current scope
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param scope
+ * the current scope
+ */
+ public Param(CTFTrace trace, DeclarationScope scope) {
+ fTrace = trace;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static TypedefParser INSTANCE = new TypedefParser();
+
+ private TypedefParser() {
+ }
+
+ /**
+ * Parses a typedef node. This creates and registers a new declaration for
+ * each declarator found in the typedef.
+ *
+ * @param typedef
+ * A TYPEDEF node.
+ *
+ * @return map of type name to type declaration
+ * @throws ParseException
+ * If there is an error creating the declaration.
+ */
+ @Override
+ public Map<String, IDeclaration> parse(CommonTree typedef, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = ((Param) param).fDeclarationScope;
+
+ CommonTree typeDeclaratorListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
+ if (typeDeclaratorListNode == null) {
+ throw new ParseException("Cannot have a typedef without a declarator"); //$NON-NLS-1$
+ }
+ CommonTree typeSpecifierListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
+ if (typeSpecifierListNode == null) {
+ throw new ParseException("Cannot have a typedef without specifiers"); //$NON-NLS-1$
+ }
+ List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
+
+ Map<String, IDeclaration> declarations = new HashMap<>();
+
+ for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
+ StringBuilder identifierSB = new StringBuilder();
+ CTFTrace trace = ((Param) param).fTrace;
+ IDeclaration typeDeclaration = TypeDeclaratorParser.INSTANCE.parse(typeDeclaratorNode, new TypeDeclaratorParser.Param(trace, typeSpecifierListNode, scope, identifierSB));
+
+ if ((typeDeclaration instanceof VariantDeclaration)
+ && !((VariantDeclaration) typeDeclaration).isTagged()) {
+ throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
+ }
+
+ scope.registerType(identifierSB.toString(), typeDeclaration);
+
+ declarations.put(identifierSB.toString(), typeDeclaration);
+ }
+ return declarations;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Unary Integer Parser, along with Unary string parser, one of the two most
+ * used parsers in TSDL. Converts a string representation of an integer into a
+ * java {@link Long}
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public final class UnaryIntegerParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final UnaryIntegerParser INSTANCE = new UnaryIntegerParser();
+
+ private UnaryIntegerParser() {
+ }
+
+ /**
+ * Parses an unary integer (dec, hex or oct).
+ *
+ * @param unaryInteger
+ * An unary integer node.
+ *
+ * @return The integer value.
+ * @throws ParseException
+ * on an invalid integer format ("bob" for example)
+ */
+ @Override
+ public Long parse(CommonTree unaryInteger, ICommonTreeParserParameter notUsed) throws ParseException {
+ List<CommonTree> children = unaryInteger.getChildren();
+ CommonTree value = children.get(0);
+ String strval = value.getText();
+
+ long intval;
+ try {
+ intval = Long.decode(strval);
+ } catch (NumberFormatException e) {
+ throw new ParseException("Invalid integer format: " + strval, e); //$NON-NLS-1$
+ }
+
+ /* The rest of children are sign */
+ if ((children.size() % 2) == 0) {
+ return -intval;
+ }
+ return intval;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Unary String Parser, along with Unary integer parser, one of the two most
+ * used parsers in TSDL. Takes a basic node of the AST and converts it to a java
+ * {@link String}.]
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public final class UnaryStringParser implements ICommonTreeParser {
+
+ /** Instance */
+ public static final UnaryStringParser INSTANCE = new UnaryStringParser();
+
+ private UnaryStringParser() {
+ }
+
+ /**
+ * Parses a unary string node and return the string value.
+ *
+ * @param unaryString
+ * The unary string node to parse (type UNARY_EXPRESSION_STRING
+ * or UNARY_EXPRESSION_STRING_QUOTES).
+ *
+ * @return The string value.
+ * @throws ParseException
+ * The tree node (unaryString) is not a unary string.
+ */
+ /*
+ * It would be really nice to remove the quotes earlier, such as in the
+ * parser.
+ */
+ @Override
+ public String parse(CommonTree unaryString, ICommonTreeParserParameter notUsed) throws ParseException {
+ CommonTree value = (CommonTree) unaryString.getChild(0);
+ if (value.getType() == CTFParser.UNARY_EXPRESSION_STRING) {
+ value = (CommonTree) value.getChild(0);
+ }
+ String strval = value.getText();
+ if (strval == null) {
+ throw new ParseException("Unary String was null"); //$NON-NLS-1$
+ }
+
+ /* Remove quotes */
+ if (unaryString.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES) {
+ strval = strval.substring(1, strval.length() - 1);
+ }
+
+ return strval;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.enumeration;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Body parser for an enumeration, this parses the list of elements in an enum
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class EnumBodyParser implements ICommonTreeParser {
+
+ /**
+ * Enum declaration parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+
+ private final EnumDeclaration fEnumDeclaration;
+
+ /**
+ * Constructor
+ *
+ * @param enumDeclaration
+ * the enumeration
+ */
+ public Param(EnumDeclaration enumDeclaration) {
+ fEnumDeclaration = enumDeclaration;
+ }
+
+ }
+
+ /**
+ * The instance
+ */
+ public static final EnumBodyParser INSTANCE = new EnumBodyParser();
+
+ private EnumBodyParser() {
+ }
+
+ @Override
+ public EnumDeclaration parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ Param parameter = (Param) param;
+ EnumDeclaration enumDeclaration = parameter.fEnumDeclaration;
+ List<CommonTree> enumerators = tree.getChildren();
+ /*
+ * Start at -1, so that if the first enumrator has no explicit value, it
+ * will choose 0
+ */
+ for (CommonTree enumerator : enumerators) {
+ EnumeratorParser.INSTANCE.parse(enumerator, new EnumeratorParser.Param(enumDeclaration));
+ }
+ return enumDeclaration;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.enumeration;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser;
+
+/**
+ * This parses the internal type of the enum
+ *
+ * @author Matthew Khouzam - Initial implementation and API
+ *
+ */
+public class EnumContainerParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object with a trace and scope
+ *
+ * @author Matthew Khouzam
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+
+ private final DeclarationScope fCurrentScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param currentScope
+ * the scope
+ */
+ public Param(CTFTrace trace, DeclarationScope currentScope) {
+ fTrace = trace;
+ fCurrentScope = currentScope;
+ }
+
+ }
+
+ /**
+ * The instance
+ */
+ public static final EnumContainerParser INSTANCE = new EnumContainerParser();
+
+ private EnumContainerParser() {
+ }
+
+ /**
+ * Parses an enum container type node and returns the corresponding integer
+ * type.
+ *
+ * @param enumContainerType
+ * An ENUM_CONTAINER_TYPE node.
+ *
+ * @return An integer declaration corresponding to the container type.
+ * @throws ParseException
+ * If the type does not parse correctly or if it is not an
+ * integer type.
+ */
+ @Override
+ public IntegerDeclaration parse(CommonTree enumContainerType, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ Param parameter = (Param) param;
+ DeclarationScope scope = parameter.fCurrentScope;
+
+ /* Get the child, which should be a type specifier list */
+ CommonTree typeSpecifierList = (CommonTree) enumContainerType.getChild(0);
+
+ CTFTrace trace = ((Param) param).fTrace;
+ /* Parse it and get the corresponding declaration */
+ IDeclaration decl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifierList, new TypeSpecifierListParser.Param(trace, null, null, scope));
+
+ /* If is is an integer, return it, else throw an error */
+ if (decl instanceof IntegerDeclaration) {
+ return (IntegerDeclaration) decl;
+ }
+ throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.enumeration;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ *
+ * Enumerations are a mapping between an integer type and a table of strings.
+ * The numerical representation of the enumeration follows the integer type
+ * specified by the metadata. The enumeration mapping table is detailed in the
+ * enumeration description within the metadata. The mapping table maps inclusive
+ * value ranges (or single values) to strings. Instead of being limited to
+ * simple `value -> string` mappings, these enumerations map `[ start_value ...
+ * end_value ] -> string`, which map inclusive ranges of values to strings. An
+ * enumeration from the C language can be represented in this format by having
+ * the same `start_value` and `end_value` for each mapping, which is in fact a
+ * range of size 1. This single-value range is supported without repeating the
+ * start and end values with the `value = string` declaration. Enumerations need
+ * to contain at least one entry. <br>
+ *
+ * <pre>
+enum name : integer_type {
+ somestring = start_value1 ... end_value1 ,
+ "other string" = start_value2 ... end_value2 ,
+ yet_another_string, will be assigned to end_value2 + 1 ,
+ "some other string" = value,
+ //...
+}
+ * </pre>
+ *
+ * If the values are omitted, the enumeration starts at 0 and increment of 1 for
+ * each entry. An entry with omitted value that follows a range entry takes as
+ * value the `end_value` of the previous range + 1:
+ *
+ * <pre>
+enum name : unsigned int {
+ ZERO,
+ ONE,
+ TWO,
+ TEN = 10,
+ ELEVEN,
+}
+ * </pre>
+ *
+ * Overlapping ranges within a single enumeration are implementation defined.
+ * <br>
+ * A nameless enumeration can be declared as a field type or as part of a
+ * `typedef`:
+ *
+ * <pre>
+enum : integer_type {
+ // ...
+}
+ * </pre>
+ *
+ * Enumerations omitting the container type`:integer_type`use the`int`type(for
+ * compatibility with C99).The`int`type _must be_ previously declared,e.g.:
+ *
+ * <pre>
+ * typealias integer{size=32;align=32;signed=true;}:=int;
+
+enum{
+// ...
+}
+ * </pre>
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Description
+ *
+ */
+public class EnumParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter Object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+
+ private final DeclarationScope fCurrentScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Parameter object constructor
+ *
+ * @param trace
+ * Trace to populate
+ * @param currentScope
+ * the current scope
+ */
+ public Param(CTFTrace trace, DeclarationScope currentScope) {
+ fTrace = trace;
+ fCurrentScope = currentScope;
+ }
+
+ }
+
+ /**
+ * Instance
+ */
+ public static final EnumParser INSTANCE = new EnumParser();
+
+ private EnumParser() {
+ }
+
+ /**
+ * Parses an enum declaration and returns the corresponding declaration.
+ *
+ * @param theEnum
+ * An ENUM node.
+ *
+ * @return The corresponding enum declaration.
+ * @throws ParseException
+ * there was an error parsing the enum. Probably a mal-formed
+ * tree.
+ */
+ @Override
+ public EnumDeclaration parse(CommonTree theEnum, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ Param parameter = (Param) param;
+ DeclarationScope scope = parameter.fCurrentScope;
+
+ List<CommonTree> children = theEnum.getChildren();
+
+ /* The return value */
+ EnumDeclaration enumDeclaration = null;
+
+ /* Name */
+ String enumName = null;
+
+ /* Body */
+ CommonTree enumBody = null;
+
+ /* Container type */
+ IntegerDeclaration containerTypeDeclaration = null;
+
+ /* Loop on all children and identify what we have to work with. */
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.ENUM_NAME: {
+ CommonTree enumNameIdentifier = (CommonTree) child.getChild(0);
+ enumName = enumNameIdentifier.getText();
+ break;
+ }
+ case CTFParser.ENUM_BODY: {
+ enumBody = child;
+ break;
+ }
+ case CTFParser.ENUM_CONTAINER_TYPE: {
+ CTFTrace trace = ((Param) param).fTrace;
+ containerTypeDeclaration = EnumContainerParser.INSTANCE.parse(child, new EnumContainerParser.Param(trace, scope));
+ break;
+ }
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ /*
+ * If the container type has not been defined explicitly, we assume it
+ * is "int".
+ */
+ if (containerTypeDeclaration == null) {
+ IDeclaration enumDecl;
+ /*
+ * it could be because the enum was already declared.
+ */
+ if (enumName != null) {
+ scope.setName(enumName);
+ enumDecl = scope.lookupEnumRecursive(enumName);
+ if (enumDecl != null) {
+ return (EnumDeclaration) enumDecl;
+ }
+ }
+
+ IDeclaration decl = scope.lookupTypeRecursive("int"); //$NON-NLS-1$
+
+ if (decl == null) {
+ throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$
+ } else if (!(decl instanceof IntegerDeclaration)) {
+ throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$
+ }
+
+ containerTypeDeclaration = (IntegerDeclaration) decl;
+ }
+
+ /*
+ * If it has a body, it's a new declaration, otherwise it's a reference
+ * to an existing declaration. Same logic as struct.
+ */
+ if (enumBody != null) {
+ /*
+ * If enum has a name, check if already defined in the current
+ * scope.
+ */
+ if ((enumName != null)
+ && (scope.lookupEnum(enumName) != null)) {
+ throw new ParseException("enum " + enumName //$NON-NLS-1$
+ + " already defined"); //$NON-NLS-1$
+ }
+
+ /* Create the declaration */
+ enumDeclaration = new EnumDeclaration(containerTypeDeclaration);
+
+ /* Parse the body */
+ EnumBodyParser.INSTANCE.parse(enumBody, new EnumBodyParser.Param(enumDeclaration));
+
+ /* If the enum has name, add it to the current scope. */
+ if (enumName != null) {
+ scope.registerEnum(enumName, enumDeclaration);
+ }
+ } else {
+ if (enumName != null) {
+ /* Name and !body */
+
+ /* Lookup the name in the current scope. */
+ enumDeclaration = scope.lookupEnumRecursive(enumName);
+
+ /*
+ * If not found, it means that an enum with such name has not
+ * been defined
+ */
+ if (enumDeclaration == null) {
+ throw new ParseException("enum " + enumName //$NON-NLS-1$
+ + " is not defined"); //$NON-NLS-1$
+ }
+ } else {
+ /* !Name and !body */
+ throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
+ }
+ }
+
+ return enumDeclaration;
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.enumeration;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryStringParser;
+
+/**
+ * The parser for individual enumerators within an enum body
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ *
+ */
+public final class EnumeratorParser implements ICommonTreeParser {
+
+ /**
+ * A parameter containing an enum declaration
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final EnumDeclaration fEnumDeclaration;
+
+ /**
+ * Constructor
+ *
+ * @param enumDeclaration
+ * the enum declaration to populate
+ */
+ public Param(EnumDeclaration enumDeclaration) {
+ fEnumDeclaration = enumDeclaration;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public static final EnumeratorParser INSTANCE = new EnumeratorParser();
+
+ private EnumeratorParser() {
+ }
+
+ /**
+ * Parses an enumerator node and adds an enumerator declaration to an
+ * enumeration declaration.
+ *
+ * The high value of the range of the last enumerator is needed in case the
+ * current enumerator does not specify its value.
+ *
+ * @param enumerator
+ * An ENUM_ENUMERATOR node.
+ * @param param
+ * an enumeration declaration to which will be added the
+ * enumerator.
+ * @return The high value of the value range of the current enumerator.
+ * @throws ParseException
+ * if the element failed to add
+ */
+ @Override
+ public Long parse(CommonTree enumerator, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ EnumDeclaration enumDeclaration = ((Param) param).fEnumDeclaration;
+
+ List<CommonTree> children = enumerator.getChildren();
+
+ long low = 0, high = 0;
+ boolean valueSpecified = false;
+ String label = null;
+
+ for (CommonTree child : children) {
+ if (isAnyUnaryString(child)) {
+ label = UnaryStringParser.INSTANCE.parse(child, null);
+ } else if (child.getType() == CTFParser.ENUM_VALUE) {
+
+ valueSpecified = true;
+
+ low = UnaryIntegerParser.INSTANCE.parse((CommonTree) child.getChild(0), null);
+ high = low;
+ } else if (child.getType() == CTFParser.ENUM_VALUE_RANGE) {
+
+ valueSpecified = true;
+
+ low = UnaryIntegerParser.INSTANCE.parse((CommonTree) child.getChild(0), null);
+ high = UnaryIntegerParser.INSTANCE.parse((CommonTree) child.getChild(1), null);
+ } else {
+ throw childTypeError(child);
+ }
+ }
+
+ if (low > high) {
+ throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
+ }
+ if (valueSpecified && !enumDeclaration.add(low, high, label)) {
+ throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
+ } else if (!valueSpecified && !enumDeclaration.add(label)) {
+ throw new ParseException("enum cannot add element " + label); //$NON-NLS-1$
+ }
+
+ if (valueSpecified && (BigInteger.valueOf(low).compareTo(enumDeclaration.getContainerType().getMinValue()) == -1 ||
+ BigInteger.valueOf(high).compareTo(enumDeclaration.getContainerType().getMaxValue()) == 1)) {
+ throw new ParseException("enum value is not in range"); //$NON-NLS-1$
+ }
+
+ return high;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.environment;
+
+import java.util.List;
+import java.util.Map;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * A scope containing pairs of values that are immutable to the trace.
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ *
+ */
+public final class EnvironmentParser implements ICommonTreeParser {
+
+ /**
+ * The instance
+ */
+ public static final EnvironmentParser INSTANCE = new EnvironmentParser();
+
+ private EnvironmentParser() {
+ }
+
+ @Override
+ public Map<String, String> parse(CommonTree environment, ICommonTreeParserParameter param) {
+
+ ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
+ List<CommonTree> children = environment.getChildren();
+ for (CommonTree child : children) {
+ String left;
+ String right;
+ left = child.getChild(0).getChild(0).getChild(0).getText();
+ right = child.getChild(1).getChild(0).getChild(0).getText();
+ builder.put(left, right);
+ }
+ return builder.build();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.core.trace.ICTFStream;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryStringParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream.StreamIdParser;
+import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
+
+/**
+ * The declaration of an event
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ *
+ */
+public final class EventDeclarationParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object, contains a trace, an event and a scope
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final EventDeclaration fEvent;
+ private final CTFTrace fTrace;
+ private final DeclarationScope fDeclarationScope;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param event
+ * the event to populate
+ * @param scope
+ * the current scope
+ */
+ public Param(CTFTrace trace, EventDeclaration event, DeclarationScope scope) {
+ fTrace = trace;
+ fEvent = event;
+ fDeclarationScope = scope;
+ }
+
+ }
+
+ /**
+ * Instance
+ */
+ public static final EventDeclarationParser INSTANCE = new EventDeclarationParser();
+
+ private EventDeclarationParser() {
+ }
+
+ @Override
+ public EventDeclaration parse(CommonTree eventDecl, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = ((Param) param).fDeclarationScope;
+ EventDeclaration event = ((Param) param).fEvent;
+ CTFTrace fTrace = ((Param) param).fTrace;
+
+ /* There should be a left and right */
+
+ CommonTree leftNode = (CommonTree) eventDecl.getChild(0);
+ CommonTree rightNode = (CommonTree) eventDecl.getChild(1);
+
+ List<CommonTree> leftStrings = leftNode.getChildren();
+
+ if (!isAnyUnaryString(leftStrings.get(0))) {
+ throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
+ }
+
+ String left = concatenateUnaryStrings(leftStrings);
+
+ if (left.equals(MetadataStrings.NAME2)) {
+ if (event.nameIsSet()) {
+ throw new ParseException("name already defined"); //$NON-NLS-1$
+ }
+
+ String name = EventNameParser.INSTANCE.parse(rightNode, null);
+
+ event.setName(name);
+ } else if (left.equals(MetadataStrings.ID)) {
+ if (event.idIsSet()) {
+ throw new ParseException("id already defined"); //$NON-NLS-1$
+ }
+
+ long id = EventIDParser.INSTANCE.parse(rightNode, null);
+ if (id > Integer.MAX_VALUE) {
+ throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id); //$NON-NLS-1$
+ }
+ if (id < 0) {
+ throw new ParseException("negative id, unsupported. id : " + id); //$NON-NLS-1$
+ }
+ event.setId((int) id);
+ } else if (left.equals(MetadataStrings.STREAM_ID)) {
+ if (event.streamIsSet()) {
+ throw new ParseException("stream id already defined"); //$NON-NLS-1$
+ }
+
+ long streamId = StreamIdParser.INSTANCE.parse(rightNode, null);
+
+ /*
+ * If the event has a stream and it is defined, look up the stream,
+ * if it is the available, assign it. If not, the event is
+ * malformed.
+ */
+ ICTFStream iStream = fTrace.getStream(streamId);
+ if (!(iStream instanceof CTFStream)) {
+ throw new ParseException("Event specified stream with ID " + streamId + ". But no stream with that ID was defined"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ CTFStream ctfStream = (CTFStream) iStream;
+ event.setStream(ctfStream);
+ } else if (left.equals(MetadataStrings.CONTEXT)) {
+ if (event.contextIsSet()) {
+ throw new ParseException("context already defined"); //$NON-NLS-1$
+ }
+
+ CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
+
+ if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
+ throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
+ }
+
+ IDeclaration contextDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope));
+
+ if (!(contextDecl instanceof StructDeclaration)) {
+ throw new ParseException("context expects a struct"); //$NON-NLS-1$
+ }
+
+ event.setContext((StructDeclaration) contextDecl);
+ } else if (left.equals(MetadataStrings.FIELDS_STRING)) {
+ if (event.fieldsIsSet()) {
+ throw new ParseException("fields already defined"); //$NON-NLS-1$
+ }
+
+ CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
+
+ if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
+ throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
+ }
+
+ IDeclaration fieldsDecl;
+ fieldsDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope));
+
+ if (!(fieldsDecl instanceof StructDeclaration)) {
+ throw new ParseException("fields expects a struct"); //$NON-NLS-1$
+ }
+ /*
+ * The underscores in the event names. These underscores were added
+ * by the LTTng tracer.
+ */
+ final StructDeclaration fields = (StructDeclaration) fieldsDecl;
+ event.setFields(fields);
+ } else if (left.equals(MetadataStrings.LOGLEVEL2)) {
+ long logLevel = UnaryIntegerParser.INSTANCE.parse((CommonTree) rightNode.getChild(0), null);
+ event.setLogLevel(logLevel);
+ } else {
+ /* Custom event attribute, we'll add it to the attributes map */
+ String right = UnaryStringParser.INSTANCE.parse((CommonTree) rightNode.getChild(0), null);
+ event.setCustomAttribute(left, right);
+ }
+ return event;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+
+/**
+ * An event identifier (ID) relates to the class (a type) of event within an
+ * event stream, e.g. event irq_entry.
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ * @author Efficios - Description
+ *
+ */
+public final class EventIDParser implements ICommonTreeParser {
+
+ private static final String INVALID_VALUE_ERROR = "Invalid value for event id"; //$NON-NLS-1$
+
+ /**
+ * The instance
+ */
+ public static final EventIDParser INSTANCE = new EventIDParser();
+
+ private EventIDParser() {
+ }
+
+ @Override
+ public Long parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException {
+
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+
+ if (isUnaryInteger(firstChild)) {
+ if (tree.getChildCount() > 1) {
+ throw new ParseException(INVALID_VALUE_ERROR);
+ }
+ long intval = UnaryIntegerParser.INSTANCE.parse(firstChild, null);
+ if (intval > Integer.MAX_VALUE) {
+ throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$
+ }
+ return intval;
+ }
+ throw new ParseException(INVALID_VALUE_ERROR);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Parser for event names
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class EventNameParser implements ICommonTreeParser {
+ /**
+ * Instance
+ */
+ public static final EventNameParser INSTANCE = new EventNameParser();
+
+ private EventNameParser() {
+ }
+
+ @Override
+ public String parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException {
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+
+ if (isAnyUnaryString(firstChild)) {
+ return concatenateUnaryStrings(tree.getChildren());
+ }
+ throw new ParseException("invalid value for event name"); //$NON-NLS-1$
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.core.trace.ICTFStream;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeAliasParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypedefParser;
+import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
+
+/**
+ *
+ *
+ * An event stream can be divided into contiguous event packets of variable
+ * size. An event packet can contain a certain amount of padding at the end. The
+ * stream header is repeated at the beginning of each event packet. The
+ * rationale for the event stream design choices is explained in Stream header
+ * rationale.
+ * <p>
+ * The event stream header will therefore be referred to as the event packet
+ * header throughout the rest of this document.
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ * @author Efficios - Documentation
+ *
+ */
+public class EventParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object with trace and scope
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+
+ private final DeclarationScope fCurrentScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param currentScope
+ * the scope
+ */
+ public Param(CTFTrace trace, DeclarationScope currentScope) {
+ fTrace = trace;
+ fCurrentScope = currentScope;
+ }
+
+ }
+
+ /**
+ * The instance
+ */
+ public static final EventParser INSTANCE = new EventParser();
+
+ private EventParser() {
+ }
+
+ /**
+ * Parses an enum declaration and returns the corresponding declaration.
+ *
+ * @param eventNode
+ * An event node.
+ * @param param
+ * the parameter object
+ *
+ * @return The corresponding enum declaration.
+ * @throws ParseException
+ * event stream was badly defined
+ */
+ @Override
+ public EventDeclaration parse(CommonTree eventNode, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ Param parameter = (Param) param;
+ CTFTrace trace = ((Param) param).fTrace;
+ List<CommonTree> children = eventNode.getChildren();
+ if (children == null) {
+ throw new ParseException("Empty event block"); //$NON-NLS-1$
+ }
+
+ EventDeclaration event = new EventDeclaration();
+
+ DeclarationScope scope = new DeclarationScope(parameter.fCurrentScope, MetadataStrings.EVENT);
+
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.TYPEALIAS:
+ TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(trace, scope));
+ break;
+ case CTFParser.TYPEDEF:
+ TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(trace, scope));
+ break;
+ case CTFParser.CTF_EXPRESSION_TYPE:
+ case CTFParser.CTF_EXPRESSION_VAL:
+ EventDeclarationParser.INSTANCE.parse(child, new EventDeclarationParser.Param(trace, event, scope));
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ if (!event.nameIsSet()) {
+ throw new ParseException("Event name not set"); //$NON-NLS-1$
+ }
+
+ /*
+ * If the event did not specify a stream, then the trace must be single
+ * stream
+ */
+ if (!event.streamIsSet()) {
+ if (trace.nbStreams() > 1) {
+ throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$
+ }
+
+ /*
+ * If the event did not specify a stream, the only existing stream
+ * must not have an id. Note: That behavior could be changed, it
+ * could be possible to just get the only existing stream, whatever
+ * is its id.
+ */
+ ICTFStream iStream = trace.getStream(null);
+ if (iStream instanceof CTFStream) {
+ CTFStream ctfStream = (CTFStream) iStream;
+ event.setStream(ctfStream);
+ } else {
+ throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
+ }
+ }
+
+ /*
+ * Add the event to the stream.
+ */
+ event.getStream().addEvent(event);
+
+ return event;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * A local static scope consists in the scope generated by the declaration of
+ * fields within a compound type. A static scope is a local static scope
+ * augmented with the nested sub-static-scopes it contains.
+ * <p>
+ * A dynamic scope consists in the static scope augmented with the implicit
+ * event structure definition hierarchy.
+ * <p>
+ * Multiple declarations of the same field name within a local static scope is
+ * not valid. It is however valid to re-use the same field name in different
+ * local scopes.
+ * <p>
+ * Nested static and dynamic scopes form lookup paths. These are used for
+ * variant tag and sequence length references. They are used at the variant and
+ * sequence definition site to look up the location of the tag field associated
+ * with a variant, and to lookup up the location of the length field associated
+ * with a sequence.
+ * <p>
+ * Variants and sequences can refer to a tag field either using a relative path
+ * or an absolute path. The relative path is relative to the scope in which the
+ * variant or sequence performing the lookup is located. Relative paths are only
+ * allowed to lookup within the same static scope, which includes its nested
+ * static scopes. Lookups targeting parent static scopes need to be performed
+ * with an absolute path.
+ * <p>
+ * Absolute path lookups use the full path including the dynamic scope followed
+ * by a . and then the static scope. Therefore, variants (or sequences) in lower
+ * levels in the dynamic scope (e.g., event context) can refer to a tag (or
+ * length) field located in upper levels (e.g., in the event header) by
+ * specifying, in this case, the associated tag with
+ * <stream.event.header.field_name>. This allows, for instance, the event
+ * context to define a variant referring to the id field of the event header as
+ * selector.
+ * <p>
+ * The dynamic scope prefixes are thus:
+ * <ul>
+ * <li>Trace environment: <env. ></li>
+ * <li>Trace packet header: <trace.packet.header. ></li>
+ * <li>Stream packet context: <stream.packet.context. ></li>
+ * <li>Event header: <stream.event.header. ></li>
+ * <li>Stream event context: <stream.event.context. ></li>
+ * <li>Event context: <event.context. ></li>
+ * <li>Event payload: <event.fields. ></li>
+ * </ul>
+ * <p>
+ * The target dynamic scope must be specified explicitly when referring to a
+ * field outside of the static scope (absolute scope reference). No conflict can
+ * occur between relative and dynamic paths, because the keywords trace, stream,
+ * and event are reserved, and thus not permitted as field names. It is
+ * recommended that field names clashing with CTF and C99 reserved keywords use
+ * an underscore prefix to eliminate the risk of generating a description
+ * containing an invalid field name. Consequently, fields starting with an
+ * underscore should have their leading underscore removed by the CTF trace
+ * readers.
+ * <p>
+ * The information available in the dynamic scopes can be thought of as the
+ * current tracing context. At trace production, information about the current
+ * context is saved into the specified scope field levels. At trace consumption,
+ * for each event, the current trace context is therefore readable by accessing
+ * the upper dynamic scopes.
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ * @author Efficios - Description
+ *
+ */
+public final class EventScopeParser implements ICommonTreeParser {
+
+ /**
+ * Parameter object containing a list of common trees
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final List<CommonTree> fList;
+
+ /**
+ * Constructor
+ *
+ * @param list
+ * parameter list
+ */
+ public Param(List<CommonTree> list) {
+ fList = list;
+
+ }
+
+ }
+
+ /**
+ * Instance
+ */
+ public static final EventScopeParser INSTANCE = new EventScopeParser();
+
+ private EventScopeParser() {
+ }
+
+ /**
+ * Parses in a different way, the AST node is unused, and the event list
+ * contains data to read. This converts a scope from a set of strings to
+ * "event.subscope1.subscope2".
+ *
+ * @param unused
+ * unused AST node
+ * @param param
+ * a list of tree nodes that contain the scope description.
+ * @return a concatenated string of the scope
+ */
+ @Override
+ public String parse(CommonTree unused, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ List<CommonTree> lengthChildren = ((Param) param).fList;
+ CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
+ String lengthName;
+ switch (nextElem.getType()) {
+ case CTFParser.UNARY_EXPRESSION_STRING:
+ case CTFParser.IDENTIFIER:
+ List<CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size());
+ lengthName = MetadataStrings.EVENT + '.' + concatenateUnaryStrings(sublist);
+ break;
+ default:
+ throw new ParseException("Unsupported scope event." + nextElem); //$NON-NLS-1$
+ }
+ return lengthName;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.floatingpoint;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.nio.ByteOrder;
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.types.FloatDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.AlignmentParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.ByteOrderParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+
+/**
+ *
+ * The floating point values byte ordering is defined in the TSDL metadata.
+ * <p>
+ * Floating point values follow the IEEE 754-2008 standard interchange formats.
+ * Description of the floating point values include the exponent and mantissa
+ * size in bits. Some requirements are imposed on the floating point values:
+ * <ul>
+ * <li>FLT_RADIX must be 2.</li>
+ * <li>mant_dig is the number of digits represented in the mantissa. It is
+ * specified by the ISO C99 standard, section 5.2.4, as FLT_MANT_DIG,
+ * DBL_MANT_DIG and LDBL_MANT_DIG as defined by <float.h>.</li>
+ * <li>exp_dig is the number of digits represented in the exponent. Given that
+ * mant_dig is one bit more than its actual size in bits (leading 1 is not
+ * needed) and also given that the sign bit always takes one bit, exp_dig can be
+ * specified as:</li>
+ * <ul>
+ * <li>sizeof(float) * CHAR_BIT - FLT_MANT_DIG</li>
+ * <li>sizeof(double) * CHAR_BIT - DBL_MANT_DIG</li>
+ * <li>sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG</li>
+ * <li>
+ * </ul>
+ * </ul>
+ *
+ * @author Matthew Khouzam - initial API and implementation
+ * @auttor Efficios - Description
+ *
+ */
+public class FloatDeclarationParser implements ICommonTreeParser {
+
+ private static final String FLOAT_UNKNOWN_ATTRIBUTE = "Float: unknown attribute "; //$NON-NLS-1$
+ private static final String FLOAT_MISSING_SIZE_ATTRIBUTE = "Float: missing size attribute"; //$NON-NLS-1$
+ private static final String IDENTIFIER_MUST_BE_A_STRING = "Left side of ctf expression must be a string"; //$NON-NLS-1$
+
+ /**
+ * Parameter object with only a trace in it
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ */
+ public Param(CTFTrace trace) {
+ fTrace = trace;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public static final FloatDeclarationParser INSTANCE = new FloatDeclarationParser();
+
+ private static final int DEFAULT_FLOAT_EXPONENT = 8;
+ private static final int DEFAULT_FLOAT_MANTISSA = 24;
+
+ private FloatDeclarationParser() {
+ }
+
+ /**
+ * Parses a float node and returns a floating point declaration of the
+ * type @link {@link FloatDeclaration}.
+ *
+ * @param floatingPoint
+ * AST node of type FLOAT
+ * @param param
+ * parameter containing the trace
+ * @return the float declaration
+ * @throws ParseException
+ * if a float AST is malformed
+ */
+ @Override
+ public FloatDeclaration parse(CommonTree floatingPoint, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ CTFTrace trace = ((Param) param).fTrace;
+ List<CommonTree> children = floatingPoint.getChildren();
+
+ /*
+ * If the integer has no attributes, then it is missing the size
+ * attribute which is required
+ */
+ if (children == null) {
+ throw new ParseException(FLOAT_MISSING_SIZE_ATTRIBUTE);
+ }
+
+ /* The return value */
+ ByteOrder byteOrder = trace.getByteOrder();
+ long alignment = 0;
+
+ int exponent = DEFAULT_FLOAT_EXPONENT;
+ int mantissa = DEFAULT_FLOAT_MANTISSA;
+
+ /* Iterate on all integer children */
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.CTF_EXPRESSION_VAL:
+ /*
+ * An assignment expression must have 2 children, left and right
+ */
+
+ CommonTree leftNode = (CommonTree) child.getChild(0);
+ CommonTree rightNode = (CommonTree) child.getChild(1);
+
+ List<CommonTree> leftStrings = leftNode.getChildren();
+
+ if (!isAnyUnaryString(leftStrings.get(0))) {
+ throw new ParseException(IDENTIFIER_MUST_BE_A_STRING);
+ }
+ String left = concatenateUnaryStrings(leftStrings);
+
+ if (left.equals(MetadataStrings.EXP_DIG)) {
+ exponent = UnaryIntegerParser.INSTANCE.parse((CommonTree) rightNode.getChild(0), null).intValue();
+ } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
+ byteOrder = ByteOrderParser.INSTANCE.parse(rightNode, new ByteOrderParser.Param(trace));
+ } else if (left.equals(MetadataStrings.MANT_DIG)) {
+ mantissa = UnaryIntegerParser.INSTANCE.parse((CommonTree) rightNode.getChild(0), null).intValue();
+ } else if (left.equals(MetadataStrings.ALIGN)) {
+ alignment = AlignmentParser.INSTANCE.parse(rightNode, null);
+ } else {
+ throw new ParseException(FLOAT_UNKNOWN_ATTRIBUTE + left);
+ }
+
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+ int size = mantissa + exponent;
+ if (size == 0) {
+ throw new ParseException(FLOAT_MISSING_SIZE_ATTRIBUTE);
+ }
+
+ if (alignment == 0) {
+ alignment = 1;
+ }
+
+ return new FloatDeclaration(exponent, mantissa, byteOrder, alignment);
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryString;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+
+/**
+ * Parse the base of an integer, can return 16, 10, 8 or 2
+ *
+ * @author Matthew Khouzam
+ */
+public final class BaseParser implements ICommonTreeParser {
+
+ /**
+ * BaseParser instance
+ */
+ public static final BaseParser INSTANCE = new BaseParser();
+
+ private static final String INVALID_VALUE_FOR_BASE = "Invalid value for base"; //$NON-NLS-1$
+ private static final int INTEGER_BASE_16 = 16;
+ private static final int INTEGER_BASE_10 = 10;
+ private static final int INTEGER_BASE_8 = 8;
+ private static final int INTEGER_BASE_2 = 2;
+
+ private BaseParser() { }
+
+ @Override
+ public Integer parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException {
+
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+
+ if (isUnaryInteger(firstChild)) {
+ if (tree.getChildCount() > 1) {
+ throw new ParseException("invalid base value"); //$NON-NLS-1$
+ }
+
+ long intval = UnaryIntegerParser.INSTANCE.parse(firstChild, null);
+ if ((intval == INTEGER_BASE_2) || (intval == INTEGER_BASE_8) || (intval == INTEGER_BASE_10)
+ || (intval == INTEGER_BASE_16)) {
+ return (int) intval;
+ }
+ throw new ParseException(INVALID_VALUE_FOR_BASE);
+ } else if (isUnaryString(firstChild)) {
+ switch (concatenateUnaryStrings(tree.getChildren())) {
+ case MetadataStrings.DECIMAL:
+ case MetadataStrings.DEC:
+ case MetadataStrings.DEC_CTE:
+ case MetadataStrings.INT_MOD:
+ case MetadataStrings.UNSIGNED_CTE:
+ return INTEGER_BASE_10;
+ case MetadataStrings.HEXADECIMAL:
+ case MetadataStrings.HEX:
+ case MetadataStrings.X:
+ case MetadataStrings.X2:
+ case MetadataStrings.POINTER:
+ return INTEGER_BASE_16;
+ case MetadataStrings.OCT:
+ case MetadataStrings.OCTAL:
+ case MetadataStrings.OCTAL_CTE:
+ return INTEGER_BASE_8;
+ case MetadataStrings.BIN:
+ case MetadataStrings.BINARY:
+ return INTEGER_BASE_2;
+ default:
+ throw new ParseException(INVALID_VALUE_FOR_BASE);
+ }
+ } else {
+ throw new ParseException(INVALID_VALUE_FOR_BASE);
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+
+/**
+ * A reference to the clock map in a given integer.
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class ClockMapParser implements ICommonTreeParser {
+
+ private static final @NonNull String EMPTY_STRING = ""; //$NON-NLS-1$
+
+ /**
+ * Instance
+ */
+ public static final ClockMapParser INSTANCE = new ClockMapParser();
+
+ private ClockMapParser() {
+ }
+
+ @Override
+ public String parse(CommonTree tree, ICommonTreeParserParameter param) {
+ String clock = tree.getChild(1).getChild(0).getChild(0).getText();
+ return clock == null ? EMPTY_STRING : clock;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.nio.ByteOrder;
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.types.Encoding;
+import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.Activator;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.Messages;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.AlignmentParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.ByteOrderParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.SizeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.string.EncodingParser;
+
+/**
+ * Signed integers are represented in two-complement. Integer alignment, size,
+ * signedness and byte ordering are defined in the TSDL metadata. Integers
+ * aligned on byte size (8-bit) and with length multiple of byte size (8-bit)
+ * correspond to the C99 standard integers. In addition, integers with alignment
+ * and/or size that are not a multiple of the byte size are permitted; these
+ * correspond to the C99 standard bitfields, with the added specification that
+ * the CTF integer bitfields have a fixed binary representation. Integer size
+ * needs to be a positive integer. Integers of size 0 are forbidden. An
+ * MIT-licensed reference implementation of the CTF portable bitfields is
+ * available here.
+ *
+ * Binary representation of integers:
+ * <ul>
+ * <li>On little and big endian: Within a byte, high bits correspond to an
+ * integer high bits, and low bits correspond to low bits</li>
+ * <li>On little endian: Integer across multiple bytes are placed from the less
+ * significant to the most significant Consecutive integers are placed from
+ * lower bits to higher bits (even within a byte)</li>
+ * <li>On big endian: Integer across multiple bytes are placed from the most
+ * significant to the less significant Consecutive integers are placed from
+ * higher bits to lower bits (even within a byte)</li>
+ * </ul>
+ *
+ * This binary representation is derived from the bitfield implementation in GCC
+ * for little and big endian. However, contrary to what GCC does, integers can
+ * cross units boundaries (no padding is required). Padding can be explicitly
+ * added to follow the GCC layout if needed.
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - javadoc preamble
+ *
+ */
+public class IntegerDeclarationParser implements ICommonTreeParser {
+
+ /**
+ * Parameter Object with a trace
+ *
+ * @author Matthew Khouzam
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ */
+ public Param(CTFTrace trace) {
+ fTrace = trace;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public static final IntegerDeclarationParser INSTANCE = new IntegerDeclarationParser();
+
+ private static final @NonNull String ENCODING = "encoding"; //$NON-NLS-1$
+ private static final @NonNull String EMPTY_STRING = ""; //$NON-NLS-1$
+ private static final int DEFAULT_INT_BASE = 10;
+ private static final @NonNull String MAP = "map"; //$NON-NLS-1$
+ private static final @NonNull String BASE = "base"; //$NON-NLS-1$
+ private static final @NonNull String SIZE = "size"; //$NON-NLS-1$
+ private static final @NonNull String SIGNED = "signed"; //$NON-NLS-1$
+
+ private IntegerDeclarationParser() {
+ }
+
+ /**
+ * Parses an integer declaration node.
+ *
+ * @param parameter
+ * parent trace, for byte orders
+ *
+ * @return The corresponding integer declaration.
+ */
+ @Override
+ public IntegerDeclaration parse(CommonTree integer, ICommonTreeParserParameter parameter) throws ParseException {
+ if (!(parameter instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ CTFTrace trace = ((Param) parameter).fTrace;
+ List<CommonTree> children = integer.getChildren();
+
+ /*
+ * If the integer has no attributes, then it is missing the size
+ * attribute which is required
+ */
+ if (children == null) {
+ throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
+ }
+
+ /* The return value */
+ IntegerDeclaration integerDeclaration = null;
+ boolean signed = false;
+ ByteOrder byteOrder = trace.getByteOrder();
+ long size = 0;
+ long alignment = 0;
+ int base = DEFAULT_INT_BASE;
+ @NonNull
+ String clock = EMPTY_STRING;
+
+ Encoding encoding = Encoding.NONE;
+
+ /* Iterate on all integer children */
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.CTF_EXPRESSION_VAL:
+ /*
+ * An assignment expression must have 2 children, left and right
+ */
+
+ CommonTree leftNode = (CommonTree) child.getChild(0);
+ CommonTree rightNode = (CommonTree) child.getChild(1);
+
+ List<CommonTree> leftStrings = leftNode.getChildren();
+
+ if (!isAnyUnaryString(leftStrings.get(0))) {
+ throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
+ }
+ String left = concatenateUnaryStrings(leftStrings);
+
+ switch (left) {
+ case SIGNED:
+ signed = SignedParser.INSTANCE.parse(rightNode, null);
+ break;
+ case MetadataStrings.BYTE_ORDER:
+ byteOrder = ByteOrderParser.INSTANCE.parse(rightNode, new ByteOrderParser.Param(trace));
+ break;
+ case SIZE:
+ size = SizeParser.INSTANCE.parse(rightNode, null);
+ break;
+ case MetadataStrings.ALIGN:
+ alignment = AlignmentParser.INSTANCE.parse(rightNode, null);
+ break;
+ case BASE:
+ base = BaseParser.INSTANCE.parse(rightNode, null);
+ break;
+ case ENCODING:
+ encoding = EncodingParser.INSTANCE.parse(rightNode, null);
+ break;
+ case MAP:
+ clock = ClockMapParser.INSTANCE.parse(rightNode, null);
+ break;
+ default:
+ Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownIntegerAttributeWarning + " " + left); //$NON-NLS-1$
+ break;
+ }
+
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ if (size <= 0) {
+ throw new ParseException("Invalid size attribute in Integer: " + size); //$NON-NLS-1$
+ }
+
+ if (alignment == 0) {
+ alignment = 1;
+ }
+
+ integerDeclaration = IntegerDeclaration.createDeclaration((int) size, signed, base,
+ byteOrder, encoding, clock, alignment);
+
+ return integerDeclaration;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryString;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+
+/**
+ * Singed status, whether an integer is capable of accepting negative values or
+ * not.
+ *
+ * @author Matthew Khouzam
+ */
+public class SignedParser implements ICommonTreeParser {
+ /**
+ * Instance
+ */
+ public static final SignedParser INSTANCE = new SignedParser();
+
+ private static final String INVALID_BOOLEAN_VALUE = "Invalid boolean value "; //$NON-NLS-1$
+
+ private SignedParser() {
+ }
+
+ /**
+ * Parses whether the parent is signed or not. Typical syntax would be
+ * "signed = true;" or "signed = false;"
+ *
+ * @param tree
+ * the AST node containing "signed = boolean;"
+ * @param unused
+ * unused
+ * @return @link {@link Boolean#TRUE} if signed, {@link Boolean#FALSE} if
+ * unsigned
+ * @throws ParseException
+ * on a malformed tree
+ */
+ @Override
+ public Boolean parse(CommonTree tree, ICommonTreeParserParameter unused) throws ParseException {
+ boolean ret = false;
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+
+ if (isUnaryString(firstChild)) {
+ String strval = concatenateUnaryStrings(tree.getChildren());
+
+ if (strval.equals(MetadataStrings.TRUE)
+ || strval.equals(MetadataStrings.TRUE2)) {
+ ret = true;
+ } else if (strval.equals(MetadataStrings.FALSE)
+ || strval.equals(MetadataStrings.FALSE2)) {
+ ret = false;
+ } else {
+ throw new ParseException(INVALID_BOOLEAN_VALUE
+ + firstChild.getChild(0).getText());
+ }
+ } else if (isUnaryInteger(firstChild)) {
+ /* Happens if the value is something like "1234.hello" */
+ if (tree.getChildCount() > 1) {
+ throw new ParseException(INVALID_BOOLEAN_VALUE);
+ }
+
+ long intval = UnaryIntegerParser.INSTANCE.parse(firstChild, null);
+
+ if (intval == 1) {
+ ret = true;
+ } else if (intval == 0) {
+ ret = false;
+ } else {
+ throw new ParseException(INVALID_BOOLEAN_VALUE
+ + firstChild.getChild(0).getText());
+ }
+ } else {
+ throw new ParseException(INVALID_BOOLEAN_VALUE);
+ }
+ return ret;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.Tree;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.CTFStrings;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IEventHeaderDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.Activator;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.Messages;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser;
+import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
+
+/**
+ *
+ * An <em>event stream</em> can be divided into contiguous event packets of
+ * variable size. An event packet can contain a certain amount of padding at the
+ * end. The stream header is repeated at the beginning of each event packet.
+ * <br>
+ * The event stream header will therefore be referred to as the
+ * <em>event packet header</em> throughout the rest of this document. <br>
+ *
+ * An event stream is divided in contiguous event packets of variable size.
+ * These subdivisions allow the trace analyzer to perform a fast binary search
+ * by time within the stream (typically requiring to index only the event packet
+ * headers) without reading the whole stream. These subdivisions have a variable
+ * size to eliminate the need to transfer the event packet padding when
+ * partially filled event packets must be sent when streaming a trace for live
+ * viewing/analysis. An event packet can contain a certain amount of padding at
+ * the end. Dividing streams into event packets is also useful for network
+ * streaming over UDP and flight recorder mode tracing (a whole event packet can
+ * be swapped out of the buffer atomically for reading). <br>
+ * The stream header is repeated at the beginning of each event packet to allow
+ * flexibility in terms of:
+ * <ul>
+ * <li>streaming support</li>
+ * <li>allowing arbitrary buffers to be discarded without making the trace
+ * unreadable</li>
+ * <li>allow UDP packet loss handling by either dealing with missing event
+ * packet or asking for re-transmission</li>
+ * <li>transparently support flight recorder mode</li>
+ * <li>transparently support crash dump</li>
+ * </ul>
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Description
+ *
+ */
+public final class StreamDeclarationParser extends AbstractScopedCommonTreeParser {
+
+ private static final String IDENTIFIER_MUST_BE_A_STRING = "Left side of CTF assignment must be a string"; //$NON-NLS-1$
+ private static final String PACKET_CONTEXT = "packet.context "; //$NON-NLS-1$
+ private static final String EVENT_CONTEXT = "event.context "; //$NON-NLS-1$
+ private static final String EVENT_HEADER = "event.header "; //$NON-NLS-1$
+ private static final String STREAM_ID = "stream id "; //$NON-NLS-1$
+ private static final String EXPECTS_A_STRUCT = "expects a struct"; //$NON-NLS-1$
+ private static final String SCOPE_NOT_FOUND = "scope not found"; //$NON-NLS-1$
+ private static final String EXPECTS_A_TYPE_SPECIFIER = "expects a type specifier"; //$NON-NLS-1$
+ private static final String ALREADY_DEFINED = "already defined"; //$NON-NLS-1$
+
+ /**
+ * A parameter object, contains a trace, a stream and a scope
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final CTFStream fStream;
+ private final CTFTrace fTrace;
+ private final DeclarationScope fDeclarationScope;
+
+ /**
+ * The parameter object
+ *
+ * @param trace
+ * the trace
+ * @param stream
+ * the stream
+ * @param scope
+ * the scope
+ */
+ public Param(CTFTrace trace, CTFStream stream, DeclarationScope scope) {
+ fTrace = trace;
+ fStream = stream;
+ fDeclarationScope = scope;
+ }
+
+ }
+
+ /**
+ * Instance
+ */
+ public static final StreamDeclarationParser INSTANCE = new StreamDeclarationParser();
+
+ private StreamDeclarationParser() {
+ }
+
+ /**
+ * Parse a stream declaration.
+ *
+ * @param streamDecl
+ * the AST node containing the STREAM type
+ * @param param
+ * The stream to fill, the trace and the current scope
+ * @return the stream declaration
+ * @throws ParseException
+ * if the stream AST node is malformed
+ */
+ @Override
+ public CTFStream parse(CommonTree streamDecl, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = (((Param) param).fDeclarationScope);
+ CTFStream stream = ((Param) param).fStream;
+ CTFTrace fTrace = ((Param) param).fTrace;
+
+ /* There should be a left and right */
+
+ CommonTree leftNode = (CommonTree) streamDecl.getChild(0);
+ CommonTree rightNode = (CommonTree) streamDecl.getChild(1);
+
+ List<CommonTree> leftStrings = leftNode.getChildren();
+
+ if (!isAnyUnaryString(leftStrings.get(0))) {
+ throw new ParseException(IDENTIFIER_MUST_BE_A_STRING);
+ }
+
+ String left = concatenateUnaryStrings(leftStrings);
+
+ if (left.equals(MetadataStrings.ID)) {
+ if (stream.isIdSet()) {
+ throw new ParseException(STREAM_ID + ALREADY_DEFINED);
+ }
+
+ long streamID = StreamIdParser.INSTANCE.parse(rightNode, null);
+
+ stream.setId(streamID);
+ } else if (left.equals(MetadataStrings.EVENT_HEADER)) {
+ if (stream.isEventHeaderSet()) {
+ throw new ParseException(EVENT_HEADER + ALREADY_DEFINED);
+ }
+
+ CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
+
+ if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
+ throw new ParseException(EVENT_HEADER + EXPECTS_A_TYPE_SPECIFIER);
+ }
+
+ IDeclaration eventHeaderDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope));
+ DeclarationScope eventHeaderScope = lookupStructName(typeSpecifier, scope);
+ if (eventHeaderScope == null) {
+ throw new ParseException(EVENT_HEADER + SCOPE_NOT_FOUND);
+ }
+ DeclarationScope eventScope = new DeclarationScope(scope, MetadataStrings.EVENT);
+ eventScope.addChild(eventHeaderScope);
+ eventHeaderScope.setName(CTFStrings.HEADER);
+
+ if (eventHeaderDecl instanceof StructDeclaration) {
+ stream.setEventHeader((StructDeclaration) eventHeaderDecl);
+ } else if (eventHeaderDecl instanceof IEventHeaderDeclaration) {
+ stream.setEventHeader((IEventHeaderDeclaration) eventHeaderDecl);
+ } else {
+ throw new ParseException(EVENT_HEADER + EXPECTS_A_STRUCT);
+ }
+
+ } else if (left.equals(MetadataStrings.EVENT_CONTEXT)) {
+ if (stream.isEventContextSet()) {
+ throw new ParseException(EVENT_CONTEXT + ALREADY_DEFINED);
+ }
+
+ CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
+
+ if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
+ throw new ParseException(EVENT_CONTEXT + EXPECTS_A_TYPE_SPECIFIER);
+ }
+
+ IDeclaration eventContextDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope));
+
+ if (!(eventContextDecl instanceof StructDeclaration)) {
+ throw new ParseException(EVENT_CONTEXT + EXPECTS_A_STRUCT);
+ }
+
+ stream.setEventContext((StructDeclaration) eventContextDecl);
+ } else if (left.equals(MetadataStrings.PACKET_CONTEXT)) {
+ if (stream.isPacketContextSet()) {
+ throw new ParseException(PACKET_CONTEXT + ALREADY_DEFINED);
+ }
+
+ CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
+
+ if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
+ throw new ParseException(PACKET_CONTEXT + EXPECTS_A_TYPE_SPECIFIER);
+ }
+
+ IDeclaration packetContextDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope));
+
+ if (!(packetContextDecl instanceof StructDeclaration)) {
+ throw new ParseException(PACKET_CONTEXT + EXPECTS_A_STRUCT);
+ }
+
+ stream.setPacketContext((StructDeclaration) packetContextDecl);
+ } else {
+ Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownStreamAttributeWarning + ' ' + left);
+ }
+ return stream;
+ }
+
+ private static DeclarationScope lookupStructName(CommonTree typeSpecifier, DeclarationScope scope) {
+ /*
+ * This needs a struct.struct_name.name to work, luckily, that is 99.99%
+ * of traces we receive.
+ */
+ final Tree potentialStruct = typeSpecifier.getChild(0);
+ DeclarationScope eventHeaderScope = null;
+ if (potentialStruct.getType() == (CTFParser.STRUCT)) {
+ final Tree potentialStructName = potentialStruct.getChild(0);
+ if (potentialStructName.getType() == (CTFParser.STRUCT_NAME)) {
+ final String name = potentialStructName.getChild(0).getText();
+ eventHeaderScope = scope.lookupChildRecursive(name);
+ }
+ }
+ /*
+ * If that fails, maybe the struct is anonymous
+ */
+ if (eventHeaderScope == null) {
+ eventHeaderScope = scope.lookupChildRecursive(MetadataStrings.STRUCT);
+ }
+ /*
+ * This can still be null
+ */
+ return eventHeaderScope;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+
+/**
+ * <strong>Stream ID</strong>, used as reference to stream description in
+ * metadata. This field is optional if there is only one stream description in
+ * the metadata, but becomes required if there are more than one stream in the
+ * TSDL metadata description.
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Javadoc
+ *
+ */
+public class StreamIdParser implements ICommonTreeParser {
+
+ /** Instance */
+ public static final StreamIdParser INSTANCE = new StreamIdParser();
+
+ private StreamIdParser() {
+ }
+
+ /**
+ * Parses a stream id
+ *
+ * @param tree
+ * the AST node with "id = N;"
+ * @return the value of the stream as a {@link Long}
+ */
+ @Override
+ public Long parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException {
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+ if (isUnaryInteger(firstChild)) {
+ if (tree.getChildCount() > 1) {
+ throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
+ }
+ long intval = UnaryIntegerParser.INSTANCE.parse(firstChild, null);
+ return intval;
+ }
+ throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeAliasParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypedefParser;
+import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream;
+
+/**
+ * A stream is a collection of packets with events in them. It will contain data
+ * types.
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class StreamParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter Object with a trace and scope
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+
+ private final DeclarationScope fCurrentScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param currentScope
+ * the scope
+ */
+ public Param(CTFTrace trace, DeclarationScope currentScope) {
+ fTrace = trace;
+ fCurrentScope = currentScope;
+ }
+
+ }
+
+ /**
+ * The instance
+ */
+ public static final StreamParser INSTANCE = new StreamParser();
+
+ private StreamParser() {
+ }
+
+ /**
+ * Parses an stream declaration and returns a stream type
+ *
+ * @param streamNode
+ * the steam node
+ * @param param
+ * the parameter object
+ *
+ * @return The corresponding enum declaration.
+ * @throws ParseException
+ * badly defined stream
+ */
+ @Override
+ public CTFStream parse(CommonTree streamNode, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ Param parameter = (Param) param;
+ CTFTrace trace = ((Param) param).fTrace;
+ CTFStream stream = new CTFStream(trace);
+
+ List<CommonTree> children = streamNode.getChildren();
+ if (children == null) {
+ throw new ParseException("Empty stream block"); //$NON-NLS-1$
+ }
+
+ DeclarationScope scope = new DeclarationScope(parameter.fCurrentScope, MetadataStrings.STREAM);
+
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.TYPEALIAS:
+ TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(trace, scope));
+ break;
+ case CTFParser.TYPEDEF:
+ TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(trace, scope));
+ break;
+ case CTFParser.CTF_EXPRESSION_TYPE:
+ case CTFParser.CTF_EXPRESSION_VAL:
+ StreamDeclarationParser.INSTANCE.parse(child, new StreamDeclarationParser.Param(trace, stream, scope));
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ if (stream.isIdSet() &&
+ (!trace.packetHeaderIsSet() || !trace.getPacketHeader().hasField(MetadataStrings.STREAM_ID))) {
+ throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
+ }
+
+ trace.addStream(stream);
+
+ return stream;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryString;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryStringParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event.EventScopeParser;
+
+/**
+ * The stream scope parser, this parses a scope of a given stream. It can get
+ * the scope of the stream like "stream.packet.header".
+ *
+ * @author Matthew Khouzam - Initial API and implementation
+ *
+ */
+public final class StreamScopeParser implements ICommonTreeParser {
+
+ /**
+ * Parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final List<CommonTree> fList;
+
+ /**
+ * Constructor
+ *
+ * @param list
+ * a list of commonTrees to parse
+ */
+ public Param(List<CommonTree> list) {
+ fList = list;
+ }
+
+ }
+
+ /**
+ * Instance
+ */
+ public static final StreamScopeParser INSTANCE = new StreamScopeParser();
+
+ private StreamScopeParser() {
+ }
+
+ /**
+ * Parses the scope of the stream and returns a concatenated string of the
+ * elements
+ *
+ * @param unused
+ * unused
+ * @param param
+ * the parameter containing a list of ASTs describing the stream
+ * scope
+ * @return a string of the scope like "stream.context"
+ * @throws ParseException
+ * if the ASTs are malformed
+ */
+ @Override
+ public String parse(CommonTree unused, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ List<@NonNull CommonTree> lengthChildren = ((Param) param).fList;
+ final List<@NonNull CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size());
+
+ CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
+ String lengthName = null;
+ if (isUnaryString(nextElem)) {
+ lengthName = UnaryStringParser.INSTANCE.parse(nextElem, null);
+ }
+
+ int type = nextElem.getType();
+ if ((CTFParser.tokenNames[CTFParser.EVENT]).equals(lengthName)) {
+ type = CTFParser.EVENT;
+ }
+ switch (type) {
+ case CTFParser.IDENTIFIER:
+ lengthName = concatenateUnaryStrings(sublist);
+ break;
+ case CTFParser.EVENT:
+ lengthName = EventScopeParser.INSTANCE.parse(null, new EventScopeParser.Param(sublist));
+ break;
+ default:
+ if (lengthName == null) {
+ throw new ParseException("Unsupported scope stream." + nextElem); //$NON-NLS-1$
+ }
+ }
+ return MetadataStrings.STREAM + '.' + lengthName;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.string;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryString;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.ctf.core.event.types.Encoding;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Parse the encoding field. This can be "ascii", "utf8" or "none"
+ *
+ * @author Matthew Khouzam
+ */
+public class EncodingParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final EncodingParser INSTANCE = new EncodingParser();
+
+ private EncodingParser() { }
+
+ private static final String INVALID_VALUE_FOR_ENCODING = "Invalid value for encoding"; //$NON-NLS-1$
+
+ /**
+ * Gets the value of an "encoding" integer attribute.
+ *
+ * @return The "encoding" value.
+ * @throws ParseException
+ * for unknown or malformed encoding
+ */
+ @Override
+ public Encoding parse(CommonTree tree, ICommonTreeParserParameter param) throws ParseException {
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+
+ if (isUnaryString(firstChild)) {
+ String strval = concatenateUnaryStrings(tree.getChildren());
+
+ if (strval.equals(MetadataStrings.UTF8)) {
+ return Encoding.UTF8;
+ } else if (strval.equals(MetadataStrings.ASCII)) {
+ return Encoding.ASCII;
+ } else if (strval.equals(MetadataStrings.NONE)) {
+ return Encoding.NONE;
+ } else {
+ throw new ParseException(INVALID_VALUE_FOR_ENCODING);
+ }
+ }
+ throw new ParseException(INVALID_VALUE_FOR_ENCODING);
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.string;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.ctf.core.event.types.Encoding;
+import org.eclipse.tracecompass.ctf.core.event.types.StringDeclaration;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ * Strings are an array of bytes of variable size and are terminated by a '\0'
+ * “NULL” character. Their encoding is described in the TSDL metadata. In
+ * absence of encoding attribute information, the default encoding is UTF-8.
+ *
+ * TSDL metadata representation of a named string type:
+ *
+ * <pre>
+ * typealias string {
+ * encoding = /* UTF8 OR ASCII * /;
+ * } := name;
+ * </pre>
+ *
+ * A nameless string type can be declared as a field type:
+ *
+ * <pre>
+ * string field_name; /* use default UTF8 encoding * /
+ * </pre>
+ *
+ * Strings are always aligned on byte size.
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Javadoc Preable
+ *
+ */
+public class StringDeclarationParser implements ICommonTreeParser {
+
+ /**
+ * Instance
+ */
+ public static final StringDeclarationParser INSTANCE = new StringDeclarationParser();
+
+ private static final @NonNull String ENCODING = "encoding"; //$NON-NLS-1$
+
+ private StringDeclarationParser() {
+ }
+
+ /**
+ * Parse a string declaration node and return a {@link StringDeclaration}
+ *
+ * @param string
+ * the string declaration AST node
+ * @param unused
+ * unused
+ * @return a {@link StringDeclaration} describing the string layout
+ * @throws ParseException
+ * the AST is malformed
+ */
+ @Override
+ public StringDeclaration parse(CommonTree string, ICommonTreeParserParameter unused) throws ParseException {
+ List<CommonTree> children = string.getChildren();
+ StringDeclaration stringDeclaration = null;
+
+ if (children == null) {
+ stringDeclaration = StringDeclaration.getStringDeclaration(Encoding.UTF8);
+ } else {
+ Encoding encoding = Encoding.UTF8;
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.CTF_EXPRESSION_VAL:
+ /*
+ * An assignment expression must have 2 children, left and
+ * right
+ */
+
+ CommonTree leftNode = (CommonTree) child.getChild(0);
+ CommonTree rightNode = (CommonTree) child.getChild(1);
+
+ List<CommonTree> leftStrings = leftNode.getChildren();
+
+ if (!isAnyUnaryString(leftStrings.get(0))) {
+ throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
+ }
+ String left = concatenateUnaryStrings(leftStrings);
+
+ if (left.equals(ENCODING)) {
+ encoding = EncodingParser.INSTANCE.parse(rightNode, null);
+ } else {
+ throw new ParseException("String: unknown attribute " //$NON-NLS-1$
+ + left);
+ }
+
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ stringDeclaration = StringDeclaration.getStringDeclaration(encoding);
+ }
+
+ return stringDeclaration;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.struct;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeAliasParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypedefParser;
+
+/**
+ * A struct body can have any of the following elements, even though some of
+ * them do not make sense:
+ * <ul>
+ * <li>align</li>
+ * <li>callsite</li>
+ * <li>const</li>
+ * <li>char</li>
+ * <li>clock</li>
+ * <li>double</li>
+ * <li>enum</li>
+ * <li>env</li>
+ * <li>event</li>
+ * <li>floating_point</li>
+ * <li>float</li>
+ * <li>integer</li>
+ * <li>int</li>
+ * <li>long</li>
+ * <li>short</li>
+ * <li>signed</li>
+ * <li>stream</li>
+ * <li>string</li>
+ * <li>struct</li>
+ * <li>trace</li>
+ * <li>typealias</li>
+ * <li>typedef</li>
+ * <li>unsigned</li>
+ * <li>variant</li>
+ * <li>void</li>
+ * <li>_Bool</li>
+ * <li>_Complex</li>
+ * <li>_Imaginary</li>
+ * </ul>
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class StructBodyParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * The parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final @Nullable String fName;
+ private final StructDeclaration fStructDeclaration;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param structDeclaration
+ * struct declaration to populate
+ * @param trace
+ * the trace
+ * @param name
+ * the struct name
+ * @param scope
+ * the current scope
+ */
+ public Param(StructDeclaration structDeclaration, CTFTrace trace, @Nullable String name, DeclarationScope scope) {
+ fStructDeclaration = structDeclaration;
+ fTrace = trace;
+ fDeclarationScope = scope;
+ fName = name;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static StructBodyParser INSTANCE = new StructBodyParser();
+
+ private StructBodyParser() {
+ }
+
+ /**
+ * Parse the body of a struct, so anything between the '{' '}'
+ *
+ * @param structBody
+ * the struct body AST node
+ * @param param
+ * the struct body parameters
+ * @return {@link StructDeclaration} that is now populated
+ * @throws ParseException
+ * The AST is malformed
+ */
+ @Override
+ public StructDeclaration parse(CommonTree structBody, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ String structName = ((Param) param).fName;
+ final DeclarationScope scope = new DeclarationScope(((Param) param).fDeclarationScope, structName == null ? MetadataStrings.STRUCT : structName);
+ StructDeclaration structDeclaration = ((Param) param).fStructDeclaration;
+ List<CommonTree> structDeclarations = structBody.getChildren();
+ if (structDeclarations == null) {
+ structDeclarations = Collections.emptyList();
+ }
+
+ /*
+ * If structDeclaration is null, structBody has no children and the
+ * struct body is empty.
+ */
+
+ CTFTrace trace = ((Param) param).fTrace;
+
+ for (CommonTree declarationNode : structDeclarations) {
+ switch (declarationNode.getType()) {
+ case CTFParser.TYPEALIAS:
+ TypeAliasParser.INSTANCE.parse(declarationNode, new TypeAliasParser.Param(trace, scope));
+ break;
+ case CTFParser.TYPEDEF:
+ TypedefParser.INSTANCE.parse(declarationNode, new TypedefParser.Param(trace, scope));
+ StructDeclarationParser.INSTANCE.parse(declarationNode, new StructDeclarationParser.Param(structDeclaration, trace, scope));
+ break;
+ case CTFParser.SV_DECLARATION:
+ StructDeclarationParser.INSTANCE.parse(declarationNode, new StructDeclarationParser.Param(structDeclaration, trace, scope));
+ break;
+ default:
+ throw childTypeError(declarationNode);
+ }
+ }
+ return structDeclaration;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.struct;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeDeclaratorParser;
+
+/**
+ * Structures follow the ISO/C standard for structures
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class StructDeclarationParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final StructDeclaration fStruct;
+ private final DeclarationScope fDeclarationScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param struct
+ * the structure declaration
+ * @param trace
+ * the trace
+ * @param scope
+ * the current scope
+ */
+ public Param(StructDeclaration struct, CTFTrace trace, DeclarationScope scope) {
+ fStruct = struct;
+ fTrace = trace;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static StructDeclarationParser INSTANCE = new StructDeclarationParser();
+
+ private StructDeclarationParser() {
+ }
+
+ /**
+ * Parses a declaration found in a struct.
+ *
+ * @param declaration
+ * A SV_DECLARATION node.
+ * @param param
+ * The parameter object
+ * @throws ParseException
+ * for poorly formed structs (duplicate fields, etc...)
+ */
+ @Override
+ public StructDeclaration parse(CommonTree declaration, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ DeclarationScope scope = ((Param) param).fDeclarationScope;
+ StructDeclaration struct = ((Param) param).fStruct;
+ /* Get the type specifier list node */
+ CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
+
+ if (typeSpecifierListNode == null) {
+ throw new ParseException("Cannot have an struct without a type specifier"); //$NON-NLS-1$
+ }
+
+ /* Get the type declarator list node */
+ CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
+
+ if (typeDeclaratorListNode == null) {
+ throw new ParseException("Cannot have an struct without a declarator"); //$NON-NLS-1$
+ }
+
+ /* Get the type declarator list */
+ List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
+
+ /*
+ * For each type declarator, parse the declaration and add a field to
+ * the struct
+ */
+ for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
+
+ StringBuilder identifierSB = new StringBuilder();
+
+ CTFTrace trace = ((Param) param).fTrace;
+ IDeclaration decl = TypeDeclaratorParser.INSTANCE.parse(typeDeclaratorNode, new TypeDeclaratorParser.Param(trace, typeSpecifierListNode, scope, identifierSB));
+ String fieldName = identifierSB.toString();
+ scope.registerIdentifier(fieldName, decl);
+
+ if (struct.hasField(fieldName)) {
+ throw new ParseException("struct: duplicate field " //$NON-NLS-1$
+ + fieldName);
+ }
+
+ struct.addField(fieldName, decl);
+
+ }
+ return struct;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.struct;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.AlignmentParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.types.StructDeclarationFlattener;
+
+/**
+ *
+ * Structures are aligned on the largest alignment required by basic types
+ * contained within the structure. (This follows the ISO/C standard for
+ * structures) <br>
+ * TSDL metadata representation of a named structure:
+ *
+ * <pre>
+struct name {
+ field_type field_name;
+ field_type field_name;
+ // ...
+};
+ * </pre>
+ *
+ * Example:
+ *
+ * <pre>
+struct example {
+ integer { // nameless type
+ size = 16;
+ signed = true;
+ align = 16;
+ } first_field_name;
+ uint64_t second_field_name; // named type declared in the metadata
+};
+ * </pre>
+ *
+ * The fields are placed in a sequence next to each other. They each possess a
+ * field name, which is a unique identifier within the structure. The identifier
+ * is not allowed to use any [reserved keyword](#specC.1.2). Replacing reserved
+ * keywords with underscore-prefixed field names is <strong>recommended</strong>
+ * . Fields starting with an underscore should have their leading underscore
+ * removed by the CTF trace readers. <br>
+ * A nameless structure can be declared as a field type or as part of a
+ * `typedef`:
+ *
+ * <pre>
+struct {
+ // ...
+}
+ *
+ * </pre>
+ *
+ * Alignment for a structure compound type can be forced to a minimum value by
+ * adding an `align` specifier after the declaration of a structure body. This
+ * attribute is read as: `align(value)`. The value is specified in bits. The
+ * structure will be aligned on the maximum value between this attribute and the
+ * alignment required by the basic types contained within the structure. e.g.
+ *
+ * <pre>
+struct {
+ // ...
+} align(32)
+}
+ * </pre>
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Javadoc preamble
+ */
+public class StructParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final @Nullable CommonTree fIdentifier;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param identifier
+ * the identifier
+ * @param scope
+ * the current scope
+ */
+ public Param(CTFTrace trace, @Nullable CommonTree identifier, DeclarationScope scope) {
+ fTrace = trace;
+ fIdentifier = identifier;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static StructParser INSTANCE = new StructParser();
+
+ private StructParser() {
+ }
+
+ /**
+ * Parse the struct AST node, So everything in "struct a {...};"
+ *
+ * @param struct
+ * the struct AST node
+ * @param param
+ * the parameter object of {@link Param} type.
+ * @return a {@link StructDeclaration} that is fully populated
+ * @throws ParseException
+ * the AST is malformed
+ */
+ @Override
+ public StructDeclaration parse(CommonTree struct, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ final DeclarationScope scope = ((Param) param).fDeclarationScope;
+ CommonTree identifier = ((Param) param).fIdentifier;
+
+ List<CommonTree> children = struct.getChildren();
+
+ /* The return value */
+ StructDeclaration structDeclaration = null;
+
+ /* Name */
+ String structName = null;
+ boolean hasName = false;
+
+ /* Body */
+ CommonTree structBody = null;
+ boolean hasBody = false;
+
+ /* Align */
+ long structAlign = 0;
+
+ /* Loop on all children and identify what we have to work with. */
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.STRUCT_NAME: {
+ hasName = true;
+ CommonTree structNameIdentifier = (CommonTree) child.getChild(0);
+ structName = structNameIdentifier.getText();
+ break;
+ }
+ case CTFParser.STRUCT_BODY: {
+ hasBody = true;
+
+ structBody = child;
+ break;
+ }
+ case CTFParser.ALIGN: {
+ CommonTree structAlignExpression = (CommonTree) child.getChild(0);
+
+ structAlign = AlignmentParser.INSTANCE.parse(structAlignExpression, null);
+ break;
+ }
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ if (!hasName && identifier != null) {
+ structName = identifier.getText();
+ hasName = true;
+ }
+
+ /*
+ * If a struct has just a body and no name (just like the song,
+ * "A Struct With No Name" by America (sorry for that...)), it's a
+ * definition of a new type, so we create the type declaration and
+ * return it. We can't add it to the declaration scope since there is no
+ * name, but that's what we want because it won't be possible to use it
+ * again to declare another field.
+ *
+ * If it has just a name, we look it up in the declaration scope and
+ * return the associated declaration. If it is not found in the
+ * declaration scope, it means that a struct with that name has not been
+ * declared, which is an error.
+ *
+ * If it has both, then we create the type declaration and register it
+ * to the current scope.
+ *
+ * If it has none, then what are we doing here ?
+ */
+ if (hasBody) {
+ /*
+ * If struct has a name, check if already defined in the current
+ * scope.
+ */
+ if (hasName && (scope.lookupStruct(structName) != null)) {
+ throw new ParseException("struct " + structName //$NON-NLS-1$
+ + " already defined."); //$NON-NLS-1$
+ }
+ /* Create the declaration */
+ structDeclaration = new StructDeclaration(structAlign);
+
+ CTFTrace trace = ((Param) param).fTrace;
+ /* Parse the body */
+ StructBodyParser.INSTANCE.parse(structBody, new StructBodyParser.Param(structDeclaration, trace, structName, scope));
+ /* If struct has name, add it to the current scope. */
+ if (hasName) {
+ scope.registerStruct(structName, structDeclaration);
+ }
+ } else /* !hasBody */ {
+ if (hasName) {
+ /* Name and !body */
+
+ /* Lookup the name in the current scope. */
+ structDeclaration = scope.lookupStructRecursive(structName);
+
+ /*
+ * If not found, it means that a struct with such name has not
+ * been defined
+ */
+ if (structDeclaration == null) {
+ throw new ParseException("struct " + structName //$NON-NLS-1$
+ + " is not defined"); //$NON-NLS-1$
+ }
+ } else {
+ /* !Name and !body */
+
+ /* We can't do anything with that. */
+ throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
+ }
+ }
+ return StructDeclarationFlattener.tryFlattenStruct(structDeclaration);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.nio.ByteOrder;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration.Pair;
+import org.eclipse.tracecompass.ctf.core.event.types.FloatDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.Activator;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.Messages;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.ByteOrderParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser;
+
+/**
+ *
+ * A <em>trace<em> is divided into multiple event streams. Each event stream
+ * contains a subset of the trace event types. <br>
+ * The final output of the trace, after its generation and optional transport
+ * over the network, is expected to be either on permanent or temporary storage
+ * in a virtual file system. Because each event stream is appended to while a
+ * trace is being recorded, each is associated with a distinct set of files for
+ * output. Therefore, a stored trace can be represented as a directory
+ * containing zero, one or more files per stream. <br>
+ * Metadata description associated with the trace contains information on trace
+ * event types expressed in the _Trace Stream Description Language_ (TSDL). This
+ * language describes: <br>
+ * <ul>
+ * <li>Trace version</li>
+ * <li>Types available</li>
+ * <li>Per-trace event header description</li>
+ * <li>Per-stream event header description</li>
+ * <li>Per-stream event context description</li>
+ * <li>Per-event
+ * <ul>
+ * <li>Event type to stream mapping</li>
+ * <li>Event type to name mapping</li>
+ * <li>Event type to ID mapping</li>
+ * <li>Event context description</li>
+ * <li>Event fields description</li>
+ * </ul>
+ * </ul>
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class TraceDeclarationParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+
+ private final DeclarationScope fCurrentScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Parameter Object
+ *
+ * @param trace
+ * the trace
+ * @param currentScope
+ * the current scope
+ */
+ public Param(CTFTrace trace, DeclarationScope currentScope) {
+ fTrace = trace;
+ fCurrentScope = currentScope;
+ }
+
+ }
+
+ /**
+ * Parser instance
+ */
+ public static final TraceDeclarationParser INSTANCE = new TraceDeclarationParser();
+
+ private TraceDeclarationParser() {
+ }
+
+ /**
+ * Parse a trace AST node
+ *
+ * @param traceDecl
+ * trace AST node
+ * @param param
+ * A parameter object of the type {@link Param}
+ * @return a {@link CTFTrace} that is populated
+ * @throws ParseException
+ * if the AST is malformed
+ */
+ @Override
+ public CTFTrace parse(CommonTree traceDecl, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ CTFTrace trace = ((Param) param).fTrace;
+ DeclarationScope scope = ((Param) param).fCurrentScope;
+
+ /* There should be a left and right */
+ CommonTree leftNode = (CommonTree) traceDecl.getChild(0);
+ CommonTree rightNode = (CommonTree) traceDecl.getChild(1);
+
+ List<CommonTree> leftStrings = leftNode.getChildren();
+
+ if (!isAnyUnaryString(leftStrings.get(0))) {
+ throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
+ }
+
+ String left = concatenateUnaryStrings(leftStrings);
+
+ if (left.equals(MetadataStrings.MAJOR)) {
+ if (trace.majorIsSet()) {
+ throw new ParseException("major is already set"); //$NON-NLS-1$
+ }
+
+ trace.setMajor(VersionNumberParser.INSTANCE.parse(rightNode, null));
+ } else if (left.equals(MetadataStrings.MINOR)) {
+ if (trace.minorIsSet()) {
+ throw new ParseException("minor is already set"); //$NON-NLS-1$
+ }
+
+ trace.setMinor(VersionNumberParser.INSTANCE.parse(rightNode, null));
+ } else if (left.equals(MetadataStrings.UUID_STRING)) {
+ UUID uuid = UUIDParser.INSTANCE.parse(rightNode, null);
+
+ /*
+ * If uuid was already set by a metadata packet, compare it to see
+ * if it matches
+ */
+ if (trace.uuidIsSet()) {
+ if (trace.getUUID().compareTo(uuid) != 0) {
+ throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
+ + trace.getUUID() + " but metadata says " + uuid); //$NON-NLS-1$
+ }
+ } else {
+ trace.setUUID(uuid);
+ }
+
+ } else if (left.equals(MetadataStrings.BYTE_ORDER)) {
+ ByteOrder byteOrder = ByteOrderParser.INSTANCE.parse(rightNode, new ByteOrderParser.Param(trace));
+
+ /*
+ * If byte order was already set by a metadata packet, compare it to
+ * see if it matches
+ */
+ if (trace.getByteOrder() != null) {
+ if (trace.getByteOrder() != byteOrder) {
+ throw new ParseException(
+ "Endianness mismatch. Magic number says " //$NON-NLS-1$
+ + trace.getByteOrder()
+ + " but metadata says " + byteOrder); //$NON-NLS-1$
+ }
+ } else {
+ trace.setByteOrder(byteOrder);
+
+ final DeclarationScope currentScope = scope;
+ for (String type : currentScope.getTypeNames()) {
+ IDeclaration d = currentScope.lookupType(type);
+ if (d instanceof IntegerDeclaration) {
+ addByteOrder(byteOrder, currentScope, type, (IntegerDeclaration) d);
+ } else if (d instanceof FloatDeclaration) {
+ addByteOrder(byteOrder, currentScope, type, (FloatDeclaration) d);
+ } else if (d instanceof EnumDeclaration) {
+ addByteOrder(byteOrder, currentScope, type, (EnumDeclaration) d);
+ } else if (d instanceof StructDeclaration) {
+ setAlign(currentScope, (StructDeclaration) d, byteOrder);
+ }
+ }
+ }
+ } else if (left.equals(MetadataStrings.PACKET_HEADER)) {
+ if (trace.packetHeaderIsSet()) {
+ throw new ParseException("packet.header already defined"); //$NON-NLS-1$
+ }
+
+ CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
+
+ if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
+ throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
+ }
+
+ IDeclaration packetHeaderDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(trace, null, null, scope));
+
+ if (!(packetHeaderDecl instanceof StructDeclaration)) {
+ throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
+ }
+
+ trace.setPacketHeader((StructDeclaration) packetHeaderDecl);
+ } else {
+ Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownTraceAttributeWarning + " " + left); //$NON-NLS-1$
+ }
+ return trace;
+ }
+
+ private static void addByteOrder(ByteOrder byteOrder,
+ final DeclarationScope parentScope, String name,
+ IntegerDeclaration decl) throws ParseException {
+
+ if (!decl.isByteOrderSet()) {
+ IntegerDeclaration newI;
+ newI = IntegerDeclaration.createDeclaration(decl.getLength(), decl.isSigned(),
+ decl.getBase(), byteOrder, decl.getEncoding(),
+ decl.getClock(), decl.getAlignment());
+ parentScope.replaceType(name, newI);
+ }
+ }
+
+ private static void addByteOrder(ByteOrder byteOrder, DeclarationScope parentScope, String name, EnumDeclaration decl) throws ParseException {
+ if (!decl.isByteOrderSet()) {
+ final IntegerDeclaration containerType = decl.getContainerType();
+ EnumDeclaration newEnum = new EnumDeclaration(IntegerDeclaration.createDeclaration(containerType.getLength(), containerType.isSigned(),
+ containerType.getBase(), byteOrder, containerType.getEncoding(),
+ containerType.getClock(), containerType.getAlignment()));
+ for (Entry<String, Pair> entry : decl.getEnumTable().entrySet()) {
+ newEnum.add(entry.getValue().getFirst(), entry.getValue().getSecond(), entry.getKey());
+ }
+
+ parentScope.replaceType(name, newEnum);
+ }
+ }
+
+ private static void addByteOrder(ByteOrder byteOrder, DeclarationScope parentScope, String name, FloatDeclaration decl) throws ParseException {
+ if (!decl.isByteOrderSet()) {
+ FloatDeclaration newFloat = new FloatDeclaration(decl.getExponent(), decl.getMantissa(), byteOrder, decl.getAlignment());
+ parentScope.replaceType(name, newFloat);
+ }
+ }
+
+ private void setAlign(DeclarationScope parentScope, StructDeclaration sd,
+ ByteOrder byteOrder) throws ParseException {
+
+ for (String s : sd.getFieldsList()) {
+ IDeclaration d = sd.getField(s);
+
+ if (d instanceof StructDeclaration) {
+ setAlign(parentScope, (StructDeclaration) d, byteOrder);
+
+ } else if (d instanceof VariantDeclaration) {
+ setAlign(parentScope, (VariantDeclaration) d, byteOrder);
+ } else if (d instanceof IntegerDeclaration) {
+ IntegerDeclaration decl = (IntegerDeclaration) d;
+ if (decl.getByteOrder() != byteOrder) {
+ IntegerDeclaration newI;
+ newI = IntegerDeclaration.createDeclaration(decl.getLength(),
+ decl.isSigned(), decl.getBase(), byteOrder,
+ decl.getEncoding(), decl.getClock(),
+ decl.getAlignment());
+ sd.getFields().put(s, newI);
+ }
+ }
+ }
+ }
+
+ private void setAlign(DeclarationScope parentScope, VariantDeclaration vd,
+ ByteOrder byteOrder) throws ParseException {
+
+ for (String s : vd.getFields().keySet()) {
+ IDeclaration d = vd.getFields().get(s);
+
+ if (d instanceof StructDeclaration) {
+ setAlign(parentScope, (StructDeclaration) d, byteOrder);
+
+ } else if (d instanceof IntegerDeclaration) {
+ IntegerDeclaration decl = (IntegerDeclaration) d;
+ IntegerDeclaration newI;
+ newI = IntegerDeclaration.createDeclaration(decl.getLength(),
+ decl.isSigned(), decl.getBase(), byteOrder,
+ decl.getEncoding(), decl.getClock(),
+ decl.getAlignment());
+ vd.getFields().put(s, newI);
+ }
+ }
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream.StreamScopeParser;
+
+/**
+ * TSDL uses three different types of scoping: a lexical scope is used for
+ * declarations and type definitions, and static and dynamic scopes are used for
+ * variants references to tag fields (with relative and absolute path lookups)
+ * and for sequence references to length fields.
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Description
+ *
+ */
+public final class TraceScopeParser implements ICommonTreeParser {
+
+ /**
+ * Parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final List<CommonTree> fList;
+
+ /**
+ * Parameter object constructor
+ *
+ * @param list
+ * the list of subtrees
+ */
+ public Param(List<CommonTree> list) {
+ fList = list;
+
+ }
+
+ }
+
+ /**
+ * Instance
+ */
+ public static final TraceScopeParser INSTANCE = new TraceScopeParser();
+
+ private TraceScopeParser() {
+ }
+
+ /**
+ * Parse a trace scope to get a concatenated scope name. Like
+ * "trace.version.minor"
+ *
+ * @param unused
+ * unused
+ * @param param
+ * a {@link Param} containing the list of ASTs to make the scope
+ * @return a {@link String} of the scope
+ * @throws ParseException
+ * an AST was malformed
+ *
+ */
+ @Override
+ public String parse(CommonTree unused, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ List<@NonNull CommonTree> lengthChildren = ((Param) param).fList;
+ CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0);
+ switch (nextElem.getType()) {
+ case CTFParser.IDENTIFIER:
+ return concatenateUnaryStrings(lengthChildren.subList(1, lengthChildren.size()));
+ case CTFParser.STREAM:
+ return StreamScopeParser.INSTANCE.parse(null, new StreamScopeParser.Param(lengthChildren.subList(1, lengthChildren.size())));
+ default:
+ throw new ParseException("Unsupported scope trace." + nextElem); //$NON-NLS-1$
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString;
+
+import java.util.UUID;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryStringParser;
+
+/**
+ * <strong>Trace UUID</strong>, used to ensure the event packet match the
+ * metadata used. Note: we cannot use a metadata checksum in every cases instead
+ * of a UUID because metadata can be appended to while tracing is active. This
+ * field is optional.
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class UUIDParser implements ICommonTreeParser {
+
+ private static final String INVALID_FORMAT_FOR_UUID = "Invalid format for UUID"; //$NON-NLS-1$
+ private static final String INVALID_VALUE_FOR_UUID = "Invalid value for UUID"; //$NON-NLS-1$
+ /** Instance */
+ public static final UUIDParser INSTANCE = new UUIDParser();
+
+ private UUIDParser() {
+ }
+
+ /**
+ * Parse a UUID String and get a {@link UUID} in return.
+ *
+ * @param tree
+ * the UUID AST
+ * @param unused
+ * unused
+ * @return a {@link UUID}
+ * @throws ParseException
+ * the AST was malformed
+ */
+ @Override
+ public UUID parse(CommonTree tree, ICommonTreeParserParameter unused) throws ParseException {
+
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+
+ if (isAnyUnaryString(firstChild)) {
+ if (tree.getChildCount() > 1) {
+ throw new ParseException(INVALID_VALUE_FOR_UUID);
+ }
+
+ String uuidstr = UnaryStringParser.INSTANCE.parse(firstChild, null);
+
+ try {
+ return UUID.fromString(uuidstr);
+ } catch (IllegalArgumentException e) {
+ throw new ParseException(INVALID_FORMAT_FOR_UUID, e);
+ }
+ }
+ throw new ParseException(INVALID_VALUE_FOR_UUID);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.UnaryIntegerParser;
+
+/**
+ * A version number parser looking up major/minor
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public final class VersionNumberParser implements ICommonTreeParser {
+
+ private static final String ERROR = "Invalid value for major/minor"; //$NON-NLS-1$
+
+ /**
+ * The instance
+ */
+ public static final VersionNumberParser INSTANCE = new VersionNumberParser();
+
+ private VersionNumberParser() {
+ }
+
+ /**
+ * Parse a version and get the major or minor value
+ *
+ * @param tree
+ * the AST node of the version
+ * @param unused
+ * unused
+ * @return the version value as a {@link Long}
+ * @throws ParseException
+ * the AST is malformed
+ */
+ @Override
+ public Long parse(CommonTree tree, ICommonTreeParserParameter unused) throws ParseException {
+
+ CommonTree firstChild = (CommonTree) tree.getChild(0);
+
+ if (isUnaryInteger(firstChild)) {
+ if (tree.getChildCount() > 1) {
+ throw new ParseException(ERROR);
+ }
+ long version = UnaryIntegerParser.INSTANCE.parse(firstChild, null);
+ if (version < 0) {
+ throw new ParseException(ERROR);
+ }
+ return version;
+ }
+ throw new ParseException(ERROR);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.variant;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeAliasParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypedefParser;
+
+/**
+ * Variant body parser. This handles all the inside of a variant, so it handles
+ * everything between the '{' and '}' of a TSDL variant declaration.
+ *
+ * @author Matthew Khouzam
+ *
+ */
+public class VariantBodyParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final @Nullable String fName;
+ private final VariantDeclaration fVariantDeclaration;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param variantDeclaration
+ * the declaration to populate
+ * @param trace
+ * the trace
+ * @param name
+ * the variant name
+ * @param scope
+ * the current scope
+ */
+ public Param(VariantDeclaration variantDeclaration, CTFTrace trace, @Nullable String name, DeclarationScope scope) {
+ fVariantDeclaration = variantDeclaration;
+ fTrace = trace;
+ fDeclarationScope = scope;
+ fName = name;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static VariantBodyParser INSTANCE = new VariantBodyParser();
+
+ private VariantBodyParser() {
+ }
+
+ /**
+ * Parse the variant body, fills the variant with the results.
+ *
+ * @param variantBody
+ * the variant body AST node
+ * @param param
+ * the {@link Param} parameter object
+ * @return a populated {@link VariantDeclaration}
+ * @throws ParseException
+ * if the AST is malformed
+ */
+ @Override
+ public VariantDeclaration parse(CommonTree variantBody, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+
+ String variantName = ((Param) param).fName;
+ VariantDeclaration variantDeclaration = ((Param) param).fVariantDeclaration;
+ List<CommonTree> variantDeclarations = variantBody.getChildren();
+
+ final DeclarationScope scope = new DeclarationScope(((Param) param).fDeclarationScope, variantName == null ? MetadataStrings.VARIANT : variantName);
+ CTFTrace trace = ((Param) param).fTrace;
+ for (CommonTree declarationNode : variantDeclarations) {
+ switch (declarationNode.getType()) {
+ case CTFParser.TYPEALIAS:
+ TypeAliasParser.INSTANCE.parse(declarationNode, new TypeAliasParser.Param(trace, scope));
+ break;
+ case CTFParser.TYPEDEF:
+ Map<String, IDeclaration> decs = TypedefParser.INSTANCE.parse(declarationNode, new TypedefParser.Param(trace, scope));
+ for (Entry<String, IDeclaration> declarationEntry : decs.entrySet()) {
+ variantDeclaration.addField(declarationEntry.getKey(), declarationEntry.getValue());
+ }
+ break;
+ case CTFParser.SV_DECLARATION:
+ VariantDeclarationParser.INSTANCE.parse(declarationNode, new VariantDeclarationParser.Param(variantDeclaration, trace, scope));
+ break;
+ default:
+ throw childTypeError(declarationNode);
+ }
+ }
+
+ return variantDeclaration;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.variant;
+
+import java.util.List;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeDeclaratorParser;
+
+/**
+ * This parses the (sub)declarations located IN a variant declaration.
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Javadoc
+ *
+ */
+public class VariantDeclarationParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter Object
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final VariantDeclaration fVariant;
+ private final DeclarationScope fDeclarationScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Parameter Object Contructor
+ *
+ * @param variant
+ * variant declaration to populate
+ * @param trace
+ * trace
+ * @param scope
+ * current scope
+ */
+ public Param(VariantDeclaration variant, CTFTrace trace, DeclarationScope scope) {
+ fVariant = variant;
+ fTrace = trace;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * Instance
+ */
+ public final static VariantDeclarationParser INSTANCE = new VariantDeclarationParser();
+
+ private VariantDeclarationParser() {
+ }
+
+ /**
+ * Parses the variant declaration and gets a {@link VariantDeclaration}
+ * back.
+ *
+ * @param declaration
+ * the variant declaration AST node
+ * @param param
+ * the {@link Param} parameter object
+ * @return the {@link VariantDeclaration}
+ * @throws ParseException
+ * if the AST is malformed
+ */
+ @Override
+ public VariantDeclaration parse(CommonTree declaration, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ VariantDeclaration variant = ((Param) param).fVariant;
+ final DeclarationScope scope = ((Param) param).fDeclarationScope;
+ /* Get the type specifier list node */
+ CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
+ if (typeSpecifierListNode == null) {
+ throw new ParseException("Variant need type specifiers"); //$NON-NLS-1$
+ }
+
+ /* Get the type declarator list node */
+ CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
+ if (typeDeclaratorListNode == null) {
+ throw new ParseException("Cannot have empty variant"); //$NON-NLS-1$
+ }
+ /* Get the type declarator list */
+ List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
+
+ /*
+ * For each type declarator, parse the declaration and add a field to
+ * the variant
+ */
+ for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
+
+ StringBuilder identifierSB = new StringBuilder();
+ CTFTrace trace = ((Param) param).fTrace;
+ IDeclaration decl = TypeDeclaratorParser.INSTANCE.parse(typeDeclaratorNode,
+ new TypeDeclaratorParser.Param(trace, typeSpecifierListNode, scope, identifierSB));
+
+ String name = identifierSB.toString();
+
+ if (variant.hasField(name)) {
+ throw new ParseException("variant: duplicate field " //$NON-NLS-1$
+ + name);
+ }
+
+ scope.registerIdentifier(name, decl);
+
+ variant.addField(name, decl);
+ }
+ return variant;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.variant;
+
+import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.antlr.runtime.tree.CommonTree;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope;
+import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
+import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
+import org.eclipse.tracecompass.ctf.parser.CTFParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
+
+/**
+ *
+ * A CTF variant is a selection between different types. A CTF variant must
+ * always be defined within the scope of a structure or within fields contained
+ * within a structure (defined recursively). A _tag_ enumeration field must
+ * appear in either the same static scope, prior to the variant field (in field
+ * declaration order), in an upper static scope, or in an upper dynamic scope
+ * (see [Static and dynamic scopes](#spec7.3.2)). The type selection is
+ * indicated by the mapping from the enumeration value to the string used as
+ * variant type selector. The field to use as tag is specified by the
+ * `tag_field`, specified between `< >` after the `variant` keyword for unnamed
+ * variants, and after _variant name_ for named variants. It is not required
+ * that each enumeration mapping appears as variant type tag field. It is also
+ * not required that each variant type tag appears as enumeration mapping.
+ * However, it is required that any enumeration mapping encountered within a
+ * stream has a matching variant type tag field. <br>
+ * The alignment of the variant is the alignment of the type as selected by the
+ * tag value for the specific instance of the variant. The size of the variant
+ * is the size as selected by the tag value for the specific instance of the
+ * variant. <br>
+ * The alignment of the type containing the variant is independent of the
+ * variant alignment. For instance, if a structure contains two fields, a 32-bit
+ * integer, aligned on 32 bits, and a variant, which contains two choices:
+ * either a 32-bit field, aligned on 32 bits, or a 64-bit field, aligned on 64
+ * bits, the alignment of the outmost structure will be 32-bit (the alignment of
+ * its largest field, disregarding the alignment of the variant). The alignment
+ * of the variant will depend on the selector: if the variant's 32-bit field is
+ * selected, its alignment will be 32-bit, or 64-bit otherwise. It is important
+ * to note that variants are specifically tailored for compactness in a stream.
+ * Therefore, the relative offsets of compound type fields can vary depending on
+ * the offset at which the compound type starts if it contains a variant that
+ * itself contains a type with alignment larger than the largest field contained
+ * within the compound type. This is caused by the fact that the compound type
+ * may contain the enumeration that select the variant's choice, and therefore
+ * the alignment to be applied to the compound type cannot be determined before
+ * encountering the enumeration. <br>
+ * Each variant type selector possess a field name, which is a unique identifier
+ * within the variant. The identifier is not allowed to use any [reserved
+ * keyword](#C.1.2). Replacing reserved keywords with underscore-prefixed field
+ * names is recommended. Fields starting with an underscore should have their
+ * leading underscore removed by the CTF trace readers. <br>
+ * A named variant declaration followed by its definition within a structure
+ * declaration: <br>
+ *
+ * <pre>
+variant name {
+ field_type sel1;
+ field_type sel2;
+ field_type sel3;
+ // ...
+};
+
+struct {
+ enum : integer_type { sel1, sel2, sel3, <em>more</em> } tag_field;
+ // ...
+ variant name <tag_field> v;
+}
+ * </pre>
+ *
+ * An unnamed variant definition within a structure is expressed by the
+ * following TSDL metadata: <br>
+ *
+ * <pre>
+struct {
+ enum : integer_type { sel1, sel2, sel3, <em>more</em> } tag_field;
+ // ...
+ variant <tag_field> {
+ field_type sel1;
+ field_type sel2;
+ field_type sel3;
+ // ...
+ } v;
+}
+ * </pre>
+ *
+ * Example of a named variant within a sequence that refers to a single tag
+ * field: <br>
+ *
+ * <pre>
+variant example {
+ uint32_t a;
+ uint64_t b;
+ short c;
+};
+
+struct {
+ enum : uint2_t { a, b, c } choice;
+ unsigned int seqlen;
+ variant example <choice> v[seqlen];
+}
+ * </pre>
+ *
+ * Example of an unnamed variant: <br>
+ *
+ * <pre>
+struct {
+ enum : uint2_t { a, b, c, d } choice;
+
+ // Unrelated fields can be added between the variant and its tag
+ int32_t somevalue;
+ variant <choice> {
+ uint32_t a;
+ uint64_t b;
+ short c;
+ struct {
+ unsigned int field1;
+ uint64_t field2;
+ } d;
+ } s;
+}
+ * </pre>
+ *
+ * Example of an unnamed variant within an array: <br>
+ *
+ * <pre>
+struct {
+ enum : uint2_t { a, b, c } choice;
+ variant <choice> {
+ uint32_t a;
+ uint64_t b;
+ short c;
+ } v[10];
+}
+ * </pre>
+ *
+ * <br>
+ * Example of a variant type definition within a structure, where the defined
+ * type is then declared within an array of structures. This variant refers to a
+ * tag located in an upper static scope. This example clearly shows that a
+ * variant type definition referring to the tag `x` uses the closest preceding
+ * field from the static scope of the type definition. <br>
+ *
+ * <pre>
+struct {
+ enum : uint2_t { a, b, c, d } x;
+
+ // "x" refers to the preceding "x" enumeration in the
+ // static scope of the type definition.
+
+ typedef variant <x> {
+ uint32_t a;
+ uint64_t b;
+ short c;
+ } example_variant;
+
+ struct {
+ enum : int { x, y, z } x; // This enumeration is not used by "v".
+
+ // "v" uses the "enum : uint2_t { a, b, c, d }" tag.
+ example_variant v;
+ } a[10];
+}
+ * </pre>
+ *
+ * @author Matthew Khouzam
+ * @author Efficios - Javadoc preamble
+ *
+ *
+ */
+public class VariantParser extends AbstractScopedCommonTreeParser {
+
+ /**
+ * Parameter object with a trace and current scope
+ *
+ * @author Matthew Khouzam
+ *
+ */
+ @NonNullByDefault
+ public static final class Param implements ICommonTreeParserParameter {
+ private final DeclarationScope fDeclarationScope;
+ private final CTFTrace fTrace;
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * the trace
+ * @param scope
+ * the current scope
+ */
+ public Param(CTFTrace trace, DeclarationScope scope) {
+ fTrace = trace;
+ fDeclarationScope = scope;
+ }
+ }
+
+ /**
+ * The instance
+ */
+ public final static VariantParser INSTANCE = new VariantParser();
+
+ private VariantParser() {
+ }
+
+ /**
+ * Parse the variant
+ *
+ * @param variant
+ * the variant AST node
+ * @param param
+ * the {@link Param} parameter object
+ * @return a populated {@link VariantDeclaration}
+ * @throws ParseException
+ * the AST is malformed
+ */
+ @Override
+ public VariantDeclaration parse(CommonTree variant, ICommonTreeParserParameter param) throws ParseException {
+ if (!(param instanceof Param)) {
+ throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+ }
+ final DeclarationScope scope = ((Param) param).fDeclarationScope;
+
+ List<CommonTree> children = variant.getChildren();
+ VariantDeclaration variantDeclaration = null;
+
+ boolean hasName = false;
+ String variantName = null;
+
+ boolean hasBody = false;
+ CommonTree variantBody = null;
+
+ boolean hasTag = false;
+ String variantTag = null;
+
+ for (CommonTree child : children) {
+ switch (child.getType()) {
+ case CTFParser.VARIANT_NAME:
+
+ hasName = true;
+
+ CommonTree variantNameIdentifier = (CommonTree) child.getChild(0);
+
+ variantName = variantNameIdentifier.getText();
+
+ break;
+ case CTFParser.VARIANT_TAG:
+
+ hasTag = true;
+
+ CommonTree variantTagIdentifier = (CommonTree) child.getChild(0);
+
+ variantTag = variantTagIdentifier.getText();
+
+ break;
+ case CTFParser.VARIANT_BODY:
+
+ hasBody = true;
+
+ variantBody = child;
+
+ break;
+ default:
+ throw childTypeError(child);
+ }
+ }
+
+ if (hasBody) {
+ /*
+ * If variant has a name, check if already defined in the current
+ * scope.
+ */
+ if (hasName
+ && (scope.lookupVariant(variantName) != null)) {
+ throw new ParseException("variant " + variantName //$NON-NLS-1$
+ + " already defined."); //$NON-NLS-1$
+ }
+
+ /* Create the declaration */
+ variantDeclaration = new VariantDeclaration();
+
+ CTFTrace trace = ((Param) param).fTrace;
+ /* Parse the body */
+ VariantBodyParser.INSTANCE.parse(variantBody, new VariantBodyParser.Param(variantDeclaration, trace, variantName, scope));
+
+ /* If variant has name, add it to the current scope. */
+ if (hasName) {
+ scope.registerVariant(variantName, variantDeclaration);
+ }
+ } else /* !hasBody */ {
+ if (hasName) {
+ /* Name and !body */
+
+ /* Lookup the name in the current scope. */
+ variantDeclaration = scope.lookupVariantRecursive(variantName);
+
+ /*
+ * If not found, it means that a struct with such name has not
+ * been defined
+ */
+ if (variantDeclaration == null) {
+ throw new ParseException("variant " + variantName //$NON-NLS-1$
+ + " is not defined"); //$NON-NLS-1$
+ }
+ } else {
+ /* !Name and !body */
+
+ /* We can't do anything with that. */
+ throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
+ }
+ }
+
+ if (hasTag) {
+ variantDeclaration.setTag(variantTag);
+
+ IDeclaration decl = scope.lookupIdentifierRecursive(variantTag);
+ if (decl == null) {
+ throw new ParseException("Variant tag not found: " + variantTag); //$NON-NLS-1$
+ }
+ if (!(decl instanceof EnumDeclaration)) {
+ throw new ParseException("Variant tag must be an enum: " + variantTag); //$NON-NLS-1$
+ }
+ EnumDeclaration tagDecl = (EnumDeclaration) decl;
+ Set<String> intersection = new HashSet<>(tagDecl.getLabels());
+ intersection.retainAll(variantDeclaration.getFields().keySet());
+ if (intersection.isEmpty()) {
+ throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName); //$NON-NLS-1$
+ }
+ }
+
+ return variantDeclaration;
+ }
+
+}
import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
import org.eclipse.tracecompass.ctf.core.trace.ICTFStream;
import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration;
-import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException;
+import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException;
/**
* <b><u>Stream</u></b>
/**
* This test validates the CTF-Parser implementation.
*
- * The goal of these tests is to validate syntactic rules and not the
- * CTF semantic. Each test parses a string with a given rule of the
- * compiled parser and validates the resulting tree by using match rules.
+ * The goal of these tests is to validate syntactic rules and not the CTF
+ * semantic. Each test parses a string with a given rule of the compiled parser
+ * and validates the resulting tree by using match rules.
*
* @author Etienne Bergeron
*/
}
if (tree.getType() != fType) {
fail("Type mismatch!" +
- " expected:" + fType +
- " actual:" + tree.getType());
+ " expected:" + fType +
+ " actual:" + tree.getType());
}
if (fText != null) {
- if (tree.getText().compareTo(fText) != 0) {
+ if (!fText.equals(tree.getText())) {
fail("Text mismatch!" +
" expected:" + fText +
" actual:" + tree.getText());
} else {
if (tree.getChildren().size() != size) {
fail("Invalid number of childs!"
- + " expected:" + size
- + " actual:" + tree.getChildren().size());
+ + " expected:" + size
+ + " actual:" + tree.getChildren().size());
}
for (int i = 0; i < size; ++i) {
// Test cases
// ------------------------------------------------------------------------
-
/**
* Validate that parsing of an empty expression is invalid.
*/
@Test
public void testIntegerLiteralPrimaryExpression() {
Matches(Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "123")),
+ Node(CTFParser.DECIMAL_LITERAL, "123")),
primaryExpression("123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_HEX,
- Node(CTFParser.HEX_LITERAL, "0x123")),
+ Node(CTFParser.HEX_LITERAL, "0x123")),
primaryExpression("0x123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_OCT,
- Node(CTFParser.OCTAL_LITERAL, "0123")),
+ Node(CTFParser.OCTAL_LITERAL, "0123")),
primaryExpression("0123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "123"),
- Node(CTFParser.SIGN, "-")),
+ Node(CTFParser.DECIMAL_LITERAL, "123"),
+ Node(CTFParser.SIGN, "-")),
primaryExpression("-123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "123"),
- Node(CTFParser.SIGN, "-")),
+ Node(CTFParser.DECIMAL_LITERAL, "123"),
+ Node(CTFParser.SIGN, "-")),
primaryExpression(" - 123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "123"),
- Node(CTFParser.SIGN, "-"),
- Node(CTFParser.SIGN, "-"),
- Node(CTFParser.SIGN, "+")),
+ Node(CTFParser.DECIMAL_LITERAL, "123"),
+ Node(CTFParser.SIGN, "-"),
+ Node(CTFParser.SIGN, "-"),
+ Node(CTFParser.SIGN, "+")),
primaryExpression(" - - + 123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_HEX,
- Node(CTFParser.HEX_LITERAL, "0x123"),
- Node(CTFParser.SIGN, "+"),
- Node(CTFParser.SIGN, "-")),
+ Node(CTFParser.HEX_LITERAL, "0x123"),
+ Node(CTFParser.SIGN, "+"),
+ Node(CTFParser.SIGN, "-")),
primaryExpression("+ - 0x123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_OCT,
- Node(CTFParser.OCTAL_LITERAL, "0123"),
- Node(CTFParser.SIGN, "+"),
- Node(CTFParser.SIGN, "-")),
+ Node(CTFParser.OCTAL_LITERAL, "0123"),
+ Node(CTFParser.SIGN, "+"),
+ Node(CTFParser.SIGN, "-")),
primaryExpression("+ - 0123"));
}
@Test
public void testStringLiteralPrimaryExpression() {
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING_QUOTES,
- Node(CTFParser.STRING_LITERAL, "\"aaa\"")),
+ Node(CTFParser.STRING_LITERAL, "\"aaa\"")),
primaryExpression("\"aaa\""));
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING_QUOTES,
- Node(CTFParser.STRING_LITERAL, "L\"aaa\"")),
+ Node(CTFParser.STRING_LITERAL, "L\"aaa\"")),
primaryExpression("L\"aaa\""));
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING_QUOTES,
- Node(CTFParser.STRING_LITERAL, "\"aaa\\n\"")),
+ Node(CTFParser.STRING_LITERAL, "\"aaa\\n\"")),
primaryExpression("\"aaa\\n\""));
}
@Test
public void testKeywordPrimaryExpression() {
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.SIGNEDTOK, "signed")),
+ Node(CTFParser.SIGNEDTOK, "signed")),
primaryExpression("signed"));
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.ALIGNTOK, "align")),
+ Node(CTFParser.ALIGNTOK, "align")),
primaryExpression("align"));
}
@Test
public void testIdentifierPrimaryExpression() {
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.IDENTIFIER, "x")),
primaryExpression("x"));
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "_123")),
+ Node(CTFParser.IDENTIFIER, "_123")),
primaryExpression("_123"));
}
@Test
public void testSimpleUnaryExpression() {
Matches(Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "123")),
+ Node(CTFParser.DECIMAL_LITERAL, "123")),
unaryExpression("123"));
Matches(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.IDENTIFIER, "x")),
unaryExpression("x"));
}
@Test
public void testArrayUnaryExpression() {
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "1"))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "1"))),
unaryExpression("x[1]"));
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "n"))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "n"))),
unaryExpression("x[n]"));
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "n")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "1"))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "n")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "1"))),
unaryExpression("x[n][1]"));
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "n")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "1"),
- Node(CTFParser.SIGN, "+"))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "n")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "1"),
+ Node(CTFParser.SIGN, "+"))),
unaryExpression("x[n][+1]"));
}
public void testSpecialArrayUnaryExpression() {
// Added for CTF-v1.8
Matches(List(Node(CTFParser.TRACE),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "n"))),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "n"))),
unaryExpression("trace[n]"));
Matches(List(Node(CTFParser.CLOCK),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "n")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "1"))),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "n")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "1"))),
unaryExpression("clock[n][1]"));
}
@Test
public void testMemberUnaryExpression() {
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.DOT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "y")))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.DOT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "y")))),
unaryExpression("x.y"));
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.DOT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "y"))),
- Node(CTFParser.DOT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "z")))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.DOT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "y"))),
+ Node(CTFParser.DOT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "z")))),
unaryExpression("x.y.z"));
}
@Test
public void testPointerUnaryExpression() {
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.ARROW,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "y")))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.ARROW,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "y")))),
unaryExpression("x->y"));
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.ARROW,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "y"))),
- Node(CTFParser.ARROW,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "z")))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.ARROW,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "y"))),
+ Node(CTFParser.ARROW,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "z")))),
unaryExpression("x->y->z"));
}
@Test
public void testMixedUnaryExpression() {
Matches(List(Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "x")),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "2")),
- Node(CTFParser.ARROW,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "y"))),
- Node(CTFParser.DOT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "z"))),
- Node(CTFParser.OPENBRAC),
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "1"))),
+ Node(CTFParser.IDENTIFIER, "x")),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "2")),
+ Node(CTFParser.ARROW,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "y"))),
+ Node(CTFParser.DOT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "z"))),
+ Node(CTFParser.OPENBRAC),
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "1"))),
unaryExpression("x[2]->y.z[1]"));
}
@Test
public void testEnumDeclaration() {
Matches(Node(CTFParser.DECLARATION,
- Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.ENUM,
- Node(CTFParser.ENUM_NAME,
- Node(CTFParser.IDENTIFIER, "name")),
- Node(CTFParser.ENUM_BODY,
- Node(CTFParser.ENUM_ENUMERATOR,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "A"))))))),
+ Node(CTFParser.TYPE_SPECIFIER_LIST,
+ Node(CTFParser.ENUM,
+ Node(CTFParser.ENUM_NAME,
+ Node(CTFParser.IDENTIFIER, "name")),
+ Node(CTFParser.ENUM_BODY,
+ Node(CTFParser.ENUM_ENUMERATOR,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "A"))))))),
declaration("enum name { A };"));
Matches(Node(CTFParser.DECLARATION,
- Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.ENUM,
- Node(CTFParser.ENUM_NAME, All()),
- Node(CTFParser.ENUM_CONTAINER_TYPE,
- Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.INTTOK))),
- Node(CTFParser.ENUM_BODY, All())))),
+ Node(CTFParser.TYPE_SPECIFIER_LIST,
+ Node(CTFParser.ENUM,
+ Node(CTFParser.ENUM_NAME, All()),
+ Node(CTFParser.ENUM_CONTAINER_TYPE,
+ Node(CTFParser.TYPE_SPECIFIER_LIST,
+ Node(CTFParser.INTTOK))),
+ Node(CTFParser.ENUM_BODY, All())))),
declaration("enum name : int { A };"));
Matches(Node(CTFParser.DECLARATION,
Node(CTFParser.TYPE_SPECIFIER_LIST,
Node(CTFParser.ENUM,
- Node(CTFParser.ENUM_BODY, All())))),
+ Node(CTFParser.ENUM_BODY, All())))),
declaration("enum { A };"));
Matches(Node(CTFParser.DECLARATION,
Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.ENUM,
- Node(CTFParser.ENUM_CONTAINER_TYPE,
- Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.INTTOK))),
- Node(CTFParser.ENUM_BODY, All())))),
+ Node(CTFParser.ENUM,
+ Node(CTFParser.ENUM_CONTAINER_TYPE,
+ Node(CTFParser.TYPE_SPECIFIER_LIST,
+ Node(CTFParser.INTTOK))),
+ Node(CTFParser.ENUM_BODY, All())))),
declaration("enum : int { A };"));
}
declaration("enum { };"));
Matches(Node(CTFParser.DECLARATION,
- Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.ENUM,
- Node(CTFParser.ENUM_BODY,
- Node(CTFParser.ENUM_ENUMERATOR,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "A"))),
- Node(CTFParser.ENUM_ENUMERATOR,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "B")),
- Node(CTFParser.ENUM_VALUE,
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "2")))),
- Node(CTFParser.ENUM_ENUMERATOR,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "C")),
- Node(CTFParser.ENUM_VALUE_RANGE,
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "3")),
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "5")))))))),
+ Node(CTFParser.TYPE_SPECIFIER_LIST,
+ Node(CTFParser.ENUM,
+ Node(CTFParser.ENUM_BODY,
+ Node(CTFParser.ENUM_ENUMERATOR,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "A"))),
+ Node(CTFParser.ENUM_ENUMERATOR,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "B")),
+ Node(CTFParser.ENUM_VALUE,
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "2")))),
+ Node(CTFParser.ENUM_ENUMERATOR,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "C")),
+ Node(CTFParser.ENUM_VALUE_RANGE,
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "3")),
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "5")))))))),
declaration("enum { A, B=2, C=3...5 };"));
Matches(Node(CTFParser.DECLARATION,
- Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.ENUM,
- Node(CTFParser.ENUM_BODY,
- Node(CTFParser.ENUM_ENUMERATOR,
- Node(CTFParser.UNARY_EXPRESSION_STRING_QUOTES,
- Node(CTFParser.STRING_LITERAL, "\"A\""))),
- Node(CTFParser.ENUM_ENUMERATOR,
- Node(CTFParser.UNARY_EXPRESSION_STRING_QUOTES,
- Node(CTFParser.STRING_LITERAL, "\"B\"")),
- All()))))),
+ Node(CTFParser.TYPE_SPECIFIER_LIST,
+ Node(CTFParser.ENUM,
+ Node(CTFParser.ENUM_BODY,
+ Node(CTFParser.ENUM_ENUMERATOR,
+ Node(CTFParser.UNARY_EXPRESSION_STRING_QUOTES,
+ Node(CTFParser.STRING_LITERAL, "\"A\""))),
+ Node(CTFParser.ENUM_ENUMERATOR,
+ Node(CTFParser.UNARY_EXPRESSION_STRING_QUOTES,
+ Node(CTFParser.STRING_LITERAL, "\"B\"")),
+ All()))))),
declaration("enum { \"A\", \"B\"=2 };"));
}
@Ignore("The grammar need to be fixed to support empty ctf-body.")
@Test
public void testEmptyDeclaration() {
- /* TODO: An exception is throw when building an common tree without
- * assignments in the ctf-body.
+ /*
+ * TODO: An exception is throw when building an common tree without
+ * assignments in the ctf-body.
*/
Matches(All(),
declaration("env { };"));
@Test
public void testEnvDeclaration() {
Matches(Node(CTFParser.ENV,
- Node(CTFParser.CTF_EXPRESSION_VAL,
- Node(CTFParser.CTF_LEFT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "pid"))),
- Node(CTFParser.CTF_RIGHT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "value"))))),
+ Node(CTFParser.CTF_EXPRESSION_VAL,
+ Node(CTFParser.CTF_LEFT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "pid"))),
+ Node(CTFParser.CTF_RIGHT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "value"))))),
declaration("env { pid = value; };"));
Matches(Node(CTFParser.ENV,
- Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
- Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
- Node(CTFParser.CTF_EXPRESSION_VAL, All(), All())),
+ Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
+ Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
+ Node(CTFParser.CTF_EXPRESSION_VAL, All(), All())),
declaration("env { pid = value; proc_name = \"name\"; x = y;};"));
}
@Test
public void testTraceDeclaration() {
Matches(Node(CTFParser.TRACE,
- Node(CTFParser.CTF_EXPRESSION_VAL,
- Node(CTFParser.CTF_LEFT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "major"))),
- Node(CTFParser.CTF_RIGHT,
- Node(CTFParser.UNARY_EXPRESSION_DEC,
- Node(CTFParser.DECIMAL_LITERAL, "1"))))),
+ Node(CTFParser.CTF_EXPRESSION_VAL,
+ Node(CTFParser.CTF_LEFT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "major"))),
+ Node(CTFParser.CTF_RIGHT,
+ Node(CTFParser.UNARY_EXPRESSION_DEC,
+ Node(CTFParser.DECIMAL_LITERAL, "1"))))),
declaration("trace { major = 1; };"));
Matches(Node(CTFParser.TRACE,
- Node(CTFParser.CTF_EXPRESSION_TYPE,
- Node(CTFParser.CTF_LEFT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "packet")),
- Node(CTFParser.DOT,
- Node(CTFParser.UNARY_EXPRESSION_STRING,
- Node(CTFParser.IDENTIFIER, "header")))),
- Node(CTFParser.CTF_RIGHT,
- Node(CTFParser.TYPE_SPECIFIER_LIST,
- Node(CTFParser.STRUCT,
- Node(CTFParser.STRUCT_NAME,
- Node(CTFParser.IDENTIFIER, "dummy"))))))),
+ Node(CTFParser.CTF_EXPRESSION_TYPE,
+ Node(CTFParser.CTF_LEFT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "packet")),
+ Node(CTFParser.DOT,
+ Node(CTFParser.UNARY_EXPRESSION_STRING,
+ Node(CTFParser.IDENTIFIER, "header")))),
+ Node(CTFParser.CTF_RIGHT,
+ Node(CTFParser.TYPE_SPECIFIER_LIST,
+ Node(CTFParser.STRUCT,
+ Node(CTFParser.STRUCT_NAME,
+ Node(CTFParser.IDENTIFIER, "dummy"))))))),
declaration("trace { packet.header := struct dummy; };"));
/* TODO: This test crash the parser. */
Matches(Node(CTFParser.TRACE,
- All()),
+ All()),
declaration("trace { typedef x y; };"));
Matches(Node(CTFParser.TRACE,
- Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
- Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
- Node(CTFParser.CTF_EXPRESSION_TYPE, All(), All())),
+ Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
+ Node(CTFParser.CTF_EXPRESSION_VAL, All(), All()),
+ Node(CTFParser.CTF_EXPRESSION_TYPE, All(), All())),
declaration("trace { major = 1; minor = 1;"
- + "packet.header := struct dummy; };"));
+ + "packet.header := struct dummy; };"));
}
}
ERRORS.put("integer-encoding-invalid", "Invalid value for encoding");
ERRORS.put("integer-negative-bit-size", "Invalid value for size");
ERRORS.put("integer-range", "Invalid integer format: 23452397856348975623897562893746589237465289374658923764598237645897234658723648579236");
- ERRORS.put("integer-signed-as-string", "org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException");
+ ERRORS.put("integer-signed-as-string", "Invalid boolean value");
ERRORS.put("integer-signed-invalid", "Invalid boolean value svp");
ERRORS.put("integer-size-as-string", "Invalid value for size");
- ERRORS.put("integer-size-missing", "org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException");
+ ERRORS.put("integer-size-missing", "Invalid boolean value");
ERRORS.put("struct-align-enum", "Invalid value for alignment");
ERRORS.put("struct-align-huge", "Invalid integer format: 0xFFFFFFFFU");
ERRORS.put("struct-align-negative", "Invalid value for alignment : -8");