Sync with 5.3.0
[deliverable/titan.core.git] / compiler2 / ttcn3 / PatternString.cc
CommitLineData
970ed795
EL
1///////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2000-2014 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#include "PatternString.hh"
9#include "../../common/pattern.hh"
10#include "../CompilerError.hh"
11#include "../Code.hh"
12
13#include "TtcnTemplate.hh"
14
15namespace Ttcn {
16
17 // =================================
18 // ===== PatternString::ps_elem_t
19 // =================================
20
21 struct PatternString::ps_elem_t {
22 enum kind_t {
23 PSE_STR,
24 PSE_REF,
25 PSE_REFDSET
26 } kind;
27 union {
28 string *str;
29 Ttcn::Reference *ref;
30 };
31 ps_elem_t(kind_t p_kind, const string& p_str);
32 ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref);
33 ps_elem_t(const ps_elem_t& p);
34 ~ps_elem_t();
35 ps_elem_t* clone() const;
36 void set_fullname(const string& p_fullname);
37 void set_my_scope(Scope *p_scope);
38 void chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value);
39 void set_code_section(GovernedSimple::code_section_t p_code_section);
40 };
41
42 PatternString::ps_elem_t::ps_elem_t(kind_t p_kind, const string& p_str)
43 : kind(p_kind)
44 {
45 str = new string(p_str);
46 }
47
48 PatternString::ps_elem_t::ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref)
49 : kind(p_kind)
50 {
51 if (!p_ref) FATAL_ERROR("PatternString::ps_elem_t::ps_elem_t()");
52 ref = p_ref;
53 }
54
55 PatternString::ps_elem_t::~ps_elem_t()
56 {
57 switch(kind) {
58 case PSE_STR:
59 delete str;
60 break;
61 case PSE_REF:
62 case PSE_REFDSET:
63 delete ref;
64 break;
65 } // switch kind
66 }
67
68 PatternString::ps_elem_t* PatternString::ps_elem_t::clone() const
69 {
70 FATAL_ERROR("PatternString::ps_elem_t::clone");
71 }
72
73 void PatternString::ps_elem_t::set_fullname(const string& p_fullname)
74 {
75 switch(kind) {
76 case PSE_REF:
77 case PSE_REFDSET:
78 ref->set_fullname(p_fullname);
79 break;
80 default:
81 ;
82 } // switch kind
83 }
84
85 void PatternString::ps_elem_t::set_my_scope(Scope *p_scope)
86 {
87 switch(kind) {
88 case PSE_REF:
89 case PSE_REFDSET:
90 ref->set_my_scope(p_scope);
91 break;
92 default:
93 ;
94 } // switch kind
95 }
96
97 void PatternString::ps_elem_t::chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value)
98 {
99 if (kind != PSE_REF) FATAL_ERROR("PatternString::ps_elem_t::chk_ref()");
100 Value* v = 0;
101 Value* v_last = 0;
102 Common::Assignment* ass = ref->get_refd_assignment();
103 if (!ass)
104 return;
105 Ttcn::FieldOrArrayRefs* t_subrefs = ref->get_subrefs();
106 Type* ref_type = ass->get_Type()->get_type_refd_last()->get_field_type(
107 t_subrefs, expected_value);
108 Type::typetype_t tt;
109 switch (pstr_type) {
110 case PatternString::CSTR_PATTERN:
111 tt = Type::T_CSTR;
112 if (ref_type->get_typetype() != Type::T_CSTR)
113 TTCN_pattern_error("Type of the referenced %s '%s' should be "
114 "'charstring'", ass->get_assname(), ref->get_dispname().c_str());
115 break;
116 case PatternString::USTR_PATTERN:
117 tt = ref_type->get_typetype();
118 if (tt != Type::T_CSTR && tt != Type::T_USTR)
119 TTCN_pattern_error("Type of the referenced %s '%s' should be either "
120 "'charstring' or 'universal charstring'", ass->get_assname(),
121 ref->get_dispname().c_str());
122 break;
123 default:
124 FATAL_ERROR("Unknown pattern string type");
125 }
126 Type* refcheckertype = Type::get_pooltype(tt);
127 switch (ass->get_asstype()) {
128 case Common::Assignment::A_MODULEPAR_TEMP:
129 case Common::Assignment::A_VAR_TEMPLATE:
130 // error reporting moved up
131 break;
132 case Common::Assignment::A_TEMPLATE: {
133 Template* templ = ass->get_Template();
134 refcheckertype->chk_this_template_ref(templ);
135 refcheckertype->chk_this_template_generic(templ, INCOMPLETE_ALLOWED,
136 OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, 0);
137 switch (templ->get_templatetype()) {
138 case Template::SPECIFIC_VALUE:
139 v_last = templ->get_specific_value();
140 break;
141 case Template::CSTR_PATTERN: {
142 Ttcn::PatternString* ps = templ->get_cstr_pattern();
143 if (!ps->has_refs())
144 v_last = ps->get_value();
145 break; }
146 case Template::USTR_PATTERN: {
147 Ttcn::PatternString* ps = templ->get_ustr_pattern();
148 if (!ps->has_refs())
149 v_last = ps->get_value();
150 break; }
151 default:
152 TTCN_pattern_error("Unable to resolve referenced '%s' to character "
153 "string type. '%s' template cannot be used.",
154 ref->get_dispname().c_str(), templ->get_templatetype_str());
155 break;
156 }
157 break; }
158 default: {
159 Reference *t_ref = ref->clone();
160 t_ref->set_location(*ref);
161 v = new Value(Value::V_REFD, t_ref);
162 v->set_my_governor(refcheckertype);
163 v->set_my_scope(ref->get_my_scope());
164 v->set_location(*ref);
165 refcheckertype->chk_this_value(v, 0, expected_value,
166 INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK);
167 v_last = v->get_value_refd_last();
168 }
169 }
170 if (v_last && (v_last->get_valuetype() == Value::V_CSTR ||
171 v_last->get_valuetype() == Value::V_USTR)) {
172 // the reference points to a constant
173 // substitute the reference with the known value
174 delete ref;
175 kind = PSE_STR;
176 if (v_last->get_valuetype() == Value::V_CSTR)
177 str = new string(v_last->get_val_str());
178 else
179 str = new string(v_last->get_val_ustr().get_stringRepr_for_pattern());
180 }
181 delete v;
182 }
183
184 void PatternString::ps_elem_t::set_code_section
185 (GovernedSimple::code_section_t p_code_section)
186 {
187 switch(kind) {
188 case PSE_REF:
189 case PSE_REFDSET:
190 ref->set_code_section(p_code_section);
191 break;
192 default:
193 ;
194 } // switch kind
195 }
196
197 // =================================
198 // ===== PatternString
199 // =================================
200
201 PatternString::PatternString(const PatternString& p)
202 : Node(p), my_scope(0), pattern_type(p.pattern_type)
203 {
204 size_t nof_elems = p.elems.size();
205 for (size_t i = 0; i < nof_elems; i++) elems.add(p.elems[i]->clone());
206 }
207
208 PatternString::ps_elem_t *PatternString::get_last_elem() const
209 {
210 if (elems.empty()) return 0;
211 ps_elem_t *last_elem = elems[elems.size() - 1];
212 if (last_elem->kind == ps_elem_t::PSE_STR) return last_elem;
213 else return 0;
214 }
215
216 PatternString::~PatternString()
217 {
218 size_t nof_elems = elems.size();
219 for (size_t i = 0; i < nof_elems; i++) delete elems[i];
220 elems.clear();
221 delete cstr_value;
222 }
223
224 PatternString *PatternString::clone() const
225 {
226 return new PatternString(*this);
227 }
228
229 void PatternString::set_fullname(const string& p_fullname)
230 {
231 Node::set_fullname(p_fullname);
232 size_t nof_elems = elems.size();
233 for(size_t i = 0; i < nof_elems; i++) elems[i]->set_fullname(p_fullname);
234 }
235
236 void PatternString::set_my_scope(Scope *p_scope)
237 {
238 my_scope = p_scope;
239 size_t nof_elems = elems.size();
240 for (size_t i = 0; i < nof_elems; i++) elems[i]->set_my_scope(p_scope);
241 }
242
243 void PatternString::set_code_section
244 (GovernedSimple::code_section_t p_code_section)
245 {
246 size_t nof_elems = elems.size();
247 for (size_t i = 0; i < nof_elems; i++)
248 elems[i]->set_code_section(p_code_section);
249 }
250
251 void PatternString::addChar(char c)
252 {
253 ps_elem_t *last_elem = get_last_elem();
254 if (last_elem) *last_elem->str += c;
255 else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, string(c)));
256 }
257
258 void PatternString::addString(const char *p_str)
259 {
260 ps_elem_t *last_elem = get_last_elem();
261 if (last_elem) *last_elem->str += p_str;
262 else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, string(p_str)));
263 }
264
265 void PatternString::addString(const string& p_str)
266 {
267 ps_elem_t *last_elem = get_last_elem();
268 if (last_elem) *last_elem->str += p_str;
269 else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, p_str));
270 }
271
272 void PatternString::addRef(Ttcn::Reference *p_ref)
273 {
274 elems.add(new ps_elem_t(ps_elem_t::PSE_REF, p_ref));
275 }
276
277 void PatternString::addRefdCharSet(Ttcn::Reference *p_ref)
278 {
279 elems.add(new ps_elem_t(ps_elem_t::PSE_REFDSET, p_ref));
280 }
281
282 string PatternString::get_full_str() const
283 {
284 string s;
285 for(size_t i=0; i<elems.size(); i++) {
286 ps_elem_t *pse=elems[i];
287 switch(pse->kind) {
288 case ps_elem_t::PSE_STR:
289 s+=*pse->str;
290 break;
291 case ps_elem_t::PSE_REFDSET:
292 s+="\\N";
293 /* no break */
294 case ps_elem_t::PSE_REF:
295 s+='{';
296 s+=pse->ref->get_dispname();
297 s+='}';
298 } // switch kind
299 } // for
300 return s;
301 }
302
303 void PatternString::set_pattern_type(pstr_type_t p_type) {
304 pattern_type = p_type;
305 }
306
307 PatternString::pstr_type_t PatternString::get_pattern_type() const {
308 return pattern_type;
309 }
310
311 bool PatternString::has_refs() const
312 {
313 for (size_t i = 0; i < elems.size(); i++) {
314 switch (elems[i]->kind) {
315 case ps_elem_t::PSE_REF:
316 case ps_elem_t::PSE_REFDSET:
317 return true;
318 default:
319 break;
320 }
321 }
322 return false;
323 }
324
325 void PatternString::chk_refs(Type::expected_value_t expected_value)
326 {
327 for(size_t i=0; i<elems.size(); i++) {
328 ps_elem_t *pse=elems[i];
329 switch(pse->kind) {
330 case ps_elem_t::PSE_STR:
331 break;
332 case ps_elem_t::PSE_REFDSET:
333 /* actually, not supported */
334 break;
335 case ps_elem_t::PSE_REF:
336 pse->chk_ref(pattern_type, expected_value);
337 break;
338 } // switch kind
339 } // for
340 }
341
342 /** \todo implement */
343 void PatternString::chk_recursions(ReferenceChain&)
344 {
345
346 }
347
348 void PatternString::chk_pattern()
349 {
350 string str;
351 for (size_t i = 0; i < elems.size(); i++) {
352 ps_elem_t *pse = elems[i];
353 if (pse->kind != ps_elem_t::PSE_STR)
354 FATAL_ERROR("PatternString::chk_pattern()");
355 str += *pse->str;
356 }
357 char* posix_str = 0;
358 switch (pattern_type) {
359 case CSTR_PATTERN:
360 posix_str = TTCN_pattern_to_regexp(str.c_str());
361 break;
362 case USTR_PATTERN:
363 posix_str = TTCN_pattern_to_regexp_uni(str.c_str());
364 }
365 Free(posix_str);
366 }
367
368 bool PatternString::chk_self_ref(Common::Assignment *lhs)
369 {
370 for (size_t i = 0, e = elems.size(); i < e; ++i) {
371 ps_elem_t *pse = elems[i];
372 switch (pse->kind) {
373 case ps_elem_t::PSE_STR:
374 break;
375 case ps_elem_t::PSE_REFDSET:
376 /* actually, not supported */
377 break;
378 case ps_elem_t::PSE_REF: {
379 Ttcn::Assignment *ass = pse->ref->get_refd_assignment();
380 if (ass == lhs) return true;
381 break; }
382 } // switch
383 }
384 return false;
385 }
386
387 void PatternString::join_strings()
388 {
389 // points to the previous string element otherwise it is NULL
390 ps_elem_t *prev_str = 0;
391 for (size_t i = 0; i < elems.size(); ) {
392 ps_elem_t *pse = elems[i];
393 if (pse->kind == ps_elem_t::PSE_STR) {
394 const string& str = *pse->str;
395 if (str.size() > 0) {
396 // the current element is a non-empty string
397 if (prev_str) {
398 // append str to prev_str and drop pse
399 *prev_str->str += str;
400 delete pse;
401 elems.replace(i, 1);
402 // don't increment i
403 } else {
404 // keep pse for the next iteration
405 prev_str = pse;
406 i++;
407 }
408 } else {
409 // the current element is an empty string
410 // simply drop it
411 delete pse;
412 elems.replace(i, 1);
413 // don't increment i
414 }
415 } else {
416 // pse is not a string
417 // forget prev_str
418 prev_str = 0;
419 i++;
420 }
421 }
422 }
423
424 string PatternString::create_charstring_literals(Common::Module *p_mod)
425 {
426 /* The cast is there for the benefit of OPTIONAL<CHARSTRING>, because
427 * it doesn't have operator+(). Only the first member needs the cast
428 * (the others will be automagically converted to satisfy
429 * CHARSTRING::operator+(const CHARSTRING&) ) */
430 string s;
431 if (pattern_type == CSTR_PATTERN)
432 s = "CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
433 else
434 s = "UNIVERSAL_CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
435 size_t nof_elems = elems.size();
436 if (nof_elems > 0) {
437 // the pattern is not empty
438 for (size_t i = 0; i < nof_elems; i++) {
439 if (i > 0) s += " + ";
440 ps_elem_t *pse = elems[i];
441 switch (pse->kind) {
442 case ps_elem_t::PSE_STR:
443 s += p_mod->add_charstring_literal(*pse->str);
444 break;
445 case ps_elem_t::PSE_REFDSET:
446 /* actually, not supported */
447 FATAL_ERROR("PatternString::create_charstring_literals()");
448 break;
449 case ps_elem_t::PSE_REF: {
450 expression_struct expr;
451 Code::init_expr(&expr);
452 pse->ref->generate_code(&expr);
453 if (expr.preamble || expr.postamble)
454 FATAL_ERROR("PatternString::create_charstring_literals()");
455 s += expr.expr;
456 Common::Assignment* assign = pse->ref->get_refd_assignment();
457
458 if ((assign->get_asstype() == Common::Assignment::A_TEMPLATE
459 || assign->get_asstype() == Common::Assignment::A_MODULEPAR_TEMP
460 || assign->get_asstype() == Common::Assignment::A_VAR_TEMPLATE))
461 {
462 if ((assign->get_Type()->get_typetype() == Type::T_CSTR
463 || assign->get_Type()->get_typetype() == Type::T_USTR)) {
464 s += ".get_single_value()";
465 }
466 else {
467 s += ".valueof()";
468 }
469 }
470
471 Code::free_expr(&expr);
472 break; }
473 } // switch kind
474 } // for
475 } else {
476 // empty pattern: create an empty string literal for it
477 s += p_mod->add_charstring_literal(string());
478 }
479 s += ')';
480 return s;
481 }
482
483 void PatternString::dump(unsigned level) const
484 {
485 DEBUG(level, "%s", get_full_str().c_str());
486 }
487
488 Common::Value* PatternString::get_value() {
489 if (!cstr_value && !has_refs())
490 cstr_value = new Common::Value(Common::Value::V_CSTR,
491 new string(get_full_str()));
492 return cstr_value;
493 }
494
495} // namespace Ttcn
496
497 // =================================
498 // ===== TTCN_pattern_XXXX
499 // =================================
500
501/* These functions are used by common charstring pattern parser. */
502
503void TTCN_pattern_error(const char *fmt, ...)
504{
505 char *msg=mcopystr("Charstring pattern: ");
506 msg=mputstr(msg, fmt);
507 va_list args;
508 va_start(args, fmt);
509 Common::Error_Context::report_error(0, msg, args);
510 va_end(args);
511 Free(msg);
512}
513
514void TTCN_pattern_warning(const char *fmt, ...)
515{
516 char *msg=mcopystr("Charstring pattern: ");
517 msg=mputstr(msg, fmt);
518 va_list args;
519 va_start(args, fmt);
520 Common::Error_Context::report_warning(0, msg, args);
521 va_end(args);
522 Free(msg);
523}
This page took 0.046028 seconds and 5 git commands to generate.