Commit | Line | Data |
---|---|---|
b1ea73b5 MK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2015 Ericsson | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials | |
5 | * are made available under the terms of the Eclipse Public License v1.0 | |
6 | * which accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | *******************************************************************************/ | |
9 | package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl; | |
10 | ||
11 | import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.childTypeError; | |
12 | import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings; | |
13 | import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString; | |
14 | import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isUnaryInteger; | |
15 | ||
16 | import java.util.Collections; | |
17 | import java.util.LinkedList; | |
18 | import java.util.List; | |
19 | ||
20 | import org.antlr.runtime.tree.CommonTree; | |
21 | import org.eclipse.jdt.annotation.NonNull; | |
22 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
23 | import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope; | |
24 | import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; | |
25 | import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration; | |
26 | import org.eclipse.tracecompass.ctf.core.trace.CTFTrace; | |
27 | import org.eclipse.tracecompass.ctf.parser.CTFParser; | |
28 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser; | |
29 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; | |
30 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.event.EventScopeParser; | |
31 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.stream.StreamScopeParser; | |
32 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace.TraceScopeParser; | |
33 | import org.eclipse.tracecompass.internal.ctf.core.event.types.ArrayDeclaration; | |
34 | import org.eclipse.tracecompass.internal.ctf.core.event.types.SequenceDeclaration; | |
35 | ||
36 | /** | |
37 | * A type declarator parser | |
38 | * | |
39 | * @author Matthew Khouzam | |
40 | * | |
41 | */ | |
4055c3a1 | 42 | public final class TypeDeclaratorParser extends AbstractScopedCommonTreeParser { |
b1ea73b5 MK |
43 | |
44 | /** | |
45 | * The parameter object for type declarator parsers | |
46 | * | |
47 | * @author Matthew Khouzam | |
48 | * | |
49 | */ | |
50 | @NonNullByDefault | |
51 | public static final class Param implements ICommonTreeParserParameter { | |
52 | private final DeclarationScope fDeclarationScope; | |
53 | private final CommonTree fListNode; | |
54 | private final StringBuilder fBuilder; | |
55 | private final CTFTrace fTrace; | |
56 | ||
57 | /** | |
58 | * Parameter constructor | |
59 | * | |
60 | * @param trace | |
61 | * the trace | |
62 | * @param listNode | |
63 | * the listNode | |
64 | * @param scope | |
65 | * the scope | |
66 | * @param builder | |
67 | * the string builder to populate | |
68 | */ | |
69 | public Param(CTFTrace trace, CommonTree listNode, DeclarationScope scope, StringBuilder builder) { | |
70 | fTrace = trace; | |
71 | fListNode = listNode; | |
72 | fDeclarationScope = scope; | |
73 | fBuilder = builder; | |
74 | } | |
75 | } | |
76 | ||
77 | /** | |
78 | * The instance | |
79 | */ | |
5c50e284 | 80 | public static final TypeDeclaratorParser INSTANCE = new TypeDeclaratorParser(); |
b1ea73b5 MK |
81 | |
82 | private TypeDeclaratorParser() { | |
83 | } | |
84 | ||
85 | /** | |
86 | * Parses a pair type declarator / type specifier list and returns the | |
87 | * corresponding declaration. If it is present, it also writes the | |
88 | * identifier of the declarator in the given {@link StringBuilder}. | |
89 | * | |
90 | * @param typeDeclarator | |
91 | * A TYPE_DECLARATOR node. | |
92 | * @param param | |
93 | * the parameter object | |
94 | * @return The corresponding declaration. | |
95 | * @throws ParseException | |
96 | * If there is an error finding or creating the declaration. | |
97 | */ | |
98 | @Override | |
99 | public IDeclaration parse(CommonTree typeDeclarator, ICommonTreeParserParameter param) throws ParseException { | |
100 | if (!(param instanceof Param)) { | |
101 | throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$ | |
102 | } | |
103 | DeclarationScope scope = ((Param) param).fDeclarationScope; | |
104 | CTFTrace trace = ((Param) param).fTrace; | |
105 | CommonTree typeSpecifierList = ((Param) param).fListNode; | |
106 | ||
107 | IDeclaration declaration = null; | |
108 | List<CommonTree> children = null; | |
109 | List<@NonNull CommonTree> pointers = new LinkedList<>(); | |
110 | List<CommonTree> lengths = new LinkedList<>(); | |
111 | CommonTree identifier = null; | |
112 | ||
113 | /* Separate the tokens by type */ | |
114 | if (typeDeclarator != null) { | |
115 | children = typeDeclarator.getChildren(); | |
116 | for (CommonTree child : children) { | |
117 | ||
118 | switch (child.getType()) { | |
119 | case CTFParser.POINTER: | |
120 | pointers.add(child); | |
121 | break; | |
122 | case CTFParser.IDENTIFIER: | |
123 | identifier = child; | |
124 | break; | |
125 | case CTFParser.LENGTH: | |
126 | lengths.add(child); | |
127 | break; | |
128 | default: | |
129 | throw childTypeError(child); | |
130 | } | |
131 | } | |
132 | ||
133 | } | |
134 | ||
135 | /* | |
136 | * Parse the type specifier list, which is the "base" type. For example, | |
137 | * it would be int in int a[3][len]. | |
138 | */ | |
139 | declaration = TypeSpecifierListParser.INSTANCE.parse(typeSpecifierList, new TypeSpecifierListParser.Param(trace, pointers, identifier, scope)); | |
140 | ||
141 | /* | |
142 | * Each length subscript means that we must create a nested array or | |
143 | * sequence. For example, int a[3][len] means that we have an array of 3 | |
144 | * (sequences of length 'len' of (int)). | |
145 | */ | |
146 | if (!lengths.isEmpty()) { | |
147 | /* We begin at the end */ | |
148 | Collections.reverse(lengths); | |
149 | ||
150 | for (CommonTree length : lengths) { | |
151 | /* | |
152 | * By looking at the first expression, we can determine whether | |
153 | * it is an array or a sequence. | |
154 | */ | |
155 | List<CommonTree> lengthChildren = length.getChildren(); | |
156 | ||
157 | CommonTree first = lengthChildren.get(0); | |
158 | if (isUnaryInteger(first)) { | |
159 | /* Array */ | |
160 | int arrayLength = UnaryIntegerParser.INSTANCE.parse(first, null).intValue(); | |
161 | ||
162 | if (arrayLength < 1) { | |
163 | throw new ParseException("Array length is negative"); //$NON-NLS-1$ | |
164 | } | |
165 | ||
166 | /* Create the array declaration. */ | |
167 | declaration = new ArrayDeclaration(arrayLength, declaration); | |
168 | } else if (isAnyUnaryString(first)) { | |
169 | /* Sequence */ | |
170 | String lengthName = concatenateUnaryStrings(lengthChildren); | |
171 | ||
172 | /* check that lengthName was declared */ | |
173 | if (isSignedIntegerField(lengthName, scope)) { | |
174 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
175 | } | |
176 | /* Create the sequence declaration. */ | |
177 | declaration = new SequenceDeclaration(lengthName, | |
178 | declaration); | |
179 | } else if (isTrace(first)) { | |
180 | /* Sequence */ | |
181 | String lengthName = TraceScopeParser.INSTANCE.parse(null, new TraceScopeParser.Param(lengthChildren)); | |
182 | ||
183 | /* check that lengthName was declared */ | |
184 | if (isSignedIntegerField(lengthName, scope)) { | |
185 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
186 | } | |
187 | /* Create the sequence declaration. */ | |
188 | declaration = new SequenceDeclaration(lengthName, | |
189 | declaration); | |
190 | ||
191 | } else if (isStream(first)) { | |
192 | /* Sequence */ | |
193 | String lengthName = StreamScopeParser.INSTANCE.parse(null, new StreamScopeParser.Param(lengthChildren)); | |
194 | ||
195 | /* check that lengthName was declared */ | |
196 | if (isSignedIntegerField(lengthName, scope)) { | |
197 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
198 | } | |
199 | /* Create the sequence declaration. */ | |
200 | declaration = new SequenceDeclaration(lengthName, | |
201 | declaration); | |
202 | } else if (isEvent(first)) { | |
203 | /* Sequence */ | |
204 | String lengthName = EventScopeParser.INSTANCE.parse(null, new EventScopeParser.Param(lengthChildren)); | |
205 | ||
206 | /* check that lengthName was declared */ | |
207 | if (isSignedIntegerField(lengthName, scope)) { | |
208 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
209 | } | |
210 | /* Create the sequence declaration. */ | |
211 | declaration = new SequenceDeclaration(lengthName, | |
212 | declaration); | |
213 | } else { | |
214 | throw childTypeError(first); | |
215 | } | |
216 | } | |
217 | } | |
218 | ||
219 | if (identifier != null) { | |
220 | final String text = identifier.getText(); | |
221 | if (text == null) { | |
222 | throw new ParseException("Cannot have unidentified declarator"); //$NON-NLS-1$ | |
223 | } | |
224 | ((Param) param).fBuilder.append(text); | |
225 | registerType(declaration, text, scope); | |
226 | } | |
227 | ||
228 | return declaration; | |
229 | } | |
230 | ||
231 | private static boolean isSignedIntegerField(String lengthName, DeclarationScope scope) throws ParseException { | |
232 | IDeclaration decl = scope.lookupIdentifierRecursive(lengthName); | |
233 | if (decl instanceof IntegerDeclaration) { | |
234 | return ((IntegerDeclaration) decl).isSigned(); | |
235 | } | |
236 | throw new ParseException("Is not an integer: " + lengthName); //$NON-NLS-1$ | |
237 | ||
238 | } | |
239 | ||
240 | private static boolean isEvent(CommonTree first) { | |
241 | return first.getType() == CTFParser.EVENT; | |
242 | } | |
243 | ||
244 | private static boolean isStream(CommonTree first) { | |
245 | return first.getType() == CTFParser.STREAM; | |
246 | } | |
247 | ||
248 | private static boolean isTrace(CommonTree first) { | |
249 | return first.getType() == CTFParser.TRACE; | |
250 | } | |
251 | ||
252 | } |