Commit | Line | Data |
---|---|---|
866e5b51 | 1 | /******************************************************************************* |
3ba65808 | 2 | * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others |
866e5b51 FC |
3 | * |
4 | * All rights reserved. This program and the accompanying materials are made | |
5 | * available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
4311ac8b MAL |
9 | * Contributors: |
10 | * Matthew Khouzam - Initial Design and Grammar | |
11 | * Francis Giraldeau - Initial API and implementation | |
12 | * Simon Marchi - Initial API and implementation | |
866e5b51 FC |
13 | *******************************************************************************/ |
14 | ||
f357bcd4 | 15 | package org.eclipse.tracecompass.internal.ctf.core.event.metadata; |
866e5b51 | 16 | |
866e5b51 | 17 | import java.util.ArrayList; |
d45d05a1 | 18 | import java.util.Collection; |
866e5b51 | 19 | import java.util.List; |
d45d05a1 | 20 | import java.util.stream.Collectors; |
866e5b51 FC |
21 | |
22 | import org.antlr.runtime.tree.CommonTree; | |
a4fa4e36 | 23 | import org.eclipse.jdt.annotation.NonNull; |
b1ea73b5 | 24 | import org.eclipse.tracecompass.common.core.NonNullUtils; |
d45d05a1 | 25 | import org.eclipse.tracecompass.ctf.core.event.CTFCallsite; |
f357bcd4 | 26 | import org.eclipse.tracecompass.ctf.core.event.CTFClock; |
c8891db9 | 27 | import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope; |
f357bcd4 AM |
28 | import org.eclipse.tracecompass.ctf.core.trace.CTFTrace; |
29 | import org.eclipse.tracecompass.ctf.parser.CTFParser; | |
d45d05a1 | 30 | import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration; |
b1ea73b5 MK |
31 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.ClockParser; |
32 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeAliasParser; | |
33 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser; | |
34 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypedefParser; | |
d45d05a1 | 35 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.callsite.CallSiteParser; |
b1ea73b5 MK |
36 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.environment.EnvironmentParser; |
37 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event.EventParser; | |
38 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream.StreamParser; | |
39 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace.TraceDeclarationParser; | |
8aa463e0 | 40 | import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream; |
866e5b51 | 41 | |
52f81ef7 MK |
42 | import com.google.common.collect.Iterables; |
43 | ||
866e5b51 | 44 | /** |
251274dd | 45 | * IOStructGen |
866e5b51 | 46 | */ |
866e5b51 FC |
47 | public class IOStructGen { |
48 | ||
49 | // ------------------------------------------------------------------------ | |
50 | // Attributes | |
51 | // ------------------------------------------------------------------------ | |
52 | ||
866e5b51 FC |
53 | /** |
54 | * The trace | |
55 | */ | |
b1ea73b5 | 56 | private final @NonNull CTFTrace fTrace; |
9226cfc5 | 57 | private CommonTree fTree; |
866e5b51 FC |
58 | |
59 | /** | |
60 | * The current declaration scope. | |
61 | */ | |
b1ea73b5 | 62 | private final @NonNull DeclarationScope fRoot; |
866e5b51 | 63 | |
58129ff7 MK |
64 | /** |
65 | * Data helpers needed for streaming | |
66 | */ | |
67 | ||
68 | private boolean fHasBeenParsed = false; | |
69 | ||
866e5b51 FC |
70 | // ------------------------------------------------------------------------ |
71 | // Constructor | |
72 | // ------------------------------------------------------------------------ | |
73 | ||
9ac2eb62 | 74 | /** |
ecb12461 | 75 | * Constructor |
be6df2d8 AM |
76 | * |
77 | * @param tree | |
78 | * the tree (ANTLR generated) with the parsed TSDL data. | |
79 | * @param trace | |
80 | * the trace containing the places to put all the read metadata | |
9ac2eb62 | 81 | */ |
b1ea73b5 | 82 | public IOStructGen(CommonTree tree, @NonNull CTFTrace trace) { |
9226cfc5 MK |
83 | fTrace = trace; |
84 | fTree = tree; | |
b1ea73b5 | 85 | fRoot = NonNullUtils.checkNotNull(trace.getScope()); |
866e5b51 FC |
86 | } |
87 | ||
9ac2eb62 MK |
88 | /** |
89 | * Parse the tree and populate the trace defined in the constructor. | |
be6df2d8 | 90 | * |
9ac2eb62 | 91 | * @throws ParseException |
be6df2d8 | 92 | * If there was a problem parsing the metadata |
9ac2eb62 | 93 | */ |
866e5b51 | 94 | public void generate() throws ParseException { |
9226cfc5 | 95 | parseRoot(fTree); |
866e5b51 FC |
96 | } |
97 | ||
58129ff7 MK |
98 | /** |
99 | * Parse a partial tree and populate the trace defined in the constructor. | |
100 | * Does not check for a "trace" block as there is only one in the trace and | |
101 | * thus | |
102 | * | |
103 | * @throws ParseException | |
104 | * If there was a problem parsing the metadata | |
105 | */ | |
106 | public void generateFragment() throws ParseException { | |
9226cfc5 | 107 | parseIncompleteRoot(fTree); |
58129ff7 MK |
108 | } |
109 | ||
866e5b51 FC |
110 | // ------------------------------------------------------------------------ |
111 | // Operations | |
112 | // ------------------------------------------------------------------------ | |
113 | ||
58129ff7 MK |
114 | /** |
115 | * Sets a new tree to parse | |
116 | * | |
117 | * @param newTree | |
118 | * the new tree to parse | |
119 | */ | |
120 | public void setTree(CommonTree newTree) { | |
9226cfc5 | 121 | fTree = newTree; |
58129ff7 MK |
122 | } |
123 | ||
866e5b51 FC |
124 | /** |
125 | * Parse the root node. | |
126 | * | |
127 | * @param root | |
128 | * A ROOT node. | |
129 | * @throws ParseException | |
130 | */ | |
131 | private void parseRoot(CommonTree root) throws ParseException { | |
866e5b51 FC |
132 | |
133 | List<CommonTree> children = root.getChildren(); | |
866e5b51 FC |
134 | |
135 | CommonTree traceNode = null; | |
52f81ef7 | 136 | boolean hasStreams = false; |
3de23137 | 137 | List<CommonTree> events = new ArrayList<>(); |
d45d05a1 | 138 | Collection<CTFCallsite> callsites = new ArrayList<>(); |
466f6d95 MK |
139 | for (CommonTree child : children) { |
140 | final int type = child.getType(); | |
141 | switch (type) { | |
142 | case CTFParser.DECLARATION: | |
52f81ef7 | 143 | parseRootDeclaration(child); |
466f6d95 MK |
144 | break; |
145 | case CTFParser.TRACE: | |
146 | if (traceNode != null) { | |
147 | throw new ParseException("Only one trace block is allowed"); //$NON-NLS-1$ | |
866e5b51 | 148 | } |
466f6d95 | 149 | traceNode = child; |
52f81ef7 | 150 | parseTrace(traceNode); |
466f6d95 MK |
151 | break; |
152 | case CTFParser.STREAM: | |
b1ea73b5 | 153 | StreamParser.INSTANCE.parse(child, new StreamParser.Param(fTrace, fRoot)); |
52f81ef7 | 154 | hasStreams = true; |
466f6d95 MK |
155 | break; |
156 | case CTFParser.EVENT: | |
157 | events.add(child); | |
158 | break; | |
159 | case CTFParser.CLOCK: | |
b1ea73b5 MK |
160 | CTFClock ctfClock = ClockParser.INSTANCE.parse(child, null); |
161 | String nameValue = ctfClock.getName(); | |
162 | fTrace.addClock(nameValue, ctfClock); | |
466f6d95 MK |
163 | break; |
164 | case CTFParser.ENV: | |
b1ea73b5 | 165 | fTrace.setEnvironment(EnvironmentParser.INSTANCE.parse(child, null)); |
466f6d95 | 166 | break; |
d45d05a1 MK |
167 | case CTFParser.CALLSITE: |
168 | callsites.add(CallSiteParser.INSTANCE.parse(child, null)); | |
169 | break; | |
466f6d95 | 170 | default: |
4ed7d9c1 | 171 | throw childTypeError(child); |
866e5b51 | 172 | } |
466f6d95 | 173 | } |
466f6d95 MK |
174 | if (traceNode == null) { |
175 | throw new ParseException("Missing trace block"); //$NON-NLS-1$ | |
176 | } | |
d45d05a1 | 177 | parseEvents(events, callsites, hasStreams); |
52f81ef7 MK |
178 | fHasBeenParsed = true; |
179 | } | |
866e5b51 | 180 | |
d45d05a1 | 181 | private void parseEvents(List<CommonTree> events, Collection<CTFCallsite> staticCallsites, boolean hasStreams) throws ParseException { |
52f81ef7 | 182 | if (!hasStreams && !events.isEmpty()) { |
466f6d95 MK |
183 | /* Add an empty stream that will have a null id */ |
184 | fTrace.addStream(new CTFStream(fTrace)); | |
185 | } | |
466f6d95 | 186 | for (CommonTree event : events) { |
d45d05a1 MK |
187 | EventDeclaration ev = EventParser.INSTANCE.parse(event, new EventParser.Param(fTrace, fRoot)); |
188 | List<CTFCallsite> callsites = staticCallsites.stream().filter(cs -> ev.getName().equals(cs.getEventName())).collect(Collectors.toList()); | |
189 | ev.addCallsites(callsites); | |
190 | ||
866e5b51 | 191 | } |
58129ff7 MK |
192 | } |
193 | ||
194 | private void parseIncompleteRoot(CommonTree root) throws ParseException { | |
466f6d95 | 195 | if (!fHasBeenParsed) { |
58129ff7 MK |
196 | throw new ParseException("You need to run generate first"); //$NON-NLS-1$ |
197 | } | |
52f81ef7 | 198 | List<CommonTree> children = root.getChildren(); |
58129ff7 | 199 | List<CommonTree> events = new ArrayList<>(); |
d45d05a1 | 200 | Collection<CTFCallsite> callsites = new ArrayList<>(); |
58129ff7 MK |
201 | for (CommonTree child : children) { |
202 | final int type = child.getType(); | |
203 | switch (type) { | |
204 | case CTFParser.DECLARATION: | |
52f81ef7 | 205 | parseRootDeclaration(child); |
58129ff7 MK |
206 | break; |
207 | case CTFParser.TRACE: | |
208 | throw new ParseException("Trace block defined here, please use generate and not generateFragment to parse this fragment"); //$NON-NLS-1$ | |
209 | case CTFParser.STREAM: | |
b1ea73b5 | 210 | StreamParser.INSTANCE.parse(child, new StreamParser.Param(fTrace, fRoot)); |
58129ff7 MK |
211 | break; |
212 | case CTFParser.EVENT: | |
213 | events.add(child); | |
214 | break; | |
215 | case CTFParser.CLOCK: | |
b1ea73b5 MK |
216 | CTFClock ctfClock = ClockParser.INSTANCE.parse(child, null); |
217 | String nameValue = ctfClock.getName(); | |
218 | fTrace.addClock(nameValue, ctfClock); | |
58129ff7 MK |
219 | break; |
220 | case CTFParser.ENV: | |
b1ea73b5 | 221 | fTrace.setEnvironment(EnvironmentParser.INSTANCE.parse(child, null)); |
58129ff7 | 222 | break; |
d45d05a1 MK |
223 | case CTFParser.CALLSITE: |
224 | callsites.add(CallSiteParser.INSTANCE.parse(child, null)); | |
225 | break; | |
58129ff7 | 226 | default: |
4ed7d9c1 | 227 | throw childTypeError(child); |
58129ff7 MK |
228 | } |
229 | } | |
d45d05a1 | 230 | parseEvents(events, callsites, !Iterables.isEmpty(fTrace.getStreams())); |
866e5b51 FC |
231 | } |
232 | ||
233 | private void parseTrace(CommonTree traceNode) throws ParseException { | |
866e5b51 | 234 | |
b1ea73b5 | 235 | CTFTrace trace = fTrace; |
866e5b51 FC |
236 | List<CommonTree> children = traceNode.getChildren(); |
237 | if (children == null) { | |
238 | throw new ParseException("Trace block is empty"); //$NON-NLS-1$ | |
239 | } | |
240 | ||
866e5b51 FC |
241 | for (CommonTree child : children) { |
242 | switch (child.getType()) { | |
243 | case CTFParser.TYPEALIAS: | |
b1ea73b5 | 244 | TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(trace, fRoot)); |
866e5b51 FC |
245 | break; |
246 | case CTFParser.TYPEDEF: | |
b1ea73b5 | 247 | TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(trace, fRoot)); |
866e5b51 FC |
248 | break; |
249 | case CTFParser.CTF_EXPRESSION_TYPE: | |
250 | case CTFParser.CTF_EXPRESSION_VAL: | |
b1ea73b5 | 251 | TraceDeclarationParser.INSTANCE.parse(child, new TraceDeclarationParser.Param(fTrace, fRoot)); |
866e5b51 FC |
252 | break; |
253 | default: | |
4ed7d9c1 | 254 | throw childTypeError(child); |
866e5b51 FC |
255 | } |
256 | } | |
257 | ||
258 | /* | |
259 | * If trace byte order was not specified and not using packet based | |
260 | * metadata | |
261 | */ | |
9226cfc5 | 262 | if (fTrace.getByteOrder() == null) { |
866e5b51 FC |
263 | throw new ParseException("Trace byte order not set"); //$NON-NLS-1$ |
264 | } | |
866e5b51 FC |
265 | } |
266 | ||
866e5b51 FC |
267 | /** |
268 | * Parses a declaration at the root level. | |
269 | * | |
270 | * @param declaration | |
271 | * The declaration subtree. | |
272 | * @throws ParseException | |
273 | */ | |
274 | private void parseRootDeclaration(CommonTree declaration) | |
275 | throws ParseException { | |
866e5b51 FC |
276 | |
277 | List<CommonTree> children = declaration.getChildren(); | |
866e5b51 FC |
278 | |
279 | for (CommonTree child : children) { | |
280 | switch (child.getType()) { | |
281 | case CTFParser.TYPEDEF: | |
b1ea73b5 | 282 | TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(fTrace, fRoot)); |
866e5b51 FC |
283 | break; |
284 | case CTFParser.TYPEALIAS: | |
b1ea73b5 | 285 | TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(fTrace, fRoot)); |
866e5b51 FC |
286 | break; |
287 | case CTFParser.TYPE_SPECIFIER_LIST: | |
b1ea73b5 | 288 | TypeSpecifierListParser.INSTANCE.parse(child, new TypeSpecifierListParser.Param(fTrace, null, null, fRoot)); |
866e5b51 FC |
289 | break; |
290 | default: | |
4ed7d9c1 | 291 | throw childTypeError(child); |
866e5b51 FC |
292 | } |
293 | } | |
294 | } | |
295 | ||
296 | /** | |
b1ea73b5 MK |
297 | * Throws a ParseException stating that the parent-child relation between |
298 | * the given node and its parent is not valid. It means that the shape of | |
299 | * the AST is unexpected. | |
866e5b51 | 300 | * |
b1ea73b5 MK |
301 | * @param child |
302 | * The invalid child node. | |
303 | * @return ParseException with details | |
866e5b51 | 304 | */ |
b1ea73b5 MK |
305 | private static ParseException childTypeError(CommonTree child) { |
306 | CommonTree parent = (CommonTree) child.getParent(); | |
307 | String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$ | |
308 | + " can't have a child of type " //$NON-NLS-1$ | |
309 | + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$ | |
866e5b51 | 310 | |
4ed7d9c1 | 311 | return new ParseException(error); |
866e5b51 FC |
312 | } |
313 | ||
866e5b51 | 314 | } |