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
15 * Szabo, Janos Zoltan – initial implementation
16 * Zalanyi, Balazs Andor
18 ******************************************************************************/
19 #include "PatternString.hh"
20 #include "../../common/pattern.hh"
21 #include "../CompilerError.hh"
23 #include "../../common/JSON_Tokenizer.hh"
25 #include "TtcnTemplate.hh"
29 // =================================
30 // ===== PatternString::ps_elem_t
31 // =================================
33 struct PatternString::ps_elem_t
{
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
);
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
);
54 PatternString::ps_elem_t::ps_elem_t(kind_t p_kind
, const string
& p_str
)
57 str
= new string(p_str
);
60 PatternString::ps_elem_t::ps_elem_t(kind_t p_kind
, Ttcn::Reference
*p_ref
)
63 if (!p_ref
) FATAL_ERROR("PatternString::ps_elem_t::ps_elem_t()");
67 PatternString::ps_elem_t::~ps_elem_t()
80 PatternString::ps_elem_t
* PatternString::ps_elem_t::clone() const
82 FATAL_ERROR("PatternString::ps_elem_t::clone");
85 void PatternString::ps_elem_t::set_fullname(const string
& p_fullname
)
90 ref
->set_fullname(p_fullname
);
97 void PatternString::ps_elem_t::set_my_scope(Scope
*p_scope
)
102 ref
->set_my_scope(p_scope
);
109 void PatternString::ps_elem_t::chk_ref(PatternString::pstr_type_t pstr_type
, Type::expected_value_t expected_value
)
111 if (kind
!= PSE_REF
) FATAL_ERROR("PatternString::ps_elem_t::chk_ref()");
114 Common::Assignment
* ass
= ref
->get_refd_assignment();
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
);
122 case PatternString::CSTR_PATTERN
:
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());
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());
136 FATAL_ERROR("Unknown pattern string type");
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
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();
153 case Template::CSTR_PATTERN
: {
154 Ttcn::PatternString
* ps
= templ
->get_cstr_pattern();
156 v_last
= ps
->get_value();
158 case Template::USTR_PATTERN
: {
159 Ttcn::PatternString
* ps
= templ
->get_ustr_pattern();
161 v_last
= ps
->get_value();
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());
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();
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
188 if (v_last
->get_valuetype() == Value::V_CSTR
)
189 str
= new string(v_last
->get_val_str());
191 str
= new string(v_last
->get_val_ustr().get_stringRepr_for_pattern());
196 void PatternString::ps_elem_t::set_code_section
197 (GovernedSimple::code_section_t p_code_section
)
202 ref
->set_code_section(p_code_section
);
209 // =================================
210 // ===== PatternString
211 // =================================
213 PatternString::PatternString(const PatternString
& p
)
214 : Node(p
), my_scope(0), pattern_type(p
.pattern_type
)
216 size_t nof_elems
= p
.elems
.size();
217 for (size_t i
= 0; i
< nof_elems
; i
++) elems
.add(p
.elems
[i
]->clone());
220 PatternString::ps_elem_t
*PatternString::get_last_elem() const
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
;
228 PatternString::~PatternString()
230 size_t nof_elems
= elems
.size();
231 for (size_t i
= 0; i
< nof_elems
; i
++) delete elems
[i
];
236 PatternString
*PatternString::clone() const
238 return new PatternString(*this);
241 void PatternString::set_fullname(const string
& p_fullname
)
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
);
248 void PatternString::set_my_scope(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
);
255 void PatternString::set_code_section
256 (GovernedSimple::code_section_t p_code_section
)
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
);
263 void PatternString::addChar(char c
)
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
)));
270 void PatternString::addString(const char *p_str
)
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
)));
277 void PatternString::addString(const string
& p_str
)
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
));
284 void PatternString::addStringUSI(char **usi_str
, const size_t size
)
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()));
292 void PatternString::addRef(Ttcn::Reference
*p_ref
)
294 elems
.add(new ps_elem_t(ps_elem_t::PSE_REF
, p_ref
));
297 void PatternString::addRefdCharSet(Ttcn::Reference
*p_ref
)
299 elems
.add(new ps_elem_t(ps_elem_t::PSE_REFDSET
, p_ref
));
302 string
PatternString::get_full_str() const
305 for(size_t i
=0; i
<elems
.size(); i
++) {
306 ps_elem_t
*pse
=elems
[i
];
308 case ps_elem_t::PSE_STR
:
311 case ps_elem_t::PSE_REFDSET
:
314 case ps_elem_t::PSE_REF
:
316 s
+=pse
->ref
->get_dispname();
323 void PatternString::set_pattern_type(pstr_type_t p_type
) {
324 pattern_type
= p_type
;
327 PatternString::pstr_type_t
PatternString::get_pattern_type() const {
331 bool PatternString::has_refs() const
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
:
345 void PatternString::chk_refs(Type::expected_value_t expected_value
)
347 for(size_t i
=0; i
<elems
.size(); i
++) {
348 ps_elem_t
*pse
=elems
[i
];
350 case ps_elem_t::PSE_STR
:
352 case ps_elem_t::PSE_REFDSET
:
353 /* actually, not supported */
355 case ps_elem_t::PSE_REF
:
356 pse
->chk_ref(pattern_type
, expected_value
);
362 /** \todo implement */
363 void PatternString::chk_recursions(ReferenceChain
&)
368 void PatternString::chk_pattern()
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()");
378 switch (pattern_type
) {
380 posix_str
= TTCN_pattern_to_regexp(str
.c_str());
383 posix_str
= TTCN_pattern_to_regexp_uni(str
.c_str());
388 bool PatternString::chk_self_ref(Common::Assignment
*lhs
)
390 for (size_t i
= 0, e
= elems
.size(); i
< e
; ++i
) {
391 ps_elem_t
*pse
= elems
[i
];
393 case ps_elem_t::PSE_STR
:
395 case ps_elem_t::PSE_REFDSET
:
396 /* actually, not supported */
398 case ps_elem_t::PSE_REF
: {
399 Ttcn::Assignment
*ass
= pse
->ref
->get_refd_assignment();
400 if (ass
== lhs
) return true;
407 void PatternString::join_strings()
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
418 // append str to prev_str and drop pse
419 *prev_str
->str
+= str
;
424 // keep pse for the next iteration
429 // the current element is an empty string
436 // pse is not a string
444 string
PatternString::create_charstring_literals(Common::Module
*p_mod
)
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&) ) */
451 if (pattern_type
== CSTR_PATTERN
)
452 s
= "CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
454 s
= "UNIVERSAL_CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
455 size_t nof_elems
= elems
.size();
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
];
462 case ps_elem_t::PSE_STR
:
463 s
+= p_mod
->add_charstring_literal(*pse
->str
);
465 case ps_elem_t::PSE_REFDSET
:
466 /* actually, not supported */
467 FATAL_ERROR("PatternString::create_charstring_literals()");
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()");
476 Common::Assignment
* assign
= pse
->ref
->get_refd_assignment();
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
))
482 if ((assign
->get_Type()->get_typetype() == Type::T_CSTR
483 || assign
->get_Type()->get_typetype() == Type::T_USTR
)) {
484 s
+= ".get_single_value()";
491 Code::free_expr(&expr
);
496 // empty pattern: create an empty string literal for it
497 s
+= p_mod
->add_charstring_literal(string());
503 void PatternString::dump(unsigned level
) const
505 DEBUG(level
, "%s", get_full_str().c_str());
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()));
515 char* PatternString::convert_to_json()
517 string pstr
= get_value()->get_val_str();
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());
524 else { // USTR_PATTERN
525 // handle the unicode characters in \q{g,p,r,c} format
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);
542 // convert the character to UTF-8 format
543 utf8str
+= ustring_to_uft8(ustring(group
, plane
, row
, cell
));
546 else if ('\\' == pstr
[i
+ 1]) {
547 // must be handled separately, so we don't confuse \\q with \q
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);
561 return convert_to_json_string(regex_str
);
566 // =================================
567 // ===== TTCN_pattern_XXXX
568 // =================================
570 /* These functions are used by common charstring pattern parser. */
572 void TTCN_pattern_error(const char *fmt
, ...)
574 char *msg
=mcopystr("Charstring pattern: ");
575 msg
=mputstr(msg
, fmt
);
578 Common::Error_Context::report_error(0, msg
, args
);
583 void TTCN_pattern_warning(const char *fmt
, ...)
585 char *msg
=mcopystr("Charstring pattern: ");
586 msg
=mputstr(msg
, fmt
);
589 Common::Error_Context::report_warning(0, msg
, args
);