Commit 2ef75823 authored by BenceJanosSzabo's avatar BenceJanosSzabo
Browse files

Enum fields can be initialised with bin,oct,hex-strings and compile time values (artf780946)



Change-Id: I2078305852f1fcb364b756b67740485077954fdf
Signed-off-by: default avatarBenceJanosSzabo <bence.janos.szabo@ericsson.com>
parent f765da36
......@@ -9,10 +9,12 @@
* Balasko, Jeno
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
*
******************************************************************************/
#include "EnumItem.hh"
#include "Value.hh"
#include "Int.hh"
namespace Common {
......@@ -21,7 +23,7 @@ namespace Common {
// =================================
EnumItem::EnumItem(Identifier *p_name, Value *p_value)
: Node(), Location(), name(p_name), value(p_value)
: Node(), Location(), name(p_name), value(p_value), int_value(NULL)
{
if (!p_name) FATAL_ERROR("NULL parameter: Common::EnumItem::EnumItem()");
}
......@@ -31,12 +33,18 @@ EnumItem::EnumItem(const EnumItem& p)
{
name=p.name->clone();
value=p.value?p.value->clone():0;
if (p.int_value) {
int_value = new int_val_t(*p.int_value);
} else {
int_value = 0;
}
}
EnumItem::~EnumItem()
{
delete name;
delete value;
delete int_value;
}
EnumItem *EnumItem::clone() const
......@@ -60,6 +68,9 @@ void EnumItem::set_value(Value *p_value)
if(!p_value) FATAL_ERROR("NULL parameter: Common::EnumItem::set_value()");
if(value) FATAL_ERROR("Common::EnumItem::set_value()");
value=p_value;
delete int_value;
int_value = NULL;
calculate_int_value();
}
void EnumItem::set_text(const string& p_text)
......@@ -67,6 +78,57 @@ void EnumItem::set_text(const string& p_text)
text = p_text;
}
bool EnumItem::calculate_int_value() {
if (int_value) {
return true;
}
Value *v = NULL;
value->set_lowerid_to_ref();
if (value->get_valuetype() == Value::V_REFD || value->get_valuetype() == Value::V_EXPR) {
v = value->get_value_refd_last();
} else {
v = value;
}
if (v->is_unfoldable()) {
value->error("A value known at compile time was expected for enumeration `%s'",
name->get_dispname().c_str());
return false;
}
switch (v->get_valuetype()) {
case Value::V_INT:
int_value = new int_val_t(v->get_val_Int()->get_val());
break;
case Value::V_BSTR: {
long int res = strtol(v->get_val_str().c_str(), NULL, 2);
int_value = new int_val_t(res);
break;
}
case Value::V_OSTR:
case Value::V_HSTR: {
long int res = strtol(v->get_val_str().c_str(), NULL, 16);
int_value = new int_val_t(res);
break;
}
default:
value->error("INTEGER or BITSTRING or OCTETSTRING or HEXSTRING value was expected for enumeration `%s'",
name->get_dispname().c_str());
return false;
}
return true;
}
int_val_t * EnumItem::get_int_val() const {
if (value == NULL) {
FATAL_ERROR("NULL value in Common::EnumItem::calculate_int_value()");
}
if (int_value == NULL) {
FATAL_ERROR("Not calculated value in Common::EnumItem::calculate_int_value()");
}
return int_value;
}
void EnumItem::dump(unsigned level) const
{
name->dump(level);
......
......@@ -9,6 +9,7 @@
* Balasko, Jeno
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
*
******************************************************************************/
#ifndef ENUM_HH_
......@@ -19,6 +20,8 @@
namespace Common {
class int_val_t;
/**
* Class to represent an Enumeration item. Is like a NamedValue, but
* the value can be NULL, and a(n integer) value can be assigned
......@@ -29,6 +32,7 @@ private:
Identifier *name;
Value *value;
string text; ///< for TEXT encoding instruction
int_val_t *int_value;
/** Copy constructor not implemented */
EnumItem(const EnumItem&);
/** Assignment disabled */
......@@ -44,6 +48,8 @@ public:
const string& get_text() const { return text; }
void set_text(const string& p_text);
virtual void set_my_scope(Scope *p_scope);
bool calculate_int_value();
int_val_t* get_int_val() const;
virtual void dump(unsigned level) const;
};
......
......@@ -22,6 +22,7 @@
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Janos Zoltan – initial implementation
* Szabo, Bence Janos
* Szalai, Gabor
* Tatarka, Gabor
* Zalanyi, Balazs Andor
......@@ -1870,8 +1871,7 @@ namespace Common {
int min_bits=0;
int max_val=u.enums.first_unused;
for(size_t a=0;a<u.enums.eis->get_nof_eis();a++){
int val=u.enums.eis->get_ei_byIndex(a)->get_value()->get_val_Int()
->get_val();
int val=u.enums.eis->get_ei_byIndex(a)->get_int_val()->get_val();
if((max_val<0?-max_val:max_val)<(val<0?-val:val)) max_val=val;
}
if(max_val<0){ min_bits=1;max_val=-max_val;}
......@@ -4790,8 +4790,7 @@ namespace Common {
default:
FATAL_ERROR("Type::get_enum_val_byId()");
}
return u.enums.eis->get_ei_byName(p_name)->get_value()
->get_value_refd_last()->get_val_Int()->get_val();
return u.enums.eis->get_ei_byName(p_name)->get_int_val()->get_val();
}
size_t Type::get_nof_root_comps()
......
......@@ -1653,8 +1653,7 @@ void Type::chk_xer_use_nil()
complaint = BAD_ENUM;
break;
}
Value *v = ei->get_value();
const int_val_t *ival = v->get_val_Int();
const int_val_t *ival = ei->get_int_val();
const Int enumval = ival->get_val();
if ((size_t)enumval != enum_index) {
complaint = ENUM_GAP; // 35.2.2.3
......@@ -1867,8 +1866,7 @@ void Type::chk_xer_use_order(int num_attributes)
complaint = BAD_ENUM;
break;
}
Value *v = ei->get_value();
const int_val_t *ival = v->get_val_Int();
const int_val_t *ival = ei->get_int_val();
const Int enumval = ival->get_val();
if ((size_t)enumval != enum_index) {
complaint = ENUM_GAP; // 35.2.2.3
......@@ -2491,6 +2489,8 @@ void Type::chk_Enum_A()
ei->set_value(new Value(Value::V_INT, first_unused));
value_map.add(first_unused, ei);
while (value_map.has_key(++first_unused)) ;
} else {
ei->calculate_int_value();
}
}
/* checking values after the ellipsis */
......@@ -2532,6 +2532,7 @@ void Type::chk_Enum_item(EnumItem *ei, bool after_ellipsis,
Int& first_unused=u.enums.first_unused;
Value *value = ei->get_value();
if (value) {
ei->calculate_int_value();
Value *v;
{
Error_Context cntxt(ei, "In enumeration `%s'", dispname_str);
......@@ -2547,6 +2548,10 @@ void Type::chk_Enum_item(EnumItem *ei, bool after_ellipsis,
dispname_str);
return;
}
// This function is only called for ASN1 enumerated types.
// The enum_value can be get by calling v->get_int_val() which also supports
// binary, hex, oct values. ASN1 enumerated fields cannot have
// binary, hex, or oct value.
Int enum_value = v->get_val_Int()->get_val();
if (static_cast<Int>(static_cast<int>(enum_value)) != enum_value) {
value->error("The numeric value of enumeration `%s' (%s) is too "
......@@ -2608,33 +2613,37 @@ void Type::chk_Enum_T()
if (value) {
/* Handle the error node created by the parser. */
if (value->get_valuetype() == Value::V_ERROR) {
value->error("INTEGER value was expected for enumeration `%s'",
value->error("INTEGER or BITSTRING or OCTETSTRING or HEXSTRING value was expected for enumeration `%s'",
id.get_dispname().c_str());
error_flag = true;
} else {
const int_val_t *enum_value_int = value->get_val_Int();
// It used to be the same check.
if (*enum_value_int > INT_MAX ||
static_cast<Int>(static_cast<int>(enum_value_int->get_val()))
!= enum_value_int->get_val()) {
value->error("The numeric value of enumeration `%s' (%s) is "
"too large for being represented in memory",
id.get_dispname().c_str(), (enum_value_int->t_str()).c_str());
error_flag = true;
} else {
Int enum_value = enum_value_int->get_val();
if (value_map.has_key(enum_value)) {
const char *dispname_str = id.get_dispname().c_str();
value->error("Duplicate numeric value %s for enumeration `%s'",
Int2string(enum_value).c_str(), dispname_str);
EnumItem *ei2 = value_map[enum_value];
ei2->note("Value %s is already assigned to `%s'",
Int2string(enum_value).c_str(),
ei2->get_name().get_dispname().c_str());
if (ei->calculate_int_value()) {
const int_val_t *enum_value_int = ei->get_int_val();
// It used to be the same check.
if (*enum_value_int > INT_MAX ||
static_cast<Int>(static_cast<int>(enum_value_int->get_val()))
!= enum_value_int->get_val()) {
value->error("The numeric value of enumeration `%s' (%s) is "
"too large for being represented in memory",
id.get_dispname().c_str(), (enum_value_int->t_str()).c_str());
error_flag = true;
} else {
value_map.add(enum_value, ei);
Int enum_value = enum_value_int->get_val();
if (value_map.has_key(enum_value)) {
const char *dispname_str = id.get_dispname().c_str();
value->error("Duplicate numeric value %s for enumeration `%s'",
Int2string(enum_value).c_str(), dispname_str);
EnumItem *ei2 = value_map[enum_value];
ei2->note("Value %s is already assigned to `%s'",
Int2string(enum_value).c_str(),
ei2->get_name().get_dispname().c_str());
error_flag = true;
} else {
value_map.add(enum_value, ei);
}
}
} else {
error_flag = true;
}
}
}
......@@ -2649,6 +2658,8 @@ void Type::chk_Enum_T()
ei->set_value(new Value(Value::V_INT, first_unused));
value_map.add(first_unused, ei);
while (value_map.has_key(++first_unused)) ;
} else {
ei->calculate_int_value();
}
}
Int& second_unused = u.enums.second_unused;
......
......@@ -1110,7 +1110,7 @@ void Type::generate_code_Enum(output_struct *target)
e_def.xerText = TRUE;
e_def.elements[i].text = ei->get_text().c_str();
}
e_def.elements[i].value = ei->get_value()->get_val_Int()->get_val();
e_def.elements[i].value = ei->get_int_val()->get_val();
}
defEnumClass(&e_def, target);
......@@ -3000,7 +3000,7 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val
json.put_next_token(JSON_TOKEN_NAME, "numericValues");
json.put_next_token(JSON_TOKEN_ARRAY_START);
for (size_t i = 0; i < last->u.enums.eis->get_nof_eis(); ++i) {
char* num_val_str = mprintf("%lli", last->get_ei_byIndex(i)->get_value()->get_val_Int()->get_val());
char* num_val_str = mprintf("%lli", last->get_ei_byIndex(i)->get_int_val()->get_val());
json.put_next_token(JSON_TOKEN_NUMBER, num_val_str);
Free(num_val_str);
}
......
......@@ -2542,19 +2542,9 @@ Enumeration: // 45
$$ = new EnumItem($1, NULL);
$$->set_location(infile, @$);
}
| IDentifier '(' Number optError ')'
| IDentifier '(' SingleExpression optError ')'
{
Value *value = new Value(Value::V_INT, $3);
value->set_location(infile, @3);
$$ = new EnumItem($1, value);
$$->set_location(infile, @$);
}
| IDentifier '(' '-' Number optError ')'
{
*$4 = -*$4;
Value *value = new Value(Value::V_INT, $4);
value->set_location(infile, @3, @4);
$$ = new EnumItem($1, value);
$$ = new EnumItem($1, $3);
$$->set_location(infile, @$);
}
| IDentifier '(' error ')'
......
......@@ -3341,6 +3341,72 @@ type enumerated Enum { ONE(1), TWO(2), THREE(1) };
<END_TC>
:exmp.
.*---------------------------------------------------------------------*
:h4.Value notations - A value notation shall assign a value to a specific element only once with binary, octetstring, hexstring
.*---------------------------------------------------------------------*
:xmp tab=0.
<TC - A value notation shall assign a value to a specific element only once with binary, octetstring, hexstring>
<COMPILE>
<VERDICT_LEAF PASS>
<MODULE TTCN x x.ttcn>
module x {
type enumerated Enum { ONE(1), TWO('01'B), THREE('01'O), FOUR('01'H) };
}
<END_MODULE>
<RESULT IF_PASS COUNT 3>
(?im)Duplicate.+?value.+?enumeration
<END_RESULT>
<RESULT IF_PASS COUNT 3>
(?im)already.+?assigned
<END_RESULT>
<RESULT IF_PASS COUNT 1>
(?im)\bNotify\b.+?\bcode\b.+?\bnot\b.+?\bgenerated\b
<END_RESULT>
<RESULT IF_PASS COUNT 3>
(?is)\berror:
<END_RESULT>
<END_TC>
:exmp.
.*---------------------------------------------------------------------*
:h4.Enumeration allowed defining values: number, hexa, octet, binary in compile time
.*---------------------------------------------------------------------*
:xmp tab=0.
<TC - Enumeration allowed defining values: number, hexa, octet, binary in compile time>
<COMPILE>
<VERDICT_LEAF PASS>
<MODULE TTCN x x.ttcn>
module x {
type enumerated Enum { ONE(1), TWO('11'B), THREE('AB'O), FOUR('AC'H), FIVE("STR"), SIX(f()), SEVEN(c_int), EIGHT(c_bit) };
const integer c_int := 4;
const bitrstring c_bit := '010110'B;
function f() return integer {
return 123;
}
}
<END_MODULE>
<RESULT IF_PASS COUNT 1>
(?im)INTEGER.+?BITSTRING.+?OCTETSTRING.+?HEXSTRING.+?expected.+?FIVE
<END_RESULT>
<RESULT IF_PASS COUNT 1>
(?im)compile.+?time.+?was.+?expected.+?SIX
<END_RESULT>
<RESULT IF_PASS COUNT 1>
(?im)\bNotify\b.+?\bcode\b.+?\bnot\b.+?\bgenerated\b
<END_RESULT>
<RESULT IF_PASS COUNT 3>
(?is)\berror:
<END_RESULT>
<END_TC>
:exmp.
.*---------------------------------------------------------------------*
:h2.Allowed values (each evaluated expression shall conform to the context-specific rules)
.*---------------------------------------------------------------------*
......
......@@ -156,7 +156,7 @@ testcase dec_uo_emb() runs on Ord
// Example 3: USE-ORDER and USE-NIL
type record UOProductNil {
record of enumerated { id, name, price, color } order,
record of enumerated { id, name('01'O), price('10'B), color('3'H) } order,
boolean available, // not in the whitepaper
UOProductInfo info optional
}
......
......@@ -19,7 +19,7 @@ modulepar boolean UseNil_verbose := false;
type component Nil {}
type enumerated ProductColor0 { red(0), green(1), blue(2) }
type enumerated ProductColor0 { red(0), green('01'B), blue(2), yellow('12'O), black('AB'H) }
// useNil on the type (record)
type record Size {
......@@ -51,6 +51,24 @@ const NilProduct present_ := {
size := { 10 }
}
const NilProduct present_green := {
name := "shirt",
color := green,
size := { 10 }
}
const NilProduct present_yellow := {
name := "shirt",
color := yellow,
size := { 10 }
}
const NilProduct present_black := {
name := "shirt",
color := black,
size := { 10 }
}
const universal charstring str_absent_e_correct :=
"<NilProduct xmlns:xsi=\'http://www.w3.org/2001/XMLSchema-instance\'>\n" &
......@@ -102,6 +120,60 @@ const universal charstring str_present_b :=
"</NilProduct>\n" &
"\n";
const universal charstring str_present_green_e :=
"<NilProduct>\n" &
"\t<name>shirt</name>\n" &
"\t<color>green</color>\n" &
"\t<size>10</size>\n" &
"</NilProduct>\n" &
"\n";
const universal charstring str_present_green_b :=
"<NilProduct>\n" &
"\t<name>shirt</name>\n" &
"\t<color><green/></color>\n" &
"\t<size>\n" &
"\t\t<sizeval>10</sizeval>\n" &
"\t</size>\n" &
"</NilProduct>\n" &
"\n";
const universal charstring str_present_yellow_e :=
"<NilProduct>\n" &
"\t<name>shirt</name>\n" &
"\t<color>yellow</color>\n" &
"\t<size>10</size>\n" & // HO37920: no \t after 10
"</NilProduct>\n" &
"\n";
const universal charstring str_present_yellow_b :=
"<NilProduct>\n" &
"\t<name>shirt</name>\n" &
"\t<color><yellow/></color>\n" &
"\t<size>\n" &
"\t\t<sizeval>10</sizeval>\n" &
"\t</size>\n" &
"</NilProduct>\n" &
"\n";
const universal charstring str_present_black_e :=
"<NilProduct>\n" &
"\t<name>shirt</name>\n" &
"\t<color>black</color>\n" &
"\t<size>10</size>\n" & // HO37920: no \t after 10
"</NilProduct>\n" &
"\n";
const universal charstring str_present_black_b :=
"<NilProduct>\n" &
"\t<name>shirt</name>\n" &
"\t<color><black/></color>\n" &
"\t<size>\n" &
"\t\t<sizeval>10</sizeval>\n" &
"\t</size>\n" &
"</NilProduct>\n" &
"\n";
testcase encode_nil_absent() runs on Nil
{
CHECK_METHOD(bxer_enc_nilp, absent, str_absent_b);
......@@ -126,6 +198,30 @@ testcase decode_nil_present() runs on Nil
CHECK_DECODE(exer_dec_nilp, str_present_e, NilProduct, present_);
}
testcase encode_enum_nil() runs on Nil
{
CHECK_METHOD(bxer_enc_nilp, present_green, str_present_green_b);
CHECK_METHOD(exer_enc_nilp, present_green, str_present_green_e);
CHECK_METHOD(bxer_enc_nilp, present_yellow, str_present_yellow_b);
CHECK_METHOD(exer_enc_nilp, present_yellow, str_present_yellow_e);
CHECK_METHOD(bxer_enc_nilp, present_black, str_present_black_b);
CHECK_METHOD(exer_enc_nilp, present_black, str_present_black_e);
}
testcase decode_enum_nil() runs on Nil
{
CHECK_DECODE(bxer_dec_nilp, str_present_green_b, NilProduct, present_green);
CHECK_DECODE(exer_dec_nilp, str_present_green_e, NilProduct, present_green);
CHECK_DECODE(bxer_dec_nilp, str_present_yellow_b, NilProduct, present_yellow);
CHECK_DECODE(exer_dec_nilp, str_present_yellow_e, NilProduct, present_yellow);
CHECK_DECODE(bxer_dec_nilp, str_present_black_b, NilProduct, present_black);
CHECK_DECODE(exer_dec_nilp, str_present_black_e, NilProduct, present_black);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const universal charstring str_sz_absent_e :=
......@@ -800,6 +896,10 @@ control {
execute(encode_NilTypeRecAttr());
execute(decode_NilTypeRecAttr());
execute(encode_enum_nil());
execute(decode_enum_nil());
}
}
......
/******************************************************************************
* 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:
* Szabo, Bence Janos – initial implementation
*
******************************************************************************/
module EnumDefBitHexOct {
type component EmptyCT {}
const integer c_int := 45;
const bitstring c_bit := '10101111'B;
type enumerated MyEnum {
e_num (1),
e_bin ('10'B),
e_oct ('12'O),
e_hex ('AB'H),
e_bin_conv (bit2int('0111'B)),
e_oct_conv (oct2int('34'O)),
e_hex_conv (hex2int('AC'H)),
e_num_const (c_int),
e_bin_const (c_bit)
} with {
encode "RAW"
}
const MyEnum c_num := e_num;
const MyEnum c_bin := e_bin;
const MyEnum c_oct := e_oct;
const MyEnum c_hex := e_hex;
const MyEnum c_bin_conv := e_bin_conv;
const MyEnum c_oct_conv := e_oct_conv;
const MyEnum c_hex_conv := e_hex_conv;
const MyEnum c_num_const := e_num_const;
const MyEnum c_bin_const := e_bin_const;
testcase tc_basic_const_test() runs on EmptyCT {
if (c_num != e_num) {
setverdict(fail);
}
if (c_bin != e_bin) {
setverdict(fail);
}
if (c_oct != e_oct) {
setverdict(fail);
}
if (c_hex != e_hex) {
setverdict(fail);
}
if (c_bin_conv != e_bin_conv) {
setverdict(fail);
}
if (c_oct_conv != e_oct_conv) {
setverdict(fail);
}
if (c_hex_conv != e_hex_conv) {
setverdict(fail);
}
if (c_num_const != e_num_const) {
setverdict(fail);
}
if (c_bin_const != e_bin_const) {
setverdict(fail);