Commit c3535743 authored by BenceJanosSzabo's avatar BenceJanosSzabo
Browse files

implemented \N{typereference}, \N{reference} for pattern (artf724182)



Change-Id: Ia6382d9eee1ea7539ce27b049a42d0153e344fbb
Signed-off-by: default avatarBenceJanosSzabo <bence.janos.szabo@ericsson.com>
parent 27ba2d7c
......@@ -609,9 +609,11 @@ char* TTCN_pattern_to_regexp_uni(const char* p_pattern, bool p_nocase, int** gro
pattern_yy_delete_buffer(flex_buffer);
// needed by regexp to find user specified groups
if (user_groups && groups) {
*groups = (int*)Malloc(sizeof(int) * (user_groups + 1));
(*groups)[0] = user_groups;
if (user_groups /*&& groups*/) {
if (groups) {
*groups = (int*)Malloc(sizeof(int) * (user_groups + 1));
(*groups)[0] = user_groups;
}
int par = -1, index = 1;
for (size_t i = 0; i < strlen(ret_val); i++) {
......@@ -621,7 +623,7 @@ char* TTCN_pattern_to_regexp_uni(const char* p_pattern, bool p_nocase, int** gro
if (ret_val[i] == '<') {
ret_val[i] = '(';
par++;
(*groups)[index++] = par;
if (groups) (*groups)[index++] = par;
}
}
} else if (groups)
......
......@@ -2770,6 +2770,10 @@ void SubType::print_full_warning() const
"it does not constrain the root type.", my_owner->get_typename().c_str());
}
vector<SubTypeParse> * SubType::get_subtype_parsed() const {
return parsed;
}
void SubType::chk()
{
if ((checked!=STC_NO) || (subtype==ST_ERROR)) FATAL_ERROR("SubType::chk()");
......
......@@ -257,6 +257,8 @@ public:
SubtypeConstraint* get_extension() { return extension; }
string to_string() const;
vector<SubTypeParse> * get_subtype_parsed() const;
/** Set restrictions.
*
......
......@@ -36,12 +36,14 @@ namespace Ttcn {
PSE_REF,
PSE_REFDSET
} kind;
union {
string *str;
Ttcn::Reference *ref;
};
string *str;
Ttcn::Reference *ref;
Type * t; // The type of the reference in the case of PSE_REFDSET
boolean with_N; // If the reference was given as \N{ref} in the pattern
boolean is_charstring; // \N{charstring}
boolean is_universal_charstring; // \N{universal charstring}
ps_elem_t(kind_t p_kind, const string& p_str);
ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref);
ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref, boolean N);
ps_elem_t(const ps_elem_t& p);
~ps_elem_t();
ps_elem_t* clone() const;
......@@ -52,13 +54,15 @@ namespace Ttcn {
};
PatternString::ps_elem_t::ps_elem_t(kind_t p_kind, const string& p_str)
: kind(p_kind)
: kind(p_kind), ref(NULL), t(NULL), with_N(FALSE), is_charstring(FALSE),
is_universal_charstring(FALSE)
{
str = new string(p_str);
}
PatternString::ps_elem_t::ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref)
: kind(p_kind)
PatternString::ps_elem_t::ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref, boolean N)
: kind(p_kind), str(NULL), with_N(N), is_charstring(FALSE),
is_universal_charstring(FALSE)
{
if (!p_ref) FATAL_ERROR("PatternString::ps_elem_t::ps_elem_t()");
ref = p_ref;
......@@ -69,10 +73,11 @@ namespace Ttcn {
switch(kind) {
case PSE_STR:
delete str;
break;
// fall through
case PSE_REF:
case PSE_REFDSET:
delete ref;
// do not delete t
break;
} // switch kind
}
......@@ -111,6 +116,13 @@ namespace Ttcn {
if (kind != PSE_REF) FATAL_ERROR("PatternString::ps_elem_t::chk_ref()");
Value* v = 0;
Value* v_last = 0;
if (ref->get_id()->get_name() == "CHARSTRING") {
is_charstring = TRUE;
return;
} else if (ref->get_id()->get_name() == "UNIVERSAL_CHARSTRING") {
is_universal_charstring = TRUE;
return;
}
Common::Assignment* ass = ref->get_refd_assignment();
if (!ass)
return;
......@@ -137,8 +149,15 @@ namespace Ttcn {
}
Type* refcheckertype = Type::get_pooltype(tt);
switch (ass->get_asstype()) {
case Common::Assignment::A_TYPE:
kind = PSE_REFDSET;
t = ass->get_Type();
break;
case Common::Assignment::A_MODULEPAR_TEMP:
case Common::Assignment::A_VAR_TEMPLATE:
case Common::Assignment::A_VAR_TEMPLATE:
case Common::Assignment::A_PAR_TEMPL_IN:
case Common::Assignment::A_PAR_TEMPL_OUT:
case Common::Assignment::A_PAR_TEMPL_INOUT:
// error reporting moved up
break;
case Common::Assignment::A_TEMPLATE: {
......@@ -150,16 +169,20 @@ namespace Ttcn {
case Template::SPECIFIC_VALUE:
v_last = templ->get_specific_value();
break;
case Template::CSTR_PATTERN: {
Ttcn::PatternString* ps = templ->get_cstr_pattern();
if (!ps->has_refs())
v_last = ps->get_value();
break; }
case Template::USTR_PATTERN: {
Ttcn::PatternString* ps = templ->get_ustr_pattern();
if (!ps->has_refs())
v_last = ps->get_value();
break; }
case Template::CSTR_PATTERN:
if (!with_N) {
Ttcn::PatternString* ps = templ->get_cstr_pattern();
if (!ps->has_refs())
v_last = ps->get_value();
break;
}
case Template::USTR_PATTERN:
if (!with_N) {
Ttcn::PatternString* ps = templ->get_ustr_pattern();
if (!ps->has_refs())
v_last = ps->get_value();
break;
}
default:
TTCN_pattern_error("Unable to resolve referenced '%s' to character "
"string type. '%s' template cannot be used.",
......@@ -183,12 +206,18 @@ namespace Ttcn {
v_last->get_valuetype() == Value::V_USTR)) {
// the reference points to a constant
// substitute the reference with the known value
delete ref;
kind = PSE_STR;
if (v_last->get_valuetype() == Value::V_CSTR)
if (v_last->get_valuetype() == Value::V_CSTR) {
if (with_N && v_last->get_val_str().size() != 1) {
ref->error("The length of the charstring must be of length one, when it is being referenced in a pattern with \\N{ref}");
}
str = new string(v_last->get_val_str());
else
} else {
if (with_N && v_last->get_val_ustr().size() != 1) {
ref->error("The length of the universal charstring must be of length one, when it is being referenced in a pattern with \\N{ref}");
}
str = new string(v_last->get_val_ustr().get_stringRepr_for_pattern());
}
kind = PSE_STR;
}
delete v;
}
......@@ -283,20 +312,15 @@ namespace Ttcn {
void PatternString::addStringUSI(char **usi_str, const size_t size)
{
ustring s = ustring((const char**)usi_str, size);
ustring s = ustring(const_cast<const char**>(usi_str), size);
ps_elem_t *last_elem = get_last_elem();
if (last_elem) *last_elem->str += s.get_stringRepr_for_pattern().c_str();
else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, s.get_stringRepr_for_pattern()));
}
void PatternString::addRef(Ttcn::Reference *p_ref)
{
elems.add(new ps_elem_t(ps_elem_t::PSE_REF, p_ref));
}
void PatternString::addRefdCharSet(Ttcn::Reference *p_ref)
void PatternString::addRef(Ttcn::Reference *p_ref, boolean N)
{
elems.add(new ps_elem_t(ps_elem_t::PSE_REFDSET, p_ref));
elems.add(new ps_elem_t(ps_elem_t::PSE_REF, p_ref, N));
}
string PatternString::get_full_str() const
......@@ -371,7 +395,7 @@ namespace Ttcn {
for (size_t i = 0; i < elems.size(); i++) {
ps_elem_t *pse = elems[i];
if (pse->kind != ps_elem_t::PSE_STR)
FATAL_ERROR("PatternString::chk_pattern()");
FATAL_ERROR("PatternString::chk_pattern()");
str += *pse->str;
}
char* posix_str = 0;
......@@ -441,7 +465,7 @@ namespace Ttcn {
}
}
string PatternString::create_charstring_literals(Common::Module *p_mod)
string PatternString::create_charstring_literals(Common::Module *p_mod, string& preamble)
{
/* The cast is there for the benefit of OPTIONAL<CHARSTRING>, because
* it doesn't have operator+(). Only the first member needs the cast
......@@ -455,42 +479,170 @@ namespace Ttcn {
size_t nof_elems = elems.size();
if (nof_elems > 0) {
// the pattern is not empty
for (size_t i = 0; i < nof_elems; i++) {
if (i > 0) s += " + ";
ps_elem_t *pse = elems[i];
switch (pse->kind) {
case ps_elem_t::PSE_STR:
for (size_t i = 0; i < nof_elems; i++) {
if (i > 0) s += " + ";
ps_elem_t *pse = elems[i];
// \N{charstring} and \N{universal charstring}
if (pse->is_charstring) {
s += p_mod->add_charstring_literal(string("?"));
continue;
} else if (pse->is_universal_charstring) {
s += p_mod->add_charstring_literal(string("?"));
continue;
}
switch (pse->kind) {
// Known in compile time: string literal, const etc.
case ps_elem_t::PSE_STR:
s += p_mod->add_charstring_literal(*pse->str);
break;
case ps_elem_t::PSE_REFDSET:
/* actually, not supported */
FATAL_ERROR("PatternString::create_charstring_literals()");
break;
case ps_elem_t::PSE_REF: {
expression_struct expr;
Code::init_expr(&expr);
pse->ref->generate_code(&expr);
if (expr.preamble || expr.postamble)
FATAL_ERROR("PatternString::create_charstring_literals()");
// Known in compile time: string type with(out) range or list
case ps_elem_t::PSE_REFDSET: {
if (!pse->t)
FATAL_ERROR("PatternString::create_charstring_literals()");
if (!pse->t->get_sub_type()) {
// just a string type without any restrictions (or alias)
s += "\"?\"";
continue;
}
vector<Common::SubTypeParse> * vec = pse->t->get_sub_type()->get_subtype_parsed();
while (vec == NULL) { // go through aliases to find where the restrictions are
if (pse->t->get_Reference()) {
pse->t = pse->t->get_Reference()->get_refd_assignment(FALSE)->get_Type();
} else {
break;
}
if (pse->t->get_sub_type()) {
vec = pse->t->get_sub_type()->get_subtype_parsed();
} else {
break;
}
}
if (vec == NULL) {
// I don't think it can happen, but to be sure...
s += "\"?\"";
continue;
}
s+= "\"";
if (vec->size() > 1) s+= "(";
for (size_t j = 0; j < vec->size(); j++) {
Common::SubTypeParse* stp = (*vec)[j];
if (j > 0) {
s+="|\"+"; // todo what if default
}else {
s+= "\"+";
}
switch (stp->get_selection()) {
case SubTypeParse::STP_RANGE: // type charstring ("a" .. "z")
s+="\"[\" + ";
switch (stp->Min()->get_valuetype()) {
case Value::V_CSTR:
s+= p_mod->add_charstring_literal(stp->Min()->get_val_str());
s+= "+ \"-\" +";
s+= p_mod->add_charstring_literal(stp->Max()->get_val_str());
break;
case Value::V_USTR:
s+= p_mod->add_charstring_literal(stp->Min()->get_val_ustr().get_stringRepr_for_pattern());
s+= "+ \"-\" +";
s+= p_mod->add_charstring_literal(stp->Max()->get_val_ustr().get_stringRepr_for_pattern());
break;
default:
FATAL_ERROR("PatternString::create_charstring_literals()");
}
s+=" + \"]\"";
break;
case SubTypeParse::STP_SINGLE: // type charstring ("a", "b")
switch (stp->Single()->get_valuetype()) {
case Value::V_CSTR:
s+= p_mod->add_charstring_literal(stp->Single()->get_val_str());
break;
case Value::V_USTR:
s+= p_mod->add_charstring_literal(stp->Single()->get_val_ustr().get_stringRepr_for_pattern());
break;
default:
FATAL_ERROR("PatternString::create_charstring_literals()");
break;
}
break;
default:
FATAL_ERROR("PatternString::create_charstring_literals()");
}
s+= "+\"";
}
if (vec->size() > 1) s+= ")";
s+= "\"";
break; }
// Not known in compile time
case ps_elem_t::PSE_REF: {
expression_struct expr;
Code::init_expr(&expr);
pse->ref->generate_code(&expr);
if (expr.preamble || expr.postamble)
FATAL_ERROR("PatternString::create_charstring_literals()");
s += expr.expr;
Common::Assignment* assign = pse->ref->get_refd_assignment();
char* str = NULL;
// TODO: these checks will generated each time a reference is referenced in a pattern
// and it could be generated once
if (pse->with_N) {
if ((assign->get_asstype() == Common::Assignment::A_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_MODULEPAR_TEMP
|| assign->get_asstype() == Common::Assignment::A_VAR_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_IN
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_OUT
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_INOUT))
{
string value_literal = p_mod->add_charstring_literal(string("value"));
str = mputprintf(str,
"if (%s.get_istemplate_kind(%s) == FALSE) {\n"
"TTCN_error(\"Only specific value template allowed in pattern reference with \\\\N{ref}\");\n"
"}\n"
, expr.expr
, value_literal.c_str());
}
str = mputprintf(str,
"if (%s.lengthof() != 1)\n"
"{\n"
"TTCN_error(\"The length of the %scharstring must be of length one, when it is being referenced in a pattern with \\\\N{ref}\");\n"
"}\n"
, expr.expr
, assign->get_Type()->get_typetype() == Type::T_USTR ? "universal " : "");
preamble += str;
Free(str);
}
if ((assign->get_asstype() == Common::Assignment::A_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_MODULEPAR_TEMP
|| assign->get_asstype() == Common::Assignment::A_VAR_TEMPLATE))
|| assign->get_asstype() == Common::Assignment::A_VAR_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_IN
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_OUT
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_INOUT))
{
if ((assign->get_Type()->get_typetype() == Type::T_CSTR
|| assign->get_Type()->get_typetype() == Type::T_USTR)) {
|| assign->get_Type()->get_typetype() == Type::T_USTR) && !pse->with_N) {
s += ".get_single_value()";
}
else {
else if (assign->get_Type()->get_typetype() == Type::T_USTR && pse->with_N) {
s += ".valueof().get_stringRepr_for_pattern()";
} else {
s += ".valueof()";
}
} else if ((assign->get_asstype() == Common::Assignment::A_MODULEPAR
|| assign->get_asstype() == Common::Assignment::A_VAR
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL_IN
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL_OUT
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL_INOUT)
&& assign->get_Type()->get_typetype() == Type::T_USTR) {
s += ".get_stringRepr_for_pattern()";
}
Code::free_expr(&expr);
break; }
} // switch kind
Code::free_expr(&expr);
break; }
} // switch kind
} // for
} else {
// empty pattern: create an empty string literal for it
......
......@@ -69,8 +69,7 @@ namespace Ttcn {
void addString(const char *p_str);
void addString(const string& p_str);
void addStringUSI(char **usi_str, const size_t size);
void addRef(Ttcn::Reference *p_ref);
void addRefdCharSet(Ttcn::Reference *p_ref);
void addRef(Ttcn::Reference *p_ref, boolean N);
string get_full_str() const;
void set_pattern_type(pstr_type_t p_type);
......@@ -88,7 +87,7 @@ namespace Ttcn {
* generation. */
void join_strings();
/** Temporary hack... */
string create_charstring_literals(Common::Module *p_mod);
string create_charstring_literals(Common::Module *p_mod, string& preamble);
virtual void dump(unsigned level) const;
/** Called by Value::get_value_refd_last() */
......
......@@ -5028,7 +5028,7 @@ error:
// make sure all possible indices are allowed by the element
// type's subtype
for (size_t i = 0; i < nof_dims; ++i) {
Error_Context cntxt(p_index_ref, "In dimension #%lu",
Error_Context context(p_index_ref, "In dimension #%lu",
(unsigned long)(i + 1));
ArrayDimension* dim = p_array_dims->get_dim_byIndex(i);
for (size_t j = 0; j < dim->get_size(); ++j) {
......
......@@ -3109,10 +3109,14 @@ end:
case BSTR_PATTERN:
case HSTR_PATTERN:
case OSTR_PATTERN:
case CSTR_PATTERN:
case USTR_PATTERN:
str = mputprintf(str, "%s = %s;\n", name, get_single_expr(false).c_str());
break;
break;
case CSTR_PATTERN:
case USTR_PATTERN: {
string preamble;
string expr = generate_code_str_pattern(false, preamble);
str = mputprintf(str, "%s%s = %s;\n", preamble.c_str(), name, expr.c_str());
break; }
case SPECIFIC_VALUE:
if (get_code_section() == CS_POST_INIT)
str = u.specific_value->rearrange_init_code(str, my_scope->get_scope_mod_gen());
......@@ -4846,10 +4850,11 @@ compile_time:
case BSTR_PATTERN:
case HSTR_PATTERN:
case OSTR_PATTERN:
case CSTR_PATTERN:
case USTR_PATTERN:
case TEMPLATE_NOTUSED:
return true;
case CSTR_PATTERN: // Some preamble needed when \N{ref} used
case USTR_PATTERN:
return false;
case SPECIFIC_VALUE:
return u.specific_value->has_single_expr();
case TEMPLATE_REFD: {
......@@ -4893,6 +4898,25 @@ compile_time:
}
}
string Template::generate_code_str_pattern(bool cast_needed, string& preamble) {
if (cast_needed && (length_restriction || is_ifpresent))
FATAL_ERROR("Template::generate_code_str_pattern()");
string ret_val;
switch(templatetype) {
case CSTR_PATTERN:
case USTR_PATTERN:
ret_val = u.pstring
->create_charstring_literals(get_my_scope()->get_scope_mod_gen(), preamble);
break;
default:
FATAL_ERROR("Template::generate_code_str_pattern()");
}
if (cast_needed) ret_val = my_governor->get_genname_template(my_scope) +
"(" + ret_val + ")";
return ret_val;
}
string Template::get_single_expr(bool cast_needed)
{
if (cast_needed && (length_restriction || is_ifpresent))
......@@ -4955,10 +4979,6 @@ compile_time:
case OSTR_PATTERN:
return get_my_scope()->get_scope_mod_gen()
->add_octetstring_pattern(*u.pattern);
case CSTR_PATTERN:
case USTR_PATTERN:
return u.pstring
->create_charstring_literals(get_my_scope()->get_scope_mod_gen());
default:
FATAL_ERROR("Template::get_single_expr()");
}
......
......@@ -480,6 +480,8 @@ namespace Ttcn {
char *generate_code_init_all_from(char *str, const char *name);
char *generate_code_init_all_from_list(char *str, const char *name);
string generate_code_str_pattern(bool cast_needed, string& preamble);
/** Helper function for \a generate_code_expr() and get_single_expr().
* It handles the invoke operation. */
......
......@@ -182,7 +182,7 @@ if (in_set) {
Location loc(current_file, old_line, old_column, current_line, current_column);
if (ref) {
ref->set_location(loc);
ps->addRef(ref);
ps->addRef(ref, FALSE);
} else {
loc.error("Invalid reference expression");
}
......@@ -213,26 +213,42 @@ if (in_set) {
while (isalnum(yytext[id_begin + id_len]) || yytext[id_begin + id_len] == '_')
id_len++;
string id_str(id_len, yytext + id_begin);
/*
Ttcn::Reference *ref = new Ttcn::Reference(new Identifier(
Identifier::ID_TTCN, id_str));
ref->set_location(loc);
ps->addRefdCharSet(ref);
*/
ps->addRef(ref, TRUE);
int first_line = current_line, first_column = current_column;
UPDATE_LOCATION(0, yyleng);
Location loc(current_file, first_line, first_column, current_line,
current_column);
ref->set_location(loc);
if (Identifier::is_reserved_word(id_str, Identifier::ID_TTCN)) {
loc.error("Invalid character set reference: `%s' is a reserved word in "
"TTCN-3", id_str.c_str());
} else if (in_set) {
loc.warning("Character set reference `\\N{%s}' is not supported, "
"dropped out from the set", id_str.c_str());
} else {
}
}
"\\N"{WS}"{"{WS}"universal"{WS}"charstring"{WS}"}" {
/** The third {WS} is optional but if it's empty then the previous rule catches it**/
string id_str("universal charstring");
Ttcn::Reference *ref = new Ttcn::Reference(new Identifier(
Identifier::ID_TTCN, id_str));
ps->addRef(ref, TRUE);
int first_line = current_line, first_column = current_column;
UPDATE_LOCATION(0, yyleng);
Location loc(current_file, first_line, first_column, current_line,
current_column);
ref->set_location(loc);
if (in_set) {
loc.warning("Character set reference `\\N{%s}' is not supported, "
"substituted with `?'", id_str.c_str());
ps->addChar('?');
"dropped out from the set", id_str.c_str());
}
}
......
......@@ -11,7 +11,7 @@
# Ormandi, Matyas
#
##############################################################################
SADIRS := ver xer encode param template any_from
SADIRS := ver xer encode param template any_from pattern_ref
ifeq ($(RT2), yes)
SADIRS += deprecated
endif
......
##############################################################################
# Copyright (c) 2000-2016 Ericsson Telecom AB
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
# Bence Janos Szabo
#
##############################################################################
include ../common.mk