Commit | Line | Data |
---|---|---|
7329404e BB |
1 | /****************************************************************************** |
2 | * Copyright (c) 2000-2016 Ericsson Telecom AB | |
3 | * All rights reserved. This program and the accompanying materials | |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
7 | * | |
8 | * Contributors: | |
9 | * | |
10 | * Baranyi, Botond – initial implementation | |
11 | * | |
12 | ******************************************************************************/ | |
13 | ||
14 | #include "DebuggerStuff.hh" | |
15 | #include "AST.hh" | |
16 | #include "Type.hh" | |
17 | #include "ttcn3/AST_ttcn3.hh" | |
18 | #include "ttcn3/ArrayDimensions.hh" | |
19 | ||
20 | namespace Common { | |
21 | ||
22 | /** Returns a string, that contains the template parameters of the debugger's | |
23 | * port array or timer array printing function. | |
24 | * | |
25 | * Recursive (handles one array dimension per call). | |
26 | * | |
27 | * @param p_dims the array's dimensions | |
28 | * @param p_element_type name of the array's element C++ class | |
29 | * @param p_array_type name of the array's C++ class ("PORT_ARRAY" or "TIMER_ARRAY") | |
30 | * @param index the index of the currently handled dimension in \a p_dims | |
31 | */ | |
32 | string function_params_for_array_dims(Ttcn::ArrayDimensions* p_dims, | |
33 | string p_element_type, | |
34 | string p_array_type, | |
35 | size_t index = 0) | |
36 | { | |
37 | if (index == p_dims->get_nof_dims()) { | |
38 | return p_element_type; | |
39 | } | |
40 | string ret_val; | |
41 | if (index != 0) { | |
42 | ret_val = p_array_type + string("<"); | |
43 | } | |
44 | ret_val += function_params_for_array_dims(p_dims, p_element_type, p_array_type, index + 1); | |
45 | Ttcn::ArrayDimension* dim = p_dims->get_dim_byIndex(index); | |
46 | ret_val += string(", ") + Int2string(dim->get_size()) + | |
47 | string(", ") + Int2string(dim->get_offset()); | |
48 | if (index != 0) { | |
49 | ret_val += string(">"); | |
50 | } | |
51 | return ret_val; | |
52 | } | |
53 | ||
54 | /** Returns a string, that contains the template parameters of the debugger's | |
55 | * value array or template array printing function. | |
56 | * | |
57 | * Recursive (handles one array dimension per call). | |
58 | * | |
59 | * @param p_type the current type (either an array or the array element) | |
60 | * @param p_scope the current scope | |
61 | * @param p_templ indicates whether it's a template array or value array | |
62 | * @param p_first indicates whether this is the first call or a recursive call | |
63 | */ | |
64 | string function_params_for_array_type(Type* p_type, | |
65 | Scope* p_scope, | |
66 | bool p_templ, | |
67 | bool p_first = true) | |
68 | { | |
69 | string ret_val; | |
70 | if (p_type->get_typetype() != Type::T_ARRAY) { | |
71 | ret_val = p_type->get_genname_value(p_scope); | |
72 | if (p_templ) { | |
73 | ret_val += "_template"; | |
74 | } | |
75 | } | |
76 | else { | |
77 | if (!p_first) { | |
78 | if (p_templ) { | |
79 | ret_val = "TEMPLATE_ARRAY<"; | |
80 | } | |
81 | else { | |
82 | ret_val = "VALUE_ARRAY<"; | |
83 | } | |
84 | } | |
85 | Type* elem_type = p_type->get_ofType()->get_type_refd_last(); | |
86 | if (p_templ) { | |
87 | ret_val += function_params_for_array_type(elem_type, p_scope, false, false) + | |
88 | ", " + function_params_for_array_type(elem_type, p_scope, true, false); | |
89 | } | |
90 | else { | |
91 | ret_val += function_params_for_array_type(elem_type, p_scope, false, false); | |
92 | } | |
93 | Ttcn::ArrayDimension* dim = p_type->get_dimension(); | |
94 | ret_val += string(", ") + Int2string(dim->get_size()) + | |
95 | string(", ") + Int2string(dim->get_offset()); | |
96 | if (!p_first) { | |
97 | ret_val += string(">"); | |
98 | } | |
99 | } | |
100 | return ret_val; | |
101 | } | |
102 | ||
103 | /** Appends the string representations of the specified array dimensions. */ | |
104 | string array_dimensions_to_string(Ttcn::ArrayDimensions* p_dims) | |
105 | { | |
106 | string ret_val; | |
107 | for (size_t i = 0; i < p_dims->get_nof_dims(); ++i) { | |
108 | ret_val += p_dims->get_dim_byIndex(i)->get_stringRepr(); | |
109 | } | |
110 | return ret_val; | |
111 | } | |
112 | ||
113 | void calculate_type_name_and_print_function_from_type(Type* p_type, | |
114 | Type* p_type_last, | |
115 | Module* p_module, | |
116 | string& p_type_name, | |
117 | string& p_print_function) | |
118 | { | |
119 | if (p_type_last->get_typetype() == Type::T_COMPONENT) { | |
120 | p_type_name = "component"; | |
121 | } | |
122 | else if (p_type_last->is_structured_type() || | |
123 | p_type_last->get_typetype() == Type::T_ENUM_A || | |
124 | p_type_last->get_typetype() == Type::T_ENUM_T || | |
125 | p_type_last->get_typetype() == Type::T_PORT || | |
126 | p_type_last->get_typetype() == Type::T_SIGNATURE || | |
127 | p_type_last->get_typetype() == Type::T_FUNCTION || | |
128 | p_type_last->get_typetype() == Type::T_ALTSTEP || | |
129 | p_type_last->get_typetype() == Type::T_TESTCASE) { | |
130 | // user-defined type | |
131 | if (p_type_last->is_pard_type_instance()) { | |
132 | // if the referenced type is an instance of an ASN.1 parameterized type, | |
133 | // then use the last non-parameterized type in the reference chain to | |
134 | // calculate the type name | |
135 | Type* t = p_type; | |
136 | while (t->is_ref() && !t->is_pard_type_instance()) { | |
137 | p_type_name = t->get_dispname(); | |
138 | t = t->get_type_refd(); | |
139 | } | |
140 | } | |
141 | else { | |
142 | p_type_name = p_type_last->get_dispname(); | |
143 | } | |
144 | const Module* var_type_mod = p_type_last->get_my_scope()->get_scope_mod(); | |
145 | if (var_type_mod != p_module) { | |
146 | p_print_function = var_type_mod->get_modid().get_name() + "::"; | |
147 | } | |
148 | else { | |
149 | p_print_function.clear(); | |
150 | } | |
151 | p_print_function += "print_var_" + var_type_mod->get_modid().get_ttcnname(); | |
152 | } | |
153 | else { | |
154 | // built-in type, get the TTCN-3 version of the type if possible | |
155 | switch (p_type_last->get_typetype()) { | |
156 | case Type::T_GENERALSTRING: | |
157 | case Type::T_GRAPHICSTRING: | |
158 | case Type::T_TELETEXSTRING: | |
159 | case Type::T_VIDEOTEXSTRING: | |
160 | // these ASN.1 string types are not converted right by Type::get_typetype_ttcn3() | |
161 | p_type_name = "universal charstring"; | |
162 | break; | |
163 | case Type::T_UNRESTRICTEDSTRING: | |
164 | case Type::T_EMBEDDED_PDV: | |
165 | case Type::T_EXTERNAL: | |
166 | // these are converted to T_SEQ_T by Type::get_typetype_ttcn3() | |
167 | p_type_name = Type::get_typename_builtin(p_type_last->get_typetype()); | |
168 | break; | |
169 | default: | |
170 | p_type_name = Type::get_typename_builtin(p_type_last->get_typetype_ttcn3()); | |
171 | break; | |
172 | } | |
173 | } | |
174 | } | |
175 | ||
176 | char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, | |
177 | Module* current_mod /* = NULL */, | |
178 | const char* scope_name /* = NULL */) | |
179 | { | |
180 | if (current_mod == NULL) { | |
181 | current_mod = var_ass->get_my_scope()->get_scope_mod(); | |
182 | } | |
183 | ||
184 | bool is_lazy_param = false; | |
185 | switch (var_ass->get_asstype()) { | |
186 | case Common::Assignment::A_PAR_VAL: | |
187 | case Common::Assignment::A_PAR_VAL_IN: | |
188 | case Common::Assignment::A_PAR_TEMPL_IN: | |
189 | if (var_ass->get_lazy_eval()) { | |
190 | // lazy parameters have their own printing function | |
191 | is_lazy_param = true; | |
192 | } | |
193 | break; | |
194 | default: | |
195 | break; | |
196 | } | |
197 | ||
198 | // recreate the TTCN-3 version of the type name and determine the type's printing function | |
199 | string type_name, print_function; | |
200 | print_function = is_lazy_param ? "TTCN3_Debugger::print_lazy_param<" : | |
201 | "TTCN3_Debugger::print_base_var"; | |
202 | if (var_ass->get_asstype() == Common::Assignment::A_TIMER || | |
203 | var_ass->get_asstype() == Common::Assignment::A_PAR_TIMER) { | |
204 | type_name = "timer"; | |
205 | if (var_ass->get_Dimensions() != NULL) { | |
206 | // timer array | |
207 | type_name += array_dimensions_to_string(var_ass->get_Dimensions()); | |
208 | print_function = string("TTCN3_Debugger::print_timer_array<") + | |
209 | function_params_for_array_dims(var_ass->get_Dimensions(), | |
210 | string("TIMER"), string("TIMER_ARRAY")) + | |
211 | string(">"); | |
212 | } | |
213 | } | |
214 | else { | |
215 | Common::Type* var_type = var_ass->get_Type(); | |
216 | // get the type at the end of the reference chain, but don't go through | |
217 | // CHARACTER STRINGs, EMBEDDED PDVs and EXTERNALs | |
218 | while (var_type->is_ref() && var_type->get_typetype() != Type::T_EXTERNAL && | |
219 | var_type->get_typetype() != Type::T_EMBEDDED_PDV && | |
220 | var_type->get_typetype() != Type::T_UNRESTRICTEDSTRING) { | |
221 | var_type = var_type->get_type_refd(); | |
222 | } | |
223 | if (is_lazy_param) { | |
224 | print_function += var_type->get_genname_value(current_mod); | |
225 | } | |
226 | if (var_type->get_typetype() == Type::T_PORT && var_ass->get_Dimensions() != NULL) { | |
227 | // port array | |
228 | type_name = var_type->get_dispname() + | |
229 | array_dimensions_to_string(var_ass->get_Dimensions()); | |
230 | if (!is_lazy_param) { | |
231 | print_function = string("TTCN3_Debugger::print_port_array<") + | |
232 | function_params_for_array_dims(var_ass->get_Dimensions(), | |
233 | var_type->get_genname_value(current_mod), | |
234 | string("PORT_ARRAY")) + | |
235 | string(">"); | |
236 | } | |
237 | } | |
238 | else if (var_type->get_typetype() == Type::T_ARRAY) { | |
239 | string dims_str; | |
240 | Type* t = var_type; | |
241 | while (t->get_typetype() == Type::T_ARRAY) { | |
242 | dims_str += t->get_dimension()->get_stringRepr(); | |
243 | t = t->get_ofType()->get_type_refd_last(); | |
244 | } | |
245 | string dummy; | |
246 | calculate_type_name_and_print_function_from_type(t, t, current_mod, type_name, dummy); | |
247 | type_name += dims_str; | |
248 | if (!is_lazy_param) { | |
249 | switch (var_ass->get_asstype()) { | |
250 | case Common::Assignment::A_MODULEPAR_TEMP: | |
251 | case Common::Assignment::A_TEMPLATE: | |
252 | case Common::Assignment::A_VAR_TEMPLATE: | |
253 | case Common::Assignment::A_PAR_TEMPL_IN: | |
254 | case Common::Assignment::A_PAR_TEMPL_OUT: | |
255 | case Common::Assignment::A_PAR_TEMPL_INOUT: | |
256 | // template array | |
257 | print_function = string("TTCN3_Debugger::print_template_array<") + | |
258 | function_params_for_array_type(var_type, current_mod, true) + | |
259 | string(">"); | |
260 | break; | |
261 | default: | |
262 | // value array | |
263 | print_function = string("TTCN3_Debugger::print_value_array<") + | |
264 | function_params_for_array_type(var_type, current_mod, false) + | |
265 | string(">"); | |
266 | break; | |
267 | } | |
268 | } | |
269 | } | |
270 | else { | |
271 | string dummy; | |
272 | calculate_type_name_and_print_function_from_type(var_ass->get_Type(), | |
273 | var_type, current_mod, type_name, is_lazy_param ? dummy : print_function); | |
274 | } | |
275 | } | |
276 | ||
277 | switch (var_ass->get_asstype()) { | |
278 | case Common::Assignment::A_MODULEPAR_TEMP: | |
279 | case Common::Assignment::A_TEMPLATE: | |
280 | case Common::Assignment::A_VAR_TEMPLATE: | |
281 | case Common::Assignment::A_PAR_TEMPL_IN: | |
282 | case Common::Assignment::A_PAR_TEMPL_OUT: | |
283 | case Common::Assignment::A_PAR_TEMPL_INOUT: | |
284 | // add a suffix, if it's a template | |
285 | type_name += " template"; | |
286 | if (is_lazy_param) { | |
287 | print_function += "_template"; | |
288 | } | |
289 | break; | |
290 | default: | |
291 | break; | |
292 | } | |
293 | ||
294 | if (is_lazy_param) { | |
295 | print_function += ">"; | |
296 | } | |
297 | ||
298 | return mputprintf(str, "%s%s_scope%sadd_variable(&%s, \"%s\", \"%s\", %s);\n", | |
299 | scope_name != NULL ? " " : "", // add indenting for global variables | |
300 | scope_name != NULL ? scope_name : "debug", // the prefix of the debugger scope: | |
301 | // ("global" for global variables, "debug" for local variables, | |
302 | // or the component name for component variables) | |
303 | scope_name != NULL ? "->" : ".", // global scopes are pointers, local scopes | |
304 | // are local variables | |
305 | var_ass->get_genname_from_scope(current_mod, "").c_str(), // variable name in C++ | |
306 | // (HACK: an empty string is passed as the prefix parameter to get_genname_from_scope, | |
307 | // so the lazy parameter evaluation code is not generated) | |
308 | var_ass->get_id().get_ttcnname().c_str(), // variable name in TTCN-3 | |
309 | type_name.c_str(), // variable type in TTCN-3, with a suffix if it's a template | |
310 | print_function.c_str()); // variable printing function | |
311 | } | |
312 | ||
313 | char* generate_code_debugger_function_init(char* str, Common::Assignment* func_ass) | |
314 | { | |
315 | string comp_str = func_ass->get_RunsOnType() == NULL ? string("NULL") : | |
316 | string("\"") + func_ass->get_RunsOnType()->get_dispname() + string("\""); | |
317 | const char* func_type_str = NULL; | |
318 | switch (func_ass->get_asstype()) { | |
319 | case Common::Assignment::A_FUNCTION: | |
320 | case Common::Assignment::A_FUNCTION_RVAL: | |
321 | case Common::Assignment::A_FUNCTION_RTEMP: | |
322 | func_type_str = "function"; | |
323 | break; | |
324 | case Common::Assignment::A_EXT_FUNCTION: | |
325 | case Common::Assignment::A_EXT_FUNCTION_RVAL: | |
326 | case Common::Assignment::A_EXT_FUNCTION_RTEMP: | |
327 | func_type_str = "external function"; | |
328 | break; | |
329 | case Common::Assignment::A_TESTCASE: | |
330 | func_type_str = "testcase"; | |
331 | break; | |
332 | case Common::Assignment::A_ALTSTEP: | |
333 | func_type_str = "altstep"; | |
334 | break; | |
335 | case Common::Assignment::A_TEMPLATE: // parameterized template | |
336 | func_type_str = "template"; | |
337 | break; | |
338 | default: | |
339 | break; | |
340 | } | |
341 | Ttcn::FormalParList* fp_list = func_ass != NULL ? func_ass->get_FormalParList() : NULL; | |
342 | if (fp_list != NULL && fp_list->get_nof_fps() != 0) { | |
343 | // has parameters | |
344 | char* fp_names_str = NULL; | |
345 | char* fp_types_str = NULL; | |
346 | char* fp_add_var_str = NULL; | |
347 | for (size_t i = 0; i < fp_list->get_nof_fps(); ++i) { | |
348 | // gather everything needed for this parameter in sub-strings | |
349 | Ttcn::FormalPar* fp = fp_list->get_fp_byIndex(i); | |
350 | const char* fp_type_str = NULL; | |
351 | switch (fp->get_asstype()) { | |
352 | case Common::Assignment::A_PAR_VAL: | |
353 | case Common::Assignment::A_PAR_VAL_IN: | |
354 | case Common::Assignment::A_PAR_TEMPL_IN: | |
355 | fp_type_str = "in"; | |
356 | break; | |
357 | case Common::Assignment::A_PAR_VAL_INOUT: | |
358 | case Common::Assignment::A_PAR_TEMPL_INOUT: | |
359 | case Common::Assignment::A_PAR_TIMER: // treat timers and ports as 'inout' parameters | |
360 | case Common::Assignment::A_PAR_PORT: | |
361 | fp_type_str = "inout"; | |
362 | break; | |
363 | case Common::Assignment::A_PAR_VAL_OUT: | |
364 | case Common::Assignment::A_PAR_TEMPL_OUT: | |
365 | fp_type_str = "out"; | |
366 | break; | |
367 | default: | |
368 | break; | |
369 | } | |
370 | fp_names_str = mputprintf(fp_names_str, | |
371 | "param_names[%d] = \"%s\";\n", (int)i, fp->get_id().get_ttcnname().c_str()); | |
372 | fp_types_str = mputprintf(fp_types_str, | |
373 | "param_types[%d] = \"%s\";\n", (int)i, fp_type_str); | |
374 | fp_add_var_str = generate_code_debugger_add_var(fp_add_var_str, fp); | |
375 | } | |
376 | str = mputprintf(str, | |
377 | "charstring_list param_names;\n" | |
378 | "%s" | |
379 | "charstring_list param_types;\n" | |
380 | "%s" | |
381 | "TTCN3_Debug_Function debug_scope(\"%s\", \"%s\", \"%s\", param_names, param_types, %s);\n" | |
382 | "%s" | |
383 | "debug_scope.initial_snapshot();\n" | |
384 | , fp_names_str, fp_types_str | |
385 | , func_ass->get_id().get_dispname().c_str(), func_type_str | |
386 | , func_ass->get_my_scope()->get_scope_mod()->get_modid().get_ttcnname().c_str() | |
387 | , comp_str.c_str(), fp_add_var_str); | |
388 | Free(fp_names_str); | |
389 | Free(fp_types_str); | |
390 | Free(fp_add_var_str); | |
391 | } | |
392 | else { | |
393 | // no parameters | |
394 | str = mputprintf(str, | |
395 | "charstring_list no_params = NULL_VALUE;\n" | |
396 | "TTCN3_Debug_Function debug_scope(\"%s\", \"%s\", \"%s\", no_params, no_params, %s);\n" | |
397 | "debug_scope.initial_snapshot();\n" | |
398 | , func_ass->get_id().get_dispname().c_str(), func_type_str | |
399 | , func_ass->get_my_scope()->get_scope_mod()->get_modid().get_ttcnname().c_str() | |
400 | , comp_str.c_str()); | |
401 | } | |
402 | return str; | |
403 | } | |
404 | ||
405 | } |