Commit 28352dbd authored by Botond Baranyi's avatar Botond Baranyi
Browse files

implemented decmatch (artf724241)



Change-Id: I12c5ff280fa50a82db3ce4096f796146fe94dd38
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent b0caada2
......@@ -598,6 +598,7 @@ namespace Common {
{"char2int__", "char2int", "char2int_"},
{"char2oct__", "char2oct", "char2oct_"},
{"component__", "component", "component_"},
{"decmatch__", "decmatch", "decmatch_"},
{"decomp__", "decomp", "decomp_"},
{"float2int__", "float2int", "float2int_"},
{"float2str__", "float2str", "float2str_"},
......
......@@ -815,7 +815,8 @@ namespace Common {
void chk_this_template_length_restriction(Template *t);
bool chk_this_template(Template *t, namedbool is_modified, namedbool sub_chk,
namedbool implicit_omit, Common::Assignment *);
void chk_this_template_Str(Template *t);
bool chk_this_template_Str(Template *t, namedbool implicit_omit,
Common::Assignment *lhs);
/** Checks whether \a v is a correct range boundary for this type.
* Applicable to the following types: integer, float, charstring,
* universal charstring.
......
......@@ -5624,7 +5624,7 @@ bool Type::chk_this_template(Template *t, namedbool is_modified, namedbool,
case T_UTCTIME:
case T_GENERALIZEDTIME:
case T_OBJECTDESCRIPTOR:
t_last->chk_this_template_Str(t);
self_ref = t_last->chk_this_template_Str(t, implicit_omit, lhs);
break;
case T_INT:
case T_INT_A:
......@@ -5676,8 +5676,10 @@ bool Type::chk_this_template(Template *t, namedbool is_modified, namedbool,
return self_ref;
}
void Type::chk_this_template_Str(Template *t)
bool Type::chk_this_template_Str(Template *t, namedbool implicit_omit,
Common::Assignment *lhs)
{
bool self_ref = false;
typetype_t tt = get_typetype_ttcn3(typetype);
bool report_error = false;
switch (t->get_templatetype()) {
......@@ -5737,6 +5739,48 @@ void Type::chk_this_template_Str(Template *t)
if (!pstr->has_refs()) pstr->chk_pattern();
} else report_error = true;
break;
case Ttcn::Template::DECODE_MATCH:
{
Error_Context cntxt(t, "In decoding target");
TemplateInstance* target = t->get_decode_target();
target->get_Template()->set_lowerid_to_ref();
Type* target_type = target->get_expr_governor(EXPECTED_TEMPLATE);
if (target_type == NULL) {
target->error("Type of template instance cannot be determined");
break;
}
if (target->get_Type() != NULL) {
target_type = target_type->get_type_refd();
}
self_ref = target_type->chk_this_template_generic(
target->get_Template(), (target->get_DerivedRef() != NULL) ?
INCOMPLETE_ALLOWED : INCOMPLETE_NOT_ALLOWED,
OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, lhs);
target_type->get_type_refd_last()->chk_coding(false);
}
{
Value* str_enc = t->get_string_encoding();
if (str_enc != NULL) {
if (tt != T_USTR) {
str_enc->error("The encoding format parameter is only available to "
"universal charstring templates");
break;
}
Error_Context cntxt(t, "In encoding format");
str_enc->set_lowerid_to_ref();
get_pooltype(T_CSTR)->chk_this_value(str_enc, lhs, EXPECTED_DYNAMIC_VALUE,
INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK);
if (!str_enc->is_unfoldable()) {
string enc_name = str_enc->get_val_str();
if (enc_name != "UTF-8" && enc_name != "UTF-16" && enc_name != "UTF-32"
&& enc_name != "UTF-16LE" && enc_name != "UTF-16BE"
&& enc_name != "UTF-32LE" && enc_name != "UTF-32BE") {
str_enc->error("'%s' is not a valid encoding format", enc_name.c_str());
}
}
}
}
break;
default:
report_error = true;
break;
......@@ -5745,6 +5789,7 @@ void Type::chk_this_template_Str(Template *t)
t->error("%s cannot be used for type `%s'", t->get_templatetype_str(),
get_typename().c_str());
}
return self_ref;
}
void Type::chk_range_boundary_infinity(Value *v, bool is_upper)
......
......@@ -10085,6 +10085,9 @@ error:
break; // self-ref can't happen
case Ttcn::Template::TEMPLATE_INVOKE:
break; // assume self-ref can't happen
case Ttcn::Template::DECODE_MATCH:
self_ref |= chk_expr_self_ref_templ(t->get_decode_target()->get_Template(), lhs);
break;
case Ttcn::Template::TEMPLATE_ERROR:
//FATAL_ERROR("Value::chk_expr_self_ref_templ()");
break;
......
......@@ -1951,6 +1951,7 @@ void SubType::chk_this_template(Template *templ)
break;
case Template::ALL_FROM:
case Template::VALUE_LIST_ALL_FROM:
case Template::DECODE_MATCH:
break;
case Template::SUPERSET_MATCH:
case Template::SUBSET_MATCH:
......
......@@ -8119,6 +8119,9 @@ namespace Ttcn {
} // next
break; }
case Template::DECODE_MATCH:
chk_defpar_template(body->get_decode_target()->get_Template(), exp_val);
break;
} // switch templatetype
}
......
......@@ -92,6 +92,11 @@ namespace Ttcn {
case USTR_PATTERN:
u.pstring = p.u.pstring->clone();
break;
case DECODE_MATCH:
u.dec_match.str_enc = p.u.dec_match.str_enc != NULL ?
p.u.dec_match.str_enc->clone() : NULL;
u.dec_match.target = p.u.dec_match.target->clone();
break;
// default:
// FATAL_ERROR("Template::Template()");
}
......@@ -149,6 +154,12 @@ namespace Ttcn {
case USTR_PATTERN:
delete u.pstring;
break;
case DECODE_MATCH:
if (u.dec_match.str_enc != NULL) {
delete u.dec_match.str_enc;
}
delete u.dec_match.target;
break;
// default:
// FATAL_ERROR("Template::clean_up()");
}
......@@ -272,6 +283,18 @@ namespace Ttcn {
ret_val += u.pstring->get_full_str();
ret_val += "\"";
break;
case DECODE_MATCH:
ret_val += "decmatch ";
if (u.dec_match.str_enc != NULL) {
ret_val += "(";
ret_val += u.dec_match.str_enc->get_val_str();
ret_val += ") ";
}
ret_val += u.dec_match.target->get_expr_governor(
Type::EXPECTED_TEMPLATE)->get_stringRepr();
ret_val += ": ";
ret_val += u.dec_match.target->get_Template()->create_stringRepr();
break;
default:
ret_val += "<unknown template>";
break;
......@@ -441,6 +464,19 @@ namespace Ttcn {
if (!p_ps) FATAL_ERROR("Template::Template()");
u.pstring = p_ps;
}
Template::Template(Value* v, TemplateInstance* ti)
: GovernedSimple(S_TEMPLATE),
templatetype(DECODE_MATCH), my_governor(0), length_restriction(0),
is_ifpresent(false), specific_value_checked(false),
has_permutation(false), flattened(true), base_template(0)
{
if (ti == NULL) {
FATAL_ERROR("Template::Template()");
}
u.dec_match.str_enc = v;
u.dec_match.target = ti;
}
Template::~Template()
{
......@@ -513,6 +549,12 @@ namespace Ttcn {
case USTR_PATTERN:
u.pstring->set_fullname(p_fullname);
break;
case DECODE_MATCH:
if (u.dec_match.str_enc != NULL) {
u.dec_match.str_enc->set_fullname(p_fullname + ".<string_encoding>");
}
u.dec_match.target->set_fullname(p_fullname + ".<decoding_target>");
break;
// default:
// FATAL_ERROR("Template::set_fullname()");
}
......@@ -569,6 +611,12 @@ namespace Ttcn {
case USTR_PATTERN:
u.pstring->set_my_scope(p_scope);
break;
case DECODE_MATCH:
if (u.dec_match.str_enc != NULL) {
u.dec_match.str_enc->set_my_scope(p_scope);
}
u.dec_match.target->set_my_scope(p_scope);
break;
// default:
// FATAL_ERROR("Template::set_my_scope()");
}
......@@ -681,6 +729,12 @@ namespace Ttcn {
case USTR_PATTERN:
u.pstring->set_code_section(p_code_section);
break;
case DECODE_MATCH:
if (u.dec_match.str_enc != NULL) {
u.dec_match.str_enc->set_code_section(p_code_section);
}
u.dec_match.target->set_code_section(p_code_section);
break;
default:
break;
}
......@@ -849,6 +903,8 @@ namespace Ttcn {
return "character string pattern";
case USTR_PATTERN:
return "universal string pattern";
case DECODE_MATCH:
return "decoded content match";
default:
return "unknown template";
}
......@@ -1297,6 +1353,22 @@ namespace Ttcn {
}
return t;
}
Value* Template::get_string_encoding() const
{
if (templatetype != DECODE_MATCH) {
FATAL_ERROR("Template::get_decode_target()");
}
return u.dec_match.str_enc;
}
TemplateInstance* Template::get_decode_target() const
{
if (templatetype != DECODE_MATCH) {
FATAL_ERROR("Template::get_decode_target()");
}
return u.dec_match.target;
}
Template* Template::get_template_refd(ReferenceChain *refch)
{
......@@ -1867,6 +1939,9 @@ namespace Ttcn {
case USTR_PATTERN:
t->u.pstring->chk_recursions(refch);
break;
case DECODE_MATCH:
t->u.dec_match.target->chk_recursions(refch);
break;
default:
break;
}
......@@ -2551,7 +2626,7 @@ end:
case VALUE_RANGE:
case ALL_FROM:
case BSTR_PATTERN: case HSTR_PATTERN: case OSTR_PATTERN:
case CSTR_PATTERN: case USTR_PATTERN:
case CSTR_PATTERN: case USTR_PATTERN: case DECODE_MATCH:
break; // NOP
}
......@@ -3053,6 +3128,9 @@ end:
warning("Don't know how to init PERMUT");
str = mputprintf(str, "/* FIXME: PERMUT goes here, name=%s*/\n", name);
break;
case DECODE_MATCH:
str = generate_code_init_dec_match(str, name);
break;
case TEMPLATE_NOTUSED:
break;
case TEMPLATE_ERROR:
......@@ -3329,6 +3407,7 @@ end:
switch (templatetype) {
case ALL_FROM:
case VALUE_LIST_ALL_FROM:
case DECODE_MATCH:
return false;
case TEMPLATE_ERROR: /**< erroneous template */
case TEMPLATE_NOTUSED: /**< not used symbol (-) */
......@@ -4432,6 +4511,108 @@ compile_time:
}
return str;
}
char* Template::generate_code_init_dec_match(char* str, const char* name)
{
// generate a new class for this decmatch template
string class_tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id();
Type* target_type = u.dec_match.target->get_expr_governor(
Type::EXPECTED_TEMPLATE)->get_type_refd_last();
// use the name of the type at the end of the reference chain for logging
const char* type_name_ptr = target_type->get_typename_builtin(
target_type->get_typetype_ttcn3());
if (type_name_ptr == NULL) {
type_name_ptr = target_type->get_type_refd_last()->get_dispname().c_str();
}
// copy the character pointer returned by Type::get_dispname() as it might
// change before its use
char* type_name = mcopystr(type_name_ptr);
str = mputprintf(str,
"class Dec_Match_%s : public Dec_Match_Interface {\n"
// store the decoding target as a member, since both functions use it
"%s target;\n"
"public:\n"
"Dec_Match_%s(%s p_target): target(p_target) { }\n"
// called when matching, the buffer parameter contains the string to be matched
"virtual boolean match(TTCN_Buffer& buff) const\n"
"{\n"
"%s val;\n"
// decode the value
"val.decode(%s_descr_, buff, TTCN_EncDec::CT_%s);\n"
// make sure the buffer is empty after decoding and no errors occurred
"if (TTCN_EncDec::get_last_error_type() != TTCN_EncDec::ET_NONE || "
"buff.get_read_len() != 0) return FALSE;\n"
// finally, match the decoded value against the target template
"return target.match(val%s);\n"
"}\n"
"virtual void log() const\n"
"{\n"
// the decoding target is always logged as an in-line template
"TTCN_Logger::log_event_str(\"%s: \");\n"
"target.log();\n"
"}\n"
"};\n"
"%s.set_type(DECODE_MATCH);\n"
"{\n", class_tmp_id.c_str(),
target_type->get_genname_template(my_scope).c_str(), class_tmp_id.c_str(),
target_type->get_genname_template(my_scope).c_str(),
target_type->get_genname_value(my_scope).c_str(),
target_type->get_genname_typedescriptor(my_scope).c_str(),
target_type->get_coding(false).c_str(),
omit_in_value_list ? ", TRUE" : "", type_name, name);
Free(type_name);
// generate the decoding target into a temporary
string target_tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id();
if (u.dec_match.target->get_DerivedRef() != NULL) {
// it's a derived reference: initialize the decoding target with the
// base template first
expression_struct ref_expr;
Code::init_expr(&ref_expr);
u.dec_match.target->get_DerivedRef()->generate_code(&ref_expr);
if (ref_expr.preamble != NULL) {
str = mputstr(str, ref_expr.preamble);
}
str = mputprintf(str, "%s %s(%s);\n",
target_type->get_genname_template(my_scope).c_str(),
target_tmp_id.c_str(), ref_expr.expr);
if (ref_expr.postamble != NULL) {
str = mputstr(str, ref_expr.postamble);
}
Code::free_expr(&ref_expr);
}
else {
str = mputprintf(str, "%s %s;\n",
target_type->get_genname_template(my_scope).c_str(),
target_tmp_id.c_str());
}
str = u.dec_match.target->get_Template()->generate_code_init(str,
target_tmp_id.c_str());
// the string encoding format might be an expression, generate its preamble here
expression_struct coding_expr;
Code::init_expr(&coding_expr);
if (u.dec_match.str_enc != NULL) {
u.dec_match.str_enc->generate_code_expr(&coding_expr);
if (coding_expr.preamble != NULL) {
str = mputstr(str, coding_expr.preamble);
}
}
// initialize the decmatch template with an instance of the new class
// (pass the temporary template to the new instance's constructor) and
// the encoding format if it's an universal charstring
str = mputprintf(str,
"%s.set_decmatch(new Dec_Match_%s(%s)%s%s);\n",
name, class_tmp_id.c_str(), target_tmp_id.c_str(),
(coding_expr.expr != NULL) ? ", " : "",
(coding_expr.expr != NULL) ? coding_expr.expr : "");
if (coding_expr.postamble != NULL) {
str = mputstr(str, coding_expr.postamble);
}
Code::free_expr(&coding_expr);
str = mputstr(str, "}\n");
return str;
}
void Template::generate_code_expr_invoke(expression_struct *expr)
{
......@@ -4564,6 +4745,7 @@ compile_time:
case VALUE_RANGE:
case SUPERSET_MATCH:
case SUBSET_MATCH:
case DECODE_MATCH:
return true;
case TEMPLATE_ERROR:
FATAL_ERROR("Template::needs_temp_ref()");
......@@ -4621,6 +4803,7 @@ compile_time:
case SUPERSET_MATCH:
case SUBSET_MATCH:
case PERMUTATION_MATCH:
case DECODE_MATCH:
return false;
case ALL_FROM:
case VALUE_LIST_ALL_FROM:
......@@ -4758,6 +4941,14 @@ compile_time:
case VALUE_LIST_ALL_FROM:
u.all_from->dump(level+1);
break;
case DECODE_MATCH:
if (u.dec_match.str_enc != NULL) {
DEBUG(level, "string encoding:");
u.dec_match.str_enc->dump(level + 1);
}
DEBUG(level, "decoding target:");
u.dec_match.target->dump(level + 1);
break;
default:
break;
}
......
......@@ -68,7 +68,8 @@ namespace Ttcn {
HSTR_PATTERN, /**< hexstring pattern */
OSTR_PATTERN, /**< octetstring pattern */
CSTR_PATTERN, /**< character string pattern */
USTR_PATTERN /**< universal charstring pattern */
USTR_PATTERN, /**< universal charstring pattern */
DECODE_MATCH /**< decoded content match */
};
/** Status codes for the verification of template body completeness. */
......@@ -122,6 +123,11 @@ namespace Ttcn {
Ttcn::ParsedActualParameters *t_list;
Ttcn::ActualParList *ap_list;
} invoke;
/** Used by DECODE_MATCH */
struct {
Value* str_enc;
TemplateInstance* target;
} dec_match;
} u;
/** This points to the type of the template */
......@@ -203,6 +209,9 @@ namespace Ttcn {
/** Constructor for CSTR_PATTERN. */
Template(PatternString *p_ps);
/** Constructor for DECODE_MATCH */
Template(Value* v, TemplateInstance* ti);
virtual ~Template();
......@@ -289,6 +298,8 @@ namespace Ttcn {
Template* get_refd_sub_template(Ttcn::FieldOrArrayRefs *subrefs,
bool usedInIsbound,
ReferenceChain *refch);
Value* get_string_encoding() const;
TemplateInstance* get_decode_target() const;
private:
Template* get_template_refd(ReferenceChain *refch);
Template* get_refd_field_template(const Identifier& field_id,
......@@ -462,6 +473,8 @@ namespace Ttcn {
* representations in runtime. */
char *generate_code_init_set(char *str, const char *name,
bool is_superset);
char* generate_code_init_dec_match(char* str, const char* name);
char *generate_code_init_all_from(char *str, const char *name);
char *generate_code_init_all_from_list(char *str, const char *name);
......
......@@ -390,6 +390,7 @@ const RETURN(ConstKeyword);
continue RETURN(ContinueKeyword);
control RETURN(ControlKeyword);
create RETURN_DOT(CreateKeyword);
decmatch RETURN(DecodedMatchKeyword);
deactivate RETURN(DeactivateKeyword);
default RETURN(DefaultKeyword);
derefers RETURN(DerefersKeyword);
......
......@@ -535,6 +535,11 @@ static const string anyname("anytype");
struct {
visibility_t visibility;
} visbilitytype;
struct {
Value* string_encoding;
TemplateInstance* target_template;
} decode_match;
}
/* Tokens of TTCN-3 */
......@@ -604,6 +609,7 @@ static const string anyname("anytype");
%token ContinueKeyword
%token ControlKeyword
%token CreateKeyword
%token DecodedMatchKeyword
%token DeactivateKeyword
%token DefaultKeyword
%token DerefersKeyword
......@@ -1047,6 +1053,7 @@ static const string anyname("anytype");
%type <float_val> FloatOrSpecialFloatValue
%type <erroneous_indicator> ErroneousIndicator
%type <imptype> ImportSpec ImportElement
%type <decode_match> DecodedContentMatch
/*********************************************************************
* Destructors
......@@ -1737,6 +1744,14 @@ PortElementList
}
optRunsOnComprefOrSelf
%destructor {
if ($$.string_encoding != NULL) {
delete $$.string_encoding;
}
delete $$.target_template;
}
DecodedContentMatch
/*********************************************************************
* Operator precedences (lowest first)
*********************************************************************/
......@@ -1756,12 +1771,12 @@ optRunsOnComprefOrSelf
%left '*' '/' ModKeyword RemKeyword
%left UnarySign
%expect 26
%expect 53
%start GrammarRoot
/*
XXX Source of conflicts (26 S/R):
XXX Source of conflicts (53 S/R):
1.) 9 conflicts in one state
The Expression after 'return' keyword is optional in ReturnStatement.
......@@ -1769,7 +1784,7 @@ For 9 tokens the parser cannot decide whether the token is a part of
the return expression (shift) or it is the beginning of the next statement
(reduce).
2.) 9 distinct states, each with one conflict caused by token '['
2.) 10 distinct states, each with one conflict caused by token '['
The local definitions in altsteps can be followed immediately by the guard
expression. When the parser sees the '[' token it cannot decide whether it
belongs to the local definition as array dimension or array subreference
......@@ -1784,6 +1799,7 @@ The situations are the following:
- var t v := ref.objid{...}.subref <here> [
- var template t v <here> [
- var t v := function(...)<subrefs> <here> [
- var template t v := decmatch (...) ref <here> [
3.) 1 conflict
The sequence identifier.objid can be either the beginning of a module name
......@@ -1800,6 +1816,13 @@ non-standard language extension.
6.) 1 Conflict due to pattern concatenation
7.) 26 conflicts in one state
In the DecodedContentMatch rule a SingleExpression encased in round brackets is
followed by an in-line template. For 26 tokens (after the ')' ) the parser cannot
decide whether the token is the beginning of the in-line template (shift) or
the brackets are only part of the SingleExpression itself and the conflicting
token is the next segment in the expression (reduce).
Note that the parser implemented by bison always chooses to shift instead of
reduce in case of conflicts.
*/
......@@ -3176,6 +3199,11 @@ TemplateBody: // 101 is a Template*
$$->set_length_restriction($2.len_restr);
$$->set_ifpresent($2.is_ifpresent);
}
| DecodedContentMatch
{
$$ = new Template($1.string_encoding, $1.target_template);
$$->set_location(infile, @$);
}
;
SimpleSpec: // 102
......@@ -3546,6 +3574,19 @@ PermutationMatch: // 137 is a Templates*
PermutationKeyword ValueList { $$ = $2; }
;
DecodedContentMatch:
DecodedMatchKeyword '(' SingleExpression ')' InLineTemplate
{
$$.string_encoding = $3;
$$.target_template = $5;
}
| DecodedMatchKeyword InLineTemplate
{
$$.string_encoding = NULL;
$$.target_template = $2;
}
;
AnyValue: // 140
'?'
;
......
......@@ -1087,4 +1087,17 @@ public:
}
};
/** Interface/base class for decoded content matching
*
* For every decmatch template the compiler generates a new class that inherits
* this one and implements its virtual functions. An instance of the new class
* is stored in the template object, which calls the appropriate virtual
* functions when the template object's match() or log() functions are called. */
class Dec_Match_Interface {
public:
virtual boolean match(TTCN_Buffer&) const = 0;