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"
13 #include "TtcnTemplate.hh"
17 // =================================
18 // ===== PatternString::ps_elem_t
19 // =================================
21 struct PatternString::ps_elem_t
{
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
);
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
);
42 PatternString::ps_elem_t::ps_elem_t(kind_t p_kind
, const string
& p_str
)
45 str
= new string(p_str
);
48 PatternString::ps_elem_t::ps_elem_t(kind_t p_kind
, Ttcn::Reference
*p_ref
)
51 if (!p_ref
) FATAL_ERROR("PatternString::ps_elem_t::ps_elem_t()");
55 PatternString::ps_elem_t::~ps_elem_t()
68 PatternString::ps_elem_t
* PatternString::ps_elem_t::clone() const
70 FATAL_ERROR("PatternString::ps_elem_t::clone");
73 void PatternString::ps_elem_t::set_fullname(const string
& p_fullname
)
78 ref
->set_fullname(p_fullname
);
85 void PatternString::ps_elem_t::set_my_scope(Scope
*p_scope
)
90 ref
->set_my_scope(p_scope
);
97 void PatternString::ps_elem_t::chk_ref(PatternString::pstr_type_t pstr_type
, Type::expected_value_t expected_value
)
99 if (kind
!= PSE_REF
) FATAL_ERROR("PatternString::ps_elem_t::chk_ref()");
102 Common::Assignment
* ass
= ref
->get_refd_assignment();
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
);
110 case PatternString::CSTR_PATTERN
:
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());
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());
124 FATAL_ERROR("Unknown pattern string type");
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
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();
141 case Template::CSTR_PATTERN
: {
142 Ttcn::PatternString
* ps
= templ
->get_cstr_pattern();
144 v_last
= ps
->get_value();
146 case Template::USTR_PATTERN
: {
147 Ttcn::PatternString
* ps
= templ
->get_ustr_pattern();
149 v_last
= ps
->get_value();
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());
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();
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
176 if (v_last
->get_valuetype() == Value::V_CSTR
)
177 str
= new string(v_last
->get_val_str());
179 str
= new string(v_last
->get_val_ustr().get_stringRepr_for_pattern());
184 void PatternString::ps_elem_t::set_code_section
185 (GovernedSimple::code_section_t p_code_section
)
190 ref
->set_code_section(p_code_section
);
197 // =================================
198 // ===== PatternString
199 // =================================
201 PatternString::PatternString(const PatternString
& p
)
202 : Node(p
), my_scope(0), pattern_type(p
.pattern_type
)
204 size_t nof_elems
= p
.elems
.size();
205 for (size_t i
= 0; i
< nof_elems
; i
++) elems
.add(p
.elems
[i
]->clone());
208 PatternString::ps_elem_t
*PatternString::get_last_elem() const
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
;
216 PatternString::~PatternString()
218 size_t nof_elems
= elems
.size();
219 for (size_t i
= 0; i
< nof_elems
; i
++) delete elems
[i
];
224 PatternString
*PatternString::clone() const
226 return new PatternString(*this);
229 void PatternString::set_fullname(const string
& p_fullname
)
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
);
236 void PatternString::set_my_scope(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
);
243 void PatternString::set_code_section
244 (GovernedSimple::code_section_t p_code_section
)
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
);
251 void PatternString::addChar(char c
)
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
)));
258 void PatternString::addString(const char *p_str
)
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
)));
265 void PatternString::addString(const string
& p_str
)
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
));
272 void PatternString::addRef(Ttcn::Reference
*p_ref
)
274 elems
.add(new ps_elem_t(ps_elem_t::PSE_REF
, p_ref
));
277 void PatternString::addRefdCharSet(Ttcn::Reference
*p_ref
)
279 elems
.add(new ps_elem_t(ps_elem_t::PSE_REFDSET
, p_ref
));
282 string
PatternString::get_full_str() const
285 for(size_t i
=0; i
<elems
.size(); i
++) {
286 ps_elem_t
*pse
=elems
[i
];
288 case ps_elem_t::PSE_STR
:
291 case ps_elem_t::PSE_REFDSET
:
294 case ps_elem_t::PSE_REF
:
296 s
+=pse
->ref
->get_dispname();
303 void PatternString::set_pattern_type(pstr_type_t p_type
) {
304 pattern_type
= p_type
;
307 PatternString::pstr_type_t
PatternString::get_pattern_type() const {
311 bool PatternString::has_refs() const
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
:
325 void PatternString::chk_refs(Type::expected_value_t expected_value
)
327 for(size_t i
=0; i
<elems
.size(); i
++) {
328 ps_elem_t
*pse
=elems
[i
];
330 case ps_elem_t::PSE_STR
:
332 case ps_elem_t::PSE_REFDSET
:
333 /* actually, not supported */
335 case ps_elem_t::PSE_REF
:
336 pse
->chk_ref(pattern_type
, expected_value
);
342 /** \todo implement */
343 void PatternString::chk_recursions(ReferenceChain
&)
348 void PatternString::chk_pattern()
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()");
358 switch (pattern_type
) {
360 posix_str
= TTCN_pattern_to_regexp(str
.c_str());
363 posix_str
= TTCN_pattern_to_regexp_uni(str
.c_str());
368 bool PatternString::chk_self_ref(Common::Assignment
*lhs
)
370 for (size_t i
= 0, e
= elems
.size(); i
< e
; ++i
) {
371 ps_elem_t
*pse
= elems
[i
];
373 case ps_elem_t::PSE_STR
:
375 case ps_elem_t::PSE_REFDSET
:
376 /* actually, not supported */
378 case ps_elem_t::PSE_REF
: {
379 Ttcn::Assignment
*ass
= pse
->ref
->get_refd_assignment();
380 if (ass
== lhs
) return true;
387 void PatternString::join_strings()
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
398 // append str to prev_str and drop pse
399 *prev_str
->str
+= str
;
404 // keep pse for the next iteration
409 // the current element is an empty string
416 // pse is not a string
424 string
PatternString::create_charstring_literals(Common::Module
*p_mod
)
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&) ) */
431 if (pattern_type
== CSTR_PATTERN
)
432 s
= "CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
434 s
= "UNIVERSAL_CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
435 size_t nof_elems
= elems
.size();
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
];
442 case ps_elem_t::PSE_STR
:
443 s
+= p_mod
->add_charstring_literal(*pse
->str
);
445 case ps_elem_t::PSE_REFDSET
:
446 /* actually, not supported */
447 FATAL_ERROR("PatternString::create_charstring_literals()");
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()");
456 Common::Assignment
* assign
= pse
->ref
->get_refd_assignment();
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
))
462 if ((assign
->get_Type()->get_typetype() == Type::T_CSTR
463 || assign
->get_Type()->get_typetype() == Type::T_USTR
)) {
464 s
+= ".get_single_value()";
471 Code::free_expr(&expr
);
476 // empty pattern: create an empty string literal for it
477 s
+= p_mod
->add_charstring_literal(string());
483 void PatternString::dump(unsigned level
) const
485 DEBUG(level
, "%s", get_full_str().c_str());
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()));
497 // =================================
498 // ===== TTCN_pattern_XXXX
499 // =================================
501 /* These functions are used by common charstring pattern parser. */
503 void TTCN_pattern_error(const char *fmt
, ...)
505 char *msg
=mcopystr("Charstring pattern: ");
506 msg
=mputstr(msg
, fmt
);
509 Common::Error_Context::report_error(0, msg
, args
);
514 void TTCN_pattern_warning(const char *fmt
, ...)
516 char *msg
=mcopystr("Charstring pattern: ");
517 msg
=mputstr(msg
, fmt
);
520 Common::Error_Context::report_warning(0, msg
, args
);