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