Commit 7f35690d authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Reworked the checking of coding methods for types (bug 509304)



Change-Id: I872b16f62a4ba5941aa8fe1c6cd58578778eedf3
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 1ea6111d
......@@ -305,6 +305,13 @@ namespace Common {
void Modules::delay_type_encode_check(Type* p_type, bool p_encode)
{
for (size_t i = 0; i < delayed_type_enc_v.size(); ++i) {
if (delayed_type_enc_v[i]->t == p_type &&
delayed_type_enc_v[i]->enc == p_encode) {
// it's already in the list of delayed checks
return;
}
}
type_enc_t* elem = new type_enc_t;
elem->t = p_type;
elem->enc = p_encode;
......
......@@ -607,10 +607,8 @@ namespace Common {
chk_finished = false;
pard_type_instance = false;
needs_any_from_done = false;
encoding_by_function = false;
decoding_by_function = false;
asn_encoding = CT_UNDEF;
asn_decoding = CT_UNDEF;
default_encoding.type = CODING_UNSET;
default_decoding.type = CODING_UNSET;
}
void Type::clean_up()
......@@ -4396,60 +4394,70 @@ namespace Common {
}
}
void Type::set_coding_function(bool encode, const string& function_name)
{
string& coding_function = encode ? encoding_function : decoding_function;
MessageEncodingType_t& asn_coding = encode ? asn_encoding : asn_decoding;
bool& coding_by_function = encode ?
encoding_by_function : decoding_by_function;
if (!coding_function.empty()) {
// leave coding_by_function as true, this will indicate that there are
// multiple coding functions set
coding_function.clear();
void Type::set_coding_function(bool encode, Assignment* function_def)
{
if (function_def == NULL) {
FATAL_ERROR("Type::set_coding_function");
}
else if (asn_coding != CT_UNDEF) {
// a different encoding type is already set for the ASN.1 type
asn_coding = CT_MULTIPLE;
coding_function.clear();
return;
coding_t& coding = encode ? default_encoding : default_decoding;
if (coding.type == CODING_UNSET) {
// no coding method has been set yet -> OK
coding.type = CODING_BY_FUNCTION;
coding.function_def = function_def;
}
else {
if (is_asn1()) {
asn_coding = CT_PER;
}
coding_function = function_name;
coding_by_function = true;
// something has already been set -> not OK
// (the type might never be encoded/decoded, so don't report an error yet)
coding.type = CODING_MULTIPLE;
}
}
void Type::set_asn_coding(bool encode, Type::MessageEncodingType_t new_coding)
{
MessageEncodingType_t& coding = encode ? asn_encoding : asn_decoding;
bool& coding_by_function = encode ?
encoding_by_function : decoding_by_function; // true = PER coder is set
string& coding_function = encode ? encoding_function : decoding_function; // PER coder
if (coding == CT_UNDEF && !coding_by_function) {
// this is the first encoding/decoding function for this type, store it
// (also, no PER coders have been set for the type yet)
coding = new_coding;
coding_t& coding = encode ? default_encoding : default_decoding;
if (coding.type == CODING_UNSET) {
// no coding method has been set yet -> OK
coding.type = CODING_BUILT_IN;
coding.built_in_coding = new_coding;
}
else if (coding != new_coding || coding_by_function) {
// there are several encoding/decoding functions declared for this type
// with different codings (encvalue/decvalue cannot be used in this case)
coding_function.clear();
coding = CT_MULTIPLE;
else if (coding.type != CODING_BUILT_IN ||
coding.built_in_coding != new_coding) {
// a different codec or a coder function has already been set -> not OK
// (the type might never be encoded/decoded, so don't report an error yet)
coding.type = CODING_MULTIPLE;
}
}
void Type::chk_coding(bool encode, bool delayed /* = false */) {
string& coding_str = encode ? encoding_str : decoding_str;
if (!coding_str.empty())
coding_t& coding = encode ? default_encoding : default_decoding;
switch (coding.type) {
case CODING_BY_FUNCTION:
case CODING_BUILT_IN:
if (!delayed) {
// a coding method has been set by an external function's checker,
// but there might still be unchecked external functions out there;
// delay this function until everything else has been checked
Modules::delay_type_encode_check(this, encode);
}
return;
bool& coding_by_function = encode ?
encoding_by_function : decoding_by_function;
Type::MessageEncodingType_t coding = CT_UNDEF;
case CODING_UNSET:
if (!delayed) {
// this is the only case in the switch that doesn't return immediately
break;
}
// else fall through
case CODING_MULTIPLE:
error("Cannot determine the %s rules for type `%s'. "
"%s %s external functions found%s", encode ? "encoding" : "decoding",
get_typename().c_str(), coding.type == CODING_UNSET ? "No" : "Multiple",
encode ? "encoding" : "decoding",
(coding.type == CODING_MULTIPLE && is_asn1()) ? " with different rules" : "");
return;
default:
FATAL_ERROR("Type::chk_coding");
}
if (!is_asn1()) {
if (!is_asn1()) { // TTCN-3 types
if (!w_attrib_path) {
error("No coding rule specified for type '%s'", get_typename().c_str());
return;
......@@ -4484,17 +4492,19 @@ namespace Common {
{
if (target->get_mapping_type() ==
Ttcn::TypeMappingTarget::TM_FUNCTION) {
if (!coding_str.empty())
if (coding.type != CODING_UNSET) {
target->error("Multiple definition of this target");
coding_str = target->get_function()->
get_genname_from_scope(my_scope);
coding_by_function = true;
}
else {
coding.type = CODING_BY_FUNCTION;
coding.function_def = target->get_function();
}
} else {
target->error("Only function is supported to do this mapping");
}
}
}
if (coding_str.empty()) {
if (coding.type == CODING_UNSET) {
ea.warning("Extension attribute is found for %s but without "
"typemappings", encode ? "encvalue" : "decvalue");
}
......@@ -4516,7 +4526,7 @@ namespace Common {
delete extatrs;
}
if (!coding_str.empty())
if (coding.type != CODING_UNSET)
return;
end_ext:
......@@ -4527,107 +4537,83 @@ namespace Common {
if (real_attribs[i-1]->get_attribKeyword()
== SingleWithAttrib::AT_ENCODE) {
found = true;
coding = get_enc_type(*real_attribs[i-1]);
coding.type = CODING_BUILT_IN;
coding.built_in_coding = get_enc_type(*real_attribs[i-1]);
}
}
if (coding == CT_UNDEF) {
if (coding.type == CODING_UNSET) {
// no "encode" attribute found
error("No coding rule specified for type '%s'", get_typename().c_str());
return;
}
}
else { // ASN.1 type
coding = encode ? asn_encoding : asn_decoding;
if ((coding == CT_UNDEF && delayed) || coding == CT_MULTIPLE) {
// either this is the delayed call and no external functions have been
// found, or there was already more than one function
error("Cannot determine the %s rules for ASN.1 type `%s'. "
"%s %s external functions found%s", encode ? "encoding" : "decoding",
get_typename().c_str(), coding == CT_UNDEF ? "No" : "Multiple",
encode ? "encoding" : "decoding",
coding == CT_UNDEF ? "" : " with different rules");
return;
}
if (!delayed) {
// there have been no errors so far in determining the coding type,
// but there might still be unchecked external functions out there;
if (coding.built_in_coding == CT_CUSTOM) {
// the type has a custom encoding attribute, but no external coder
// function with that encoding has been found yet;
// delay this function until everything else has been checked
Modules::delay_type_encode_check(this, encode);
return;
// set the coding type back to UNSET for delayed call
coding.type = CODING_UNSET;
}
else if (!has_encoding(coding.built_in_coding)) {
error("Type '%s' cannot be coded with the selected method '%s'",
get_typename().c_str(), get_encoding_name(coding.built_in_coding));
}
}
if (coding != CT_CUSTOM && !has_encoding(coding)) {
error("Type '%s' cannot be coded with the selected method '%s'",
get_typename().c_str(),
get_encoding_name(coding));
return;
}
switch (coding) {
case CT_RAW:
coding_str = "RAW";
break;
case CT_TEXT:
coding_str = "TEXT";
break;
case CT_XER:
coding_str = "XER, XER_EXTENDED"; // TODO: fine tuning this parameter
break;
case CT_JSON:
coding_str = "JSON, FALSE"; // with compact printing
break;
case CT_BER: {
coding_str = "BER, ";
BerAST* ber = berattrib;
if (!ber) // use default settings if attributes are not specified
ber = new BerAST;
if (encode)
coding_str += ber->get_encode_str();
else
coding_str += ber->get_decode_str();
if (!berattrib)
delete ber;
break; }
case CT_PER:
case CT_CUSTOM: {
// the coding function is set by its semantic checker in this case
string& coding_function = encode ? encoding_function : decoding_function;
if (coding_function.empty() && coding_by_function) {
error("Multiple %s %s functions set for type `%s'",
get_encoding_name(coding), encode ? "encoding" : "decoding",
get_typename().c_str());
}
else if (!delayed) {
// there have been no errors so far in determining the coding function,
// but there might still be unchecked external functions out there;
// delay this function until everything else has been checked
Modules::delay_type_encode_check(this, encode);
}
else if (coding_function.empty()) {
// this is the delayed call, and the coding function has still not been set
error("No %s %s function found for type `%s'", get_encoding_name(coding),
encode ? "encoding" : "decoding", get_typename().c_str());
}
else {
// this is the delayed call, and exactly one coding function has been set
coding_str = coding_function;
}
return; }
default:
error("Unknown coding selected for type '%s'", get_typename().c_str());
break;
else { // ASN.1 type
// delay this function until everything else has been checked, in case
// there is an encoder/decoder external function out there for this type
Modules::delay_type_encode_check(this, encode);
}
coding_by_function = false;
}
bool Type::is_coding_by_function(bool encode) const {
return encode ? encoding_by_function : decoding_by_function;
return (encode ? default_encoding : default_decoding).type == CODING_BY_FUNCTION;
}
const string& Type::get_coding(bool encode) const {
if (encode)
return encoding_str;
else
return decoding_str;
string Type::get_coding(bool encode) const
{
const coding_t& coding = encode ? default_encoding : default_decoding;
if (coding.type != CODING_BUILT_IN) {
FATAL_ERROR("Type::get_built_in_coding");
}
switch (coding.built_in_coding) {
case CT_RAW:
return string("RAW");
case CT_TEXT:
return string("TEXT");
case CT_XER:
return string("XER, XER_EXTENDED"); // TODO: fine tuning this parameter
case CT_JSON:
if (encode) {
return string("JSON, FALSE"); // with compact printing
}
else {
return string("JSON");
}
case CT_BER: {
string coding_str = string("BER, ");
BerAST* ber = berattrib;
if (!ber) // use default settings if attributes are not specified
ber = new BerAST;
if (encode)
coding_str += ber->get_encode_str();
else
coding_str += ber->get_decode_str();
if (!berattrib)
delete ber;
return coding_str; }
default:
FATAL_ERROR("Type::get_built_in_coding");
}
}
Assignment* Type::get_coding_function(bool encode) const
{
const coding_t& coding = encode ? default_encoding : default_decoding;
if (coding.type != CODING_BY_FUNCTION) {
FATAL_ERROR("Type::get_coding_function");
}
return coding.function_def;
}
namespace { // unnamed
......
......@@ -114,6 +114,7 @@ namespace Common {
class SignatureParamList;
class SignatureExceptions;
class CodeGenHelper;
class Assignment;
/**
* This is the base class for types.
......@@ -195,14 +196,13 @@ namespace Common {
*/
enum MessageEncodingType_t {
CT_UNDEF, /**< undefined/unused */
CT_BER, /**< ASN.1 BER */
CT_PER, /**< ASN.1 PER (not supported yet) */
CT_RAW, /**< TTCN-3 RAW */
CT_TEXT, /**< TTCN-3 TEXT */
CT_XER, /**< ASN.1 XER */
CT_JSON, /**< TTCN-3 JSON */
CT_CUSTOM, /**< user defined encoding */
CT_MULTIPLE /**< multiple codings defined for an ASN.1 type */
CT_BER, /**< ASN.1 BER (built-in) */
CT_PER, /**< ASN.1 PER (through user defined coder functions) */
CT_RAW, /**< TTCN-3 RAW (built-in) */
CT_TEXT, /**< TTCN-3 TEXT (built-in) */
CT_XER, /**< TTCN-3 XER (built-in) */
CT_JSON, /**< TTCN-3 and ASN.1 JSON (built-in) */
CT_CUSTOM /**< user defined encoding (through user defined coder functions) */
};
/** selector for value checking algorithms */
......@@ -225,7 +225,7 @@ namespace Common {
};
/** Enumeration to represent the owner of the type.
* Also align OT_UNKNOWN at line 200. */
*/
enum TypeOwner_t {
OT_UNKNOWN,
OT_TYPE_ASS, ///< ASN.1 type assignment (Ass_T)
......@@ -261,6 +261,31 @@ namespace Common {
OT_SIG_PAR, ///< signature parameter (SignatureParam)
OT_POOL ///< It's a pool type, owned by the type pool
};
/**
* Enumeration to represent the default method of encoding or decoding for a type.
*/
enum coding_type_t {
CODING_UNSET, ///< No encoding/decoding method has been set for the type.
CODING_BUILT_IN, ///< The type uses a built-in codec for encoding/decoding.
CODING_BY_FUNCTION, ///< The type uses a user defined function for encoding/decoding.
CODING_MULTIPLE ///< Multiple encoding/decoding methods have been set for the type.
};
/**
* Structure containing the default encoding or decoding settings for a type.
* These settings determine how values of the type are encoded or decoded by
* the following TTCN-3 language elements:
* 'encvalue' (encode), 'encvalue_unichar' (encode), 'decvalue' (decode),
* 'decvalue_unichar' (decode), 'decmatch' (decode) and '@decoded' (decode).
*/
struct coding_t {
coding_type_t type; ///< Type of encoding/decoding
union {
MessageEncodingType_t built_in_coding; ///< Built-in codec (if type is CODING_BUILT_IN)
Assignment* function_def; ///< Pointer to external function definition (if type is CODING_BY_FUNCTION)
};
};
/** Returns the display string of \a encoding_type. */
static const char *get_encoding_name(MessageEncodingType_t encoding_type);
......@@ -305,14 +330,9 @@ namespace Common {
vector<SubTypeParse> *parsed_restr; ///< parsed subtype restrictions are stored here until they are moved to the sub_type member
SubType *sub_type; ///< effective/aggregate subtype of this type, NULL if neither inherited nor own subtype restrictions exist
string encoding_str; // needed by codegen for encvalue() and decvalue()
string decoding_str;
bool encoding_by_function; // false - coding attribute is set, true - coding via coding function
bool decoding_by_function; // same for decoding
string encoding_function; // name of custom or PER encoder
string decoding_function; // name of custom or PER decoder
MessageEncodingType_t asn_encoding; // set by the semantic analysis of encoding
MessageEncodingType_t asn_decoding; // and decoding external functions for ASN.1 types
coding_t default_encoding; ///< default settings for encoding values of this type
coding_t default_decoding; ///< default settings for decoding values of this type
/** What kind of AST element owns the type.
* It may not be known at creation type, so it's initially OT_UNKNOWN.
* We want this information so we don't have to bother with XER
......@@ -658,12 +678,35 @@ namespace Common {
bool is_list_type(bool allow_array);
/** Sets the encoding or decoding function for the type (in case of custom
* encoding). */
void set_coding_function(bool encode, const string& function_name);
* or PER encoding). */
void set_coding_function(bool encode, Assignment* function_def);
/** Sets the codec to use when encoding or decoding the ASN.1 type */
void set_asn_coding(bool encode, MessageEncodingType_t new_coding);
/** Determines the method of encoding or decoding for values of this type
* based on its attributes and on encoder or decoder function definitions
* with this type as their input or output. An error is displayed if the
* coding method cannot be determined.
*
* @note Because this check depends on the checks of other AST elements
* (external functions), it is sometimes delayed to the end of the semantic
* analysis. */
void chk_coding(bool encode, bool delayed = false);
/** Indicates whether the type is encoded/decoded by a function or by a
* built-in codec. */
bool is_coding_by_function(bool encode) const;
const string& get_coding(bool encode) const;
/** Returns the string representation of the type's default codec.
* Used during code generation for types encoded/decoded by a built-in
* codec. */
string get_coding(bool encode) const;
/** Returns the function definition of the type's encoder/decoder function.
* Used during code generation for types encoded/decoded by functions. */
Assignment* get_coding_function(bool encode) const;
private:
static MessageEncodingType_t get_enc_type(const Ttcn::SingleWithAttrib& enc);
......
......@@ -12970,6 +12970,7 @@ error:
break;
}
Scope* scope = u.expr.ti1->get_Template()->get_my_scope();
if (!gov_last->is_coding_by_function(true)) {
const string& tmp_id = get_temporary_id();
const string& tmp_buf_id = get_temporary_id();
......@@ -12983,9 +12984,7 @@ error:
expr->preamble = mputc (expr->preamble, '\n');
}
expr->preamble = mputprintf(expr->preamble, "%s const& %s = %s",
gov_last->get_genname_typedescriptor(
u.expr.ti1->get_Template()->get_my_scope()
).c_str(),
gov_last->get_genname_typedescriptor(scope).c_str(),
tmp_ref_id.c_str(),
expr2.expr);
if (is_templ) // make a value out of the template, if needed
......@@ -12993,9 +12992,7 @@ error:
expr->preamble = mputprintf(expr->preamble,
";\n%s.encode(%s_descr_, %s, TTCN_EncDec::CT_%s",
tmp_ref_id.c_str(),
gov_last->get_genname_typedescriptor(
u.expr.ti1->get_Template()->get_my_scope()
).c_str(),
gov_last->get_genname_typedescriptor(scope).c_str(),
tmp_buf_id.c_str(),
gov_last->get_coding(true).c_str()
);
......@@ -13009,8 +13006,8 @@ error:
expr->postamble = mputstr(expr->postamble, expr2.postamble);
} else
expr->expr = mputprintf(expr->expr, "%s(%s%s)",
gov_last->get_coding(true).c_str(), expr2.expr,
is_templ ? ".valueof()" : "");
gov_last->get_coding_function(true)->get_genname_from_scope(scope).c_str(),
expr2.expr, is_templ ? ".valueof()" : "");
Code::free_expr(&expr2);
}
......@@ -13031,6 +13028,7 @@ error:
if (expr2.preamble)
expr->preamble = mputprintf(expr->preamble, "%s", expr2.preamble);
Scope* scope = u.expr.r2->get_my_scope();
if (!_type->is_coding_by_function(false)) {
const string& tmp_id = get_temporary_id();
const string& buffer_id = get_temporary_id();
......@@ -13052,9 +13050,7 @@ error:
"%s%s.decode(%s_descr_, %s, TTCN_EncDec::CT_%s);\n",
expr2.expr,
optional ? "()" : "",
_type->get_genname_typedescriptor(
u.expr.r2->get_my_scope()
).c_str(),
_type->get_genname_typedescriptor(scope).c_str(),
buffer_id.c_str(),
_type->get_coding(false).c_str()
);
......@@ -13090,7 +13086,7 @@ error:
expr->expr = mputprintf(expr->expr, "%s", retval_id.c_str());
} else
expr->expr = mputprintf(expr->expr, "%s(%s, %s)",
_type->get_coding(false).c_str(), expr1.expr, expr2.expr);
_type->get_coding_function(false)->get_genname_from_scope(scope).c_str(), expr1.expr, expr2.expr);
if (expr1.postamble)
expr->postamble = mputprintf(expr->postamble, "%s", expr1.postamble);
if (expr2.postamble)
......@@ -13127,6 +13123,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
v2_code = generate_code_char_coding_check(expr, u.expr.v2, "encvalue_unichar");
}
Scope* scope = u.expr.ti1->get_Template()->get_my_scope();
if (!gov_last->is_coding_by_function(true)) {
const string& tmp_id = get_temporary_id();
const string& tmp_buf_id = get_temporary_id();
......@@ -13140,9 +13137,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
expr->preamble = mputc (expr->preamble, '\n');
}
expr->preamble = mputprintf(expr->preamble, "%s const& %s = %s",
gov_last->get_genname_typedescriptor(
u.expr.ti1->get_Template()->get_my_scope()
).c_str(),
gov_last->get_genname_typedescriptor(scope).c_str(),
tmp_ref_id.c_str(),
expr2.expr);
if (is_templ) // make a value out of the template, if needed
......@@ -13150,9 +13145,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
expr->preamble = mputprintf(expr->preamble,
";\n%s.encode(%s_descr_, %s, TTCN_EncDec::CT_%s",
tmp_ref_id.c_str(),
gov_last->get_genname_typedescriptor(
u.expr.ti1->get_Template()->get_my_scope()
).c_str(),
gov_last->get_genname_typedescriptor(scope).c_str(),
tmp_buf_id.c_str(),
gov_last->get_coding(true).c_str()
);
......@@ -13172,8 +13165,8 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
expr->postamble = mputstr(expr->postamble, expr2.postamble);
} else {
expr->expr = mputprintf(expr->expr, "oct2unichar(bit2oct(%s(%s%s))",
gov_last->get_coding(true).c_str(), expr2.expr,
is_templ ? ".valueof()" : "");
gov_last->get_coding_function(true)->get_genname_from_scope(scope).c_str(),
expr2.expr, is_templ ? ".valueof()" : "");
if(u.expr.v2) {
expr->expr = mputprintf(expr->expr, ", %s", v2_code);
} else {
......@@ -13205,6 +13198,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
v3_code = generate_code_char_coding_check(expr, u.expr.v3, "decvalue_unichar");
}
Scope* scope = u.expr.r2->get_my_scope();
if (!_type->is_coding_by_function(false)) {
const string& tmp_id = get_temporary_id();
const string& buffer_id = get_temporary_id();
......@@ -13227,9 +13221,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
"%s%s.decode(%s_descr_, %s, TTCN_EncDec::CT_%s);\n",
expr2.expr,
optional ? "()" : "",
_type->get_genname_typedescriptor(
u.expr.r2->get_my_scope()
).c_str(),
_type->get_genname_typedescriptor(scope).c_str(),
buffer_id.c_str(),
_type->get_coding(false).c_str()
);
......@@ -13275,7 +13267,9 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
"%s = oct2unichar(bit2oct(%s), %s);\n",
ustr_ref_id.c_str(), expr1.expr,
bstr_id.c_str(), ustr_ref_id.c_str(), u.expr.v3 ? v3_code : "\"UTF-8\"",
ret_val_id.c_str(), _type->get_coding(false).c_str(), bstr_id.c_str(), expr2.expr,
ret_val_id.c_str(),
_type->get_coding_function(false)->get_genname_from_scope(scope).c_str(),
bstr_id.c_str(), expr2.expr,
ustr_ref_id.c_str(), bstr_id.c_str(), u.expr.v3 ? v3_code : "\"UTF-8\"");
expr->expr = mputprintf(expr->expr, "%s", ret_val_id.c_str());
}
......
......@@ -6569,8 +6569,7 @@ namespace Ttcn {
}
else {
// let the input type know that this is its encoding function
input_type->get_type_refd()->set_coding_function(true,
get_genname_from_scope(input_type->get_type_refd()->get_my_scope()));
input_type->get_type_refd()->set_coding_function(true, this);
// treat this as a manual external function during code generation