From b1ea73b5a2609e2cffa54e1ab5127c2c48e33719 Mon Sep 17 00:00:00 2001 From: Matthew Khouzam Date: Sat, 29 Aug 2015 15:53:47 -0400 Subject: [PATCH] ctf: split up IOStructGen into 44 files IOstructGen is a very large file, it is hard to test and maintain, this patch splits it into 42 files. This patch has several benefits. It does the following: * decreases the complexity of the file IOStructGen. * improves the modularity of the TSDL parser. * is very friendly to code navigators as the links of who calls who are more obvious. * improve testability of the parser. * improve navigability in code. * use a single pattern so each section is drop-in replaceable. * add null checks at strategic places. * ridiculously improve javadoc. * add null annotations * improve validation of data Performance is similar. Change-Id: Ie13ab1673d40b36087e7ce78d81b5379063ea3a1 Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/56740 Reviewed-by: Hudson CI Reviewed-by: Marc-Andre Laperle Tested-by: Marc-Andre Laperle --- .../annotations/java/lang/String.eea | 3 + .../annotations/java/util/List.eea | 4 + .../annotations/java/util/UUID.eea | 19 + .../org/antlr/runtime/tree/BaseTree.eea | 4 + .../org/antlr/runtime/tree/CommonTree.eea | 7 + .../ctf/core/tests/trace/CTFStreamTest.java | 2 +- .../ctf/core/tests/trace/CTFTraceTest.java | 11 +- .../META-INF/MANIFEST.MF | 12 +- .../core/event/metadata/DeclarationScope.java | 7 +- .../ctf/core/event/types/EnumDeclaration.java | 19 + .../tracecompass/ctf/core/trace/CTFTrace.java | 30 +- .../tracecompass/ctf/core/trace/Metadata.java | 29 +- .../AbstractScopedCommonTreeParser.java | 48 + .../{exceptions => }/CtfAntlrException.java | 4 +- .../event/metadata/ICommonTreeParser.java | 53 + .../ctf/core/event/metadata/IOStructGen.java | 2705 +---------------- .../ctf/core/event/metadata/Messages.java | 2 +- .../core/event/metadata/MetadataStrings.java | 2 +- .../{exceptions => }/ParseException.java | 4 +- .../core/event/metadata/messages.properties | 2 +- .../event/metadata/tsdl/AlignmentParser.java | 105 + .../event/metadata/tsdl/ByteOrderParser.java | 116 + .../core/event/metadata/tsdl/ClockParser.java | 156 + .../tsdl/PointerListStringParser.java | 58 + .../core/event/metadata/tsdl/SizeParser.java | 70 + .../core/event/metadata/tsdl/TsdlUtils.java | 125 + .../metadata/tsdl/TypeAliasAliasParser.java | 113 + .../event/metadata/tsdl/TypeAliasParser.java | 109 + .../metadata/tsdl/TypeAliasTargetParser.java | 147 + .../metadata/tsdl/TypeDeclarationParser.java | 99 + .../tsdl/TypeDeclarationStringParser.java | 81 + .../metadata/tsdl/TypeDeclaratorParser.java | 252 ++ .../tsdl/TypeSpecifierListNameParser.java | 124 + .../tsdl/TypeSpecifierListParser.java | 168 + .../tsdl/TypeSpecifierListStringParser.java | 66 + .../event/metadata/tsdl/TypedefParser.java | 113 + .../metadata/tsdl/UnaryIntegerParser.java | 66 + .../metadata/tsdl/UnaryStringParser.java | 67 + .../tsdl/enumeration/EnumBodyParser.java | 77 + .../tsdl/enumeration/EnumContainerParser.java | 99 + .../metadata/tsdl/enumeration/EnumParser.java | 262 ++ .../tsdl/enumeration/EnumeratorParser.java | 130 + .../tsdl/environment/EnvironmentParser.java | 50 + .../tsdl/event/EventDeclarationParser.java | 192 ++ .../metadata/tsdl/event/EventIDParser.java | 56 + .../metadata/tsdl/event/EventNameParser.java | 44 + .../metadata/tsdl/event/EventParser.java | 164 + .../metadata/tsdl/event/EventScopeParser.java | 151 + .../floatingpoint/FloatDeclarationParser.java | 180 ++ .../metadata/tsdl/integer/BaseParser.java | 87 + .../metadata/tsdl/integer/ClockMapParser.java | 40 + .../integer/IntegerDeclarationParser.java | 208 ++ .../metadata/tsdl/integer/SignedParser.java | 92 + .../tsdl/stream/StreamDeclarationParser.java | 257 ++ .../metadata/tsdl/stream/StreamIdParser.java | 56 + .../metadata/tsdl/stream/StreamParser.java | 127 + .../tsdl/stream/StreamScopeParser.java | 111 + .../metadata/tsdl/string/EncodingParser.java | 65 + .../tsdl/string/StringDeclarationParser.java | 119 + .../tsdl/struct/StructBodyParser.java | 159 + .../tsdl/struct/StructDeclarationParser.java | 127 + .../metadata/tsdl/struct/StructParser.java | 254 ++ .../tsdl/trace/TraceDeclarationParser.java | 303 ++ .../metadata/tsdl/trace/TraceScopeParser.java | 96 + .../event/metadata/tsdl/trace/UUIDParser.java | 72 + .../tsdl/trace/VersionNumberParser.java | 66 + .../tsdl/variant/VariantBodyParser.java | 126 + .../variant/VariantDeclarationParser.java | 128 + .../metadata/tsdl/variant/VariantParser.java | 350 +++ .../internal/ctf/core/trace/CTFStream.java | 2 +- .../ctf/parser/tests/CtfParserTest.java | 378 +-- .../ui/swtbot/tests/TestInvalidCtfTrace.java | 4 +- 72 files changed, 6737 insertions(+), 2897 deletions(-) create mode 100644 common/org.eclipse.tracecompass.common.core/annotations/java/util/List.eea create mode 100644 common/org.eclipse.tracecompass.common.core/annotations/java/util/UUID.eea create mode 100644 common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/BaseTree.eea create mode 100644 common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/CommonTree.eea create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/AbstractScopedCommonTreeParser.java rename ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/{exceptions => }/CtfAntlrException.java (98%) create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/ICommonTreeParser.java rename ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/{exceptions => }/ParseException.java (96%) create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ByteOrderParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/PointerListStringParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/SizeParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TsdlUtils.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasAliasParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasTargetParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationStringParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclaratorParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListNameParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListStringParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypedefParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryIntegerParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryStringParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumBodyParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumContainerParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumeratorParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/environment/EnvironmentParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventIDParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventNameParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventScopeParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/BaseParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/ClockMapParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/SignedParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamIdParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamScopeParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/EncodingParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructBodyParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceScopeParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/UUIDParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/VersionNumberParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantBodyParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantDeclarationParser.java create mode 100644 ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java diff --git a/common/org.eclipse.tracecompass.common.core/annotations/java/lang/String.eea b/common/org.eclipse.tracecompass.common.core/annotations/java/lang/String.eea index d08937251c..73b41b1f8a 100644 --- a/common/org.eclipse.tracecompass.common.core/annotations/java/lang/String.eea +++ b/common/org.eclipse.tracecompass.common.core/annotations/java/lang/String.eea @@ -20,6 +20,9 @@ split 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; diff --git a/common/org.eclipse.tracecompass.common.core/annotations/java/util/List.eea b/common/org.eclipse.tracecompass.common.core/annotations/java/util/List.eea new file mode 100644 index 0000000000..dd035af26a --- /dev/null +++ b/common/org.eclipse.tracecompass.common.core/annotations/java/util/List.eea @@ -0,0 +1,4 @@ +class java/util/List +subList + (II)Ljava/util/List; + (II)L1java/util/List; diff --git a/common/org.eclipse.tracecompass.common.core/annotations/java/util/UUID.eea b/common/org.eclipse.tracecompass.common.core/annotations/java/util/UUID.eea new file mode 100644 index 0000000000..116f7ffd10 --- /dev/null +++ b/common/org.eclipse.tracecompass.common.core/annotations/java/util/UUID.eea @@ -0,0 +1,19 @@ +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; diff --git a/common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/BaseTree.eea b/common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/BaseTree.eea new file mode 100644 index 0000000000..c3e0b19430 --- /dev/null +++ b/common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/BaseTree.eea @@ -0,0 +1,4 @@ +class org/antlr/runtime/tree/BaseTree +getFirstChildWithType + (I)Lorg/antlr/runtime/tree/Tree; + (I)L0org/antlr/runtime/tree/Tree; diff --git a/common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/CommonTree.eea b/common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/CommonTree.eea new file mode 100644 index 0000000000..279e458a3c --- /dev/null +++ b/common/org.eclipse.tracecompass.common.core/annotations/org/antlr/runtime/tree/CommonTree.eea @@ -0,0 +1,7 @@ +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 diff --git a/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFStreamTest.java b/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFStreamTest.java index 6c29917134..e9b3202eee 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFStreamTest.java +++ b/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFStreamTest.java @@ -26,7 +26,7 @@ import org.eclipse.tracecompass.ctf.core.tests.shared.CtfTestTraceUtils; 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; diff --git a/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFTraceTest.java b/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFTraceTest.java index fa9b59fe1b..8a4dfd2762 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFTraceTest.java +++ b/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/CTFTraceTest.java @@ -31,12 +31,14 @@ import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; 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 CTFTraceTest contains tests for the class * {@link CTFTrace}. @@ -370,10 +372,10 @@ public class CTFTraceTest { @Test public void testLookupEnvironment_3() { String key = "test"; - fixture.addEnvironmentVar(key, key); + fixture.setEnvironment(ImmutableMap. of(key, key)); String result = fixture.getEnvironment().get(key); assertNotNull(result); - assertTrue(result.equals(key)); + assertEquals(key, result); } /** @@ -382,8 +384,7 @@ public class CTFTraceTest { @Test public void testLookupEnvironment_4() { String key = "test"; - fixture.addEnvironmentVar(key, "bozo"); - fixture.addEnvironmentVar(key, "the clown"); + fixture.setEnvironment(ImmutableMap. of(key, "bozo")); String result = fixture.getEnvironment().get(key); assertNotNull(result); } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF b/ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF index 3163cac192..99dcd377ee 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF +++ b/ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF @@ -21,7 +21,17 @@ Export-Package: org.eclipse.tracecompass.ctf.core, 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" diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java index fb0deeb916..d0fe08fb9e 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java @@ -23,7 +23,7 @@ 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.event.types.VariantDeclaration; -import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; /** * DeclarationScope @@ -543,4 +543,9 @@ public class DeclarationScope { 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$ + } } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/EnumDeclaration.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/EnumDeclaration.java index 77238602f3..30155e142f 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/EnumDeclaration.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/EnumDeclaration.java @@ -161,6 +161,20 @@ public final class EnumDeclaration extends Declaration implements ISimpleDatatyp return fTable.add(low, high, label); } + /** + * Add a value. Do not overlap, this is not 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) @@ -208,6 +222,11 @@ public final class EnumDeclaration extends Declaration implements ISimpleDatatyp 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); diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFTrace.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFTrace.java index e44ad4a9f0..5053c34ded 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFTrace.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFTrace.java @@ -32,6 +32,7 @@ import java.util.Map; 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; @@ -48,10 +49,12 @@ import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; 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. * @@ -125,7 +128,7 @@ public class CTFTrace implements IDefinitionScope { /** * Collection of environment variables set by the tracer */ - private final Map fEnvironment = new HashMap<>(); + private Map fEnvironment = new HashMap<>(); /** * Collection of all the clocks in a system. @@ -632,18 +635,6 @@ public class CTFTrace implements IDefinitionScope { 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 * @@ -847,6 +838,17 @@ public class CTFTrace implements IDefinitionScope { public StructDefinition getPacketHeaderDef() { return fPacketHeaderDef; } + + /** + * Sets the environment map + * + * @param parseEnvironment + * The environment map + * @since 2.0 + */ + public void setEnvironment(@NonNull Map parseEnvironment) { + fEnvironment = ImmutableMap.copyOf(parseEnvironment); + } } class MetadataFileFilter implements FileFilter { diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java index 3f054defd1..df4e97c591 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java @@ -37,13 +37,14 @@ import org.antlr.runtime.CommonTokenStream; 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; /** @@ -154,10 +155,7 @@ public class Metadata { 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); @@ -190,10 +188,14 @@ public class Metadata { } /** - * 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: + *
    + *
  • For text-only metadata, the file starts with "/* CTF" (without the + * quotes)
  • + *
  • For packet-based metadata, the file starts with correct magic number + *
  • + *
* * @param path * path to CTF trace directory @@ -257,7 +259,7 @@ public class Metadata { 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(); @@ -377,7 +379,7 @@ public class Metadata { */ 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); @@ -513,8 +515,9 @@ public class Metadata { /** * 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 diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/AbstractScopedCommonTreeParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/AbstractScopedCommonTreeParser.java new file mode 100644 index 0000000000..90b754b408 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/AbstractScopedCommonTreeParser.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * 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); + } + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/exceptions/CtfAntlrException.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/CtfAntlrException.java similarity index 98% rename from ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/exceptions/CtfAntlrException.java rename to ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/CtfAntlrException.java index bc0d85d789..101aa41fd5 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/exceptions/CtfAntlrException.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/CtfAntlrException.java @@ -1,5 +1,5 @@ /******************************************************************************* - * 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 @@ -11,7 +11,7 @@ * Matthew Khouzam - Addition to have more descriptive errors *******************************************************************************/ -package org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions; +package org.eclipse.tracecompass.internal.ctf.core.event.metadata; import java.lang.reflect.Field; diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/ICommonTreeParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/ICommonTreeParser.java new file mode 100644 index 0000000000..ba46d7f20a --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/ICommonTreeParser.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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; + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java index bd7c26dc3b..839bcd55a1 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java @@ -14,48 +14,24 @@ 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; @@ -69,31 +45,16 @@ public class IOStructGen { // 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 @@ -113,11 +74,10 @@ public class IOStructGen { * @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()); } /** @@ -170,7 +130,6 @@ public class IOStructGen { CommonTree traceNode = null; boolean hasStreams = false; List events = new ArrayList<>(); - resetScope(); for (CommonTree child : children) { final int type = child.getType(); switch (type) { @@ -185,17 +144,19 @@ public class IOStructGen { 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); @@ -205,7 +166,6 @@ public class IOStructGen { throw new ParseException("Missing trace block"); //$NON-NLS-1$ } parseEvents(events, hasStreams); - popScope(); fHasBeenParsed = true; } @@ -215,7 +175,7 @@ public class IOStructGen { fTrace.addStream(new CTFStream(fTrace)); } for (CommonTree event : events) { - parseEvent(event); + EventParser.INSTANCE.parse(event, new EventParser.Param(fTrace, fRoot)); } } @@ -225,7 +185,6 @@ public class IOStructGen { } List children = root.getChildren(); List events = new ArrayList<>(); - resetScope(); for (CommonTree child : children) { final int type = child.getType(); switch (type) { @@ -235,98 +194,45 @@ public class IOStructGen { 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 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 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 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); @@ -342,512 +248,6 @@ public class IOStructGen { } } - 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 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 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 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 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 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 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. * @@ -863,13 +263,13 @@ public class IOStructGen { 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); @@ -878,2042 +278,21 @@ public class IOStructGen { } /** - * 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 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 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 children = alias.getChildren(); - - CommonTree typeSpecifierList = null; - CommonTree typeDeclaratorList = null; - CommonTree typeDeclarator = null; - List 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 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 parseTypedef(CommonTree typedef) throws ParseException { - - CommonTree typeDeclaratorListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST); - - CommonTree typeSpecifierListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST); - - List typeDeclaratorList = typeDeclaratorListNode.getChildren(); - - Map 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 children = null; - List pointers = new LinkedList<>(); - List 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 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 lengthChildren) throws ParseException { - List 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 variantDeclarations = variantBody.getChildren(); - - pushNamedScope(variantName, MetadataStrings.VARIANT); - - for (CommonTree declarationNode : variantDeclarations) { - switch (declarationNode.getType()) { - case CTFParser.TYPEALIAS: - parseTypealias(declarationNode); - break; - case CTFParser.TYPEDEF: - Map decs = parseTypedef(declarationNode); - for (Entry 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 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 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 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 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 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 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; - } - } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/Messages.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/Messages.java index 7473266a55..55c4751a78 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/Messages.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * 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 diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/MetadataStrings.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/MetadataStrings.java index a74e2b6e69..d2ad2c0886 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/MetadataStrings.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/MetadataStrings.java @@ -1,5 +1,5 @@ /******************************************************************************* - * 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 diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/exceptions/ParseException.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/ParseException.java similarity index 96% rename from ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/exceptions/ParseException.java rename to ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/ParseException.java index 28edd0200b..c76c418b5c 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/exceptions/ParseException.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/ParseException.java @@ -1,5 +1,5 @@ /******************************************************************************* - * 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 @@ -10,7 +10,7 @@ * Contributors: Simon Marchi - Initial API and implementation *******************************************************************************/ -package org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions; +package org.eclipse.tracecompass.internal.ctf.core.event.metadata; /** diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/messages.properties b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/messages.properties index 6037ccb3f8..36e70c80f8 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/messages.properties +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# 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 diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java new file mode 100644 index 0000000000..3e57d110f5 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * 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)); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ByteOrderParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ByteOrderParser.java new file mode 100644 index 0000000000..82c4e83f38 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ByteOrderParser.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * 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: + * + *
+ * /* network and be are aliases * /
+ * byte_order= /* native OR network OR be OR le * /;
+ * 
+ * + * 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); + } +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java new file mode 100644 index 0000000000..8b4ff61977 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * 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. + *

+ * 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.: + * + *

+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;
+};
+ * 
+ * + * 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. + *

+ * Secondly, a reference to this clock should be added within an integer type: + * + *

+typealias integer {
+    size = 64; align = 1; signed = false;
+    map = clock.cycle_counter_sync.value;
+} := uint64_ccnt_t;
+ * 
+ * + * Thirdly, stream declarations can reference the clock they use as a timestamp + * source: + * + *
+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;
+};
+ * 
+ * + * 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. + *

+ * 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 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; + + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/PointerListStringParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/PointerListStringParser.java new file mode 100644 index 0000000000..228a72121d --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/PointerListStringParser.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * 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 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; + } +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/SizeParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/SizeParser.java new file mode 100644 index 0000000000..46434f8ea6 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/SizeParser.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * 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: + * + *

+ * size = /* value is in bits * /
+ * 
+ * + * @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); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TsdlUtils.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TsdlUtils.java new file mode 100644 index 0000000000..2ad93b227e --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TsdlUtils.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * 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 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); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasAliasParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasAliasParser.java new file mode 100644 index 0000000000..1a19d7f472 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasAliasParser.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * 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 integer{ blabla } part, and the target is the + * int 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 children = typeSpecifier.getChildren(); + + CommonTree typeSpecifierList = null; + CommonTree typeDeclaratorList = null; + CommonTree typeDeclarator = null; + List 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 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)); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java new file mode 100644 index 0000000000..959a36d3e2 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasTargetParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasTargetParser.java new file mode 100644 index 0000000000..348b94de25 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasTargetParser.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * 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 + * integer{ blabla } part, and the target is the int 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationParser.java new file mode 100644 index 0000000000..99ae771005 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationParser.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * 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 fPointerList; + + /** + * Constructor + * + * @param pointerList + * the list of pointers + * @param scope + * the current scope + */ + public Param(@Nullable List 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationStringParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationStringParser.java new file mode 100644 index 0000000000..8541559299 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclarationStringParser.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * 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 fList; + + /** + * Constructor + * + * @param list + * List of trees + */ + public Param(List 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 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(); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclaratorParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclaratorParser.java new file mode 100644 index 0000000000..aaecf668b1 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeDeclaratorParser.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * 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 children = null; + List<@NonNull CommonTree> pointers = new LinkedList<>(); + List 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListNameParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListNameParser.java new file mode 100644 index 0000000000..8e03a01bf7 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListNameParser.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * 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); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListParser.java new file mode 100644 index 0000000000..06a294bd06 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListParser.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * 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 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 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; + } +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListStringParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListStringParser.java new file mode 100644 index 0000000000..84e70aab43 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeSpecifierListStringParser.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypedefParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypedefParser.java new file mode 100644 index 0000000000..121868417a --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypedefParser.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * 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 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 typeDeclaratorList = typeDeclaratorListNode.getChildren(); + + Map 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryIntegerParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryIntegerParser.java new file mode 100644 index 0000000000..f367937085 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryIntegerParser.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryStringParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryStringParser.java new file mode 100644 index 0000000000..0eb8aafa1c --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryStringParser.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumBodyParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumBodyParser.java new file mode 100644 index 0000000000..e8b90446a9 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumBodyParser.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumContainerParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumContainerParser.java new file mode 100644 index 0000000000..9b41de98ca --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumContainerParser.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * 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$ + + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumParser.java new file mode 100644 index 0000000000..17ac03a51a --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumParser.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * 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.
+ * + *
+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,
+    //...
+}
+ * 
+ * + * 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: + * + *
+enum name : unsigned int {
+ ZERO,
+ ONE,
+ TWO,
+ TEN = 10,
+ ELEVEN,
+}
+ * 
+ * + * Overlapping ranges within a single enumeration are implementation defined. + *
+ * A nameless enumeration can be declared as a field type or as part of a + * `typedef`: + * + *
+enum : integer_type {
+ // ...
+}
+ * 
+ * + * Enumerations omitting the container type`:integer_type`use the`int`type(for + * compatibility with C99).The`int`type _must be_ previously declared,e.g.: + * + *
+ * typealias integer{size=32;align=32;signed=true;}:=int;
+
+enum{
+// ...
+}
+ * 
+ * + * @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 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; + + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumeratorParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumeratorParser.java new file mode 100644 index 0000000000..077ae29b9a --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumeratorParser.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/environment/EnvironmentParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/environment/EnvironmentParser.java new file mode 100644 index 0000000000..25269f56fa --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/environment/EnvironmentParser.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * 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 parse(CommonTree environment, ICommonTreeParserParameter param) { + + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + List 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(); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java new file mode 100644 index 0000000000..5ca4031eda --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * 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 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; + } +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventIDParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventIDParser.java new file mode 100644 index 0000000000..45c6ae2b47 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventIDParser.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventNameParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventNameParser.java new file mode 100644 index 0000000000..e209e354c5 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventNameParser.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * 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$ + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java new file mode 100644 index 0000000000..999f3c47a6 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * 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. + *

+ * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventScopeParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventScopeParser.java new file mode 100644 index 0000000000..97b72ea679 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventScopeParser.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * 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. + *

+ * A dynamic scope consists in the static scope augmented with the implicit + * event structure definition hierarchy. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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 + * . This allows, for instance, the event + * context to define a variant referring to the id field of the event header as + * selector. + *

+ * The dynamic scope prefixes are thus: + *

    + *
  • Trace environment:
  • + *
  • Trace packet header:
  • + *
  • Stream packet context:
  • + *
  • Event header:
  • + *
  • Stream event context:
  • + *
  • Event context:
  • + *
  • Event payload:
  • + *
+ *

+ * 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. + *

+ * 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 fList; + + /** + * Constructor + * + * @param list + * parameter list + */ + public Param(List 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 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java new file mode 100644 index 0000000000..0650c9c7e5 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * 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. + *

+ * 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: + *

    + *
  • FLT_RADIX must be 2.
  • + *
  • 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 .
  • + *
  • 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:
  • + *
      + *
    • sizeof(float) * CHAR_BIT - FLT_MANT_DIG
    • + *
    • sizeof(double) * CHAR_BIT - DBL_MANT_DIG
    • + *
    • sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG
    • + *
    • + *
    + *
+ * + * @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 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 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); + + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/BaseParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/BaseParser.java new file mode 100644 index 0000000000..44fa1bc29d --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/BaseParser.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * 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); + } + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/ClockMapParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/ClockMapParser.java new file mode 100644 index 0000000000..87d3fea326 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/ClockMapParser.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java new file mode 100644 index 0000000000..cc78c664f2 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * 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: + *
    + *
  • On little and big endian: Within a byte, high bits correspond to an + * integer high bits, and low bits correspond to low bits
  • + *
  • 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)
  • + *
  • 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)
  • + *
+ * + * 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 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 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; + } +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/SignedParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/SignedParser.java new file mode 100644 index 0000000000..973b77044a --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/SignedParser.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamDeclarationParser.java new file mode 100644 index 0000000000..75d2609f01 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamDeclarationParser.java @@ -0,0 +1,257 @@ +/******************************************************************************* + * 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 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 event stream header will therefore be referred to as the + * event packet header throughout the rest of this document.
+ * + * 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).
+ * The stream header is repeated at the beginning of each event packet to allow + * flexibility in terms of: + *
    + *
  • streaming support
  • + *
  • allowing arbitrary buffers to be discarded without making the trace + * unreadable
  • + *
  • allow UDP packet loss handling by either dealing with missing event + * packet or asking for re-transmission
  • + *
  • transparently support flight recorder mode
  • + *
  • transparently support crash dump
  • + *
+ * + * @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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamIdParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamIdParser.java new file mode 100644 index 0000000000..b10807caae --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamIdParser.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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; + +/** + * Stream ID, 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$ + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamParser.java new file mode 100644 index 0000000000..7c2deedd34 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamParser.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamScopeParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamScopeParser.java new file mode 100644 index 0000000000..4d5b80a1ec --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/stream/StreamScopeParser.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * 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 fList; + + /** + * Constructor + * + * @param list + * a list of commonTrees to parse + */ + public Param(List 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/EncodingParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/EncodingParser.java new file mode 100644 index 0000000000..00e2bd1837 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/EncodingParser.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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); + + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java new file mode 100644 index 0000000000..76a576616b --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * 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: + * + *
+ * typealias string {
+ *   encoding = /* UTF8 OR ASCII * /;
+ * } := name;
+ * 
+ * + * A nameless string type can be declared as a field type: + * + *
+ * string field_name; /* use default UTF8 encoding * /
+ * 
+ * + * 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 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructBodyParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructBodyParser.java new file mode 100644 index 0000000000..7074de29c4 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructBodyParser.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * 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: + *
    + *
  • align
  • + *
  • callsite
  • + *
  • const
  • + *
  • char
  • + *
  • clock
  • + *
  • double
  • + *
  • enum
  • + *
  • env
  • + *
  • event
  • + *
  • floating_point
  • + *
  • float
  • + *
  • integer
  • + *
  • int
  • + *
  • long
  • + *
  • short
  • + *
  • signed
  • + *
  • stream
  • + *
  • string
  • + *
  • struct
  • + *
  • trace
  • + *
  • typealias
  • + *
  • typedef
  • + *
  • unsigned
  • + *
  • variant
  • + *
  • void
  • + *
  • _Bool
  • + *
  • _Complex
  • + *
  • _Imaginary
  • + *
+ * + * @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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java new file mode 100644 index 0000000000..557966935a --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java new file mode 100644 index 0000000000..37dbb4f23b --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * 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)
+ * TSDL metadata representation of a named structure: + * + *
+struct name {
+    field_type field_name;
+    field_type field_name;
+    // ...
+};
+ * 
+ * + * Example: + * + *
+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
+};
+ * 
+ * + * 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 recommended + * . Fields starting with an underscore should have their leading underscore + * removed by the CTF trace readers.
+ * A nameless structure can be declared as a field type or as part of a + * `typedef`: + * + *
+struct {
+    // ...
+}
+ *
+ * 
+ * + * 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. + * + *
+struct {
+    // ...
+} align(32)
+}
+ * 
+ * + * @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 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); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceDeclarationParser.java new file mode 100644 index 0000000000..3c75cd530e --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceDeclarationParser.java @@ -0,0 +1,303 @@ +/******************************************************************************* + * 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 trace is divided into multiple event streams. Each event stream + * contains a subset of the trace event types.
+ * 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.
+ * Metadata description associated with the trace contains information on trace + * event types expressed in the _Trace Stream Description Language_ (TSDL). This + * language describes:
+ *
    + *
  • Trace version
  • + *
  • Types available
  • + *
  • Per-trace event header description
  • + *
  • Per-stream event header description
  • + *
  • Per-stream event context description
  • + *
  • Per-event + *
      + *
    • Event type to stream mapping
    • + *
    • Event type to name mapping
    • + *
    • Event type to ID mapping
    • + *
    • Event context description
    • + *
    • Event fields description
    • + *
    + *
+ * + * @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 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 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); + } + } + } +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceScopeParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceScopeParser.java new file mode 100644 index 0000000000..5e2784d823 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/TraceScopeParser.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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 fList; + + /** + * Parameter object constructor + * + * @param list + * the list of subtrees + */ + public Param(List 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$ + } + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/UUIDParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/UUIDParser.java new file mode 100644 index 0000000000..e7566be5cb --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/UUIDParser.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * 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; + +/** + * Trace UUID, 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); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/VersionNumberParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/VersionNumberParser.java new file mode 100644 index 0000000000..29353333b4 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/trace/VersionNumberParser.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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); + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantBodyParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantBodyParser.java new file mode 100644 index 0000000000..da14fec219 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantBodyParser.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * 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 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 decs = TypedefParser.INSTANCE.parse(declarationNode, new TypedefParser.Param(trace, scope)); + for (Entry 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantDeclarationParser.java new file mode 100644 index 0000000000..985699db26 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantDeclarationParser.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java new file mode 100644 index 0000000000..964ac7cfe9 --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java @@ -0,0 +1,350 @@ +/******************************************************************************* + * 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.
+ * 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.
+ * 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.
+ * 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.
+ * A named variant declaration followed by its definition within a structure + * declaration:
+ * + *
+variant name {
+    field_type sel1;
+    field_type sel2;
+    field_type sel3;
+    // ...
+};
+
+struct {
+    enum : integer_type { sel1, sel2, sel3, more } tag_field;
+    // ...
+    variant name  v;
+}
+ * 
+ * + * An unnamed variant definition within a structure is expressed by the + * following TSDL metadata:
+ * + *
+struct {
+    enum : integer_type { sel1, sel2, sel3, more } tag_field;
+    // ...
+    variant  {
+        field_type sel1;
+        field_type sel2;
+        field_type sel3;
+        // ...
+    } v;
+}
+ * 
+ * + * Example of a named variant within a sequence that refers to a single tag + * field:
+ * + *
+variant example {
+    uint32_t a;
+    uint64_t b;
+    short c;
+};
+
+struct {
+    enum : uint2_t { a, b, c } choice;
+    unsigned int seqlen;
+    variant example  v[seqlen];
+}
+ * 
+ * + * Example of an unnamed variant:
+ * + *
+struct {
+    enum : uint2_t { a, b, c, d } choice;
+
+    // Unrelated fields can be added between the variant and its tag
+    int32_t somevalue;
+    variant  {
+        uint32_t a;
+        uint64_t b;
+        short c;
+        struct {
+            unsigned int field1;
+            uint64_t field2;
+        } d;
+    } s;
+}
+ * 
+ * + * Example of an unnamed variant within an array:
+ * + *
+struct {
+    enum : uint2_t { a, b, c } choice;
+    variant  {
+        uint32_t a;
+        uint64_t b;
+        short c;
+    } v[10];
+}
+ * 
+ * + *
+ * 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.
+ * + *
+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  {
+      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];
+}
+ * 
+ * + * @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 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 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; + } + +} diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/trace/CTFStream.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/trace/CTFStream.java index b434e4cdbb..663dae05e8 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/trace/CTFStream.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/trace/CTFStream.java @@ -30,7 +30,7 @@ import org.eclipse.tracecompass.ctf.core.trace.CTFStreamInput; 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; /** * Stream diff --git a/ctf/org.eclipse.tracecompass.ctf.parser.tests/src/org/eclipse/tracecompass/ctf/parser/tests/CtfParserTest.java b/ctf/org.eclipse.tracecompass.ctf.parser.tests/src/org/eclipse/tracecompass/ctf/parser/tests/CtfParserTest.java index ea46b6551f..84de7488b0 100644 --- a/ctf/org.eclipse.tracecompass.ctf.parser.tests/src/org/eclipse/tracecompass/ctf/parser/tests/CtfParserTest.java +++ b/ctf/org.eclipse.tracecompass.ctf.parser.tests/src/org/eclipse/tracecompass/ctf/parser/tests/CtfParserTest.java @@ -28,9 +28,9 @@ import org.junit.Test; /** * 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 */ @@ -63,12 +63,12 @@ public class CtfParserTest { } 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()); @@ -85,8 +85,8 @@ public class CtfParserTest { } 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) { @@ -162,7 +162,6 @@ public class CtfParserTest { // Test cases // ------------------------------------------------------------------------ - /** * Validate that parsing of an empty expression is invalid. */ @@ -178,44 +177,44 @@ public class CtfParserTest { @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")); } @@ -237,15 +236,15 @@ public class CtfParserTest { @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\"")); } @@ -255,10 +254,10 @@ public class CtfParserTest { @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")); } @@ -268,10 +267,10 @@ public class CtfParserTest { @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")); } @@ -290,11 +289,11 @@ public class CtfParserTest { @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")); } @@ -304,38 +303,38 @@ public class CtfParserTest { @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]")); } @@ -346,18 +345,18 @@ public class CtfParserTest { 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]")); } @@ -367,20 +366,20 @@ public class CtfParserTest { @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")); } @@ -390,20 +389,20 @@ public class CtfParserTest { @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")); } @@ -413,19 +412,19 @@ public class CtfParserTest { @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]")); } @@ -481,39 +480,39 @@ public class CtfParserTest { @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 };")); } @@ -528,39 +527,39 @@ public class CtfParserTest { 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 };")); } @@ -570,8 +569,9 @@ public class CtfParserTest { @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 { };")); @@ -589,19 +589,19 @@ public class CtfParserTest { @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;};")); } @@ -612,41 +612,41 @@ public class CtfParserTest { @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; };")); } } diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java b/ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java index bd75d10239..5f4701b56c 100644 --- a/ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java +++ b/ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java @@ -80,10 +80,10 @@ public class TestInvalidCtfTrace { 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"); -- 2.34.1