/****************************************************************************** * Copyright (c) 2000-2021 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Baji, Laszlo * Balasko, Jeno * Baranyi, Botond * Beres, Szabolcs * Bibo, Zoltan * Cserveni, Akos * Delic, Adam * Dimitrov, Peter * Feher, Csaba * Forstner, Matyas * Gecse, Roland * Kovacs, Ferenc * Ormandi, Matyas * Raduly, Csaba * Szabados, Kristof * Szabo, Bence Janos * Szabo, Janos Zoltan – initial implementation * Szalai, Gabor * Tatarka, Gabor * Zalanyi, Balazs Andor * ******************************************************************************/ #include "../common/dbgnew.hh" #include "Value.hh" #include "AST.hh" #include "Identifier.hh" #include "Valuestuff.hh" #include "PredefFunc.hh" #include "CompField.hh" #include "CompType.hh" #include "EnumItem.hh" #include "TypeCompat.hh" #include "asn1/Block.hh" #include "asn1/TokenBuf.hh" #include "Real.hh" #include "Int.hh" #include "main.hh" #include "Setting.hh" #include "Type.hh" #include "ttcn3/TtcnTemplate.hh" #include "ttcn3/ArrayDimensions.hh" #include "ustring.hh" #include "../common/pattern.hh" #include "ttcn3/PatternString.hh" #include "ttcn3/Statement.hh" #include "ttcn3/Attributes.hh" #include "ttcn3/JsonAST.hh" #include "../common/JSON_Tokenizer.hh" #include "ttcn3/Ttcn2Json.hh" #include "ttcn3/Ttcnstuff.hh" #include <regex.h> #include <limits.h> namespace Common { static void clean_up_string_elements(map<size_t, Value>*& string_elements) { if (string_elements) { for (size_t i = 0; i < string_elements->size(); i++) delete string_elements->get_nth_elem(i); string_elements->clear(); delete string_elements; string_elements = 0; } } // ================================= // ===== Value // ================================= Value::Value(const Value& p) : GovernedSimple(p), valuetype(p.valuetype), my_governor(p.my_governor) , in_brackets(p.in_brackets) { switch(valuetype) { case V_ERROR: case V_NULL: case V_OMIT: case V_TTCN3_NULL: case V_DEFAULT_NULL: case V_FAT_NULL: case V_NOTUSED: break; case V_BOOL: u.val_bool=p.u.val_bool; break; case V_INT: u.val_Int=new int_val_t(*(p.u.val_Int)); break; case V_NAMEDINT: case V_ENUM: case V_UNDEF_LOWERID: u.val_id=p.u.val_id->clone(); break; case V_REAL: u.val_Real=p.u.val_Real; break; case V_BSTR: case V_HSTR: case V_OSTR: case V_CSTR: case V_ISO2022STR: set_val_str(new string(*p.u.str.val_str)); break; case V_USTR: set_val_ustr(new ustring(*p.u.ustr.val_ustr)); u.ustr.convert_str = p.u.ustr.convert_str; break; case V_CHARSYMS: u.char_syms = p.u.char_syms->clone(); break; case V_OID: case V_ROID: u.oid_comps=new vector<OID_comp>; for(size_t i=0; i<p.u.oid_comps->size(); i++) add_oid_comp((*p.u.oid_comps)[i]->clone()); break; case V_CHOICE: u.choice.alt_name=p.u.choice.alt_name->clone(); u.choice.alt_value=p.u.choice.alt_value->clone(); break; case V_SEQOF: case V_SETOF: case V_ARRAY: u.val_vs=p.u.val_vs->clone(); break; case V_SEQ: case V_SET: u.val_nvs=p.u.val_nvs->clone(); break; case V_REFD: u.ref.ref=p.u.ref.ref->clone(); u.ref.refd_last=0; break; case V_NAMEDBITS: for(size_t i=0; i<p.u.ids->size(); i++) { Identifier *id = p.u.ids->get_nth_elem(i); u.ids->add(id->get_name(), id->clone()); } break; case V_UNDEF_BLOCK: u.block=p.u.block->clone(); break; case V_VERDICT: u.verdict=p.u.verdict; break; case V_EXPR: u.expr.v_optype = p.u.expr.v_optype; u.expr.state = EXPR_NOT_CHECKED; switch(u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_NOW: break; case OPTYPE_GET_PORT_REF: u.expr.type = p.u.expr.type; // the type is not owned, don't copy it break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: u.expr.r2 = p.u.expr.r2 != NULL ? p.u.expr.r2->clone() : NULL; u.expr.b4 = p.u.expr.b4; // no break case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: case OPTYPE_REMOVE_BOM: u.expr.v1=p.u.expr.v1->clone(); break; case OPTYPE_HOSTID: // [v1] u.expr.v1=p.u.expr.v1?p.u.expr.v1->clone():0; break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1=p.u.expr.v1->clone(); u.expr.v2=p.u.expr.v2->clone(); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1=p.u.expr.v1->clone(); u.expr.v2=p.u.expr.v2?p.u.expr.v2->clone():0; break; case OPTYPE_UNDEF_RUNNING: // r1 [r2] b4 case OPTYPE_TMR_RUNNING: // r1 [r2] b4 u.expr.r1=p.u.expr.r1->clone(); u.expr.r2 = p.u.expr.r2 != NULL ? p.u.expr.r2->clone() : NULL; u.expr.b4 = p.u.expr.b4; break; case OPTYPE_DECODE: // r1 r2 [v3] [v4] u.expr.r1 = p.u.expr.r1->clone(); u.expr.r2 = p.u.expr.r2->clone(); u.expr.v2 = p.u.expr.v3 != NULL ? p.u.expr.v3->clone() : NULL; u.expr.v3 = p.u.expr.v4 != NULL ? p.u.expr.v4->clone() : NULL; break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1=p.u.expr.ti1->clone(); u.expr.v2 = p.u.expr.v2 != NULL ? p.u.expr.v2->clone() : NULL; u.expr.v3 = p.u.expr.v3 != NULL ? p.u.expr.v3->clone() : NULL; break; case OPTYPE_REGEXP: u.expr.ti1=p.u.expr.ti1->clone(); u.expr.t2=p.u.expr.t2->clone(); u.expr.v3=p.u.expr.v3->clone(); u.expr.b4=p.u.expr.b4; break; case OPTYPE_DECOMP: // v1 v2 v3 u.expr.v1=p.u.expr.v1->clone(); u.expr.v2=p.u.expr.v2->clone(); u.expr.v3=p.u.expr.v3->clone(); break; case OPTYPE_REPLACE: u.expr.ti1 = p.u.expr.ti1->clone(); u.expr.v2 = p.u.expr.v2->clone(); u.expr.v3 = p.u.expr.v3->clone(); u.expr.ti4 = p.u.expr.ti4->clone(); break; case OPTYPE_VALUEOF: // ti1 [subrefs2] u.expr.subrefs2 = p.u.expr.subrefs2 != NULL ? u.expr.subrefs2->clone() : NULL; // fall through case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: u.expr.ti1=p.u.expr.ti1->clone(); break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] u.expr.ti1=p.u.expr.ti1->clone(); u.expr.v2=p.u.expr.v2?p.u.expr.v2->clone():0; u.expr.v3 = p.u.expr.v3 != NULL ? p.u.expr.v3->clone() : NULL; u.expr.v4 = p.u.expr.v4 != NULL ? p.u.expr.v4->clone() : NULL; break; case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] u.expr.r1 = p.u.expr.r1->clone(); u.expr.r2 = p.u.expr.r2->clone(); u.expr.v3 = p.u.expr.v3 != NULL ? p.u.expr.v3->clone() : NULL; u.expr.v4 = p.u.expr.v4 != NULL ? p.u.expr.v4->clone() : NULL; u.expr.v5 = p.u.expr.v5 != NULL ? p.u.expr.v5->clone() : NULL; break; case OPTYPE_TMR_READ: case OPTYPE_ACTIVATE: u.expr.r1=p.u.expr.r1->clone(); break; case OPTYPE_EXECUTE: // r1 [v2] u.expr.r1=p.u.expr.r1->clone(); u.expr.v2=p.u.expr.v2?p.u.expr.v2->clone():0; break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2 case OPTYPE_CHECKSTATE_ALL: u.expr.r1=p.u.expr.r1?p.u.expr.r1->clone():0; u.expr.v2=p.u.expr.v2->clone(); break; case OPTYPE_UNDEF_CREATE: case OPTYPE_CLASS_CREATE: u.expr.r1 = p.u.expr.r1->clone(); if (p.u.expr.state != EXPR_CHECKED) { u.expr.t_list2 = p.u.expr.t_list2->clone(); } else { u.expr.ap_list2 = p.u.expr.ap_list2->clone(); u.expr.state = EXPR_CHECKED; } if (u.expr.v_optype == OPTYPE_UNDEF_CREATE) { u.expr.b4 = p.u.expr.b4; } break; case OPTYPE_COMP_CREATE: // r1 [v2] [v3] u.expr.r1=p.u.expr.r1->clone(); u.expr.v2=p.u.expr.v2?p.u.expr.v2->clone():0; u.expr.v3=p.u.expr.v3?p.u.expr.v3->clone():0; u.expr.b4 = p.u.expr.b4; break; case OPTYPE_MATCH: // v1 t2 u.expr.v1=p.u.expr.v1->clone(); u.expr.t2=p.u.expr.t2->clone(); break; case OPTYPE_ISCHOSEN: // r1 i2 u.expr.r1=p.u.expr.r1->clone(); u.expr.i2=p.u.expr.i2->clone(); break; case OPTYPE_ISCHOSEN_V: // v1 i2 u.expr.v1=p.u.expr.v1->clone(); u.expr.i2=p.u.expr.i2->clone(); break; case OPTYPE_ISCHOSEN_T: // t1 i2 u.expr.t1=p.u.expr.t1->clone(); u.expr.i2=p.u.expr.i2->clone(); break; case OPTYPE_ACTIVATE_REFD: u.expr.v1 = p.u.expr.v1->clone(); if(p.u.expr.state!=EXPR_CHECKED) u.expr.t_list2 = p.u.expr.t_list2->clone(); else { u.expr.ap_list2 = p.u.expr.ap_list2->clone(); u.expr.state = EXPR_CHECKED; } break; case OPTYPE_EXECUTE_REFD: u.expr.v1 = p.u.expr.v1->clone(); if(p.u.expr.state!=EXPR_CHECKED) u.expr.t_list2 = p.u.expr.t_list2->clone(); else { u.expr.ap_list2 = p.u.expr.ap_list2->clone(); u.expr.state = EXPR_CHECKED; } u.expr.v3 = p.u.expr.v3 ? p.u.expr.v3->clone() : 0; break; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: u.expr.logargs = p.u.expr.logargs->clone(); break; case OPTYPE_ISTEMPLATEKIND: u.expr.ti1 = p.u.expr.ti1->clone(); u.expr.v2 = p.u.expr.v2->clone(); break; case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: u.expr.type = p.u.expr.type->clone(); u.expr.r2 = p.u.expr.r2->clone(); break; case OPTYPE_CLASS_CASTING_REF: u.expr.r1 = p.u.expr.r1->clone(); u.expr.r2 = p.u.expr.r2->clone(); break; default: FATAL_ERROR("Value::Value()"); } // switch break; case V_MACRO: u.macro = p.u.macro; break; case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: u.refd_fat = p.u.refd_fat; break; case V_INVOKE: u.invoke.v = p.u.invoke.v->clone(); u.invoke.t_list = p.u.invoke.t_list?p.u.invoke.t_list->clone():0; u.invoke.ap_list = p.u.invoke.ap_list?p.u.invoke.ap_list->clone():0; break; case V_REFER: u.refered = p.u.refered->clone(); break; case V_ANY_VALUE: case V_ANY_OR_OMIT: u.len_res = p.u.len_res != NULL ? p.u.len_res->clone() : NULL; break; default: FATAL_ERROR("Value::Value()"); } // switch } void Value::chk_expr_immutability() { switch (valuetype) { case V_REFD: {/**< referenced */ Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref != NULL) { ttcn_ref->chk_immutability(); } break;} case V_EXPR: /**< expressions */ switch (u.expr.v_optype) { case OPTYPE_TESTCASENAME: // - break; case OPTYPE_NOW: // - error("Operation 'now' cannot be used in alt guards."); break; case OPTYPE_RND: // - case OPTYPE_RNDWITHVAL: /** \todo -> SEED */ // v1 warning("Random number generation 'rnd()' change the actual snapshot."); break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: // v1 case OPTYPE_NOT: // v1 case OPTYPE_NOT4B: // v1 case OPTYPE_BIT2HEX: // v1 6 case OPTYPE_BIT2INT: // v1 case OPTYPE_BIT2OCT: // v1 case OPTYPE_BIT2STR: // v1 case OPTYPE_CHAR2INT: // v1 10 case OPTYPE_CHAR2OCT: // v1 case OPTYPE_FLOAT2INT: // v1 case OPTYPE_FLOAT2STR: // v1 case OPTYPE_HEX2BIT: // v1 case OPTYPE_HEX2INT: // v1 case OPTYPE_HEX2OCT: // v1 case OPTYPE_HEX2STR: // v1 case OPTYPE_INT2CHAR: // v1 case OPTYPE_INT2FLOAT: // v1 case OPTYPE_INT2STR: // v1 20 case OPTYPE_INT2UNICHAR: // v1 case OPTYPE_OCT2BIT: // v1 case OPTYPE_OCT2CHAR: // v1 case OPTYPE_OCT2HEX: // v1 case OPTYPE_OCT2INT: // v1 case OPTYPE_OCT2STR: // v1 case OPTYPE_STR2BIT: // v1 case OPTYPE_STR2FLOAT: // v1 case OPTYPE_STR2HEX: // v1 case OPTYPE_STR2INT: // v1 30 case OPTYPE_STR2OCT: // v1 case OPTYPE_UNICHAR2INT: // v1 case OPTYPE_UNICHAR2CHAR: // v1 case OPTYPE_ENUM2INT: // v1 case OPTYPE_REMOVE_BOM: //v1 case OPTYPE_GET_STRINGENCODING: //v1 case OPTYPE_DECODE_BASE64: //v1 case OPTYPE_CBOR2JSON: // v1 case OPTYPE_JSON2CBOR: // v1 case OPTYPE_BSON2JSON: // v1 case OPTYPE_JSON2BSON: // v1 u.expr.v1->chk_expr_immutability(); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: // v1 [v2] case OPTYPE_ENCODE_BASE64: //v1 [v2] u.expr.v1->chk_expr_immutability(); if (u.expr.v2) u.expr.v2->chk_expr_immutability(); break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: // v1 v2 case OPTYPE_MULTIPLY: // v1 v2 case OPTYPE_DIVIDE: // v1 v2 40 case OPTYPE_MOD: // v1 v2 case OPTYPE_REM: // v1 v2 case OPTYPE_CONCAT: // v1 v2 case OPTYPE_EQ: // v1 v2 == case OPTYPE_LT: // v1 v2 < case OPTYPE_GT: // v1 v2 > case OPTYPE_NE: // v1 v2 != case OPTYPE_GE: // v1 v2 >= case OPTYPE_LE: // v1 v2 <= case OPTYPE_AND: // v1 v2 50 case OPTYPE_OR: // v1 v2 case OPTYPE_XOR: // v1 v2 case OPTYPE_AND4B: // v1 v2 case OPTYPE_OR4B: // v1 v2 case OPTYPE_XOR4B: // v1 v2 case OPTYPE_SHL: // v1 v2 case OPTYPE_SHR: // v1 v2 case OPTYPE_ROTL: // v1 v2 case OPTYPE_ROTR: // v1 v2 case OPTYPE_INT2BIT: // v1 v2 60 case OPTYPE_INT2HEX: // v1 v2 case OPTYPE_INT2OCT: // v1 v2 u.expr.v1->chk_expr_immutability(); u.expr.v2->chk_expr_immutability(); break; case OPTYPE_ENCODE: // ti1 [v2] [v3] 35 case OPTYPE_DECODE: // r1 r2 [v3] [v4] // not yet done. break; case OPTYPE_SUBSTR: u.expr.ti1->chk_immutability(); u.expr.v2->chk_expr_immutability(); u.expr.v3->chk_expr_immutability(); break; case OPTYPE_REGEXP: u.expr.ti1->chk_immutability(); u.expr.t2->chk_immutability(); u.expr.v3->chk_expr_immutability(); break; case OPTYPE_DECOMP: // not implemented (reference guide) u.expr.v1->chk_expr_immutability(); u.expr.v2->chk_expr_immutability(); u.expr.v3->chk_expr_immutability(); break; case OPTYPE_REPLACE: // ti1 v2 v3 ti4 u.expr.ti1->chk_immutability(); u.expr.v2->chk_expr_immutability(); u.expr.v3->chk_expr_immutability(); u.expr.ti4->chk_immutability(); break; case OPTYPE_ISVALUE: // ti1 68 case OPTYPE_ISBOUND: // ti1 case OPTYPE_ISPRESENT: // ti1 case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_VALUEOF: // ti1 case OPTYPE_TTCN2STRING: // ti1 u.expr.ti1->chk_immutability(); break; case OPTYPE_ISCHOSEN: // r1 i2 break; case OPTYPE_ISCHOSEN_V: // v1 i2 u.expr.v1->chk_expr_immutability(); break; case OPTYPE_ISCHOSEN_T: // t1 i2 u.expr.t1->chk_immutability(); break; case OPTYPE_MATCH: // v1 t2 u.expr.v1->chk_expr_immutability(); u.expr.t2->chk_immutability(); break; case OPTYPE_UNDEF_RUNNING: case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_UNDEF_CREATE: case OPTYPE_CLASS_CREATE: // todo case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_RUNNING_ANY: // - case OPTYPE_COMP_RUNNING_ALL: // - case OPTYPE_COMP_ALIVE: // v1 case OPTYPE_COMP_ALIVE_ANY: // - case OPTYPE_COMP_ALIVE_ALL: // - warning("State of component(s) may change during the actual snapshot."); break; case OPTYPE_TMR_READ: // r1 90 case OPTYPE_TMR_RUNNING: // r1 [r2] b4 case OPTYPE_TMR_RUNNING_ANY: // - warning("State of timer(s) may change during the actual snapshot."); break; case OPTYPE_GETVERDICT: // - case OPTYPE_ACTIVATE: // r1 case OPTYPE_ACTIVATE_REFD: //v1 t_list2 case OPTYPE_EXECUTE: // r1 [v2] case OPTYPE_EXECUTE_REFD: // v1 t_list2 [v3] case OPTYPE_LOG2STR: // logargs case OPTYPE_PROF_RUNNING: // - 99 case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] case OPTYPE_GET_PORT_REF: // -optypes case OPTYPE_ANY2UNISTR: // logarg: length = 1 break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2: port or any case OPTYPE_CHECKSTATE_ALL: // [r1] v2: port or all warning("State of port(s) may change during the actual snapshot."); break; case OPTYPE_HOSTID: // [v1] if (u.expr.v1) u.expr.v1->chk_expr_immutability(); break; case OPTYPE_ISTEMPLATEKIND: // ti1 v2 u.expr.v2->chk_expr_immutability(); u.expr.ti1->chk_immutability(); break; case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: u.expr.r2->chk_immutability(); break; case OPTYPE_CLASS_CASTING_REF: u.expr.r1->chk_immutability(); u.expr.r2->chk_immutability(); break; default: FATAL_ERROR("Value::chk_expr_immutability()"); } break; case V_ERROR: /**< erroneous */ case V_UNDEF_LOWERID: /**< undefined loweridentifier */ case V_NULL: /**< NULL (for ASN.1 NULL type: also in TTCN-3) */ case V_BOOL: /**< boolean */ case V_NAMEDINT: /**< integer / named number */ case V_NAMEDBITS: /**< named bits (identifiers) */ case V_INT: /**< integer */ case V_REAL: /**< real/float */ case V_ENUM: /**< enumerated */ case V_BSTR: /**< bitstring */ case V_HSTR: /**< hexstring */ case V_OSTR: /**< octetstring */ case V_CSTR: /**< charstring */ case V_USTR: /**< universal charstring */ case V_ISO2022STR: /**< ISO-2022 string (treat as octetstring) */ case V_CHARSYMS: /**< parsed ASN.1 universal string notation */ case V_OID: /**< object identifier */ case V_ROID: /**< relative object identifier */ case V_CHOICE: /**< choice; set directly by the ASN.1 parser */ case V_SEQOF: /**< sequence (record) of */ case V_SETOF: /**< set of */ case V_ARRAY: /**< array */ case V_SEQ: /**< sequence (record) */ // TODO test? case V_SET: /**< set */ case V_OPENTYPE: /**< open type */ case V_UNDEF_BLOCK: /**< undefined {block} */ case V_OMIT: /**< special value for optional values */ case V_VERDICT: /**< verdict */ case V_TTCN3_NULL: /**< TTCN-3 null (for component or default references) */ case V_DEFAULT_NULL: /**< null default reference */ case V_FAT_NULL: /**< null for function: altstep and testcase */ case V_MACRO: /**< macros (%%something) */ case V_NOTUSED: /**< not used symbol ('-') */ case V_FUNCTION: /**< function */ case V_ALTSTEP: /**< altstep */ case V_TESTCASE: /**< testcase */ case V_INVOKE: /**< invoke operation */ case V_REFER: /**< refer(function) */ case V_ANY_VALUE: /**< any value (?) - used by template concatenation */ case V_ANY_OR_OMIT: /**< any or omit (*) - used by template concatenation */ break; default: FATAL_ERROR("Value::chk_expr_immutability()"); } // switch } void Value::clean_up() { switch (valuetype) { case V_ERROR: case V_NULL: case V_BOOL: case V_REAL: case V_OMIT: case V_VERDICT: case V_TTCN3_NULL: case V_DEFAULT_NULL: case V_FAT_NULL: case V_MACRO: case V_NOTUSED: case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: break; case V_INT: delete u.val_Int; break; case V_NAMEDINT: case V_ENUM: case V_UNDEF_LOWERID: delete u.val_id; break; case V_BSTR: case V_HSTR: case V_OSTR: case V_CSTR: case V_ISO2022STR: delete u.str.val_str; clean_up_string_elements(u.str.str_elements); break; case V_USTR: delete u.ustr.val_ustr; clean_up_string_elements(u.ustr.ustr_elements); break; case V_CHARSYMS: delete u.char_syms; break; case V_OID: case V_ROID: if (u.oid_comps) { for(size_t i=0; i<u.oid_comps->size(); i++) delete (*u.oid_comps)[i]; u.oid_comps->clear(); delete u.oid_comps; } break; case V_EXPR: clean_up_expr(); break; case V_CHOICE: delete u.choice.alt_name; delete u.choice.alt_value; break; case V_SEQOF: case V_SETOF: case V_ARRAY: delete u.val_vs; break; case V_SEQ: case V_SET: delete u.val_nvs; break; case V_REFD: delete u.ref.ref; break; case V_REFER: delete u.refered; break; case V_INVOKE: delete u.invoke.v; delete u.invoke.t_list; delete u.invoke.ap_list; break; case V_NAMEDBITS: if(u.ids) { for(size_t i=0; i<u.ids->size(); i++) delete u.ids->get_nth_elem(i); u.ids->clear(); delete u.ids; } break; case V_UNDEF_BLOCK: delete u.block; break; case V_ANY_VALUE: case V_ANY_OR_OMIT: delete u.len_res; break; default: FATAL_ERROR("Value::clean_up()"); } // switch } void Value::clean_up_expr() { switch (u.expr.state) { case EXPR_CHECKING: case EXPR_CHECKING_ERR: FATAL_ERROR("Value::clean_up_expr()"); default: break; } switch (u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_GET_PORT_REF: // type (not owned) case OPTYPE_NOW: break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: delete u.expr.r2; // no break case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_REMOVE_BOM: case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: case OPTYPE_HOSTID: delete u.expr.v1; break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: delete u.expr.v1; delete u.expr.v2; break; case OPTYPE_UNDEF_RUNNING: // r1 [r2] b4 case OPTYPE_TMR_RUNNING: // r1 [r2] b4 case OPTYPE_CLASS_CASTING_REF: delete u.expr.r1; delete u.expr.r2; break; case OPTYPE_DECODE: // r1 r2 [v3] [v4] delete u.expr.r1; delete u.expr.r2; delete u.expr.v3; delete u.expr.v4; break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: delete u.expr.ti1; delete u.expr.v2; delete u.expr.v3; break; case OPTYPE_REGEXP: delete u.expr.ti1; delete u.expr.t2; delete u.expr.v3; break; case OPTYPE_DECOMP: // v1 v2 v3 delete u.expr.v1; delete u.expr.v2; delete u.expr.v3; break; case OPTYPE_REPLACE: delete u.expr.ti1; delete u.expr.v2; delete u.expr.v3; delete u.expr.ti4; break; case OPTYPE_VALUEOF: // ti1 [subrefs2] delete u.expr.subrefs2; // fall through case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: delete u.expr.ti1; break; case OPTYPE_ISTEMPLATEKIND: // ti1 v2 delete u.expr.ti1; delete u.expr.v2; break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] delete u.expr.ti1; delete u.expr.v2; delete u.expr.v3; delete u.expr.v4; break; case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] delete u.expr.r1; delete u.expr.r2; delete u.expr.v3; delete u.expr.v4; delete u.expr.v5; break; case OPTYPE_TMR_READ: case OPTYPE_ACTIVATE: delete u.expr.r1; break; case OPTYPE_EXECUTE: // r1 [v2] delete u.expr.r1; delete u.expr.v2; break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2 case OPTYPE_CHECKSTATE_ALL: delete u.expr.r1; delete u.expr.v2; break; case OPTYPE_UNDEF_CREATE: case OPTYPE_CLASS_CREATE: delete u.expr.r1; if (u.expr.state != EXPR_CHECKED) { delete u.expr.t_list2; } else { delete u.expr.ap_list2; } break; case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 delete u.expr.r1; delete u.expr.v2; delete u.expr.v3; break; case OPTYPE_MATCH: // v1 t2 delete u.expr.v1; delete u.expr.t2; break; case OPTYPE_ISCHOSEN: // r1 i2 delete u.expr.r1; delete u.expr.i2; break; case OPTYPE_ISCHOSEN_V: // v1 i2 delete u.expr.v1; delete u.expr.i2; break; case OPTYPE_ISCHOSEN_T: // t1 i2 delete u.expr.t1; delete u.expr.i2; break; case OPTYPE_ACTIVATE_REFD: //v1 t_list2 delete u.expr.v1; if(u.expr.state!=EXPR_CHECKED) delete u.expr.t_list2; else delete u.expr.ap_list2; break; case OPTYPE_EXECUTE_REFD: //v1 t_list2 [v3] delete u.expr.v1; if(u.expr.state!=EXPR_CHECKED) delete u.expr.t_list2; else delete u.expr.ap_list2; delete u.expr.v3; break; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: delete u.expr.logargs; break; case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: delete u.expr.type; delete u.expr.r2; break; default: FATAL_ERROR("Value::clean_up_expr()"); } // switch } void Value::copy_and_destroy(Value *src) { clean_up(); valuetype = src->valuetype; u = src->u; // update the pointer used for caching if it points to the value itself if (valuetype == V_REFD && u.ref.refd_last == src) u.ref.refd_last = this; src->valuetype = V_ERROR; delete src; } Value::Value(valuetype_t p_vt) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_NULL: case V_TTCN3_NULL: case V_OMIT: case V_NOTUSED: case V_ERROR: break; case V_OID: case V_ROID: u.oid_comps=new vector<OID_comp>(); break; case V_NAMEDBITS: u.ids=new map<string, Identifier>(); break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, bool p_val_bool) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_BOOL: u.val_bool=p_val_bool; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, const Int& p_val_Int) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_INT: u.val_Int=new int_val_t(p_val_Int); break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, int_val_t *p_val_Int) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype){ case V_INT: u.val_Int=p_val_Int; break; default: FATAL_ERROR("Value::Value()"); } } Value::Value(valuetype_t p_vt, string *p_val_str) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_val_str) FATAL_ERROR("NULL parameter"); switch(valuetype) { case V_BSTR: case V_HSTR: case V_OSTR: case V_CSTR: case V_ISO2022STR: set_val_str(p_val_str); break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, ustring *p_val_ustr) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (p_vt != V_USTR || !p_val_ustr) FATAL_ERROR("Value::Value()"); set_val_ustr(p_val_ustr); u.ustr.convert_str = false; } Value::Value(valuetype_t p_vt, CharSyms *p_char_syms) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (!p_char_syms) FATAL_ERROR("NULL parameter"); switch (valuetype) { case V_CHARSYMS: u.char_syms = p_char_syms; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, Identifier *p_val_id) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_val_id) FATAL_ERROR("NULL parameter"); switch(valuetype) { case V_NAMEDINT: case V_ENUM: case V_UNDEF_LOWERID: u.val_id=p_val_id; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, Identifier *p_id, Value *p_val) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_id || !p_val) FATAL_ERROR("NULL parameter"); switch(valuetype) { case V_CHOICE: u.choice.alt_name=p_id; u.choice.alt_value=p_val; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, const Real& p_val_Real) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_REAL: u.val_Real=p_val_Real; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, Values *p_vs) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_vs) FATAL_ERROR("NULL parameter"); switch(valuetype) { case V_SEQOF: case V_SETOF: case V_ARRAY: u.val_vs=p_vs; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, Value *p_v, Ttcn::ParsedActualParameters *p_t_list) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_v || !p_t_list) FATAL_ERROR("NULL parameter"); switch(valuetype) { case V_INVOKE: u.invoke.v = p_v; u.invoke.t_list = p_t_list; u.invoke.ap_list = 0; break; default: FATAL_ERROR("Value::Value()"); } } // - Value::Value(operationtype_t p_optype) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_RND: case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_NOW: break; case OPTYPE_GET_PORT_REF: u.expr.type = NULL; // will be set during semantic analysis break; default: FATAL_ERROR("Value::Value()"); } // switch } // v1 Value::Value(operationtype_t p_optype, Value *p_v1) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_UNARYPLUS: case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_REMOVE_BOM: case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: if(!p_v1) FATAL_ERROR("Value::Value()"); u.expr.v1=p_v1; break; case OPTYPE_HOSTID: u.expr.v1=p_v1; break; default: FATAL_ERROR("Value::Value()"); } // switch } // v1 [r2] b4 Value::Value(operationtype_t p_optype, Value* p_v1, Ttcn::Reference *p_r2, bool p_b4) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_COMP_RUNNING: case OPTYPE_COMP_ALIVE: if (p_v1 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.v1 = p_v1; u.expr.r2 = p_r2; u.expr.b4 = p_b4; break; default: FATAL_ERROR("Value::Value()"); } // switch } // ti1 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_ENCVALUE_UNICHAR: u.expr.v2 = NULL; u.expr.v3 = NULL; u.expr.v4 = NULL; // fall through case OPTYPE_LENGTHOF: case OPTYPE_SIZEOF: case OPTYPE_VALUEOF: case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: if(!p_ti1) FATAL_ERROR("Value::Value()"); u.expr.ti1=p_ti1; if (p_optype == OPTYPE_VALUEOF) { u.expr.subrefs2 = NULL; } break; default: FATAL_ERROR("Value::Value()"); } // switch } // ti1 subrefs2 Value::Value(operationtype_t p_optype, TemplateInstance* p_ti1, Ttcn::FieldOrArrayRefs* p_subrefs2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch (p_optype) { case OPTYPE_VALUEOF: if (p_ti1 == NULL || p_subrefs2 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.ti1 = p_ti1; u.expr.subrefs2 = p_subrefs2; break; default: FATAL_ERROR("Value::Value()"); } // switch } // r1 Value::Value(operationtype_t p_optype, Ttcn::Reference *p_r1) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_TMR_READ: case OPTYPE_ACTIVATE: if(!p_r1) FATAL_ERROR("Value::Value()"); u.expr.r1=p_r1; break; default: FATAL_ERROR("Value::Value()"); } // switch } // r1 [r2] b4 Value::Value(operationtype_t p_optype, Ttcn::Reference* p_r1, Ttcn::Reference* p_r2, bool p_b4) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch (p_optype) { case OPTYPE_UNDEF_RUNNING: if (p_r1 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.r1 = p_r1; u.expr.r2 = p_r2; u.expr.b4 = p_b4; break; default: FATAL_ERROR("Value::Value()"); } // switch } // v1 t_list2 Value::Value(operationtype_t p_optype, Value *p_v1, Ttcn::ParsedActualParameters *p_ap_list) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_ACTIVATE_REFD: if(!p_v1 || !p_ap_list) FATAL_ERROR("Value::Value()"); u.expr.v1 = p_v1; u.expr.t_list2 = p_ap_list; break; default: FATAL_ERROR("Value::Value()"); } } //v1 t_list2 v3 Value::Value(operationtype_t p_optype, Value *p_v1, Ttcn::ParsedActualParameters *p_t_list2, Value *p_v3) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_EXECUTE_REFD: if(!p_v1 || !p_t_list2) FATAL_ERROR("Value::Value()"); u.expr.v1 = p_v1; u.expr.t_list2 = p_t_list2; u.expr.v3 = p_v3; break; default: FATAL_ERROR("Value::Value()"); } } // r1 [v2] or [r1] v2 Value::Value(operationtype_t p_optype, Ttcn::Reference *p_r1, Value *p_v2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_EXECUTE: if(!p_r1) FATAL_ERROR("Value::Value()"); u.expr.r1=p_r1; u.expr.v2=p_v2; break; case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: if(!p_v2) FATAL_ERROR("Value::Value()"); u.expr.r1=p_r1; // may be null if any port or all port u.expr.v2=p_v2; break; default: FATAL_ERROR("Value::Value()"); } // switch } // r1 t_list2 b4 Value::Value(operationtype_t p_optype, Ttcn::Reference *p_r1, Ttcn::ParsedActualParameters* p_t_list2, bool p_b4) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_UNDEF_CREATE: if(!p_r1) FATAL_ERROR("Value::Value()"); u.expr.r1 = p_r1; u.expr.t_list2 = p_t_list2; u.expr.b4 = p_b4; break; default: FATAL_ERROR("Value::Value()"); } // switch } // v1 v2 Value::Value(operationtype_t p_optype, Value *p_v1, Value *p_v2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_ADD: case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: if(!p_v1 || !p_v2) FATAL_ERROR("Value::Value()"); u.expr.v1=p_v1; u.expr.v2=p_v2; break; case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: if(!p_v1) FATAL_ERROR("Value::Value()"); u.expr.v1=p_v1; // p_v2 may be NULL if there is no second param u.expr.v2=p_v2; break; default: FATAL_ERROR("Value::Value()"); } // switch } // ti1 v2 v3 ti4 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, Value *p_v2, Value *p_v3, TemplateInstance *p_ti4) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch (p_optype) { case OPTYPE_REPLACE: if (!p_ti1 || !p_v2 || !p_v3 || !p_ti4) FATAL_ERROR("Value::Value()"); u.expr.ti1 = p_ti1; u.expr.v2 = p_v2; u.expr.v3 = p_v3; u.expr.ti4 = p_ti4; break; default: FATAL_ERROR("Value::Value()"); } // switch } // v1 v2 v3 Value::Value(operationtype_t p_optype, Value *p_v1, Value *p_v2, Value *p_v3) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_DECOMP: if(!p_v1 || !p_v2 || !p_v3) FATAL_ERROR("Value::Value()"); u.expr.v1=p_v1; u.expr.v2=p_v2; u.expr.v3=p_v3; break; default: FATAL_ERROR("Value::Value()"); } // switch } // ti1 [v2] Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, Value *p_v2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_ENCVALUE_UNICHAR: u.expr.v3 = NULL; u.expr.v4 = NULL; // fall through case OPTYPE_ISTEMPLATEKIND: if(!p_ti1 || !p_v2) FATAL_ERROR("Value::Value()"); u.expr.ti1=p_ti1; u.expr.v2=p_v2; break; default: FATAL_ERROR("Value::Value()"); } // switch } // ti1 v2 v3 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, Value *p_v2, Value *p_v3) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype=p_optype; u.expr.state=EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_ENCVALUE_UNICHAR: u.expr.v4 = NULL; // fall through case OPTYPE_SUBSTR: if(!p_ti1 || !p_v2 || !p_v3) FATAL_ERROR("Value::Value()"); u.expr.ti1 = p_ti1; u.expr.v2=p_v2; u.expr.v3=p_v3; break; case OPTYPE_ENCODE: if (p_ti1 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.ti1 = p_ti1; u.expr.v2 = p_v2; u.expr.v3 = p_v3; break; default: FATAL_ERROR("Value::Value()"); } // switch } // ti1 t2 v3 b4 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, TemplateInstance *p_t2, Value *p_v3, bool p_b4) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype=p_optype; u.expr.state=EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_REGEXP: if(!p_ti1 || !p_t2 || !p_v3) FATAL_ERROR("Value::Value()"); u.expr.ti1 = p_ti1; u.expr.t2 = p_t2; u.expr.v3 = p_v3; u.expr.b4 = p_b4; break; default: FATAL_ERROR("Value::Value()"); } // switch } // ti1 v2 v3 v4 Value::Value(operationtype_t p_optype, TemplateInstance* p_ti1, Value* p_v2, Value* p_v3, Value* p_v4) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch (p_optype) { case OPTYPE_ENCVALUE_UNICHAR: if (p_ti1 == NULL || p_v2 == NULL || p_v3 == NULL || p_v4 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.ti1 = p_ti1; u.expr.v2 = p_v2; u.expr.v3 = p_v3; u.expr.v4 = p_v4; break; default: FATAL_ERROR("Value::Value()"); } } // v1 t2 Value::Value(operationtype_t p_optype, Value *p_v1, TemplateInstance *p_t2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_MATCH: if(!p_v1 || !p_t2) FATAL_ERROR("Value::Value()"); u.expr.v1=p_v1; u.expr.t2=p_t2; break; default: FATAL_ERROR("Value::Value()"); } // switch } // r1 i2 Value::Value(operationtype_t p_optype, Ttcn::Reference *p_r1, Identifier *p_i2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_ISCHOSEN: if(!p_r1 || !p_i2) FATAL_ERROR("Value::Value()"); u.expr.r1=p_r1; u.expr.i2=p_i2; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(operationtype_t p_optype, LogArguments *p_logargs) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: if (!p_logargs) FATAL_ERROR("Value::Value()"); u.expr.logargs = p_logargs; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, macrotype_t p_macrotype) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (p_vt != V_MACRO) FATAL_ERROR("Value::Value()"); switch (p_macrotype) { case MACRO_MODULEID: case MACRO_FILENAME: case MACRO_BFILENAME: case MACRO_FILEPATH: case MACRO_LINENUMBER: case MACRO_LINENUMBER_C: case MACRO_DEFINITIONID: case MACRO_SCOPE: case MACRO_TESTCASEID: break; default: FATAL_ERROR("Value::Value()"); } u.macro = p_macrotype; } Value::Value(valuetype_t p_vt, NamedValues *p_nvs) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_nvs) FATAL_ERROR("NULL parameter"); switch(valuetype) { case V_SEQ: case V_SET: u.val_nvs=p_nvs; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, Reference *p_ref) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (!p_ref) FATAL_ERROR("NULL parameter: Value::Value()"); switch(p_vt) { case V_REFD: u.ref.ref = p_ref; u.ref.refd_last = 0; break; case V_REFER: u.refered = p_ref; break; default: FATAL_ERROR("Value::Value()"); } } Value::Value(valuetype_t p_vt, Block *p_block) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_block) FATAL_ERROR("NULL parameter"); switch(valuetype) { case V_UNDEF_BLOCK: u.block=p_block; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::Value(valuetype_t p_vt, verdict_t p_verdict) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (valuetype != V_VERDICT) FATAL_ERROR("Value::Value()"); switch (p_verdict) { case Verdict_NONE: case Verdict_PASS: case Verdict_INCONC: case Verdict_FAIL: case Verdict_ERROR: break; default: FATAL_ERROR("Value::Value()"); } // switch u.verdict = p_verdict; } Value::Value(operationtype_t p_optype, Ttcn::Reference *p_r1, Ttcn::Reference *p_r2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_DECVALUE_UNICHAR: u.expr.v5 = NULL; // fall through case OPTYPE_DECODE: if(!p_r1 || !p_r2) FATAL_ERROR("Value::Value()"); u.expr.r1=p_r1; u.expr.r2=p_r2; u.expr.v3=NULL; u.expr.v4 = NULL; break; case OPTYPE_CLASS_CASTING_REF: if (p_r1 == NULL || p_r2 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.r1 = p_r1; u.expr.r2 = p_r2; break; default: FATAL_ERROR("Value::Value()"); } // switch } // r1 r2 [v3] Value::Value(operationtype_t p_optype, Ttcn::Reference *p_r1, Ttcn::Reference *p_r2, Value *p_v3) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch(p_optype) { case OPTYPE_DECVALUE_UNICHAR: u.expr.v5 = NULL; // fall through case OPTYPE_DECODE: if(!p_r1 || !p_r2 || !p_v3) FATAL_ERROR("Value::Value()"); u.expr.r1=p_r1; u.expr.r2=p_r2; u.expr.v3=p_v3; u.expr.v4 = NULL; break; default: FATAL_ERROR("Value::Value()"); } // switch } // r1 r2 [v3] [v4] Value::Value(operationtype_t p_optype, Ttcn::Reference* p_r1, Ttcn::Reference* p_r2, Value* p_v3, Value* p_v4) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch (p_optype) { case OPTYPE_DECVALUE_UNICHAR: u.expr.v5 = NULL; // fall through case OPTYPE_DECODE: if(p_r1 == NULL || p_r2 == NULL || p_v3 == NULL || p_v4 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.r1 = p_r1; u.expr.r2 = p_r2; u.expr.v3 = p_v3; u.expr.v4 = p_v4; break; default: FATAL_ERROR("Value::Value()"); } // switch } // r1 r2 [v3] [v4] [v5] Value::Value(operationtype_t p_optype, Ttcn::Reference* p_r1, Ttcn::Reference* p_r2, Value* p_v3, Value* p_v4, Value* p_v5) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch (p_optype) { case OPTYPE_DECVALUE_UNICHAR: if(p_r1 == NULL || p_r2 == NULL || p_v3 == NULL || p_v4 == NULL || p_v5 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.r1 = p_r1; u.expr.r2 = p_r2; u.expr.v3 = p_v3; u.expr.v4 = p_v4; u.expr.v5 = p_v5; break; default: FATAL_ERROR("Value::Value()"); } // switch } // V_ANY_VALUE, V_ANY_OR_OMIT Value::Value(valuetype_t p_vt, Ttcn::LengthRestriction* p_len_res) : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) { switch(p_vt) { case V_ANY_VALUE: case V_ANY_OR_OMIT: u.len_res = p_len_res; break; default: FATAL_ERROR("Value::Value()"); } // switch } // type r2 Value::Value(operationtype_t p_optype, Type* p_type, Ttcn::Reference* p_r2) : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; switch (p_optype) { case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: if (p_type == NULL || p_r2 == NULL) { FATAL_ERROR("Value::Value()"); } u.expr.type = p_type; u.expr.r2 = p_r2; break; default: FATAL_ERROR("Value::Value()"); } // switch } Value::~Value() { clean_up(); } Value *Value::clone() const { return new Value(*this); } Value::operationtype_t Value::get_optype() const { if(valuetype!=V_EXPR) FATAL_ERROR("Value::get_optype()"); return u.expr.v_optype; } Value* Value::get_concat_operand(bool first_operand) const { if (valuetype != V_EXPR || u.expr.v_optype != OPTYPE_CONCAT) { FATAL_ERROR("Value::get_concat_operand()"); } return first_operand ? u.expr.v1 : u.expr.v2; } Ttcn::LengthRestriction* Value::take_length_restriction() { if (valuetype != V_ANY_VALUE && valuetype != V_ANY_OR_OMIT) { FATAL_ERROR("Value::take_length_restriction()"); } Ttcn::LengthRestriction* ptr = u.len_res; u.len_res = NULL; return ptr; } void Value::set_my_governor(Type *p_gov) { if(!p_gov) FATAL_ERROR("Value::set_my_governor(): NULL parameter"); my_governor=p_gov; } Type *Value::get_my_governor() const { return my_governor; } void Value::set_fullname(const string& p_fullname) { GovernedSimple::set_fullname(p_fullname); switch(valuetype) { case V_CHARSYMS: u.char_syms->set_fullname(p_fullname); break; case V_OID: case V_ROID: for(size_t i=0; i<u.oid_comps->size(); i++) (*u.oid_comps)[i]->set_fullname(p_fullname+"."+Int2string(i+1)); break; case V_CHOICE: u.choice.alt_value->set_fullname(p_fullname + "." + u.choice.alt_name->get_dispname()); break; case V_SEQOF: case V_SETOF: case V_ARRAY: u.val_vs->set_fullname(p_fullname); break; case V_SEQ: case V_SET: u.val_nvs->set_fullname(p_fullname); break; case V_REFD: u.ref.ref->set_fullname(p_fullname); break; case V_REFER: u.refered->set_fullname(p_fullname); break; case V_INVOKE: u.invoke.v->set_fullname(p_fullname); if(u.invoke.t_list) u.invoke.t_list->set_fullname(p_fullname); if(u.invoke.ap_list) u.invoke.ap_list->set_fullname(p_fullname); break; case V_EXPR: set_fullname_expr(p_fullname); break; default: break; } // switch } void Value::set_my_scope(Scope *p_scope) { GovernedSimple::set_my_scope(p_scope); switch(valuetype) { case V_CHARSYMS: u.char_syms->set_my_scope(p_scope); break; case V_OID: case V_ROID: for(size_t i=0; i<u.oid_comps->size(); i++) (*u.oid_comps)[i]->set_my_scope(p_scope); break; case V_CHOICE: u.choice.alt_value->set_my_scope(p_scope); break; case V_SEQOF: case V_SETOF: case V_ARRAY: u.val_vs->set_my_scope(p_scope); break; case V_SEQ: case V_SET: u.val_nvs->set_my_scope(p_scope); break; case V_REFD: u.ref.ref->set_my_scope(p_scope); break; case V_REFER: u.refered->set_my_scope(p_scope); break; case V_INVOKE: u.invoke.v->set_my_scope(p_scope); if(u.invoke.t_list) u.invoke.t_list->set_my_scope(p_scope); if(u.invoke.ap_list) u.invoke.ap_list->set_my_scope(p_scope); break; case V_EXPR: set_my_scope_expr(p_scope); break; default: break; } // switch } void Value::set_fullname_expr(const string& p_fullname) { switch (u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_GET_PORT_REF: case OPTYPE_NOW: break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_REMOVE_BOM: case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: u.expr.v1->set_fullname(p_fullname+".<operand>"); break; case OPTYPE_HOSTID: // [v1] if(u.expr.v1) u.expr.v1->set_fullname(p_fullname+".<operand>"); break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1->set_fullname(p_fullname+".<operand1>"); u.expr.v2->set_fullname(p_fullname+".<operand2>"); break; case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->set_fullname(p_fullname+".<operand1>"); if(u.expr.v2) u.expr.v2->set_fullname(p_fullname+".<operand2>"); break; case OPTYPE_DECODE: u.expr.r1->set_fullname(p_fullname+".<operand1>"); u.expr.r2->set_fullname(p_fullname+".<operand2>"); if (u.expr.v3 != NULL) { u.expr.v3->set_fullname(p_fullname+".<operand2>"); } if (u.expr.v4 != NULL) { u.expr.v4->set_fullname(p_fullname+".<operand3>"); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->set_fullname(p_fullname+".<operand1>"); if (u.expr.v2 != NULL) { u.expr.v2->set_fullname(p_fullname+".<operand2>"); } if (u.expr.v3 != NULL) { u.expr.v3->set_fullname(p_fullname+".<operand3>"); } break; case OPTYPE_REGEXP: u.expr.ti1->set_fullname(p_fullname+".<operand1>"); u.expr.t2->set_fullname(p_fullname+".<operand2>"); u.expr.v3->set_fullname(p_fullname+".<operand3>"); break; case OPTYPE_DECOMP: // v1 v2 v3 u.expr.v1->set_fullname(p_fullname+".<operand1>"); u.expr.v2->set_fullname(p_fullname+".<operand2>"); u.expr.v3->set_fullname(p_fullname+".<operand3>"); break; case OPTYPE_REPLACE: u.expr.ti1->set_fullname(p_fullname+".<operand1>"); u.expr.v2->set_fullname(p_fullname+".<operand2>"); u.expr.v3->set_fullname(p_fullname+".<operand3>"); u.expr.ti4->set_fullname(p_fullname+".<operand4>"); break; case OPTYPE_VALUEOF: // ti1 [subrefs2] if (u.expr.subrefs2 != NULL) { u.expr.subrefs2->set_fullname(p_fullname + ".<subrefs>"); } // fall through case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->set_fullname(p_fullname+".<operand>"); break; case OPTYPE_ISTEMPLATEKIND: // ti1 v2 u.expr.ti1->set_fullname(p_fullname+".<operand1>"); u.expr.v2->set_fullname(p_fullname+".<operand2>"); break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] u.expr.ti1->set_fullname(p_fullname + ".<operand1>"); if (u.expr.v2 != NULL) { u.expr.v2->set_fullname(p_fullname + ".<operand2>"); } if (u.expr.v3 != NULL) { u.expr.v3->set_fullname(p_fullname + ".<operand3>"); } if (u.expr.v4 != NULL) { u.expr.v4->set_fullname(p_fullname + ".<operand4>"); } break; case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] u.expr.r1->set_fullname(p_fullname + ".<operand1>"); u.expr.r2->set_fullname(p_fullname + ".<operand2>"); if (u.expr.v3 != NULL) { u.expr.v3->set_fullname(p_fullname + ".<operand3>"); } if (u.expr.v4 != NULL) { u.expr.v4->set_fullname(p_fullname + ".<operand4>"); } if (u.expr.v5 != NULL) { u.expr.v4->set_fullname(p_fullname + ".<operand5>"); } break; case OPTYPE_TMR_READ: // r1 case OPTYPE_ACTIVATE: u.expr.r1->set_fullname(p_fullname+".<operand>"); break; case OPTYPE_EXECUTE: // r1 [v2] u.expr.r1->set_fullname(p_fullname+".<operand1>"); if(u.expr.v2) u.expr.v2->set_fullname(p_fullname+".<operand2>"); break; case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 u.expr.r1->set_fullname(p_fullname+".<operand1>"); if(u.expr.v2) u.expr.v2->set_fullname(p_fullname+".<operand2>"); if(u.expr.v3) u.expr.v3->set_fullname(p_fullname+".<operand3>"); break; case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4 case OPTYPE_CLASS_CREATE: // r1 t_list2 b4 u.expr.r1->set_fullname(p_fullname+".<operand1>"); u.expr.t_list2->set_fullname(p_fullname+".<parameterlist>"); break; case OPTYPE_MATCH: // v1 t2 u.expr.v1->set_fullname(p_fullname+".<operand1>"); u.expr.t2->set_fullname(p_fullname+".<operand2>"); break; case OPTYPE_ISCHOSEN: // r1 i2 u.expr.r1->set_fullname(p_fullname+".<operand>"); break; case OPTYPE_ISCHOSEN_V: // v1 i2 u.expr.v1->set_fullname(p_fullname+".<operand>"); break; case OPTYPE_ISCHOSEN_T: // t1 i2 u.expr.t1->set_fullname(p_fullname+".<operand>"); break; case OPTYPE_ACTIVATE_REFD: u.expr.v1->set_fullname(p_fullname+".<reference>"); if(u.expr.state!=EXPR_CHECKED) u.expr.t_list2->set_fullname(p_fullname+".<parameterlist>"); else u.expr.ap_list2->set_fullname(p_fullname+".<parameterlist>"); break; case OPTYPE_EXECUTE_REFD: u.expr.v1->set_fullname(p_fullname+".<reference>"); if(u.expr.state!=EXPR_CHECKED) u.expr.t_list2->set_fullname(p_fullname+".<parameterlist>"); else u.expr.ap_list2->set_fullname(p_fullname+".<parameterlist>"); if(u.expr.v3) u.expr.v3->set_fullname(p_fullname+".<operand3>"); break; case OPTYPE_LOG2STR: u.expr.logargs->set_fullname(p_fullname+".<logargs>"); break; case OPTYPE_ANY2UNISTR: u.expr.logargs->set_fullname(p_fullname+".<logarg>"); break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2 case OPTYPE_CHECKSTATE_ALL: u.expr.v2->set_fullname(p_fullname+".<operand1>"); break; case OPTYPE_UNDEF_RUNNING: // r1 [r2] b4 case OPTYPE_TMR_RUNNING: u.expr.r1->set_fullname(p_fullname+".<operand>"); if (u.expr.r2 != NULL) { u.expr.r2->set_fullname(p_fullname+".redirindex"); } break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: u.expr.v1->set_fullname(p_fullname+".<operand>"); if (u.expr.r2 != NULL) { u.expr.r2->set_fullname(p_fullname+".redirindex"); } break; case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: u.expr.type->set_fullname(p_fullname + ".<classtype>"); u.expr.r2->set_fullname(p_fullname + ".<operand>"); break; case OPTYPE_CLASS_CASTING_REF: u.expr.r1->set_fullname(p_fullname + ".<operand2>"); u.expr.r2->set_fullname(p_fullname + ".<operand1>"); break; default: FATAL_ERROR("Value::set_fullname_expr()"); } // switch } void Value::set_my_scope_expr(Scope *p_scope) { switch (u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_GET_PORT_REF: case OPTYPE_NOW: break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: if (u.expr.r2 != NULL) { u.expr.r2->set_my_scope(p_scope); } // no break case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_REMOVE_BOM: case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: u.expr.v1->set_my_scope(p_scope); break; case OPTYPE_HOSTID: // [v1] if(u.expr.v1) u.expr.v1->set_my_scope(p_scope); break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1->set_my_scope(p_scope); u.expr.v2->set_my_scope(p_scope); break; case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->set_my_scope(p_scope); if(u.expr.v2) u.expr.v2->set_my_scope(p_scope); break; case OPTYPE_UNDEF_RUNNING: // r1 [r2] b4 case OPTYPE_TMR_RUNNING: // r1 [r2] b4 u.expr.r1->set_my_scope(p_scope); if (u.expr.r2 != NULL) { u.expr.r2->set_my_scope(p_scope); } break; case OPTYPE_DECODE: // r1 r2 [v3] [v4] u.expr.r1->set_my_scope(p_scope); u.expr.r2->set_my_scope(p_scope); if (u.expr.v3 != NULL) { u.expr.v3->set_my_scope(p_scope); } if (u.expr.v4 != NULL) { u.expr.v4->set_my_scope(p_scope); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->set_my_scope(p_scope); if (u.expr.v2 != NULL) { u.expr.v2->set_my_scope(p_scope); } if (u.expr.v3 != NULL) { u.expr.v3->set_my_scope(p_scope); } break; case OPTYPE_REGEXP: u.expr.ti1->set_my_scope(p_scope); u.expr.t2->set_my_scope(p_scope); u.expr.v3->set_my_scope(p_scope); break; case OPTYPE_DECOMP: // v1 v2 v3 u.expr.v1->set_my_scope(p_scope); u.expr.v2->set_my_scope(p_scope); u.expr.v3->set_my_scope(p_scope); break; case OPTYPE_REPLACE: u.expr.ti1->set_my_scope(p_scope); u.expr.v2->set_my_scope(p_scope); u.expr.v3->set_my_scope(p_scope); u.expr.ti4->set_my_scope(p_scope); break; case OPTYPE_VALUEOF: // ti1 [subrefs2] if (u.expr.subrefs2 != NULL) { u.expr.subrefs2->set_my_scope(p_scope); } // fall through case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->set_my_scope(p_scope); break; case OPTYPE_ISTEMPLATEKIND: // ti1 v2 u.expr.ti1->set_my_scope(p_scope); u.expr.v2->set_my_scope(p_scope); break; case OPTYPE_ENCVALUE_UNICHAR: //ti1 [v2] [v3] [v4] u.expr.ti1->set_my_scope(p_scope); if (u.expr.v2 != NULL) { u.expr.v2->set_my_scope(p_scope); } if (u.expr.v3 != NULL) { u.expr.v3->set_my_scope(p_scope); } if (u.expr.v4 != NULL) { u.expr.v4->set_my_scope(p_scope); } break; case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] u.expr.r1->set_my_scope(p_scope); u.expr.r2->set_my_scope(p_scope); if (u.expr.v3 != NULL) { u.expr.v3->set_my_scope(p_scope); } if (u.expr.v4 != NULL) { u.expr.v4->set_my_scope(p_scope); } if (u.expr.v5 != NULL) { u.expr.v5->set_my_scope(p_scope); } break; case OPTYPE_TMR_READ: // r1 case OPTYPE_ACTIVATE: u.expr.r1->set_my_scope(p_scope); break; case OPTYPE_EXECUTE: // r1 [v2] u.expr.r1->set_my_scope(p_scope); if(u.expr.v2) u.expr.v2->set_my_scope(p_scope); break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2 case OPTYPE_CHECKSTATE_ALL: if(u.expr.r1) u.expr.r1->set_my_scope(p_scope); u.expr.v2->set_my_scope(p_scope); break; case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4 case OPTYPE_CLASS_CREATE: // r1 t_list2 u.expr.r1->set_my_scope(p_scope); if (u.expr.state != EXPR_CHECKED) { u.expr.t_list2->set_my_scope(p_scope); } else { u.expr.ap_list2->set_my_scope(p_scope); } break; case OPTYPE_COMP_CREATE: // r1 [v2] [v3] u.expr.r1->set_my_scope(p_scope); if(u.expr.v2) u.expr.v2->set_my_scope(p_scope); if(u.expr.v3) u.expr.v3->set_my_scope(p_scope); break; case OPTYPE_MATCH: // v1 t2 u.expr.v1->set_my_scope(p_scope); u.expr.t2->set_my_scope(p_scope); break; case OPTYPE_ISCHOSEN: // r1 i2 u.expr.r1->set_my_scope(p_scope); break; case OPTYPE_ISCHOSEN_V: // v1 i2 u.expr.v1->set_my_scope(p_scope); break; case OPTYPE_ISCHOSEN_T: // t1 i2 u.expr.t1->set_my_scope(p_scope); break; case OPTYPE_ACTIVATE_REFD: u.expr.v1->set_my_scope(p_scope); if(u.expr.state!=EXPR_CHECKED) { if(u.expr.t_list2) u.expr.t_list2->set_my_scope(p_scope); else if(u.expr.ap_list2) u.expr.ap_list2->set_my_scope(p_scope); } break; case OPTYPE_EXECUTE_REFD: u.expr.v1->set_my_scope(p_scope); if(u.expr.state!=EXPR_CHECKED) { if(u.expr.t_list2) u.expr.t_list2->set_my_scope(p_scope); else if(u.expr.ap_list2) u.expr.ap_list2->set_my_scope(p_scope); } if(u.expr.v3) u.expr.v3->set_my_scope(p_scope); break; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: u.expr.logargs->set_my_scope(p_scope); break; case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: u.expr.type->set_my_scope(p_scope); u.expr.r2->set_my_scope(p_scope); break; case OPTYPE_CLASS_CASTING_REF: u.expr.r1->set_my_scope(p_scope); u.expr.r2->set_my_scope(p_scope); break; default: FATAL_ERROR("Value::set_my_scope_expr()"); } // switch } void Value::set_genname_recursive(const string& p_genname) { size_t genname_len = p_genname.size(); if (genname_len >= 4 && p_genname.find("()()", genname_len - 4) == genname_len - 4) { // if the genname ends with ()() (i.e. the value stands for an optional // field) then drop the last () from the own genname, but leave it for // the embedded values set_genname(p_genname.substr(0, genname_len - 2)); } else set_genname(p_genname); switch(valuetype) { case V_CHOICE: { string embedded_genname(p_genname); embedded_genname += '.'; // If this is a choice value for an anytype, prepend the AT_ prefix // to the name of the alternative. The genname is used later in // Common::Value::generate_code_init_se() if (my_governor->get_type_refd_last()->get_typetype()==Type::T_ANYTYPE) embedded_genname += "AT_"; embedded_genname += u.choice.alt_name->get_name(); embedded_genname += "()"; u.choice.alt_value->set_genname_recursive(embedded_genname); break; } case V_SEQOF: case V_SETOF: { if (!is_indexed()) { size_t nof_vs = u.val_vs->get_nof_vs(); for (size_t i = 0; i < nof_vs; i++) { string embedded_genname(p_genname); embedded_genname += '['; embedded_genname += Int2string(i); embedded_genname += ']'; u.val_vs->get_v_byIndex(i)->set_genname_recursive(embedded_genname); } } else { size_t nof_ivs = u.val_vs->get_nof_ivs(); for (size_t i = 0; i < nof_ivs; i++) { string embedded_genname(p_genname); embedded_genname += '['; embedded_genname += Int2string(i); embedded_genname += ']'; u.val_vs->get_iv_byIndex(i)->get_value() ->set_genname_recursive(embedded_genname); } } break; } case V_ARRAY: { if (!my_governor) return; // error recovery Type *type = my_governor->get_type_refd_last(); if (type->get_typetype() != Type::T_ARRAY) return; // error recovery Int offset = type->get_dimension()->get_offset(); if (!is_indexed()) { size_t nof_vs = u.val_vs->get_nof_vs(); for (size_t i = 0; i < nof_vs; i++) { string embedded_genname(p_genname); embedded_genname += '['; embedded_genname += Int2string(offset + i); embedded_genname += ']'; u.val_vs->get_v_byIndex(i)->set_genname_recursive(embedded_genname); } } else { size_t nof_ivs = u.val_vs->get_nof_ivs(); for (size_t i = 0; i < nof_ivs; i++) { string embedded_genname(p_genname); embedded_genname += '['; embedded_genname += Int2string(offset + i); embedded_genname += ']'; u.val_vs->get_iv_byIndex(i)->get_value() ->set_genname_recursive(embedded_genname); } } break; } case V_SEQ: case V_SET: { if (!my_governor) return; // error recovery Type *t = my_governor->get_type_refd_last(); if (!t->is_secho()) return; // error recovery size_t nof_nvs = u.val_nvs->get_nof_nvs(); for (size_t i = 0; i < nof_nvs; i++) { NamedValue *nv = u.val_nvs->get_nv_byIndex(i); const Identifier& id = nv->get_name(); if (!t->has_comp_withName(id)) return; // error recovery string embedded_genname(p_genname); embedded_genname += '.'; embedded_genname += id.get_name(); embedded_genname += "()"; if (t->get_comp_byName(id)->get_is_optional()) embedded_genname += "()"; nv->get_value()->set_genname_recursive(embedded_genname); } break; } default: break; } // switch } void Value::set_genname_prefix(const char *p_genname_prefix) { GovernedSimple::set_genname_prefix(p_genname_prefix); switch(valuetype) { case V_CHOICE: u.choice.alt_value->set_genname_prefix(p_genname_prefix); break; case V_SEQOF: case V_SETOF: case V_ARRAY: if (!is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_vs(); i++) u.val_vs->get_v_byIndex(i)->set_genname_prefix(p_genname_prefix); } else { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) u.val_vs->get_iv_byIndex(i)->get_value() ->set_genname_prefix(p_genname_prefix); } break; case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); i++) u.val_nvs->get_nv_byIndex(i)->get_value() ->set_genname_prefix(p_genname_prefix); break; default: break; } // switch } void Value::set_code_section(code_section_t p_code_section) { GovernedSimple::set_code_section(p_code_section); switch(valuetype) { case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_GET_PORT_REF: case OPTYPE_NOW: break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: if (u.expr.r2 != NULL) { u.expr.r2->set_code_section(p_code_section); } // no break case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: case OPTYPE_REMOVE_BOM: u.expr.v1->set_code_section(p_code_section); break; case OPTYPE_HOSTID: // [v1] if(u.expr.v1) u.expr.v1->set_code_section(p_code_section); break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1->set_code_section(p_code_section); u.expr.v2->set_code_section(p_code_section); break; case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->set_code_section(p_code_section); if(u.expr.v2) u.expr.v2->set_code_section(p_code_section); break; case OPTYPE_UNDEF_RUNNING: // r1 [r2] b4 case OPTYPE_TMR_RUNNING: // r1 [r2] b4 u.expr.r1->set_code_section(p_code_section); if (u.expr.r2 != NULL) { u.expr.r2->set_code_section(p_code_section); } break; case OPTYPE_DECODE: u.expr.r1->set_code_section(p_code_section); u.expr.r2->set_code_section(p_code_section); if (u.expr.v3 != NULL) { u.expr.v3->set_code_section(p_code_section); } if (u.expr.v4 != NULL) { u.expr.v4->set_code_section(p_code_section); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->set_code_section(p_code_section); if (u.expr.v2 != NULL) { u.expr.v2->set_code_section(p_code_section); } if (u.expr.v3 != NULL) { u.expr.v3->set_code_section(p_code_section); } break; case OPTYPE_REGEXP: u.expr.ti1->set_code_section(p_code_section); u.expr.t2->set_code_section(p_code_section); u.expr.v3->set_code_section(p_code_section); break; case OPTYPE_DECOMP: // v1 v2 v3 u.expr.v1->set_code_section(p_code_section); u.expr.v2->set_code_section(p_code_section); u.expr.v3->set_code_section(p_code_section); break; case OPTYPE_REPLACE: u.expr.ti1->set_code_section(p_code_section); u.expr.v2->set_code_section(p_code_section); u.expr.v3->set_code_section(p_code_section); u.expr.ti4->set_code_section(p_code_section); break; case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_VALUEOF: // ti1 [subrefs2] case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->set_code_section(p_code_section); break; case OPTYPE_ISTEMPLATEKIND: // ti1 v2 u.expr.ti1->set_code_section(p_code_section); u.expr.v2->set_code_section(p_code_section); break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] u.expr.ti1->set_code_section(p_code_section); if (u.expr.v2 != NULL) { u.expr.v2->set_code_section(p_code_section); } if (u.expr.v3 != NULL) { u.expr.v3->set_code_section(p_code_section); } if (u.expr.v4 != NULL) { u.expr.v4->set_code_section(p_code_section); } break; case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] u.expr.r1->set_code_section(p_code_section); u.expr.r2->set_code_section(p_code_section); if (u.expr.v3 != NULL) { u.expr.v3->set_code_section(p_code_section); } if (u.expr.v4 != NULL) { u.expr.v4->set_code_section(p_code_section); } if (u.expr.v5 != NULL) { u.expr.v5->set_code_section(p_code_section); } break; case OPTYPE_TMR_READ: // r1 case OPTYPE_ACTIVATE: u.expr.r1->set_code_section(p_code_section); break; case OPTYPE_EXECUTE: // r1 [v2] u.expr.r1->set_code_section(p_code_section); if(u.expr.v2) u.expr.v2->set_code_section(p_code_section); break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2 case OPTYPE_CHECKSTATE_ALL: if(u.expr.r1) u.expr.r1->set_code_section(p_code_section); u.expr.v2->set_code_section(p_code_section); break; case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4 case OPTYPE_CLASS_CREATE: // r1 t_list2 u.expr.r1->set_code_section(p_code_section); if (u.expr.state != EXPR_CHECKED) { u.expr.t_list2->set_code_section(p_code_section); } else { for (size_t i = 0; i < u.expr.ap_list2->get_nof_pars(); ++i) { u.expr.ap_list2->get_par(i)->set_code_section(p_code_section); } u.expr.state = EXPR_CHECKED; } break; case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 u.expr.r1->set_code_section(p_code_section); if(u.expr.v2) u.expr.v2->set_code_section(p_code_section); if(u.expr.v3) u.expr.v3->set_code_section(p_code_section); break; case OPTYPE_MATCH: // v1 t2 u.expr.v1->set_code_section(p_code_section); u.expr.t2->set_code_section(p_code_section); break; case OPTYPE_ISCHOSEN: // r1 i2 u.expr.r1->set_code_section(p_code_section); break; case OPTYPE_ISCHOSEN_V: // v1 i2 u.expr.v1->set_code_section(p_code_section); break; case OPTYPE_ISCHOSEN_T: // t1 i2 u.expr.t1->set_code_section(p_code_section); break; case OPTYPE_ACTIVATE_REFD: u.expr.v1->set_code_section(p_code_section); if(u.expr.state!=EXPR_CHECKED) u.expr.t_list2->set_code_section(p_code_section); else { for(size_t i = 0; i < u.expr.ap_list2->get_nof_pars(); i++) u.expr.ap_list2->get_par(i)->set_code_section(p_code_section); u.expr.state = EXPR_CHECKED; } break; case OPTYPE_EXECUTE_REFD: u.expr.v1->set_code_section(p_code_section); if(u.expr.state!=EXPR_CHECKED) u.expr.t_list2->set_code_section(p_code_section); else { for(size_t i = 0; i < u.expr.ap_list2->get_nof_pars(); i++) u.expr.ap_list2->get_par(i)->set_code_section(p_code_section); u.expr.state = EXPR_CHECKED; } if(u.expr.v3) u.expr.v3->set_code_section(p_code_section); break; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: u.expr.logargs->set_code_section(p_code_section); break; case OPTYPE_CLASS_CASTING_REF: u.expr.r1->set_code_section(p_code_section); // no break case OPTYPE_CLASS_CASTING: case OPTYPE_OF_CLASS: u.expr.r2->set_code_section(p_code_section); break; default: FATAL_ERROR("Value::set_code_section()"); } // switch break; case V_CHOICE: u.choice.alt_value->set_code_section(p_code_section); break; case V_SEQOF: case V_SETOF: case V_ARRAY: if (!is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_vs(); i++) u.val_vs->get_v_byIndex(i)->set_code_section(p_code_section); } else { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) u.val_vs->get_iv_byIndex(i)->set_code_section(p_code_section); } break; case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); i++) u.val_nvs->get_nv_byIndex(i)->get_value() ->set_code_section(p_code_section); break; case V_REFD: u.ref.ref->set_code_section(p_code_section); break; case V_REFER: u.refered->set_code_section(p_code_section); break; case V_INVOKE: u.invoke.v->set_code_section(p_code_section); if(u.invoke.t_list) u.invoke.t_list->set_code_section(p_code_section); if(u.invoke.ap_list) for(size_t i = 0; i < u.invoke.ap_list->get_nof_pars(); i++) u.invoke.ap_list->get_par(i)->set_code_section(p_code_section); break; default: break; } // switch } void Value::change_sign() { switch(valuetype) { case V_INT: *u.val_Int=-*u.val_Int; break; case V_REAL: u.val_Real*=-1.0; break; case V_ERROR: break; default: FATAL_ERROR("Value::change_sign()"); } // switch } void Value::add_oid_comp(OID_comp* p_comp) { if(!p_comp) FATAL_ERROR("NULL parameter"); u.oid_comps->add(p_comp); p_comp->set_fullname(get_fullname()+"." +Int2string(u.oid_comps->size())); p_comp->set_my_scope(my_scope); } void Value::set_valuetype(valuetype_t p_valuetype) { if (valuetype == V_ERROR) return; else if (p_valuetype == V_ERROR) { if(valuetype==V_EXPR) { switch(u.expr.state) { case EXPR_CHECKING: u.expr.state=EXPR_CHECKING_ERR; // no break case EXPR_CHECKING_ERR: return; default: break; } } clean_up(); valuetype = V_ERROR; return; } switch(valuetype) { case V_UNDEF_LOWERID: switch(p_valuetype) { case V_ENUM: case V_NAMEDINT: break; case V_REFD: if (is_asn1()) u.ref.ref = new Asn::Ref_defd_simple(0, u.val_id); else u.ref.ref = new Ttcn::Reference(0, u.val_id); u.ref.ref->set_my_scope(get_my_scope()); u.ref.ref->set_fullname(get_fullname()); u.ref.ref->set_location(*this); u.ref.refd_last = 0; break; default: FATAL_ERROR("Value::set_valuetype()"); } // switch break; case V_UNDEF_BLOCK: { Block *t_block=u.block; Value *v=0; switch(p_valuetype) { case V_NAMEDBITS: { Node *node=t_block->parse(KW_Block_IdentifierList); v=dynamic_cast<Value*>(node); if(!v) { /* syntax error */ u.ids=new map<string, Identifier>(); } else { u.ids=v->u.ids; v->u.ids=0; } break;} case V_SEQOF: { Node *node=t_block->parse(KW_Block_SeqOfValue); v=dynamic_cast<Value*>(node); if(!v) { /* syntax error */ u.val_vs=new Values(); } else { u.val_vs=v->u.val_vs; v->u.val_vs=0; } u.val_vs->set_my_scope(get_my_scope()); u.val_vs->set_fullname(get_fullname()); break;} case V_SETOF: { Node *node=t_block->parse(KW_Block_SetOfValue); v=dynamic_cast<Value*>(node); if(!v) { /* syntax error */ u.val_vs=new Values(); } else { u.val_vs=v->u.val_vs; v->u.val_vs=0; } u.val_vs->set_my_scope(get_my_scope()); u.val_vs->set_fullname(get_fullname()); break;} case V_SEQ: { Node *node=t_block->parse(KW_Block_SequenceValue); v=dynamic_cast<Value*>(node); if(!v) { /* syntax error */ u.val_nvs=new NamedValues(); } else { u.val_nvs=v->u.val_nvs; v->u.val_nvs=0; } u.val_nvs->set_my_scope(get_my_scope()); u.val_nvs->set_fullname(get_fullname()); break;} case V_SET: { Node *node=t_block->parse(KW_Block_SetValue); v=dynamic_cast<Value*>(node); if(!v) { /* syntax error */ u.val_nvs=new NamedValues(); } else { u.val_nvs=v->u.val_nvs; v->u.val_nvs=0; } u.val_nvs->set_my_scope(get_my_scope()); u.val_nvs->set_fullname(get_fullname()); break;} case V_OID: { Node *node=t_block->parse(KW_Block_OIDValue); v=dynamic_cast<Value*>(node); if(!v) { /* syntax error */ u.oid_comps=new vector<OID_comp>(); } else { u.oid_comps=v->u.oid_comps; v->u.oid_comps=0; } for (size_t i = 0; i < u.oid_comps->size(); i++) (*u.oid_comps)[i]->set_my_scope(get_my_scope()); break;} case V_ROID: { Node *node=t_block->parse(KW_Block_ROIDValue); v=dynamic_cast<Value*>(node); if(!v) { /* syntax error */ u.oid_comps=new vector<OID_comp>(); } else { u.oid_comps=v->u.oid_comps; v->u.oid_comps=0; } for (size_t i = 0; i < u.oid_comps->size(); i++) (*u.oid_comps)[i]->set_my_scope(get_my_scope()); break;} case V_CHARSYMS: { Node *node=t_block->parse(KW_Block_CharStringValue); u.char_syms=dynamic_cast<CharSyms*>(node); if(!u.char_syms) { /* syntax error */ u.char_syms=new CharSyms(); } u.char_syms->set_my_scope(get_my_scope()); u.char_syms->set_fullname(get_fullname()); break;} default: FATAL_ERROR("Value::set_valuetype()"); } // switch delete v; delete t_block; break;} case V_REFD: if (p_valuetype == V_USTR) { Value *v_last = get_value_refd_last(); if (v_last->valuetype != V_CSTR) FATAL_ERROR("Value::set_valuetype()"); ustring *ustr = new ustring(*v_last->u.str.val_str); delete u.ref.ref; set_val_ustr(ustr); u.ustr.convert_str = true; // will be converted back to string } else if (p_valuetype == V_CSTR) { Value *v_last = get_value_refd_last(); if (v_last->valuetype != V_USTR) { FATAL_ERROR("Value::set_valuetype()"); } ustring* old_str = v_last->u.ustr.val_ustr; size_t nof_chars = old_str->size(); for (size_t i = 0; i < nof_chars; i++) { const ustring::universal_char& uchar = (*old_str)[i]; if (uchar.group != 0 || uchar.plane != 0 || uchar.row != 0) { error("This string value cannot contain multiple-byte characters, " "but it has quadruple char(%u, %u, %u, %u) at index %lu", uchar.group, uchar.plane, uchar.row, uchar.cell, (unsigned long) i); p_valuetype = V_ERROR; break; } else if (uchar.cell > 127) { error("This string value may not contain characters with code " "higher than 127, but it has character with code %u (0x%02X) " "at index %lu", uchar.cell, uchar.cell, (unsigned long) i); p_valuetype = V_ERROR; break; } } delete u.ref.ref; if (p_valuetype != V_ERROR) { set_val_str(new string(*old_str)); } u.ustr.convert_str = true; // will be converted back to string } else FATAL_ERROR("Value::set_valuetype()"); break; case V_CHARSYMS: switch(p_valuetype) { case V_CSTR: { const string& str = u.char_syms->get_string(); delete u.char_syms; set_val_str(new string(str)); break;} case V_USTR: { const ustring& ustr = u.char_syms->get_ustring(); delete u.char_syms; set_val_ustr(new ustring(ustr)); u.ustr.convert_str = false; break;} case V_ISO2022STR: { const string& str = u.char_syms->get_iso2022string(); delete u.char_syms; set_val_str(new string(str)); break;} default: FATAL_ERROR("Value::set_valuetype()"); } // switch break; case V_INT: { Real val_Real; if (p_valuetype == V_REAL) val_Real = u.val_Int->to_real(); else FATAL_ERROR("Value::set_valuetype()"); clean_up(); u.val_Real = val_Real; break; } case V_HSTR: { clean_up_string_elements(u.str.str_elements); string *old_str = u.str.val_str; switch(p_valuetype) { case V_BSTR: set_val_str(hex2bit(*old_str)); break; case V_OSTR: set_val_str(asn_hex2oct(*old_str)); break; default: FATAL_ERROR("Value::set_valuetype()"); } // switch delete old_str; break;} case V_BSTR: clean_up_string_elements(u.str.str_elements); if (p_valuetype == V_OSTR) { string *old_str = u.str.val_str; set_val_str(asn_bit2oct(*old_str)); delete old_str; } else FATAL_ERROR("Value::set_valuetype()"); break; case V_CSTR: clean_up_string_elements(u.str.str_elements); switch(p_valuetype) { case V_USTR: { string *old_str = u.str.val_str; set_val_ustr(new ustring(*old_str)); u.ustr.convert_str = true; // will be converted back to string delete old_str; break;} case V_ISO2022STR: // do nothing break; default: FATAL_ERROR("Value::set_valuetype()"); } // switch p_valuetype break; case V_USTR: clean_up_string_elements(u.ustr.ustr_elements); switch(p_valuetype) { case V_CSTR: { ustring *old_str = u.ustr.val_ustr; size_t nof_chars = old_str->size(); bool warning_flag = false; for (size_t i = 0; i < nof_chars; i++) { const ustring::universal_char& uchar = (*old_str)[i]; if (uchar.group != 0 || uchar.plane != 0 || uchar.row != 0) { error("This string value cannot contain multiple-byte characters, " "but it has quadruple char(%u, %u, %u, %u) at index %lu", uchar.group, uchar.plane, uchar.row, uchar.cell, (unsigned long) i); p_valuetype = V_ERROR; break; } else if (uchar.cell > 127 && !warning_flag) { warning("This string value may not contain characters with code " "higher than 127, but it has character with code %u (0x%02X) " "at index %lu", uchar.cell, uchar.cell, (unsigned long) i); warning_flag = true; } } if (p_valuetype != V_ERROR) set_val_str(new string(*old_str)); delete old_str; break; } case V_ISO2022STR: error("ISO-10646 string value cannot be converted to " "ISO-2022 string"); delete u.ustr.val_ustr; p_valuetype = V_ERROR; break; default: FATAL_ERROR("Value::set_valuetype()"); } // switch p_valuetype break; case V_SEQ: switch (p_valuetype) { case V_CHOICE: { NamedValues *nvs = u.val_nvs; if (nvs->get_nof_nvs() < 1) { error("Union value must have one active field"); delete nvs; valuetype = V_ERROR; return; } else if (nvs->get_nof_nvs() > 1) { error("Only one field was expected in union value instead of %lu", (unsigned long) nvs->get_nof_nvs()); } NamedValue *nv = nvs->get_nv_byIndex(0); u.choice.alt_name = nv->get_name().clone(); u.choice.alt_value = nv->steal_value(); delete nvs; break;} case V_SET: // do nothing break; case V_REAL: { NamedValues *nvs = u.val_nvs; bool err = false; /* mantissa */ Int i_mant = 0; Identifier id_mant(Identifier::ID_ASN, string("mantissa")); if (nvs->has_nv_withName(id_mant)) { Value *v_tmp = nvs->get_nv_byName(id_mant)->get_value() ->get_value_refd_last(); if (v_tmp->get_valuetype() == V_INT) { const int_val_t *i_mant_int = v_tmp->get_val_Int(); if (*i_mant_int > INT_MAX) { error("Mantissa `%s' should be less than `%d'", (i_mant_int->t_str()).c_str(), INT_MAX); err = true; } else { i_mant = i_mant_int->get_val(); } } else err = true; } else err = true; /* base */ Int i_base = 0; Identifier id_base(Identifier::ID_ASN, string("base")); if (!err && nvs->has_nv_withName(id_base)) { Value *v = nvs->get_nv_byName(id_base)->get_value(); Value *v_tmp = v->get_value_refd_last(); if (v_tmp->get_valuetype() == V_INT) { const int_val_t *i_base_int = v_tmp->get_val_Int(); if (!err && *i_base_int != 10 && *i_base_int != 2) { v->error("Base of the REAL must be 2 or 10"); err = true; } else { i_base = i_base_int->get_val(); } } else err = true; } else err = true; /* exponent */ Int i_exp = 0; Identifier id_exp(Identifier::ID_ASN, string("exponent")); if (!err && nvs->has_nv_withName(id_exp)) { Value *v_tmp = nvs->get_nv_byName(id_exp)->get_value() ->get_value_refd_last(); if (v_tmp->get_valuetype() == V_INT) { const int_val_t *i_exp_int = v_tmp->get_val_Int(); if (*i_exp_int > INT_MAX) { error("Exponent `%s' should be less than `%d'", (i_exp_int->t_str()).c_str(), INT_MAX); err = true; } else { i_exp = i_exp_int->get_val(); } } else err = true; } else err = true; /* clean up */ delete nvs; if (err) { valuetype = V_ERROR; return; } u.val_Real = i_mant * pow(static_cast<double>(i_base), static_cast<double>(i_exp)); break; } case V_NOTUSED: clean_up(); break; default: FATAL_ERROR("Value::set_valuetype()"); } // switch break; case V_SEQOF: switch (p_valuetype) { case V_SEQ: { // SEQOF -> SEQ: value list notation (TTCN-3 only) if (!my_governor) FATAL_ERROR("Value::set_valuetype()"); Type *t = my_governor->get_type_refd_last(); switch (t->get_typetype()) { case Type::T_SEQ_T: case Type::T_SEQ_A: break; default: FATAL_ERROR("Value::set_valuetype()"); } Values *vals = u.val_vs; size_t nof_vals = vals->get_nof_vs(); size_t nof_comps = t->get_nof_comps(); if (nof_vals > nof_comps) { error("Too many elements in value list notation for type `%s': " "%lu was expected instead of %lu", t->get_typename().c_str(), (unsigned long)nof_comps, (unsigned long)nof_vals); } size_t upper_limit; bool allnotused; if (nof_vals <= nof_comps) { upper_limit = nof_vals; allnotused = true; } else { upper_limit = nof_comps; allnotused = false; } u.val_nvs = new NamedValues; for (size_t i = 0; i < upper_limit; i++) { Value *v = vals->steal_v_byIndex(i); if (v->valuetype != V_NOTUSED) { allnotused = false; } NamedValue *nv = new NamedValue(t->get_comp_id_byIndex(i).clone(), v); nv->set_location(*v); u.val_nvs->add_nv(nv); } u.val_nvs->set_my_scope(get_my_scope()); u.val_nvs->set_fullname(get_fullname()); delete vals; if (allnotused && nof_vals > 0) warning("All elements of value list notation for type `%s' are not " "used symbols (`-')", t->get_typename().c_str()); break; } case V_SET: // { } -> empty set value if (u.val_vs->get_nof_vs() != 0) FATAL_ERROR("Value::set_valuetype()"); delete u.val_vs; u.val_nvs = new NamedValues; break; case V_SETOF: case V_ARRAY: // SEQOF -> SETOF or ARRAY: trivial break; default: FATAL_ERROR("Value::set_valuetype()"); } break; case V_SET: case V_CHOICE: if (p_valuetype == V_NOTUSED) { clean_up(); } else { FATAL_ERROR("Value::set_valuetype()"); } break; case V_TTCN3_NULL: switch (p_valuetype) { case V_DEFAULT_NULL: break; case V_FAT_NULL: break; default: FATAL_ERROR("Value::set_valuetype()"); } break; case V_NOTUSED: if (V_OMIT != p_valuetype) { // in case of implicit omit FATAL_ERROR("Value::set_valuetype()"); } break; default: FATAL_ERROR("Value::set_valuetype()"); } // switch valuetype=p_valuetype; } void Value::set_valuetype_COMP_NULL() { if(valuetype == V_ERROR) return; if(valuetype==V_TTCN3_NULL) { valuetype=V_EXPR; u.expr.v_optype=OPTYPE_COMP_NULL; // Nothing to check. u.expr.state=EXPR_CHECKED; } else FATAL_ERROR("Value::set_valuetype_COMP_NULL()"); } void Value::set_valuetype(valuetype_t p_valuetype, const Int& p_val_int) { if (valuetype == V_NAMEDINT && p_valuetype == V_INT) { delete u.val_id; u.val_Int = new int_val_t(p_val_int); valuetype = V_INT; } else FATAL_ERROR("Value::set_valuetype()"); } void Value::set_valuetype(valuetype_t p_valuetype, string *p_str) { if (p_str && valuetype == V_NAMEDBITS && p_valuetype == V_BSTR) { clean_up(); valuetype = V_BSTR; set_val_str(p_str); } else FATAL_ERROR("Value::set_valuetype()"); } void Value::set_valuetype(valuetype_t p_valuetype, Identifier *p_id) { if (p_id && valuetype == V_UNDEF_LOWERID && p_valuetype == V_ENUM) { delete u.val_id; u.val_id = p_id; valuetype = V_ENUM; } else FATAL_ERROR("Value::set_valuetype()"); } void Value::set_valuetype(valuetype_t p_valuetype, Assignment *p_ass) { switch (p_valuetype) { case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: if (valuetype == V_REFER && p_ass) break; // no break default: FATAL_ERROR("Value::set_valuetype()"); } delete u.refered; u.refd_fat = p_ass; valuetype = p_valuetype; } bool Value::is_undef_lowerid() { switch (valuetype) { case V_UNDEF_LOWERID: return true; case V_EXPR: if (u.expr.v_optype == OPTYPE_VALUEOF && !u.expr.ti1->get_Type() && !u.expr.ti1->get_DerivedRef()) { return u.expr.ti1->get_Template()->is_undef_lowerid(); } // no break default: return false; } } const Identifier& Value::get_undef_lowerid() { switch (valuetype) { case V_UNDEF_LOWERID: return *u.val_id; case V_EXPR: if (u.expr.v_optype != OPTYPE_VALUEOF) FATAL_ERROR("Value::get_undef_lowerid()"); return u.expr.ti1->get_Template()->get_specific_value() ->get_undef_lowerid(); default: FATAL_ERROR("Value::get_undef_lowerid()"); } const Identifier *dummy = 0; return *dummy; } void Value::set_lowerid_to_ref() { switch (valuetype) { case V_UNDEF_LOWERID: set_valuetype(V_REFD); break; case V_EXPR: // if the governor of the expression is not known (in log(), etc...) // then the governor is taken from the reference (using // v1/ti1->get_expr_governor()), but that runs before the // params were checked, this smells like a workaround :) switch (u.expr.v_optype) { case OPTYPE_ROTL: case OPTYPE_ROTR: u.expr.v1->set_lowerid_to_ref(); break; case OPTYPE_CONCAT: u.expr.v1->set_lowerid_to_ref(); u.expr.v2->set_lowerid_to_ref(); break; case OPTYPE_VALUEOF: case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_SUBSTR: case OPTYPE_REGEXP: case OPTYPE_REPLACE: case OPTYPE_TTCN2STRING: case OPTYPE_ISTEMPLATEKIND: if (!u.expr.ti1->get_Type() && !u.expr.ti1->get_DerivedRef()) { Error_Context cntxt(u.expr.ti1->get_Template(), "In the operand of operation `%s'", get_opname()); u.expr.ti1->get_Template()->set_lowerid_to_ref(); } if (u.expr.v_optype==OPTYPE_REGEXP) { if (!u.expr.t2->get_Type() && !u.expr.t2->get_DerivedRef()) { Error_Context cntxt(u.expr.t2->get_Template(), "In the operand of operation `%s'", get_opname()); u.expr.t2->get_Template()->set_lowerid_to_ref(); } } if (u.expr.v_optype==OPTYPE_REPLACE) { if (!u.expr.ti4->get_Type() && !u.expr.ti4->get_DerivedRef()) { Error_Context cntxt(u.expr.ti4->get_Template(), "In the operand of operation `%s'", get_opname()); u.expr.ti4->get_Template()->set_lowerid_to_ref(); } } break; default: break; } break; default: break; } } Type::typetype_t Value::get_expr_returntype(Type::expected_value_t exp_val, bool use_def_alt /* = false */) { switch (valuetype) { case V_CHARSYMS: case V_CHOICE: case V_SEQOF: case V_SETOF: case V_ARRAY: case V_SEQ: case V_SET: case V_UNDEF_LOWERID: case V_UNDEF_BLOCK: case V_OMIT: case V_TTCN3_NULL: case V_NOTUSED: case V_REFER: case V_FAT_NULL: case V_ANY_VALUE: case V_ANY_OR_OMIT: return Type::T_UNDEF; case V_NAMEDINT: case V_NAMEDBITS: case V_OPENTYPE: FATAL_ERROR("Value::get_expr_returntype()"); case V_ERROR: return Type::T_ERROR; case V_REFD: case V_INVOKE: { Type *t = get_expr_governor(exp_val); if (t != NULL) { t = t->get_type_refd_last(); } Type::typetype_t tt = t != NULL ? t->get_typetype_ttcn3() : Type::T_ERROR; if (use_def_alt) { while (tt == Type::T_CHOICE_T) { CompField* def_alt = t->get_default_alternative(); if (def_alt != NULL) { t = def_alt->get_type()->get_type_refd_last(); tt = t->get_typetype_ttcn3(); } else { break; // exit the 'while' loop if there's no default alternative } } } return tt; } case V_FUNCTION: return Type::T_FUNCTION; case V_ALTSTEP: return Type::T_ALTSTEP; case V_TESTCASE: return Type::T_TESTCASE; case V_EXPR: switch(u.expr.v_optype) { case OPTYPE_UNDEF_CREATE: return Type::T_UNDEF; case OPTYPE_CLASS_CREATE: return Type::T_CLASS; case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_CREATE: return Type::T_COMPONENT; case OPTYPE_UNDEF_RUNNING: case OPTYPE_COMP_RUNNING: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_MATCH: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_NOT: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_ISPRESENT: case OPTYPE_ISCHOSEN: case OPTYPE_ISCHOSEN_V: case OPTYPE_ISCHOSEN_T: case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_PROF_RUNNING: case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: case OPTYPE_ISTEMPLATEKIND: case OPTYPE_OF_CLASS: return Type::T_BOOL; case OPTYPE_GETVERDICT: return Type::T_VERDICT; case OPTYPE_GET_PORT_REF: return Type::T_PORT; case OPTYPE_VALUEOF: { Error_Context cntxt(this, "In the operand of operation `%s'", get_opname()); if (u.expr.subrefs2 != NULL) { Type* t = u.expr.ti1->get_expr_governor(Type::EXPECTED_TEMPLATE); if (t != NULL) { t = t->get_type_refd_last()->get_field_type(u.expr.subrefs2, exp_val); return t->get_type_refd_last()->get_typetype(); } return Type::T_UNDEF; } else { return u.expr.ti1->get_expr_returntype(Type::EXPECTED_TEMPLATE); } } case OPTYPE_TMR_READ: case OPTYPE_INT2FLOAT: case OPTYPE_STR2FLOAT: case OPTYPE_RND: case OPTYPE_RNDWITHVAL: case OPTYPE_NOW: return Type::T_REAL; case OPTYPE_ACTIVATE: return Type::T_DEFAULT; case OPTYPE_ACTIVATE_REFD: return Type::T_DEFAULT; case OPTYPE_EXECUTE: case OPTYPE_EXECUTE_REFD: return Type::T_VERDICT; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: { Type::typetype_t tmp_tt; { Error_Context cntxt(this, "In the operand of operation `%s'", get_opname()); u.expr.v1->set_lowerid_to_ref(); tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_INT: case Type::T_REAL: return tmp_tt; default: get_value_refd_last(); // to report the error return Type::T_ERROR; } // switch tmp_tt } case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: { Type::typetype_t tmp_tt; { Error_Context cntxt(this, "In the left operand of operation `%s'", get_opname()); u.expr.v1->set_lowerid_to_ref(); tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_INT: case Type::T_REAL: return tmp_tt; default: if(u.expr.v_optype==OPTYPE_ADD) { Type::typetype_t tmp_tt2; { Error_Context cntxt(this, "In the right operand of operation `%s'", get_opname()); u.expr.v2->set_lowerid_to_ref(); tmp_tt2=u.expr.v2->get_expr_returntype(exp_val, true); } Type::typetype_t ret_val=Type::T_ERROR; bool maybeconcat=false; switch(tmp_tt) { case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: if(tmp_tt2==tmp_tt) { maybeconcat=true; ret_val=tmp_tt; } break; case Type::T_CSTR: case Type::T_USTR: if(tmp_tt2==Type::T_CSTR || tmp_tt2==Type::T_USTR) { maybeconcat=true; if(tmp_tt==Type::T_USTR || tmp_tt2==Type::T_USTR) ret_val=Type::T_USTR; else ret_val=Type::T_CSTR; } break; default: break; } if(maybeconcat) { error("Did you mean the concat operation (`&') instead of" " addition operator (`+')?"); u.expr.v_optype=OPTYPE_CONCAT; return ret_val; } } get_value_refd_last(); // to report the error return Type::T_ERROR; } // switch tmp_tt } case OPTYPE_NOT4B: // v1 case OPTYPE_AND4B: // v1 v2 case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: { Type::typetype_t tmp_tt; { Error_Context cntxt(this, "In the %soperand of operation `%s'", u.expr.v_optype==OPTYPE_NOT4B?"":"left ", get_opname()); u.expr.v1->set_lowerid_to_ref(); tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: return tmp_tt; default: get_value_refd_last(); // to report the error return Type::T_ERROR; } // switch tmp_tt } case OPTYPE_ROTL: // v1 v2 case OPTYPE_ROTR: { Type::typetype_t tmp_tt; { Error_Context cntxt(this, "In the %s operand of operation `%s'", u.expr.v_optype==OPTYPE_ROTL || u.expr.v_optype==OPTYPE_ROTR?"left":"first", get_opname()); u.expr.v1->set_lowerid_to_ref(); tmp_tt=u.expr.v1->get_expr_returntype(exp_val); } switch(tmp_tt) { case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: case Type::T_CSTR: case Type::T_USTR: case Type::T_SETOF: case Type::T_SEQOF: case Type::T_ARRAY: return tmp_tt; default: get_value_refd_last(); // to report the error return Type::T_ERROR; } // switch tmp_tt } case OPTYPE_SUBSTR: case OPTYPE_REPLACE: { Type::typetype_t tmp_tt; { Error_Context cntxt(this, "In the operand of operation `%s'", get_opname()); u.expr.ti1->get_Template()->set_lowerid_to_ref(); tmp_tt = u.expr.ti1->get_expr_returntype(Type::EXPECTED_TEMPLATE); } switch (tmp_tt) { case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: case Type::T_CSTR: case Type::T_USTR: case Type::T_SETOF: case Type::T_SEQOF: return tmp_tt; default: get_value_refd_last(); // to report the error return Type::T_ERROR; } } case OPTYPE_REGEXP: { Type::typetype_t tmp_tt; { Error_Context cntxt(this, "In the first operand of operation `%s'", get_opname()); u.expr.ti1->get_Template()->set_lowerid_to_ref(); tmp_tt = u.expr.ti1->get_expr_returntype(Type::EXPECTED_TEMPLATE); } switch(tmp_tt) { case Type::T_CSTR: case Type::T_USTR: return tmp_tt; default: get_value_refd_last(); // to report the error return Type::T_ERROR; } // switch tmp_tt } case OPTYPE_CONCAT: { // v1 v2 Type::typetype_t tmp_tt; { Error_Context cntxt(this, "In the first operand of operation `%s'", get_opname()); u.expr.v1->set_lowerid_to_ref(); tmp_tt=u.expr.v1->get_expr_returntype(exp_val, true); } switch(tmp_tt) { case Type::T_CSTR: case Type::T_USTR: case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: case Type::T_SETOF: case Type::T_SEQOF: return tmp_tt; default: get_value_refd_last(); // to report the error return Type::T_ERROR; } // switch tmp_tt } case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CHAR2INT: case OPTYPE_UNICHAR2INT: case OPTYPE_BIT2INT: case OPTYPE_HEX2INT: case OPTYPE_OCT2INT: case OPTYPE_STR2INT: case OPTYPE_FLOAT2INT: case OPTYPE_LENGTHOF: case OPTYPE_SIZEOF: case OPTYPE_DECODE: case OPTYPE_ENUM2INT: case OPTYPE_DECVALUE_UNICHAR: return Type::T_INT; case OPTYPE_BIT2STR: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2STR: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2STR: case OPTYPE_UNICHAR2CHAR: case OPTYPE_LOG2STR: case OPTYPE_TESTCASENAME: case OPTYPE_TTCN2STRING: case OPTYPE_GET_STRINGENCODING: case OPTYPE_ENCODE_BASE64: case OPTYPE_HOSTID: return Type::T_CSTR; case OPTYPE_INT2UNICHAR: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCVALUE_UNICHAR: case OPTYPE_ANY2UNISTR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: return Type::T_USTR; case OPTYPE_INT2BIT: case OPTYPE_HEX2BIT: case OPTYPE_OCT2BIT: case OPTYPE_STR2BIT: case OPTYPE_ENCODE: return Type::T_BSTR; case OPTYPE_INT2HEX: case OPTYPE_BIT2HEX: case OPTYPE_OCT2HEX: case OPTYPE_STR2HEX: return Type::T_HSTR; case OPTYPE_INT2OCT: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_CHAR2OCT: case OPTYPE_HEX2OCT: case OPTYPE_BIT2OCT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2OCT: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: return Type::T_OSTR; case OPTYPE_DECOMP: return Type::T_OID; case OPTYPE_CLASS_CASTING: case OPTYPE_CLASS_CASTING_REF: return Type::T_CLASS; default: FATAL_ERROR("Value::get_expr_returntype(): invalid optype"); // to avoid warning return Type::T_ERROR; } // switch optype case V_MACRO: switch (u.macro) { case MACRO_MODULEID: case MACRO_FILENAME: case MACRO_BFILENAME: case MACRO_FILEPATH: case MACRO_LINENUMBER: case MACRO_DEFINITIONID: case MACRO_SCOPE: case MACRO_TESTCASEID: return Type::T_CSTR; case MACRO_LINENUMBER_C: return Type::T_INT; default: return Type::T_ERROR; } case V_NULL: return Type::T_NULL; case V_BOOL: return Type::T_BOOL; case V_INT: return Type::T_INT; case V_REAL: return Type::T_REAL; case V_ENUM: return Type::T_ENUM_T; case V_BSTR: return Type::T_BSTR; case V_HSTR: return Type::T_HSTR; case V_OSTR: return Type::T_OSTR; case V_CSTR: return Type::T_CSTR; case V_USTR: return Type::T_USTR; case V_ISO2022STR: return Type::T_GENERALSTRING; case V_OID: return Type::T_OID; case V_ROID: return Type::T_ROID; case V_VERDICT: return Type::T_VERDICT; case V_DEFAULT_NULL: return Type::T_DEFAULT; default: FATAL_ERROR("Value::get_expr_returntype(): invalid valuetype"); // to avoid warning return Type::T_ERROR; } // switch } Type* Value::get_expr_governor(Type::expected_value_t exp_val) { if(my_governor) return my_governor; switch (valuetype) { case V_INVOKE: { Type *t = u.invoke.v->get_expr_governor(exp_val); if(!t) { if(u.invoke.v->get_valuetype() != V_ERROR) u.invoke.v->error("A value of type function expected"); goto error; } t = t->get_type_refd_last(); switch(t->get_typetype()) { case Type::T_FUNCTION: { Type *t_return_type = t->get_function_return_type(); if (!t_return_type) { error("Reference to a %s was expected instead of invocation " "of behavior type `%s' with no return type", exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value", t->get_fullname().c_str()); goto error; } if (exp_val != Type::EXPECTED_TEMPLATE && t->get_returns_template()) { error("Reference to a value was expected, but functions of type " "`%s' return a template of type `%s'", t->get_typename().c_str(), t_return_type->get_typename().c_str()); goto error; } return t_return_type; } case Type::T_ALTSTEP: goto error; default: u.invoke.v->error("A value of type function expected instead of `%s'", t->get_typename().c_str()); goto error; } break; } case V_REFD: { Assignment *ass=u.ref.ref->get_refd_assignment(); Type *tmp_type=0; if (!ass) goto error; switch (ass->get_asstype()) { case Assignment::A_CONST: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_MODULEPAR_TEMP: case Assignment::A_TEMPLATE: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_VAR_TEMPLATE: case Assignment::A_FUNCTION_RVAL: case Assignment::A_FUNCTION_RTEMP: case Assignment::A_EXT_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RTEMP: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: tmp_type=ass->get_Type(); break; case Assignment::A_FUNCTION: case Assignment::A_EXT_FUNCTION: error("Reference to a %s was expected instead of a call of %s, which " "does not have return type", exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value", ass->get_description().c_str()); goto error; case Assignment::A_TYPE: if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) { Ttcn::Reference* ttcn_ref = static_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref->get_reftype() == Ref_simple::REF_THIS) { tmp_type = ass->get_Type(); break; } } // else fall through default: error("Reference to a %s was expected instead of %s", exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value", ass->get_description().c_str()); goto error; } // end switch tmp_type=tmp_type->get_field_type(u.ref.ref->get_subrefs(), exp_val); if(!tmp_type) goto error; return tmp_type; } case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_VALUEOF: case OPTYPE_SUBSTR: case OPTYPE_REGEXP: case OPTYPE_REPLACE:{ Type *tmp_type = u.expr.ti1->get_expr_governor(exp_val == Type::EXPECTED_DYNAMIC_VALUE ? Type::EXPECTED_TEMPLATE : exp_val); if (u.expr.v_optype == OPTYPE_VALUEOF && tmp_type != NULL) { tmp_type = tmp_type->get_type_refd_last()-> get_field_type(u.expr.subrefs2, exp_val); } if(tmp_type) tmp_type = tmp_type->get_type_refd_last(); return tmp_type; } case OPTYPE_ROTL: case OPTYPE_ROTR: return u.expr.v1->get_expr_governor(exp_val); case OPTYPE_CONCAT: return get_expr_governor_v1v2(exp_val); case OPTYPE_COMP_MTC: if (my_scope) return my_scope->get_mtc_system_comptype(false); else return 0; case OPTYPE_COMP_SYSTEM: if (my_scope) return my_scope->get_mtc_system_comptype(true); else return 0; case OPTYPE_COMP_SELF: if (my_scope) { Ttcn::RunsOnScope *t_ros = my_scope->get_scope_runs_on(); if (t_ros) return t_ros->get_component_type(); else return 0; } else return 0; case OPTYPE_UNDEF_CREATE: return chk_expr_operand_undef_create(); case OPTYPE_GET_PORT_REF: chk_expr_operands(NULL, exp_val); // calculate the port type return u.expr.type; case OPTYPE_CLASS_CASTING_REF: chk_expr_operands(NULL, exp_val); // no break case OPTYPE_CLASS_CASTING: return u.expr.type; default: break; } // no break default: return Type::get_pooltype(get_expr_returntype(exp_val)); } error: set_valuetype(V_ERROR); return 0; } Type* Value::get_expr_governor_v1v2(Type::expected_value_t exp_val) { Type* v1_gov = u.expr.v1->get_expr_governor(exp_val); Type* v2_gov = u.expr.v2->get_expr_governor(exp_val); if (v1_gov) { if (v2_gov) { // both have governors // return the type that is compatible with both (if there is no type mismatch) if (v1_gov->is_compatible(v2_gov, NULL, NULL)) return v1_gov; else return v2_gov; } else return v1_gov; } else { // v1 has no governor if (v2_gov) return v2_gov; else return NULL; // neither has governor } } Type *Value::get_expr_governor_last() { Value *v_last = get_value_refd_last(); if (v_last->valuetype == V_ERROR) return 0; Type *t = v_last->get_expr_governor(Type::EXPECTED_TEMPLATE); if(!t) return 0; return t->get_type_refd_last(); } Type *Value::get_invoked_type(Type::expected_value_t exp_val) { if(valuetype != V_INVOKE) FATAL_ERROR("Value::get_invoked_type()"); return u.invoke.v->get_expr_governor(exp_val); } const char* Value::get_opname() const { if(valuetype!=V_EXPR) FATAL_ERROR("Value::get_opname()"); switch(u.expr.v_optype) { case OPTYPE_RND: // - return "rnd()"; case OPTYPE_COMP_NULL: return "(component) null"; case OPTYPE_COMP_MTC: return "mtc"; case OPTYPE_COMP_SYSTEM: return "system"; case OPTYPE_COMP_SELF: return "self"; case OPTYPE_COMP_RUNNING_ANY: return "any component.running"; case OPTYPE_COMP_RUNNING_ALL: return "all component.running"; case OPTYPE_COMP_ALIVE_ANY: return "any component.alive"; case OPTYPE_COMP_ALIVE_ALL: return "all component.alive"; case OPTYPE_TMR_RUNNING_ANY: return "any timer.running"; case OPTYPE_GETVERDICT: return "getverdict()"; case OPTYPE_TESTCASENAME: return "testcasename()"; case OPTYPE_NOW: return "now"; case OPTYPE_CHECKSTATE_ANY: if (u.expr.r1) { return "port.checkstate()"; } else { return "any port.checkstate()"; } case OPTYPE_CHECKSTATE_ALL: if (u.expr.r1) { return "port.checkstate()"; } else { return "all port.checkstate()"; } case OPTYPE_UNARYPLUS: // v1 return "unary +"; case OPTYPE_UNARYMINUS: return "unary -"; case OPTYPE_NOT: return "not"; case OPTYPE_NOT4B: return "not4b"; case OPTYPE_BIT2HEX: return "bit2hex()"; case OPTYPE_BIT2INT: return "bit2int()"; case OPTYPE_BIT2OCT: return "bit2oct()"; case OPTYPE_BIT2STR: return "bit2str()"; case OPTYPE_BSON2JSON: return "bson2json()"; case OPTYPE_CBOR2JSON: return "cbor2json()"; case OPTYPE_CHAR2INT: return "char2int()"; case OPTYPE_CHAR2OCT: return "char2oct()"; case OPTYPE_FLOAT2INT: return "float2int()"; case OPTYPE_FLOAT2STR: return "float2str()"; case OPTYPE_HEX2BIT: return "hex2bit()"; case OPTYPE_HEX2INT: return "hex2int()"; case OPTYPE_HEX2OCT: return "hex2oct()"; case OPTYPE_HEX2STR: return "hex2str()"; case OPTYPE_INT2CHAR: return "int2char()"; case OPTYPE_INT2FLOAT: return "int2float()"; case OPTYPE_INT2STR: return "int2str()"; case OPTYPE_INT2UNICHAR: return "int2unichar()"; case OPTYPE_JSON2BSON: return "json2bson()"; case OPTYPE_JSON2CBOR: return "json2cbor()"; case OPTYPE_OCT2BIT: return "oct2bit()"; case OPTYPE_OCT2CHAR: return "oct2char()"; case OPTYPE_OCT2HEX: return "oct2hex()"; case OPTYPE_OCT2INT: return "oct2int()"; case OPTYPE_OCT2STR: return "oct2str()"; case OPTYPE_STR2BIT: return "str2bit()"; case OPTYPE_STR2FLOAT: return "str2float()"; case OPTYPE_STR2HEX: return "str2hex()"; case OPTYPE_STR2INT: return "str2int()"; case OPTYPE_STR2OCT: return "str2oct()"; case OPTYPE_UNICHAR2INT: return "unichar2int()"; case OPTYPE_UNICHAR2CHAR: return "unichar2char()"; case OPTYPE_UNICHAR2OCT: return "unichar2oct()"; case OPTYPE_ENUM2INT: return "enum2int()"; case OPTYPE_LENGTHOF: return "lengthof()"; case OPTYPE_SIZEOF: return "sizeof()"; case OPTYPE_RNDWITHVAL: return "rnd (seed)"; case OPTYPE_ENCODE: return "encvalue()"; case OPTYPE_DECODE: return "decvalue()"; case OPTYPE_GET_STRINGENCODING: return "get_stringencoding()"; case OPTYPE_REMOVE_BOM: return "remove_bom()"; case OPTYPE_ENCODE_BASE64: return "encode_base64()"; case OPTYPE_DECODE_BASE64: return "decode_base64()"; case OPTYPE_HOSTID: // [v1] return "hostid()"; case OPTYPE_ADD: // v1 v2 return "+"; case OPTYPE_SUBTRACT: return "-"; case OPTYPE_MULTIPLY: return "*"; case OPTYPE_DIVIDE: return "/"; case OPTYPE_MOD: return "mod"; case OPTYPE_REM: return "rem"; case OPTYPE_CONCAT: return "&"; case OPTYPE_EQ: return "=="; case OPTYPE_LT: return "<"; case OPTYPE_GT: return ">"; case OPTYPE_NE: return "!="; case OPTYPE_GE: return ">="; case OPTYPE_LE: return "<="; case OPTYPE_AND: return "and"; case OPTYPE_OR: return "or"; case OPTYPE_XOR: return "xor"; case OPTYPE_AND4B: return "and4b"; case OPTYPE_OR4B: return "or4b"; case OPTYPE_XOR4B: return "xor4b"; case OPTYPE_SHL: return "<<"; case OPTYPE_SHR: return ">>"; case OPTYPE_ROTL: return "<@"; case OPTYPE_ROTR: return "@>"; case OPTYPE_INT2BIT: return "int2bit()"; case OPTYPE_INT2HEX: return "int2hex()"; case OPTYPE_INT2OCT: return "int2oct()"; case OPTYPE_OCT2UNICHAR: return "oct2unichar()"; case OPTYPE_ENCVALUE_UNICHAR: return "encvalue_unichar()"; case OPTYPE_DECVALUE_UNICHAR: return "decvalue_unichar()"; case OPTYPE_SUBSTR: return "substr()"; case OPTYPE_REGEXP: return "regexp()"; case OPTYPE_DECOMP: return "decomp()"; case OPTYPE_REPLACE: return "replace()"; case OPTYPE_VALUEOF: // t1 [subrefs2] return "valueof()"; case OPTYPE_UNDEF_RUNNING: return "<timer or component> running"; case OPTYPE_UNDEF_CREATE: case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 case OPTYPE_CLASS_CREATE: return "create()"; case OPTYPE_COMP_RUNNING: // v1 return "component running"; case OPTYPE_COMP_ALIVE: // v1 return "alive"; case OPTYPE_TMR_READ: return "timer read"; case OPTYPE_TMR_RUNNING: return "timer running"; case OPTYPE_ACTIVATE: return "activate()"; case OPTYPE_ACTIVATE_REFD: return "activate()"; case OPTYPE_EXECUTE: // r1 [v2] case OPTYPE_EXECUTE_REFD: return "execute()"; case OPTYPE_MATCH: // v1 t2 return "match()"; case OPTYPE_ISPRESENT: return "ispresent()"; case OPTYPE_ISCHOSEN: case OPTYPE_ISCHOSEN_V: case OPTYPE_ISCHOSEN_T: return "ischosen()"; case OPTYPE_ISVALUE: return "isvalue()"; case OPTYPE_ISBOUND: return "isbound()"; case OPTYPE_ISTEMPLATEKIND: return "istemplatekind()"; case OPTYPE_LOG2STR: return "log2str()"; case OPTYPE_ANY2UNISTR: return "any2unistr()"; case OPTYPE_TTCN2STRING: return "ttcn2string()"; case OPTYPE_PROF_RUNNING: return "@profiler.running"; case OPTYPE_GET_PORT_REF: return "port.getref()"; case OPTYPE_OF_CLASS: return "of"; case OPTYPE_CLASS_CASTING: case OPTYPE_CLASS_CASTING_REF: return "=>"; default: FATAL_ERROR("Value::get_opname()"); } // switch } void Value::chk_expr_ref_ischosen() { Error_Context cntxt(this, "In the operand of operation `%s'", get_opname()); Ttcn::Reference *tmpref=u.expr.r1; Assignment *ass=tmpref->get_refd_assignment(); if (!ass) { set_valuetype(V_ERROR); return; } // Now we know whether the argument of ischosen() is a value or template. // Wrap u.expr.r1 of OPTYPE_ISCHOSEN in a value (OPTYPE_ISCHOSEN_V) // or template (OPTYPE_ISCHOSEN_T). switch (ass->get_asstype()) { case Assignment::A_CONST: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: u.expr.v1=new Value(V_REFD, tmpref); u.expr.v1->set_location(*tmpref); u.expr.v1->set_my_scope(get_my_scope()); u.expr.v1->set_fullname(get_fullname()+".<operand>"); u.expr.v_optype=OPTYPE_ISCHOSEN_V; break; case Assignment::A_MODULEPAR_TEMP: case Assignment::A_TEMPLATE: case Assignment::A_VAR_TEMPLATE: case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: u.expr.t1=new Template(Template::TEMPLATE_REFD, tmpref); // TEMPLATE_REFD constructor u.expr.t1->set_location(*tmpref); u.expr.t1->set_my_scope(get_my_scope()); u.expr.t1->set_fullname(get_fullname()+".<operand>"); u.expr.v_optype=OPTYPE_ISCHOSEN_T; break; default: tmpref->error("Reference to a value or template was expected instead of " "%s", ass->get_description().c_str()); set_valuetype(V_ERROR); break; } // switch } void Value::chk_expr_operandtype_bool(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { if(tt==Type::T_BOOL) return; if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be boolean value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_int(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { if(tt==Type::T_INT) return; if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be integer value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_float(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { if(tt==Type::T_REAL) return; else if(tt==Type::T_INT) loc->error("%s operand of operation `%s' should be float value." " Perhaps you missed an int2float() conversion function" " or `.0' at the end of the number", opnum, opname); else if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be float value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_int_float(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { switch(tt) { case Type::T_INT: case Type::T_REAL: return; default: break; } if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be integer" " or float value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_int_float_enum(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { switch(tt) { case Type::T_INT: case Type::T_REAL: case Type::T_ENUM_T: return; default: break; } if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be integer, float" " or enumerated value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_list(Type* t, const char *opnum, const char *opname, const Location *loc, bool allow_array) { if (valuetype == V_ERROR) return; if (t->get_typetype() == Type::T_ERROR) { set_valuetype(V_ERROR); return; } if (!t->is_list_type(allow_array)) { loc->error("%s operand of operation `%s' should be a string, " "`record of'%s `set of'%s value", opnum, opname, allow_array ? "," : " or", allow_array ? " or array" : ""); set_valuetype(V_ERROR); return; } TypeCompatInfo info(my_scope->get_scope_mod(), my_governor, t, true, u.expr.v_optype == OPTYPE_LENGTHOF); // The only outsider. TypeChain l_chain; TypeChain r_chain; if (my_governor && my_governor->is_list_type(allow_array) && !my_governor->is_compatible(t, &info, this, &l_chain, &r_chain)) { if (info.is_subtype_error()) { // this is ok. if (info.needs_conversion()) set_needs_conversion(); } else if (!info.is_erroneous()) { error("%s operand of operation `%s' is of type `%s', but a value of " "type `%s' was expected here", opnum, opname, t->get_typename().c_str(), my_governor->get_typename().c_str()); } else { error("%s", info.get_error_str_str().c_str()); } } else { if (info.needs_conversion()) set_needs_conversion(); } } void Value::chk_expr_operandtype_str(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { switch(tt) { case Type::T_CSTR: case Type::T_USTR: case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: return; default: break; } if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be string value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_charstr(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { switch(tt) { case Type::T_CSTR: case Type::T_USTR: return; default: break; } if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be (universal)" " charstring value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_cstr(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { if(tt==Type::T_CSTR) return; if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be charstring value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_binstr(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { switch(tt) { case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: return; default: break; } if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be binary string value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_bstr(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { if(tt==Type::T_BSTR) return; if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be bitstring value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_hstr(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { if(tt==Type::T_HSTR) return; if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be hexstring value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtype_ostr(Type::typetype_t tt, const char *opnum, const char *opname, const Location *loc) { if(tt==Type::T_OSTR) return; if(tt!=Type::T_ERROR) loc->error("%s operand of operation `%s' should be octetstring value", opnum, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtypes_same(Type::typetype_t tt1, Type::typetype_t tt2, const char *opname) { if(valuetype==V_ERROR) return; // if(u.expr.state==EXPR_CHECKING_ERR) return; if(tt1==Type::T_ERROR || tt2==Type::T_ERROR) { set_valuetype(V_ERROR); return; } if(tt1==tt2) return; error("The operands of operation `%s' should be of same type", opname); set_valuetype(V_ERROR); } /* For predefined functions. */ void Value::chk_expr_operandtypes_same_with_opnum(Type::typetype_t tt1, Type::typetype_t tt2, const char *opnum1, const char *opnum2, const char *opname) { if(valuetype==V_ERROR) return; if(tt1==Type::T_ERROR || tt2==Type::T_ERROR) { set_valuetype(V_ERROR); return; } if(tt1==tt2) return; error("The %s and %s operands of operation `%s' should be of same type", opnum1, opnum2, opname); set_valuetype(V_ERROR); } void Value::chk_expr_operandtypes_compat(Type::expected_value_t exp_val, Value *v1, Value *v2, const char *opnum1, const char *opnum2) { start: if (valuetype == V_ERROR) return; // if (u.expr.state == EXPR_CHECKING_ERR) return; Type::typetype_t tt1 = v1->get_expr_returntype(exp_val); Type::typetype_t tt2 = v2->get_expr_returntype(exp_val); if (tt1 == Type::T_ERROR || tt2 == Type::T_ERROR) { set_valuetype(V_ERROR); return; } if (tt1 == Type::T_UNDEF) { if (tt2 == Type::T_UNDEF) { if (v1->is_undef_lowerid()) { if (v2->is_undef_lowerid()) { Scope *scope = get_my_scope(); Module *my_mod = scope->get_scope_mod(); const Identifier& id1 = v1->get_undef_lowerid(); if (scope->has_ass_withId(id1) || my_mod->has_imported_ass_withId(id1)) { /* It can be ref-ref, ref-enum or enum-ref. Perhaps we * should examine this situation better, but now I suppose * the first is ref, not enum. */ v1->set_lowerid_to_ref(); goto start; } else { const Identifier& id2 = v2->get_undef_lowerid(); if (scope->has_ass_withId(id2) || my_mod->has_imported_ass_withId(id2)) { v2->set_lowerid_to_ref(); goto start; } } /* This is perhaps enum-enum, but it has no real * significance, so this should be an error. */ } else { v1->set_lowerid_to_ref(); goto start; } } else if (v2->is_undef_lowerid()) { v2->set_lowerid_to_ref(); goto start; } error("Cannot determine the type of the operands in operation `%s'", get_opname()); set_valuetype(V_ERROR); return; } else if (v1->is_undef_lowerid() && tt2 != Type::T_ENUM_T) { v1->set_lowerid_to_ref(); goto start; } else { /* v1 is something undefined, but not lowerid; v2 has * returntype (perhaps also governor) */ } } else if (tt2 == Type::T_UNDEF) { /* but tt1 is not undef */ if (v2->is_undef_lowerid() && tt1 != Type::T_ENUM_T) { v2->set_lowerid_to_ref(); goto start; } else { /* v2 is something undefined, but not lowerid; v1 has * returntype (perhaps also governor) */ } } /* Now undef_lower_id's are converted to references, or the other * value has governor; let's see the governors, if they exist. */ Type *t1 = v1->get_expr_governor(exp_val); Type *t2 = v2->get_expr_governor(exp_val); if (t1) { if (t2) { // Both value has governor. Are they compatible? According to 7.1.2 // and C.34 it's required to have the same root types for // OPTYPE_{CONCAT,REPLACE}. TypeCompatInfo info1(my_scope->get_scope_mod(), t1, t2, true, u.expr.v_optype == OPTYPE_REPLACE); TypeCompatInfo info2(my_scope->get_scope_mod(), t2, t1, true, u.expr.v_optype == OPTYPE_REPLACE); TypeChain l_chain1, l_chain2; TypeChain r_chain1, r_chain2; bool compat_t1 = t1->is_compatible(t2, &info1, this, &l_chain1, &r_chain1); bool compat_t2 = t2->is_compatible(t1, &info2, NULL, &l_chain2, &r_chain2); if (!compat_t1 && !compat_t2) { if (v1->is_ref()) { CompField* def_alt = t1->get_default_alternative(); Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(v1->get_reference()); if (def_alt != NULL && ttcn_ref != NULL) { Error_Context cntxt(v1, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), t1->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt->get_name()); return chk_expr_operandtypes_compat(exp_val, v1, v2, opnum1, opnum2); } } if (v2->is_ref()) { CompField* def_alt = t2->get_default_alternative(); Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(v2->get_reference()); if (def_alt != NULL && ttcn_ref != NULL) { Error_Context cntxt(v2, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), t2->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt->get_name()); return chk_expr_operandtypes_compat(exp_val, v1, v2, opnum1, opnum2); } } if (!info1.is_erroneous() && !info2.is_erroneous()) { // the subtypes don't need to be compatible here if (!info1.is_subtype_error() && !info2.is_subtype_error()) { error("The operands of operation `%s' should be of compatible " "types", get_opname()); set_valuetype(V_ERROR); } else { if (info1.needs_conversion() || info2.needs_conversion()) { set_needs_conversion(); // Avoid folding. return; } } } else { if (info1.is_erroneous()) v1->error("%s", info1.get_error_str_str().c_str()); else if (info2.is_erroneous()) v2->error("%s", info2.get_error_str_str().c_str()); set_valuetype(V_ERROR); } return; } else if (info1.needs_conversion() || info2.needs_conversion()) { set_needs_conversion(); // Avoid folding. return; } } else { // t1, no t2. v2->set_my_governor(t1); t1->chk_this_value_ref(v2); if (v2->valuetype == V_OMIT) { Error_Context cntxt(this, "In %s operand of operation `%s'", opnum1, get_opname()); v1->chk_expr_omit_comparison(exp_val); } else { Error_Context cntxt(this, "In %s operand of operation `%s'", opnum2, get_opname()); (void)t1->chk_this_value(v2, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); goto start; } } } else if (t2) { v1->set_my_governor(t2); t2->chk_this_value_ref(v1); if (v1->valuetype == V_OMIT) { Error_Context cntxt(this, "In %s operand of operation `%s'", opnum2, get_opname()); v2->chk_expr_omit_comparison(exp_val); } else { Error_Context cntxt(this, "In %s operand of operation `%s'", opnum1, get_opname()); (void)t2->chk_this_value(v1, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); goto start; } } else { // Neither v1 nor v2 has a governor. Let's see the returntypes. if (tt1 == Type::T_UNDEF || tt2 == Type::T_UNDEF) { // Here, it cannot be that both are T_UNDEF. // TODO: What if "a" == char(0, 0, 0, 65) or self == null etc. error("Please use reference as %s operand of operator `%s'", tt1 == Type::T_UNDEF ? opnum1 : opnum2, get_opname()); set_valuetype(V_ERROR); return; } // Deny type compatibility if no governors found. The typetype_t must // be the same. TODO: How can this happen? // Default false the 5th param if (!Type::is_compatible_tt_tt(tt1, tt2, false, false, false) && !Type::is_compatible_tt_tt(tt2, tt1, false, false, false)) { error("The operands of operation `%s' should be of compatible types", get_opname()); set_valuetype(V_ERROR); } } } void Value::chk_expr_operand_undef_running(Type::expected_value_t exp_val, Ttcn::Reference *ref, bool any_from, Ttcn::Reference* index_ref, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; // if(u.expr.state==EXPR_CHECKING_ERR) return; Assignment *t_ass = ref->get_refd_assignment(); if(!t_ass) goto error; switch(t_ass->get_asstype()) { case Assignment::A_TIMER: case Assignment::A_PAR_TIMER: u.expr.v_optype=OPTYPE_TMR_RUNNING; chk_expr_operand_tmrref(ref, opnum, get_opname(), any_from); chk_expr_dynamic_part(exp_val, true); if (index_ref != NULL) { Ttcn::Reference* index_ref2 = dynamic_cast<Ttcn::Reference*>(index_ref); if (index_ref2 == NULL) { FATAL_ERROR("Value::chk_expr_operand_undef_running"); } Ttcn::Statement::chk_index_redirect(index_ref2, t_ass->get_Dimensions(), any_from, "timer"); } break; case Assignment::A_CONST: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: { u.expr.v_optype = OPTYPE_COMP_RUNNING; Value* val = new Value(V_REFD, ref); val->set_my_scope(my_scope); val->set_fullname(ref->get_fullname()); val->set_location(*ref); u.expr.v1 = val; Type* t = chk_expr_operand_compref(val, opnum, get_opname(), any_from); chk_expr_dynamic_part(exp_val, false); if (index_ref != NULL && t != NULL) { t = t->get_type_refd_last(); Ttcn::ArrayDimensions dummy; while (t->get_typetype() == Type::T_ARRAY) { dummy.add(t->get_dimension()->clone()); t = t->get_ofType()->get_type_refd_last(); } Ttcn::Reference* index_ref2 = dynamic_cast<Ttcn::Reference*>(index_ref); if (index_ref2 == NULL) { FATAL_ERROR("Value::chk_expr_operand_undef_running"); } Ttcn::Statement::chk_index_redirect(index_ref2, &dummy, any_from, "component"); } break; } default: ref->error("%s operand of operation `%s' should be timer or" " component reference instead of %s", opnum, opname, t_ass->get_description().c_str()); goto error; } // switch return; error: set_valuetype(V_ERROR); } Type *Value::chk_expr_operand_undef_create() { if (valuetype != V_EXPR || (u.expr.v_optype != OPTYPE_UNDEF_CREATE && u.expr.v_optype != OPTYPE_CLASS_CREATE && u.expr.v_optype != OPTYPE_COMP_CREATE)) FATAL_ERROR("Value::chk_expr_operand_undef_create()"); Assignment *t_ass = u.expr.r1->get_refd_assignment(); if (!t_ass) goto error; if (t_ass->get_asstype() == Assignment::A_TYPE) { Type *t_type = t_ass->get_Type()->get_field_type(u.expr.r1->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE); if (!t_type) goto error; t_type = t_type->get_type_refd_last(); if (t_type->get_typetype() == Type::T_COMPONENT || t_type->get_typetype() == Type::T_CLASS) { if (my_governor) { Type *my_governor_last = my_governor->get_type_refd_last(); if (my_governor_last->get_typetype() == t_type->get_typetype() && !my_governor_last->is_compatible(t_type, NULL, NULL)) { u.expr.r1->error("Incompatible %s types: operation " "`create' should refer to `%s' instead of " "`%s'", t_type->get_typetype() == Type::T_CLASS ? "class" : "component", my_governor_last->get_typename().c_str(), t_type->get_typename().c_str()); goto error; } } if (u.expr.v_optype == OPTYPE_UNDEF_CREATE) { if (t_type->get_typetype() == Type::T_COMPONENT) { // convert the parameter list to component 'create' parameters size_t nof_pars = u.expr.t_list2->get_nof_tis(); if (nof_pars > 2) { u.expr.t_list2->error("Operation `create' for a component type cannot have more than 2 parameters"); goto error; } else { Value* name_val = NULL; Value* loc_val = NULL; if (nof_pars >= 1) { Ttcn::TemplateInstance* name_par = u.expr.t_list2->get_ti_byIndex(0); if (name_par->get_Template()->get_templatetype() != Ttcn::Template::TEMPLATE_NOTUSED) { if (name_par->get_Template()->is_Value()) { name_val = name_par->get_Template()->get_Value(); } else { name_par->error("A specific value without matching symbols was expected for the " "first parameter of operation `create'"); goto error; } } if (nof_pars == 2) { Ttcn::TemplateInstance* loc_par = u.expr.t_list2->get_ti_byIndex(1); if (loc_par->get_Template()->get_templatetype() != Ttcn::Template::TEMPLATE_NOTUSED) { if (loc_par->get_Template()->is_Value()) { loc_val = loc_par->get_Template()->get_Value(); } else { loc_par->error("A specific value without matching symbols was expected for the " "second parameter of operation `create'"); if (name_val != NULL) { delete name_val; } goto error; } } } } delete u.expr.t_list2; u.expr.v_optype = OPTYPE_COMP_CREATE; u.expr.v2 = name_val; u.expr.v3 = loc_val; } } else { // T_CLASS if (u.expr.b4) { // 'alive' keyword is set error("Keyword `alive' cannot be used when creating an object of class type"); goto error; } u.expr.v_optype = OPTYPE_CLASS_CREATE; } } return t_type; } else { u.expr.r1->error("Type mismatch: reference to a component or class type " "was expected in operation `create' instead of `%s'", t_type->get_typename().c_str()); } } else { u.expr.r1->error("Operation `create' should refer to a component or class " "type instead of %s", t_ass->get_description().c_str()); } error: set_valuetype(V_ERROR); return NULL; } void Value::chk_expr_comptype_compat() { if (valuetype != V_EXPR) FATAL_ERROR("Value::chk_expr_comptype_compat()"); if (!my_governor || !my_scope) return; Type *my_governor_last = my_governor->get_type_refd_last(); if (my_governor_last->get_typetype() != Type::T_COMPONENT) return; Type *t_comptype; switch (u.expr.v_optype) { case OPTYPE_COMP_MTC: t_comptype = my_scope->get_mtc_system_comptype(false); break; case OPTYPE_COMP_SYSTEM: t_comptype = my_scope->get_mtc_system_comptype(true); break; case OPTYPE_COMP_SELF: { Ttcn::RunsOnScope *t_ros = my_scope->get_scope_runs_on(); t_comptype = t_ros ? t_ros->get_component_type() : 0; break; } default: FATAL_ERROR("Value::chk_expr_comptype_compat()"); t_comptype = 0; break; } if (t_comptype && !my_governor_last->is_compatible(t_comptype, NULL, NULL)) { error("Incompatible component types: a component reference of " "type `%s' was expected, but `%s' has type `%s'", my_governor_last->get_typename().c_str(), get_opname(), t_comptype->get_typename().c_str()); set_valuetype(V_ERROR); } } Type* Value::chk_expr_operand_compref(Value *val, const char *opnum, const char *opname, bool any_from) { Type* ret_val; if(valuetype == V_ERROR) return NULL; switch(val->get_valuetype()) { case V_INVOKE: { Error_Context cntxt(this, "In `%s' operation", opname); Value *v_last = val->get_value_refd_last(); if(!v_last) goto error; ret_val = v_last->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE); if(!ret_val) goto error; Type* t = ret_val->get_type_refd_last(); if(t->get_typetype() != (any_from ? Type::T_ARRAY : Type::T_COMPONENT)) { v_last->error("%s operand of operation `%s': Type mismatch:" " component%s reference was expected instead of `%s'", opnum, opname, any_from ? " array" : "", t->get_typename().c_str()); goto error; } if (any_from) { while (t->get_typetype() == Type::T_ARRAY) { t = t->get_ofType()->get_type_refd_last(); } if (t->get_typetype() != Type::T_COMPONENT) { v_last->error("%s operand of operation `%s': Type mismatch:" " component array reference was expected instead of array" " of type `%s'", opnum, opname, t->get_typename().c_str()); goto error; } } return ret_val; } case V_REFD: { Reference *ref = val->get_reference(); Assignment *t_ass = ref->get_refd_assignment(); Value *t_val = 0; if (!t_ass) goto error; switch(t_ass->get_asstype()) { case Assignment::A_CONST: t_val = t_ass->get_Value(); // no break case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: { ret_val=t_ass->get_Type() ->get_field_type(ref->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE); if(!ret_val) goto error; Type* t_type=ret_val->get_type_refd_last(); if (t_type->get_typetype() == Type::T_CHOICE_T) { CompField* def_alt = t_type->get_default_alternative(); Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(ref); if (def_alt != NULL && ttcn_ref != NULL) { Error_Context cntxt(val, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), t_type->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt->get_name()); return chk_expr_operand_compref(val, opnum, opname, any_from); } } if(t_type->get_typetype() != (any_from ? Type::T_ARRAY : Type::T_COMPONENT)) { ref->error("%s operand of operation `%s': Type mismatch:" " component%s reference was expected instead of `%s'", opnum, opname, any_from ? " array" : "", t_type->get_typename().c_str()); goto error; } if (any_from) { while (t_type->get_typetype() == Type::T_ARRAY) { t_type = t_type->get_ofType()->get_type_refd_last(); } if (t_type->get_typetype() != Type::T_COMPONENT) { ref->error("%s operand of operation `%s': Type mismatch:" " component array reference was expected instead of array" " of type `%s'", opnum, opname, t_type->get_typename().c_str()); goto error; } } break;} default: ref->error("%s operand of operation `%s' should be" " component reference instead of %s", opnum, opname, t_ass->get_description().c_str()); goto error; } if (t_val) { ReferenceChain refch(this, "While searching referenced value"); t_val = t_val->get_refd_sub_value(ref->get_subrefs(), 0, false, &refch); if (!t_val) return NULL; t_val = t_val->get_value_refd_last(); if (t_val->valuetype != V_EXPR) return NULL; switch (t_val->u.expr.v_optype) { case OPTYPE_COMP_NULL: ref->error("%s operand of operation `%s' refers to `null' component " "reference", opnum, opname); goto error; case OPTYPE_COMP_MTC: ref->error("%s operand of operation `%s' refers to the component " "reference of the `mtc'", opnum, opname); goto error; case OPTYPE_COMP_SYSTEM: ref->error("%s operand of operation `%s' refers to the component " "reference of the `system'", opnum, opname); goto error; default: break; } } return ret_val;} default: FATAL_ERROR("Value::chk_expr_operand_compref()"); } error: set_valuetype(V_ERROR); return NULL; } void Value::chk_expr_operand_tmrref(Ttcn::Reference *ref, const char *opnum, const char *opname, bool any_from) { if(valuetype==V_ERROR) return; // if(u.expr.state==EXPR_CHECKING_ERR) return; Assignment *t_ass = ref->get_refd_assignment(); if(!t_ass) goto error; switch(t_ass->get_asstype()) { case Assignment::A_TIMER: { Ttcn::ArrayDimensions *t_dims = t_ass->get_Dimensions(); if (t_dims) t_dims->chk_indices(ref, "timer", false, Type::EXPECTED_DYNAMIC_VALUE, any_from); else { if (any_from) { ref->error("%s operand of operation `%s': Reference to a timer " "array was expected instead of a timer", opnum, opname); } else if (ref->get_subrefs()) { ref->error("%s operand of operation `%s': " "Reference to single timer `%s' cannot have field or array " "sub-references", opnum, opname, t_ass->get_id().get_dispname().c_str()); goto error; } } break; } case Assignment::A_PAR_TIMER: if (any_from) { ref->error("%s operand of operation `%s': Reference to a timer array " "was expected instead of a timer parameter", opnum, opname); } if (ref->get_subrefs()) { ref->error("%s operand of operation `%s': " "Reference to %s cannot have field or array sub-references", opnum, opname, t_ass->get_description().c_str()); goto error; } break; default: ref->error("%s operand of operation `%s' should be timer" "%s instead of %s", opnum, opname, any_from ? " array" : "", t_ass->get_description().c_str()); goto error; } // switch return; error: set_valuetype(V_ERROR); } void Value::chk_expr_operand_activate(Ttcn::Reference *ref, const char *, const char *opname) { if(valuetype==V_ERROR) return; // if(u.expr.state==EXPR_CHECKING_ERR) return; Error_Context cntxt(this, "In `%s' operation", opname); if (!ref->chk_activate_argument()) set_valuetype(V_ERROR); } void Value::chk_expr_operand_activate_refd(Value *val, Ttcn::TemplateInstances* t_list2, Ttcn::ActualParList *&parlist, const char *, const char *opname) { if(valuetype==V_ERROR) return; Error_Context cntxt(this, "In `%s' operation", opname); Type *t = val->get_expr_governor_last(); if (t) { switch (t->get_typetype()) { case Type::T_ERROR: set_valuetype(V_ERROR); break; case Type::T_ALTSTEP: { Ttcn::FormalParList *fp_list = t->get_fat_parameters(); bool is_erroneous = fp_list->chk_actual_parlist(t_list2, parlist); if(is_erroneous) { delete parlist; parlist = 0; set_valuetype(V_ERROR); } else { parlist->set_fullname(get_fullname()); parlist->set_my_scope(get_my_scope()); if (!fp_list->chk_activate_argument(parlist, get_stringRepr().c_str())) set_valuetype(V_ERROR); } break; } default: error("Reference to an altstep was expected in the argument of " "`derefers()' instead of `%s'", t->get_typename().c_str()); set_valuetype(V_ERROR); break; } } else set_valuetype(V_ERROR); } void Value::chk_expr_operand_execute(Ttcn::Reference *ref, Value *val, const char *, const char *opname) { if(valuetype==V_ERROR) return; // if(u.expr.state==EXPR_CHECKING_ERR) return; Error_Context cntxt(this, "In `%s' operation", opname); Assignment *t_ass = ref->get_refd_assignment(); bool error_flag = false; if (t_ass) { if (t_ass->get_asstype() != Common::Assignment::A_TESTCASE) { ref->error("Reference to a testcase was expected in the argument " "instead of %s", t_ass->get_description().c_str()); error_flag = true; } } else error_flag = true; if (val) { val->chk_expr_float(Type::EXPECTED_DYNAMIC_VALUE); Value *v_last = val->get_value_refd_last(); switch (v_last->valuetype) { case V_REAL: { ttcn3float v_real = v_last->get_val_Real(); if (v_real < 0.0) { val->error("The testcase guard timer has negative value: `%s'", Real2string(v_real).c_str()); error_flag = true; } break; } case V_ERROR: error_flag = true; break; default: break; } } if (error_flag) set_valuetype(V_ERROR); } void Value::chk_expr_operand_execute_refd(Value *v1, Ttcn::TemplateInstances* t_list2, Ttcn::ActualParList *&parlist, Value *v3, const char *, const char *opname) { if(valuetype==V_ERROR) return; Error_Context cntxt(this, "In `%s' operation", opname); Type *t = v1->get_expr_governor_last(); if (t) { switch (t->get_typetype()) { case Type::T_ERROR: set_valuetype(V_ERROR); break; case Type::T_TESTCASE: { Ttcn::FormalParList *fp_list = t->get_fat_parameters(); bool is_erroneous = fp_list->chk_actual_parlist(t_list2, parlist); if(is_erroneous) { delete parlist; parlist = 0; set_valuetype(V_ERROR); } else { parlist->set_fullname(get_fullname()); parlist->set_my_scope(get_my_scope()); } break; } default: v1->error("Reference to a value of type testcase was expected in the " "argument of `derefers()' instead of `%s'", t->get_typename().c_str()); set_valuetype(V_ERROR); break; } } else set_valuetype(V_ERROR); if (v3) { v3->chk_expr_float(Type::EXPECTED_DYNAMIC_VALUE); Value *v_last = v3->get_value_refd_last(); switch (v_last->valuetype) { case V_REAL: { ttcn3float v_real = v_last->get_val_Real(); if(v_real < 0.0) { v3->error("The testcase guard timer has negative value: `%s'", Real2string(v_real).c_str()); set_valuetype(V_ERROR); } break; } case V_ERROR: set_valuetype(V_ERROR); break; default: break; } } } void Value::chk_invoke(Type::expected_value_t exp_val) { if(valuetype == V_ERROR) return; if(valuetype != V_INVOKE) FATAL_ERROR("Value::chk_invoke()"); if(!u.invoke.t_list) return; //already checked Error_Context cntxt(this, "In `apply()' operation"); Type *t = u.invoke.v->get_expr_governor_last(); if (!t) { set_valuetype(V_ERROR); return; } switch (t->get_typetype()) { case Type::T_ERROR: set_valuetype(V_ERROR); return; case Type::T_FUNCTION: break; default: u.invoke.v->error("A value of type function was expected in the " "argument instead of `%s'", t->get_typename().c_str()); set_valuetype(V_ERROR); return; } my_scope->chk_runs_on_clause(t, *this, "call"); Ttcn::FormalParList *fp_list = t->get_fat_parameters(); Ttcn::ActualParList *parlist = new Ttcn::ActualParList; bool is_erroneous = fp_list->fold_named_and_chk(u.invoke.t_list, parlist); delete u.invoke.t_list; u.invoke.t_list = 0; if(is_erroneous) { delete parlist; u.invoke.ap_list = 0; } else { parlist->set_fullname(get_fullname()); parlist->set_my_scope(get_my_scope()); u.invoke.ap_list = parlist; } switch (exp_val) { case Type::EXPECTED_CONSTANT: error("An evaluable constant value was expected instead of operation " "`apply()'"); set_valuetype(V_ERROR); break; case Type::EXPECTED_STATIC_VALUE: error("A static value was expected instead of operation `apply()'"); set_valuetype(V_ERROR); break; default: break; } // switch } void Value::chk_expr_eval_value(Value *val, Type &t, ReferenceChain *refch, Type::expected_value_t exp_val) { bool self_ref = false; if(valuetype==V_ERROR) return; // Commented out to report more errors :) // e.g.: while ( 2 + Nonexi03 > 2 + Nonexi04 ) {} // if(u.expr.state==EXPR_CHECKING_ERR) return; switch(val->get_valuetype()) { case V_REFD: self_ref = t.chk_this_refd_value(val, 0, exp_val, refch); break; case V_EXPR: case V_MACRO: case V_INVOKE: val->get_value_refd_last(refch, exp_val); break; default: break; } // switch if(val->get_valuetype()==V_ERROR) set_valuetype(V_ERROR); (void)self_ref; } void Value::chk_expr_eval_ti(TemplateInstance *ti, Type *type, ReferenceChain *refch, Type::expected_value_t exp_val) { bool self_ref = false; ti->chk(type); if (exp_val != Type::EXPECTED_TEMPLATE && ti->get_DerivedRef()) { ti->error("Reference to a %s value was expected instead of an in-line " "modified template", exp_val == Type::EXPECTED_CONSTANT ? "constant" : "static"); set_valuetype(V_ERROR); return; } Template *templ = ti->get_Template(); switch (templ->get_templatetype()) { case Template::TEMPLATE_REFD: // not foldable if (exp_val == Type::EXPECTED_TEMPLATE) { templ = templ->get_template_refd_last(refch); if (templ->get_templatetype() == Template::TEMPLATE_ERROR) set_valuetype(V_ERROR); } else { ti->error("Reference to a %s value was expected instead of %s", exp_val == Type::EXPECTED_CONSTANT ? "constant" : "static", templ->get_reference()->get_refd_assignment() ->get_description().c_str()); set_valuetype(V_ERROR); } break; case Template::SPECIFIC_VALUE: { Value *val = templ->get_specific_value(); switch (val->get_valuetype()) { case V_REFD: self_ref = type->chk_this_refd_value(val, 0, exp_val, refch); break; case V_EXPR: val->get_value_refd_last(refch, exp_val); default: break; } // switch if (val->get_valuetype() == V_ERROR) set_valuetype(V_ERROR); break; } case Template::TEMPLATE_ERROR: set_valuetype(V_ERROR); break; default: break; } // switch (void)self_ref; } void Value::chk_expr_val_int_pos0(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; if(*val->get_val_Int()<0) { val->error("%s operand of operation `%s' should not be negative", opnum, opname); set_valuetype(V_ERROR); } } void Value::chk_expr_val_int_pos7bit(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; if(*val->get_val_Int()<0 || *val->get_val_Int()>127) { val->error("%s operand of operation `%s' should be in range 0..127", opnum, opname); set_valuetype(V_ERROR); } } void Value::chk_expr_val_int_pos31bit(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; if(*val->get_val_Int()<0 || *val->get_val_Int()>2147483647) { val->error("%s operand of operation `%s' should be in range" " 0..2147483647", opnum, opname); set_valuetype(V_ERROR); } } void Value::chk_expr_val_int_float_not0(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; if((val->get_expr_returntype()==Type::T_INT && *val->get_val_Int()==0) || (val->get_expr_returntype()==Type::T_REAL && val->get_val_Real()==0.0)) { val->error("%s operand of operation `%s' should not be zero", opnum, opname); set_valuetype(V_ERROR); } } void Value::chk_expr_val_large_int(Value *val, const char *opnum, const char *opname) { if (valuetype == V_ERROR) return; if (u.expr.state == EXPR_CHECKING_ERR) return; if (val->get_expr_returntype() != Type::T_INT) return; if (val->is_unfoldable()) return; const int_val_t *val_int = val->get_val_Int(); if (*val_int > static_cast<Int>(INT_MAX)) { val->error("%s operand of operation `%s' should be less than `%d' " "instead of `%s'", opnum, opname, INT_MAX, (val_int->t_str()).c_str()); set_valuetype(V_ERROR); } } void Value::chk_expr_val_len1(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; if(val->get_val_strlen()!=1) { val->error("%s operand of operation `%s' should be of length 1", opnum, opname); set_valuetype(V_ERROR); } } void Value::chk_expr_val_str_len_even(Value *val, const char *opnum, const char *opname) { if (valuetype == V_ERROR || u.expr.state == EXPR_CHECKING_ERR) return; Value *v_last = val->get_value_refd_last(); if (v_last->valuetype == V_CSTR) { size_t len = v_last->get_val_strlen(); if (len % 2) { val->error("%s operand of operation `%s' should contain even number " "of characters instead of %lu", opnum, opname, (unsigned long) len); set_valuetype(V_ERROR); } } else if (v_last->valuetype == V_REFD) { Ttcn::FieldOrArrayRefs *t_subrefs = v_last->u.ref.ref->get_subrefs(); if (t_subrefs && t_subrefs->refers_to_string_element()) { val->error("%s operand of operation `%s' should contain even number " "of characters, but a string element contains 1", opnum, opname); set_valuetype(V_ERROR); } } } void Value::chk_expr_val_str_bindigits(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; const string& s=val->get_val_str(); for(size_t i=0; i<s.size(); i++) { char c=s[i]; if(!(c=='0' || c=='1')) { val->error("%s operand of operation `%s' can contain only" " binary digits (position %lu is `%c')", opnum, opname, (unsigned long) i, c); set_valuetype(V_ERROR); return; } } } void Value::chk_expr_val_str_hexdigits(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; const string& s=val->get_val_str(); for(size_t i=0; i<s.size(); i++) { char c=s[i]; if(!((c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f'))) { val->error("%s operand of operation `%s' can contain only valid " "hexadecimal digits (position %lu is `%c')", opnum, opname, (unsigned long) i, c); set_valuetype(V_ERROR); return; } } } void Value::chk_expr_val_str_7bitoctets(Value *val, const char *opnum, const char *opname) { if (valuetype == V_ERROR || u.expr.state == EXPR_CHECKING_ERR) return; Value *v = val->get_value_refd_last(); if (v->valuetype != V_OSTR) return; const string& s = val->get_val_str(); size_t n_octets = s.size() / 2; for (size_t i = 0; i < n_octets; i++) { char c = s[2 * i]; if (!(c >= '0' && c <= '7')) { val->error("%s operand of operation `%s' shall consist of octets " "within the range 00 .. 7F, but the string `%s'O contains octet " "%c%c at index %lu", opnum, opname, s.c_str(), c, s[2 * i + 1], (unsigned long) i); set_valuetype(V_ERROR); return; } } } void Value::chk_expr_val_str_int(Value *val, const char *opnum, const char *opname) { if (valuetype == V_ERROR || u.expr.state == EXPR_CHECKING_ERR) return; Value *v_last = val->get_value_refd_last(); if (v_last->valuetype != V_CSTR) return; const string& s = v_last->get_val_str(); enum { S_INITIAL, S_INITIAL_WS, S_FIRST, S_ZERO, S_MORE, S_END, S_ERR } state = S_INITIAL; // state: expected characters // S_INITIAL, S_INITIAL_WS: +, -, first digit, leading whitespace // S_FIRST: first digit // S_ZERO, S_MORE: more digit(s), trailing whitespace // S_END: trailing whitespace // S_ERR: error was found, stop for (size_t i = 0; i < s.size(); i++) { char c = s[i]; switch (state) { case S_INITIAL: case S_INITIAL_WS: if (c == '+' || c == '-') state = S_FIRST; else if (c == '0') state = S_ZERO; else if (c >= '1' && c <= '9') state = S_MORE; else if (string::is_whitespace(c)) { if (state == S_INITIAL) { val->warning("Leading whitespace was detected and ignored in the " "operand of operation `%s'", opname); state = S_INITIAL_WS; } } else state = S_ERR; break; case S_FIRST: if (c == '0') state = S_ZERO; else if (c >= '1' && c <= '9') state = S_MORE; else state = S_ERR; break; case S_ZERO: if (c >= '0' && c <= '9') { val->warning("Leading zero digit was detected and ignored in the " "operand of operation `%s'", opname); state = S_MORE; } else if (string::is_whitespace(c)) state = S_END; else state = S_ERR; break; case S_MORE: if (c >= '0' && c <= '9') {} else if (string::is_whitespace(c)) state = S_END; else state = S_ERR; break; case S_END: if (!string::is_whitespace(c)) state = S_ERR; break; default: break; } if (state == S_ERR) { if (string::is_printable(c)) { val->error("%s operand of operation `%s' should be a string " "containing a valid integer value, but invalid character `%c' " "was detected at index %lu", opnum, opname, c, (unsigned long) i); } else { val->error("%s operand of operation `%s' should be a string " "containing a valid integer value, but invalid character with " "character code %u was detected at index %lu", opnum, opname, c, (unsigned long) i); } set_valuetype(V_ERROR); break; } } switch (state) { case S_INITIAL: case S_INITIAL_WS: val->error("%s operand of operation `%s' should be a string containing a " "valid integer value instead of an empty string", opnum, opname); set_valuetype(V_ERROR); break; case S_FIRST: val->error("%s operand of operation `%s' should be a string containing a " "valid integer value, but only a sign character was detected", opnum, opname); set_valuetype(V_ERROR); break; case S_END: val->warning("Trailing whitespace was detected and ignored in the " "operand of operation `%s'", opname); break; default: break; } } void Value::chk_expr_val_str_float(Value *val, const char *opnum, const char *opname) { if (valuetype == V_ERROR || u.expr.state == EXPR_CHECKING_ERR) return; Value *v_last = val->get_value_refd_last(); if (v_last->valuetype == V_REFD) { Ttcn::FieldOrArrayRefs *t_subrefs = v_last->u.ref.ref->get_subrefs(); if (t_subrefs && t_subrefs->refers_to_string_element()) { val->error("%s operand of operation `%s' should be a string containing " "a valid float value instead of a string element, which cannot " "represent a floating point number", opnum, opname); set_valuetype(V_ERROR); } return; } else if (v_last->valuetype != V_CSTR) return; const string& s = v_last->get_val_str(); size_t start = 0; size_t end = s.size(); while (string::is_whitespace(s[start])) { if (start == 0) { val->warning("Leading whitespace was detected and ignored in the " "operand of operation `%s'", opname); } ++start; } while (end > start && string::is_whitespace(s[end - 1])) { if (end == s.size()) { val->warning("Trailing whitespace was detected and ignored in the " "operand of operation `%s'", opname); } --end; } if ((end - start == 8 && s.find("infinity", start) == start) || (end - start == 9 && s.find("-infinity", start) == start) || (end - start == 12 && s.find("not_a_number", start) == start)) { // special values => OK return; } // otherwise look for a real number enum { S_INITIAL, S_FIRST_M, S_ZERO_M, S_MORE_M, S_FIRST_F, S_MORE_F, S_INITIAL_E, S_FIRST_E, S_ZERO_E, S_MORE_E, S_ERR } state = S_INITIAL; // state: expected characters // S_INITIAL, S_INITIAL_WS: +, -, first digit of integer part in mantissa, // leading whitespace // S_FIRST_M: first digit of integer part in mantissa // S_ZERO_M, S_MORE_M: more digits of mantissa, decimal dot, E // S_FIRST_F: first digit of fraction // S_MORE_F: more digits of fraction, E, trailing whitespace // S_INITIAL_E: +, -, first digit of exponent // S_FIRST_E: first digit of exponent // S_ZERO_E, S_MORE_E: more digits of exponent, trailing whitespace // S_END: trailing whitespace // S_ERR: error was found, stop for (size_t i = start; i < end; i++) { char c = s[i]; switch (state) { case S_INITIAL: if (c == '+' || c == '-') state = S_FIRST_M; else if (c == '0') state = S_ZERO_M; else if (c >= '1' && c <= '9') state = S_MORE_M; else state = S_ERR; break; case S_FIRST_M: if (c == '0') state = S_ZERO_M; else if (c >= '1' && c <= '9') state = S_MORE_M; else state = S_ERR; break; case S_ZERO_M: if (c == '.') state = S_FIRST_F; else if (c == 'E' || c == 'e') state = S_INITIAL_E; else if (c >= '0' && c <= '9') { state = S_MORE_M; } else state = S_ERR; break; case S_MORE_M: if (c == '.') state = S_FIRST_F; else if (c == 'E' || c == 'e') state = S_INITIAL_E; else if (c >= '0' && c <= '9') {} else state = S_ERR; break; case S_FIRST_F: if (c >= '0' && c <= '9') state = S_MORE_F; else state = S_ERR; break; case S_MORE_F: if (c == 'E' || c == 'e') state = S_INITIAL_E; else if (c >= '0' && c <= '9') {} else state = S_ERR; break; case S_INITIAL_E: if (c == '+' || c == '-') state = S_FIRST_E; else if (c == '0') state = S_ZERO_E; else if (c >= '1' && c <= '9') state = S_MORE_E; else state = S_ERR; break; case S_FIRST_E: if (c == '0') state = S_ZERO_E; else if (c >= '1' && c <= '9') state = S_MORE_E; else state = S_ERR; break; case S_ZERO_E: if (c >= '0' && c <= '9') { state = S_MORE_E; } else state = S_ERR; break; case S_MORE_E: if (c >= '0' && c <= '9') {} else state = S_ERR; break; default: break; } if (state == S_ERR) { if (string::is_printable(c)) { val->error("%s operand of operation `%s' should be a string " "containing a valid float value, but invalid character `%c' " "was detected at index %lu", opnum, opname, c, (unsigned long) i); } else { val->error("%s operand of operation `%s' should be a string " "containing a valid float value, but invalid character with " "character code %u was detected at index %lu", opnum, opname, c, (unsigned long) i); } set_valuetype(V_ERROR); break; } } switch (state) { case S_INITIAL: val->error("%s operand of operation `%s' should be a string containing a " "valid float value instead of an empty string", opnum, opname); set_valuetype(V_ERROR); break; case S_FIRST_M: val->error("%s operand of operation `%s' should be a string containing a " "valid float value, but only a sign character was detected", opnum, opname); set_valuetype(V_ERROR); break; case S_ZERO_M: case S_MORE_M: // HL67862: Missing decimal dot allowed for str2float break; case S_FIRST_F: // HL67862: Missing fraction part is allowed for str2float break; case S_INITIAL_E: case S_FIRST_E: val->error("%s operand of operation `%s' should be a string containing a " "valid float value, but the exponent is missing after the `E' sign", opnum, opname); set_valuetype(V_ERROR); break; default: break; } } void Value::chk_expr_val_ustr_7bitchars(Value *val, const char *opnum, const char *opname) { if (valuetype == V_ERROR || u.expr.state == EXPR_CHECKING_ERR) return; Value *v = val->get_value_refd_last(); if (v->valuetype != V_USTR) return; const ustring& us = v->get_val_ustr(); for (size_t i = 0; i < us.size(); i++) { const ustring::universal_char& uchar = us[i]; if (uchar.group != 0 || uchar.plane != 0 || uchar.row != 0 || uchar.cell > 127) { val->error("%s operand of operation `%s' shall consist of characters " "within the range char(0, 0, 0, 0) .. char(0, 0, 0, 127), but the " "string %s contains character char(%u, %u, %u, %u) at index %lu", opnum, opname, us.get_stringRepr().c_str(), uchar.group, uchar.plane, uchar.row, uchar.cell, (unsigned long) i); set_valuetype(V_ERROR); return; } } } void Value::chk_expr_val_bitstr_intsize(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; const string& bstr=val->get_val_str(); // see also PredefFunc.cc::bit2int() size_t nof_bits = bstr.size(); // skip the leading zeros size_t start_index = 0; while (start_index < nof_bits && bstr[start_index] == '0') start_index++; // check whether the remaining bits fit in Int if (nof_bits - start_index > 8 * sizeof(Int) - 1) { val->error("%s operand of operation `%s' is too large (maximum number" " of bits in integer is %lu)", opnum, opname, (unsigned long) (8 * sizeof(Int) - 1)); set_valuetype(V_ERROR); } } void Value::chk_expr_val_hexstr_intsize(Value *val, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(val->is_unfoldable()) return; const string& hstr=val->get_val_str(); // see also PredefFunc.cc::hex2int() size_t nof_digits = hstr.size(); // skip the leading zeros size_t start_index = 0; while (start_index < nof_digits && hstr[start_index] == '0') start_index++; // check whether the remaining hex digits fit in Int if (nof_digits - start_index > 2 * sizeof(Int) || (nof_digits - start_index == 2 * sizeof(Int) && char_to_hexdigit(hstr[start_index]) > 7)) { val->error("%s operand of operation `%s' is too large (maximum number" " of bits in integer is %lu)", opnum, opname, (unsigned long) (8 * sizeof(Int) - 1)); set_valuetype(V_ERROR); } } void Value::chk_expr_operands_int2binstr() { if (valuetype == V_ERROR || u.expr.state == EXPR_CHECKING_ERR) return; if (u.expr.v1->is_unfoldable()) return; if (u.expr.v2->is_unfoldable()) return; // It is already checked that i1 and i2 are non-negative. Error_Context cntxt(this, "In operation `%s'", get_opname()); const int_val_t *i1 = u.expr.v1->get_val_Int(); const int_val_t *i2 = u.expr.v2->get_val_Int(); if (!i2->is_native()) { u.expr.v2->error("The length of the resulting string is too large for " "being represented in memory"); set_valuetype(V_ERROR); return; } Int nof_bits = i2->get_val(); if (u.expr.v1->is_unfoldable()) return; switch (u.expr.v_optype) { case OPTYPE_INT2BIT: break; case OPTYPE_INT2HEX: nof_bits *= 4; break; case OPTYPE_INT2OCT: nof_bits *= 8; break; default: FATAL_ERROR("Value::chk_expr_operands_int2binstr()"); } if (*i1 >> nof_bits > 0) { // Expensive? u.expr.v1->error("Value %s does not fit in length %s", i1->t_str().c_str(), i2->t_str().c_str()); set_valuetype(V_ERROR); } } void Value::chk_expr_operands_str_samelen() { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; Value *v1=u.expr.v1; if(v1->is_unfoldable()) return; Value *v2=u.expr.v2; if(v2->is_unfoldable()) return; Error_Context cntxt(this, "In operation `%s'", get_opname()); size_t i1=v1->get_val_strlen(); size_t i2=v2->get_val_strlen(); if(i1!=i2) { error("The operands should have the same length"); set_valuetype(V_ERROR); } } void Value::chk_expr_operands_replace() { // The fourth operand doesn't need to be checked at all here. if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; Value* v1 = u.expr.ti1->get_specific_value(); if (!v1) return; Error_Context cntxt(this, "In operation `%s'", get_opname()); size_t list_len = 0; bool list_len_known = false; if (v1->valuetype == V_REFD) { Ttcn::FieldOrArrayRefs *subrefs = v1->u.ref.ref->get_subrefs(); if (subrefs && subrefs->refers_to_string_element()) { warning("Replacing a string element does not make any sense"); list_len = 1; list_len_known = true; } } if (!v1->is_unfoldable()) { list_len = v1->is_string_type(Type::EXPECTED_TEMPLATE) ? v1->get_val_strlen() : v1->get_value_refd_last()->get_nof_comps(); list_len_known = true; } if (!list_len_known) return; if (u.expr.v2->is_unfoldable()) { if (!u.expr.v3->is_unfoldable()) { const int_val_t *len_int_3 = u.expr.v3->get_val_Int(); if (*len_int_3 > static_cast<Int>(list_len)) { error("Third operand `len' (%s) is greater than the length of " "the first operand (%lu)", (len_int_3->t_str()).c_str(), (unsigned long)list_len); set_valuetype(V_ERROR); } } } else { const int_val_t *index_int_2 = u.expr.v2->get_val_Int(); if (u.expr.v3->is_unfoldable()) { if (*index_int_2 > static_cast<Int>(list_len)) { error("Second operand `index' (%s) is greater than the length of " "the first operand (%lu)", (index_int_2->t_str()).c_str(), (unsigned long)list_len); set_valuetype(V_ERROR); } } else { const int_val_t *len_int_3 = u.expr.v3->get_val_Int(); if (*index_int_2 + *len_int_3 > static_cast<Int>(list_len)) { error("The sum of second operand `index' (%s) and third operand " "`len' (%s) is greater than the length of the first operand (%lu)", (index_int_2->t_str()).c_str(), (len_int_3->t_str()).c_str(), (unsigned long)list_len); set_valuetype(V_ERROR); } } } } void Value::chk_expr_operands_substr() { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; Value* v1 = u.expr.ti1->get_specific_value(); if (!v1) return; Error_Context cntxt(this, "In operation `%s'", get_opname()); size_t list_len = 0; bool list_len_known = false; if (v1->valuetype == V_REFD) { Ttcn::FieldOrArrayRefs *subrefs = v1->u.ref.ref->get_subrefs(); if (subrefs && subrefs->refers_to_string_element()) { warning("Taking the substring of a string element does not make any " "sense"); list_len = 1; list_len_known = true; } } if (!list_len_known && !v1->is_unfoldable()) { list_len = v1->is_string_type(Type::EXPECTED_TEMPLATE) ? v1->get_val_strlen() : v1->get_value_refd_last()->get_nof_comps(); list_len_known = true; } // Do nothing if the length of the first operand is unknown. if (!list_len_known) return; if (u.expr.v2->is_unfoldable()) { if (!u.expr.v3->is_unfoldable()) { const int_val_t *returncount_int_3 = u.expr.v3->get_val_Int(); // Only the third operand is known. if (*returncount_int_3 > static_cast<Int>(list_len)) { error("Third operand `returncount' (%s) is greater than the " "length of the first operand (%lu)", (returncount_int_3->t_str()).c_str(), (unsigned long)list_len); set_valuetype(V_ERROR); } } } else { const int_val_t *index_int_2 = u.expr.v2->get_val_Int(); if (u.expr.v3->is_unfoldable()) { // Only the second operand is known. if (*index_int_2 > static_cast<Int>(list_len)) { error("Second operand `index' (%s) is greater than the length " "of the first operand (%lu)", (index_int_2->t_str()).c_str(), (unsigned long)list_len); set_valuetype(V_ERROR); } } else { // Both second and third operands are known. const int_val_t *returncount_int_3 = u.expr.v3->get_val_Int(); if (*index_int_2 + *returncount_int_3 > static_cast<Int>(list_len)) { error("The sum of second operand `index' (%s) and third operand " "`returncount' (%s) is greater than the length of the first operand " "(%lu)", (index_int_2->t_str()).c_str(), (returncount_int_3->t_str()).c_str(), (unsigned long)list_len); set_valuetype(V_ERROR); } } } } void Value::chk_expr_operands_regexp() { if (valuetype == V_ERROR || u.expr.state == EXPR_CHECKING_ERR) return; Value* v1 = u.expr.ti1->get_specific_value(); Value* v2 = u.expr.t2->get_specific_value(); if (!v1 || !v2) return; Error_Context cntxt(this, "In operation `regexp()'"); Value* v1_last = v1->get_value_refd_last(); if (v1_last->valuetype == V_CSTR) { // the input string is available at compile time const string& instr = v1_last->get_val_str(); const char *input_str = instr.c_str(); size_t instr_len = strlen(input_str); if (instr_len < instr.size()) { v1->warning("The first operand of `regexp()' contains a " "character with character code zero at index %s. The rest of the " "string will be ignored during matching", Int2string(instr_len).c_str()); } } size_t nof_groups = 0; Value *v2_last = v2->get_value_refd_last(); if (v2_last->valuetype == V_CSTR) { // the pattern is available at compile time const string& expression = v2_last->get_val_str(); const char *pattern_str = expression.c_str(); size_t pattern_len = strlen(pattern_str); if (pattern_len < expression.size()) { v2->warning("The second operand of `regexp()' contains a " "character with character code zero at index %s. The rest of the " "string will be ignored during matching", Int2string(pattern_len).c_str()); } char *posix_str; { Error_Context cntxt2(v2, "In character string pattern"); posix_str = TTCN_pattern_to_regexp(pattern_str); } if (posix_str != NULL) { regex_t posix_regexp; int ret_val = regcomp(&posix_regexp, posix_str, REG_EXTENDED); if (ret_val != 0) { char msg[512]; regerror(ret_val, &posix_regexp, msg, sizeof(msg)); FATAL_ERROR("Value::chk_expr_operands_regexp(): " \ "regcomp() failed: %s", msg); } if (posix_regexp.re_nsub > 0) nof_groups = posix_regexp.re_nsub; else { v2->error("The character pattern in the second operand of " "`regexp()' does not contain any groups"); set_valuetype(V_ERROR); } regfree(&posix_regexp); Free(posix_str); } else { // the pattern is faulty // the error has been reported by TTCN_pattern_to_regexp set_valuetype(V_ERROR); } } if (nof_groups > 0) { Value *v3 = u.expr.v3->get_value_refd_last(); if (v3->valuetype == V_INT) { // the group number is available at compile time const int_val_t *groupno_int = v3->get_val_Int(); if (*groupno_int >= static_cast<Int>(nof_groups)) { u.expr.v3->error("The the third operand of `regexp()' is too " "large: The requested group index is %s, but the pattern " "contains only %s group%s", (groupno_int->t_str()).c_str(), Int2string(nof_groups).c_str(), nof_groups > 1 ? "s" : ""); set_valuetype(V_ERROR); } } } } void Value::chk_expr_operands_ischosen(ReferenceChain *refch, Type::expected_value_t exp_val) { const char *opname = get_opname(); Error_Context cntxt(this, "In the operand of operation `%s'", opname); Type *t_governor; const Location *loc; bool error_flag = false; switch (u.expr.v_optype) { case OPTYPE_ISCHOSEN_V: // u.expr.v1 is always a referenced value t_governor = u.expr.v1->get_expr_governor(exp_val); if (t_governor) { u.expr.v1->set_my_governor(t_governor); t_governor->chk_this_refd_value(u.expr.v1, 0, exp_val, refch); if (u.expr.v1->valuetype == V_ERROR) error_flag = true; } else error_flag = true; loc = u.expr.v1; break; case OPTYPE_ISCHOSEN_T: // u.expr.t1 is always a referenced template if (exp_val == Type::EXPECTED_DYNAMIC_VALUE) exp_val = Type::EXPECTED_TEMPLATE; t_governor = u.expr.t1->get_expr_governor(exp_val); if (t_governor) { u.expr.t1->set_my_governor(t_governor); // // FIXME: commenting out the 2 lines below "fixes" the ischosen for HQ46602 // u.expr.t1->get_template_refd_last(refch); if (u.expr.t1->get_templatetype() == Template::TEMPLATE_ERROR) error_flag = true; } else error_flag = true; if (exp_val != Type::EXPECTED_TEMPLATE) { u.expr.t1->error("Reference to a %s value was expected instead of %s", exp_val == Type::EXPECTED_CONSTANT ? "constant" : "static", u.expr.t1->get_reference()->get_refd_assignment() ->get_description().c_str()); error_flag = true; } loc = u.expr.t1; break; default: FATAL_ERROR("Value::chk_expr_operands_ischosen()"); t_governor = 0; loc = 0; } if (t_governor) { t_governor = t_governor->get_type_refd_last(); switch (t_governor->get_typetype()) { case Type::T_ERROR: error_flag = true; break; case Type::T_CHOICE_A: case Type::T_CHOICE_T: case Type::T_ANYTYPE: case Type::T_OPENTYPE: if (!t_governor->has_comp_withName(*u.expr.i2)) { CompField* def_alt = t_governor->get_default_alternative(); Ttcn::Reference* ref = u.expr.v_optype == OPTYPE_ISCHOSEN_V ? dynamic_cast<Ttcn::Reference*>(u.expr.v1->get_reference()) : u.expr.t1->get_reference(); if (def_alt != NULL && ref != NULL) { Error_Context cntxt2(ref, "Using default alternative `%s' in value or template of union type `%s'", def_alt->get_name().get_dispname().c_str(), t_governor->get_typename().c_str()); ref->use_default_alternative(def_alt->get_name()); if (u.expr.v_optype == OPTYPE_ISCHOSEN_V) { u.expr.v1->set_my_governor(def_alt->get_type()); } else { u.expr.t1->set_my_governor(def_alt->get_type()); } chk_expr_operands_ischosen(refch, exp_val); return; } error(t_governor->get_typetype()==Type::T_ANYTYPE ? "%s does not have a field named `%s'" : "Union type `%s' does not have a field named `%s'", t_governor->get_typename().c_str(), u.expr.i2->get_dispname().c_str()); error_flag = true; } break; default: loc->error("The operand of operation `%s' should be a union value " "or template instead of `%s'", opname, t_governor->get_typename().c_str()); error_flag = true; break; } } if (error_flag) set_valuetype(V_ERROR); } void Value::chk_dyn_enc_str(Type* type) { if (legacy_codec_handling) { FATAL_ERROR("Value::chk_dyn_enc_str()"); } Type* t_ct = type->get_type_w_coding_table(); if (t_ct == NULL) { return; // an error has already been displayed } bool val_error = false; ustring us = get_val_ustr(); for (size_t i = 0; i < us.size(); ++i) { const ustring::universal_char& uc = us[i]; if (uc.group != 0 || uc.plane != 0 || uc.row != 0) { // this surely won't match any of the type's encodings, since // 'encode' attributes cannot contain multi-byte characters val_error = true; break; } } if (!val_error) { string s(us); Type::MessageEncodingType_t coding = Type::get_enc_type(s); bool built_in = (coding != Type::CT_PER && coding != Type::CT_CUSTOM); val_error = true; const vector<Common::Type::coding_t>& ct = t_ct->get_coding_table(); for (size_t i = 0; i < ct.size(); ++i) { if (built_in == ct[i]->built_in && ((built_in && coding == ct[i]->built_in_coding) || (!built_in && s == ct[i]->custom_coding.name))) { val_error = false; break; } } } if (val_error) { error("The encoding string does not match any encodings of type `%s'", type->get_typename().c_str()); } } void Value::chk_expr_operand_encode(ReferenceChain *refch, Type::expected_value_t exp_val) { const char* opname = u.expr.v_optype == OPTYPE_ENCODE ? "encvalue" : "encvalue_unichar"; Type t_chk(Type::T_ERROR); Type* t_type; { Error_Context cntxt(this, "In the first parameter of %s()", opname); Type* t_type_last; Type::expected_value_t ti_exp_val = exp_val; if (ti_exp_val == Type::EXPECTED_DYNAMIC_VALUE) ti_exp_val = Type::EXPECTED_TEMPLATE; t_type = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (t_type) { chk_expr_eval_ti(u.expr.ti1, t_type, refch, ti_exp_val); if (valuetype!=V_ERROR) u.expr.ti1->get_Template()->chk_specific_value(false); t_type_last = t_type->get_type_refd_last(); } else { error("Cannot determine type of value"); set_valuetype(V_ERROR); return; } // todo: fix this /*if (u.expr.par1_is_value && u.expr.v1->get_valuetype() != V_REFD) { error("Expecting a value of a type with coding attributes in first" "parameter of encvalue() which belongs to a generic type '%s'", t_type->get_typename().c_str()); goto error; }*/ if(!disable_attribute_validation()) { Type* t_type_coding = legacy_codec_handling ? t_type_last : t_type; t_type_coding->chk_coding(true, my_scope->get_scope_mod()); } switch (t_type_last->get_typetype()) { case Type::T_UNDEF: case Type::T_ERROR: case Type::T_NULL: case Type::T_REFD: case Type::T_REFDSPEC: case Type::T_SELTYPE: case Type::T_VERDICT: case Type::T_PORT: case Type::T_COMPONENT: case Type::T_DEFAULT: case Type::T_SIGNATURE: case Type::T_FUNCTION: case Type::T_ALTSTEP: case Type::T_TESTCASE: error("Type of parameter of encvalue() cannot be '%s'", t_type_last->get_typename().c_str()); set_valuetype(V_ERROR); return; default: break; } } Value* v_enc_info = u.expr.v_optype == OPTYPE_ENCODE ? u.expr.v2 : u.expr.v3; if (v_enc_info != NULL) { Error_Context cntxt(this, "In the %s parameter of %s()", u.expr.v_optype == OPTYPE_ENCODE ? "second" : "third", opname); if (legacy_codec_handling) { warning("The `encoding_info' parameter of %s() is ignored when using " "legacy codec handling", opname); } v_enc_info->set_lowerid_to_ref(); Type::typetype_t tt = v_enc_info->get_expr_returntype(exp_val); if (tt == Type::T_CHOICE_T && v_enc_info->is_ref() && chk_expr_operand_default_alternative(v_enc_info, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_ENCODE ? "Second" : "Third", opname, v_enc_info); chk_expr_eval_value(v_enc_info, t_chk, refch, exp_val); // this parameter is currently ignored } Value* v_dyn_enc = u.expr.v_optype == OPTYPE_ENCODE ? u.expr.v3 : u.expr.v4; if (v_dyn_enc != NULL) { Error_Context cntxt(this, "In the %s operand of %s()", u.expr.v_optype == OPTYPE_ENCODE ? "third" : "fourth", opname); if (legacy_codec_handling) { warning("The `dynamic_encoding' parameter of %s() is ignored when " "using legacy codec handling", opname); } v_dyn_enc->set_lowerid_to_ref(); Type::typetype_t tt = v_dyn_enc->get_expr_returntype(exp_val); if (tt == Type::T_CHOICE_T && v_dyn_enc->is_ref() && chk_expr_operand_default_alternative(v_dyn_enc, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_ENCODE ? "Third" : "Fourth", opname, v_dyn_enc); chk_expr_eval_value(v_dyn_enc, t_chk, refch, exp_val); if (!legacy_codec_handling && !v_dyn_enc->is_unfoldable(refch, exp_val)) { v_dyn_enc->chk_dyn_enc_str(t_type); } } } void Value::chk_expr_operands_decode(ReferenceChain *refch, Type::expected_value_t exp_val) { const char* opname = u.expr.v_optype == OPTYPE_DECODE ? "decvalue" : "decvalue_unichar"; Type* t_type = 0; { Error_Context cntxt(this, "In the parameters of %s()", opname); Ttcn::Reference* ref = u.expr.r1; Ttcn::FieldOrArrayRefs* t_subrefs = ref->get_subrefs(); Type* t_type_last = 0; Assignment* t_ass = ref->get_refd_assignment(); if (!t_ass) { error("Could not determine the assignment for first parameter"); goto error; } switch (t_ass->get_asstype()) { case Assignment::A_PAR_VAL_IN: t_ass->use_as_lvalue(*this); break; case Assignment::A_CONST: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_MODULEPAR_TEMP: case Assignment::A_TEMPLATE: ref->error("Reference to '%s' cannot be used as the first operand of " "the 'decvalue' operation", t_ass->get_assname()); goto error; break; case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: break; case Assignment::A_VAR_TEMPLATE: case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: { Template* t = new Template(Template::TEMPLATE_REFD, ref->clone()); t->set_location(*ref); t->set_my_scope(get_my_scope()); t->set_fullname(get_fullname()+".<operand>"); Template* t_last = t->get_template_refd_last(); if (t_last->get_templatetype() != Template::SPECIFIC_VALUE && t_last != t) { ref->error("Specific value template was expected instead of '%s'.", t->get_template_refd_last()->get_templatetype_str()); delete t; goto error; } delete t; break; } default: ref->error("Reference to '%s' cannot be used.", t_ass->get_assname()); goto error; } t_type = t_ass->get_Type()->get_field_type(t_subrefs, Type::EXPECTED_DYNAMIC_VALUE); if (!t_type) { goto error; } if (t_type->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T) { CompField* def_alt = t_type->get_default_alternative(); if (def_alt != NULL) { Error_Context cntxt2(ref, "Using default alternative `%s' in reference to value of union type `%s'", def_alt->get_name().get_dispname().c_str(), t_type->get_typename().c_str()); ref->use_default_alternative(def_alt->get_name()); chk_expr_operands_decode(refch, exp_val); return; } } switch(u.expr.v_optype) { case OPTYPE_DECODE: if (t_type->get_type_refd_last()->get_typetype() != Type::T_BSTR){ error("First parameter has to be a bitstring"); goto error; } break; case OPTYPE_DECVALUE_UNICHAR: if (t_type->get_type_refd_last()->get_typetype() != Type::T_USTR){ error("First parameter has to be a universal charstring"); goto error; } break; default: FATAL_ERROR("Value::chk_expr_decode_operands()"); break; } ref = u.expr.r2; t_subrefs = ref->get_subrefs(); t_ass = ref->get_refd_assignment(); if (!t_ass) { error("Could not determine the assignment for second parameter"); goto error; } // Extra check for HM59355. switch (t_ass->get_asstype()) { case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: break; default: ref->error("Reference to '%s' cannot be used.", t_ass->get_assname()); goto error; } t_type = t_ass->get_Type()->get_field_type(t_subrefs, Type::EXPECTED_DYNAMIC_VALUE); if (!t_type) { goto error; } t_type_last = t_type->get_type_refd_last(); switch (t_type_last->get_typetype()) { case Type::T_UNDEF: case Type::T_ERROR: case Type::T_NULL: case Type::T_REFD: case Type::T_REFDSPEC: case Type::T_SELTYPE: case Type::T_VERDICT: case Type::T_PORT: case Type::T_COMPONENT: case Type::T_DEFAULT: case Type::T_SIGNATURE: case Type::T_FUNCTION: case Type::T_ALTSTEP: case Type::T_TESTCASE: error("Type of second parameter cannot be %s", t_type_last->get_typename().c_str()); goto error; default: break; } if(!disable_attribute_validation()) { Type* t_type_coding = legacy_codec_handling ? t_type_last : t_type; t_type_coding->chk_coding(false, my_scope->get_scope_mod()); } } { Type t_chk(Type::T_ERROR); Value* v_enc_info = u.expr.v_optype == OPTYPE_DECODE ? u.expr.v3 : u.expr.v4; if (v_enc_info != NULL) { Error_Context cntxt2(this, "In the %s parameter of %s()", u.expr.v_optype == OPTYPE_DECODE ? "third" : "fourth", opname); if (legacy_codec_handling) { warning("The `encoding_info' parameter of %s() is ignored when using " "legacy codec handling", opname); } v_enc_info->set_lowerid_to_ref(); Type::typetype_t tt = v_enc_info->get_expr_returntype(exp_val); if (tt == Type::T_CHOICE_T && v_enc_info->is_ref() && chk_expr_operand_default_alternative(v_enc_info, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_DECODE ? "Third" : "Fourth", opname, v_enc_info); chk_expr_eval_value(v_enc_info, t_chk, refch, exp_val); // this parameter is currently ignored } Value* v_dyn_enc = u.expr.v_optype == OPTYPE_DECODE ? u.expr.v4 : u.expr.v5; if (v_dyn_enc != NULL) { Error_Context cntxt2(this, "In the %s operand of %s()", u.expr.v_optype == OPTYPE_DECODE ? "fourth" : "fifth", opname); if (legacy_codec_handling) { warning("The `dynamic_encoding' parameter of %s() is ignored when " "using legacy codec handling", opname); } v_dyn_enc->set_lowerid_to_ref(); Type::typetype_t tt = v_dyn_enc->get_expr_returntype(exp_val); if (tt == Type::T_CHOICE_T && v_dyn_enc->is_ref() && chk_expr_operand_default_alternative(v_dyn_enc, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt, u.expr.v_optype == OPTYPE_DECODE ? "Fourth" : "Fifth", opname, v_dyn_enc); chk_expr_eval_value(v_dyn_enc, t_chk, refch, exp_val); if (!legacy_codec_handling && !v_dyn_enc->is_unfoldable(refch, exp_val)) { v_dyn_enc->chk_dyn_enc_str(t_type); } } } return; error: set_valuetype(V_ERROR); } void Value::chk_expr_omit_comparison(Type::expected_value_t exp_val) { Ttcn::FieldOrArrayRefs *subrefs; Identifier *field_id = 0; Assignment *t_ass; Type *t_type; if (valuetype == V_ERROR) return; else if (valuetype != V_REFD) { error("Only a referenced value can be compared with `omit'"); goto error; } subrefs = u.ref.ref->get_subrefs(); if (subrefs) field_id = subrefs->remove_last_field(); if (!field_id) { error("Only a reference pointing to an optional record or set field " "can be compared with `omit'"); goto error; } t_ass = u.ref.ref->get_refd_assignment(); if (!t_ass) goto error; t_type = t_ass->get_Type()->get_field_type(subrefs, exp_val); if (!t_type) goto error; t_type = t_type->get_type_refd_last(); switch (t_type->get_typetype()) { case Type::T_ERROR: goto error; case Type::T_SEQ_A: case Type::T_SEQ_T: case Type::T_SET_A: case Type::T_SET_T: break; default: error("Only a reference pointing to an optional field of a record" " or set type can be compared with `omit'"); goto error; } if (!t_type->has_comp_withName(*field_id)) { error("Type `%s' does not have field named `%s'", t_type->get_typename().c_str(), field_id->get_dispname().c_str()); goto error; } else if (!t_type->get_comp_byName(*field_id)->get_is_optional()) { error("Field `%s' is mandatory in type `%s'. It cannot be compared with " "`omit'", field_id->get_dispname().c_str(), t_type->get_typename().c_str()); goto error; } // putting the last field_id back to subrefs subrefs->add(new Ttcn::FieldOrArrayRef(field_id)); return; error: set_valuetype(V_ERROR); delete field_id; } Int Value::chk_eval_expr_sizeof(ReferenceChain *refch, Type::expected_value_t exp_val, Type* def_alt_type) { if(valuetype==V_ERROR) return -1; if(u.expr.state==EXPR_CHECKING_ERR) return -1; if(exp_val==Type::EXPECTED_DYNAMIC_VALUE) exp_val=Type::EXPECTED_TEMPLATE; Error_Context cntxt(this, "In the operand of" " operation `%s'", get_opname()); Int result = -1; Template* t_templ = u.expr.ti1->get_Template(); if (!t_templ) { FATAL_ERROR("chk_eval_expr_sizeof()\n"); } t_templ = t_templ->get_template_refd_last(refch); // Timer and port arrays are handled separately if (t_templ->get_templatetype() == Template::SPECIFIC_VALUE) { Value* val = t_templ->get_specific_value(); if (val->get_valuetype() == V_UNDEF_LOWERID) { val->set_lowerid_to_ref(); } if (val && val->get_valuetype() == V_REFD) { Reference* ref = val->get_reference(); Assignment* t_ass = ref->get_refd_assignment(); Common::Assignment::asstype_t asstype = t_ass ? t_ass->get_asstype() : Assignment::A_ERROR; if (asstype == Assignment::A_PORT || asstype == Assignment::A_TIMER) { if (t_ass->get_Dimensions()) { // here we have a timer or port array Ttcn::FieldOrArrayRefs* t_subrefs = ref->get_subrefs(); Ttcn::ArrayDimensions *t_dims = t_ass->get_Dimensions(); t_dims->chk_indices(ref, t_ass->get_assname(), true, Type::EXPECTED_DYNAMIC_VALUE); size_t refd_dim; if (t_subrefs) { refd_dim = t_subrefs->get_nof_refs(); size_t nof_dims = t_dims->get_nof_dims(); if (refd_dim >= nof_dims) { u.expr.ti1->error("Operation is not applicable to a %s", t_ass->get_assname()); set_valuetype(V_ERROR); return -1; } } else refd_dim = 0; return t_dims->get_dim_byIndex(refd_dim)->get_size(); } else { u.expr.ti1->error("Operation is not applicable to single `%s'", t_ass->get_description().c_str()); set_valuetype(V_ERROR); return -1; } } } } Value* t_val = 0; Type* t_type = 0; Assignment* t_ass = 0; Reference* ref = 0; Ttcn::FieldOrArrayRefs* t_subrefs = 0; t_type = def_alt_type != NULL ? def_alt_type : chk_expr_operands_ti(u.expr.ti1, exp_val); if (t_type) { chk_expr_eval_ti(u.expr.ti1, t_type, refch, exp_val); t_type = t_type->get_type_refd_last(); } else { error("Cannot determine type of value"); goto error; } if(valuetype==V_ERROR) return -1; t_templ = t_templ->get_template_refd_last(refch); switch(t_templ->get_templatetype()) { case Template::TEMPLATE_ERROR: goto error; case Template::INDEXED_TEMPLATE_LIST: return -1; case Template::TEMPLATE_REFD: ref = t_templ->get_reference(); t_ass = ref->get_refd_assignment(); t_subrefs = ref->get_subrefs(); break; case Template::TEMPLATE_LIST: case Template::NAMED_TEMPLATE_LIST: // computed later break; case Template::SPECIFIC_VALUE: { t_val=t_templ->get_specific_value()->get_value_refd_last(refch); if(t_val) { switch(t_val->get_valuetype()) { case V_SEQOF: case V_SETOF: case V_ARRAY: case V_ROID: case V_OID: case V_SEQ: case V_SET: break; case V_REFD: { ref = t_val->get_reference(); t_ass = ref->get_refd_assignment(); t_subrefs = ref->get_subrefs(); break; } default: u.expr.ti1->error("Operation is not applicable to `%s'", t_val->create_stringRepr().c_str()); goto error; } } break; } default: u.expr.ti1->error("Operation is not applicable to %s `%s'", t_templ->get_templatetype_str(), t_templ->get_fullname().c_str()); goto error; } // switch if (t_ass) { switch(t_ass->get_asstype()) { case Assignment::A_ERROR: goto error; case Assignment::A_CONST: t_val = t_ass->get_Value(); break; case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_MODULEPAR_TEMP: if(exp_val==Type::EXPECTED_CONSTANT) { u.expr.ti1->error("Reference to an (evaluable) constant value was " "expected instead of %s", t_ass->get_description().c_str()); goto error; } break; case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: switch(exp_val) { case Type::EXPECTED_CONSTANT: u.expr.ti1->error("Reference to a constant value was expected instead of %s", t_ass->get_description().c_str()); goto error; break; case Type::EXPECTED_STATIC_VALUE: u.expr.ti1->error("Reference to a static value was expected instead of %s", t_ass->get_description().c_str()); goto error; break; default: break; } break; case Assignment::A_TEMPLATE: t_templ = t_ass->get_Template(); // no break case Assignment::A_VAR_TEMPLATE: case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: if (exp_val!=Type::EXPECTED_TEMPLATE) { u.expr.ti1->error("Reference to a value was expected instead of %s", t_ass->get_description().c_str()); goto error; } break; case Assignment::A_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL: switch(exp_val) { case Type::EXPECTED_CONSTANT: u.expr.ti1->error("Reference to a constant value was expected instead of " "the return value of %s", t_ass->get_description().c_str()); goto error; break; case Type::EXPECTED_STATIC_VALUE: u.expr.ti1->error("Reference to a static value was expected instead of " "the return value of %s", t_ass->get_description().c_str()); goto error; break; default: break; } break; case Assignment::A_FUNCTION_RTEMP: case Assignment::A_EXT_FUNCTION_RTEMP: if(exp_val!=Type::EXPECTED_TEMPLATE) u.expr.ti1->error("Reference to a value was expected instead of a call" " of %s, which returns a template", t_ass->get_description().c_str()); goto error; break; case Assignment::A_TIMER: case Assignment::A_PORT: if (u.expr.v_optype == OPTYPE_SIZEOF) { // sizeof is applicable to timer and port arrays Ttcn::ArrayDimensions *t_dims = t_ass->get_Dimensions(); if (!t_dims) { u.expr.ti1->error("Operation is not applicable to single %s", t_ass->get_description().c_str()); goto error; } t_dims->chk_indices(ref, t_ass->get_assname(), true, Type::EXPECTED_DYNAMIC_VALUE); size_t refd_dim; if (t_subrefs) { refd_dim = t_subrefs->get_nof_refs(); size_t nof_dims = t_dims->get_nof_dims(); if (refd_dim > nof_dims) goto error; else if (refd_dim == nof_dims) { u.expr.ti1->error("Operation is not applicable to a %s", t_ass->get_assname()); goto error; } } else refd_dim = 0; return t_dims->get_dim_byIndex(refd_dim)->get_size(); } // no break default: u.expr.ti1->error("Reference to a %s was expected instead of %s", exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value", t_ass->get_description().c_str()); goto error; } // end switch t_type = t_ass->get_Type()->get_field_type(t_subrefs, exp_val); if (!t_type) goto error; t_type = t_type->get_type_refd_last(); switch(t_type->get_typetype()) { case Type::T_ERROR: goto error; case Type::T_SEQOF: case Type::T_SETOF: // no break case Type::T_SEQ_T: case Type::T_SET_T: case Type::T_SEQ_A: case Type::T_SET_A: case Type::T_ARRAY: // ok break; case Type::T_OID: case Type::T_ROID: break; case Type::T_CHOICE_T: if (ref != NULL) { CompField* def_alt = t_type->get_default_alternative(); Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(ref); if (def_alt != NULL && ttcn_ref != NULL) { Error_Context cntxt2(ref, "Using default alternative `%s' in value or template of union type `%s'", def_alt->get_name().get_dispname().c_str(), t_type->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt->get_name()); return chk_eval_expr_sizeof(refch, exp_val, def_alt->get_type()); } } // otherwise fall through default: u.expr.ti1->error("Reference to value or template of type record, record of," " set, set of, objid or array was expected"); goto error; } // switch } // check for index overflows in subrefs if possible if (t_val) { switch (t_val->get_valuetype()) { case V_SEQOF: case V_SETOF: case V_ARRAY: if (t_val->is_indexed()) { return -1; } break; default: break; } /* The reference points to a constant. */ if (!t_subrefs || !t_subrefs->has_unfoldable_index()) { t_val = t_val->get_refd_sub_value(t_subrefs, 0, false, refch); if (!t_val) goto error; t_val=t_val->get_value_refd_last(refch); } else { t_val = 0; } } else if (t_templ) { /* The size of INDEXED_TEMPLATE_LIST nodes is unknown at compile time. Don't try to evaluate it at compile time. */ if (t_templ->get_templatetype() == Template::INDEXED_TEMPLATE_LIST) { return -1; /* The reference points to a static template. */ } else if (!t_subrefs || !t_subrefs->has_unfoldable_index()) { t_templ = t_templ->get_refd_sub_template(t_subrefs, ref && ref->getUsedInIsbound(), refch); if (!t_templ) goto error; t_templ = t_templ->get_template_refd_last(refch); } else { t_templ = 0; } } if(u.expr.v_optype==OPTYPE_SIZEOF) { if(t_templ) { switch(t_templ->get_templatetype()) { case Template::TEMPLATE_ERROR: goto error; case Template::TEMPLATE_REFD: // not foldable t_templ=0; break; case Template::SPECIFIC_VALUE: t_val=t_templ->get_specific_value()->get_value_refd_last(refch); t_templ=0; break; case Template::TEMPLATE_LIST: case Template::NAMED_TEMPLATE_LIST: break; default: u.expr.ti1->error("Operation is not applicable to %s `%s'", t_templ->get_templatetype_str(), t_templ->get_fullname().c_str()); goto error; } // switch } if(t_val) { switch(t_val->get_valuetype()) { case V_SEQOF: case V_SETOF: case V_ARRAY: case V_SEQ: case V_SET: case V_OID: case V_ROID: // ok break; default: // error is already reported t_val=0; break; } // switch } } /* evaluation */ if(t_type->get_typetype()==Type::T_ARRAY) { result = t_type->get_dimension()->get_size(); } else if(t_templ) { // sizeof() switch(t_templ->get_templatetype()) { case Template::TEMPLATE_LIST: if(t_templ->temps_contains_anyornone_symbol()) { if(t_templ->is_length_restricted()) { Ttcn::LengthRestriction *lr = t_templ->get_length_restriction(); if (lr->get_is_range()) { Value *v_upper = lr->get_upper_value(); if (v_upper) { if (v_upper->valuetype == V_INT) { Int nof_comps = static_cast<Int>(t_templ->get_nof_comps_not_anyornone()); if (v_upper->u.val_Int->get_val() == nof_comps) result = nof_comps; else { u.expr.ti1->error("`sizeof' operation is not applicable for " "templates without exact size"); goto error; } } } else { u.expr.ti1->error("`sizeof' operation is not applicable for " "templates containing `*' without upper boundary in the " "length restriction"); goto error; } } else { Value *v_single = lr->get_single_value(); if (v_single->valuetype == V_INT) result = v_single->u.val_Int->get_val(); } } else { // not length restricted u.expr.ti1->error("`sizeof' operation is not applicable for templates" " containing `*' without length restriction"); goto error; } } else result=t_templ->get_nof_listitems(); break; case Template::NAMED_TEMPLATE_LIST: result=0; for(size_t i=0; i<t_templ->get_nof_comps(); i++) if(t_templ->get_namedtemp_byIndex(i)->get_template() ->get_templatetype()!=Template::OMIT_VALUE) result++; return result; default: FATAL_ERROR("Value::chk_eval_expr_sizeof()"); } // switch } else if(t_val) { switch(t_val->get_valuetype()) { case V_SEQOF: case V_SETOF: case V_ARRAY: case V_OID: case V_ROID: result=t_val->get_nof_comps(); break; case V_SEQ: case V_SET: result=0; for(size_t i=0; i<t_val->get_nof_comps(); i++) if(t_val->get_se_comp_byIndex(i)->get_value() ->get_valuetype()!=V_OMIT) result++; break; default: FATAL_ERROR("Value::chk_eval_expr_sizeof()"); } // switch } return result; error: set_valuetype(V_ERROR); return -1; } Type *Value::chk_expr_operands_ti(TemplateInstance* ti, Type::expected_value_t exp_val) { Type *governor = ti->get_expr_governor(exp_val); if (!governor) { ti->get_Template()->set_lowerid_to_ref(); governor = ti->get_expr_governor(exp_val); } if (!governor) { string str; ti->append_stringRepr( str); ti->error("Cannot determine the argument type of %s in the `%s' operation.\n" "If type is known, use valueof(<type>: %s) as argument.", str.c_str(), get_opname(), str.c_str()); set_valuetype(V_ERROR); } return governor; } void Value::chk_expr_operands_match(Type::expected_value_t exp_val) { start: Type *governor = u.expr.v1->get_expr_governor(exp_val); if (!governor) governor = u.expr.t2->get_expr_governor( exp_val == Type::EXPECTED_DYNAMIC_VALUE ? Type::EXPECTED_TEMPLATE : exp_val); if (!governor) { Template *t_temp = u.expr.t2->get_Template(); if (t_temp->is_undef_lowerid()) { // We convert the template to reference first even if the value is also // an undef lowerid. The user can prevent this by explicit type // specification. t_temp->set_lowerid_to_ref(); goto start; } else if (u.expr.v1->is_undef_lowerid()) { u.expr.v1->set_lowerid_to_ref(); goto start; } } if (!governor) { error("Cannot determine the type of arguments in `match()' operation"); set_valuetype(V_ERROR); return; } u.expr.v1->set_my_governor(governor); { Error_Context cntxt(this, "In the first argument of `match()'" " operation"); governor->chk_this_value_ref(u.expr.v1); (void)governor->chk_this_value(u.expr.v1, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); } { Error_Context cntxt(this, "In the second argument of `match()' " "operation"); u.expr.t2->chk(governor); } } void Value::chk_expr_dynamic_part(Type::expected_value_t exp_val, bool allow_controlpart, bool allow_runs_on, bool require_runs_on) { Ttcn::StatementBlock *my_sb; switch (exp_val) { case Type::EXPECTED_CONSTANT: error("An evaluable constant value was expected instead of operation " "`%s'", get_opname()); goto error; case Type::EXPECTED_STATIC_VALUE: error("A static value was expected instead of operation `%s'", get_opname()); goto error; default: break; } // switch if (!my_scope) FATAL_ERROR("Value::chk_expr_dynamic_part()"); my_sb = dynamic_cast<Ttcn::StatementBlock*>(my_scope); if (!my_sb) { error("Operation `%s' is allowed only within statements", get_opname()); goto error; } if (!allow_controlpart && !my_sb->get_my_def()) { error("Operation `%s' is not allowed in the control part", get_opname()); goto error; } if (!allow_runs_on && my_scope->get_scope_runs_on()) { error("Operation `%s' cannot be used in a definition that has " "`runs on' clause", get_opname()); goto error; } if (require_runs_on && !my_scope->get_scope_runs_on()) { error("Operation `%s' can be used only in a definition that has " "`runs on' clause", get_opname()); goto error; } return; error: set_valuetype(V_ERROR); } void Value::chk_expr_operand_valid_float(Value* v, const char *opnum, const char *opname) { if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) return; if(v->is_unfoldable()) return; if(v->get_expr_returntype()!=Type::T_REAL) return; ttcn3float r = v->get_val_Real(); if (isSpecialFloatValue(r)) { v->error("%s operand of operation `%s' cannot be %s, it must be a numeric value", opnum, opname, Real2string(r).c_str()); set_valuetype(V_ERROR); } } bool Value::chk_expr_operand_default_alternative(Value* v, ReferenceChain *refch, Type::expected_value_t exp_val) { if (!v->is_ref()) { FATAL_ERROR("Value::chk_default_alternative_ref"); } Type* t = v->get_expr_governor(exp_val); CompField* def_alt = t->get_default_alternative(); Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(v->get_reference()); if (def_alt != NULL && ttcn_ref != NULL) { Error_Context cntxt(v, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), t->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt->get_name()); if (u.expr.state != EXPR_CHECKING_ERR) { chk_expr_operands(refch, exp_val); } return true; } return false; } bool Value::chk_expr_operand_default_alternative(TemplateInstance* ti, Type* ti_gov, ReferenceChain *refch, Type::expected_value_t exp_val) { CompField* def_alt = ti_gov->get_default_alternative(); if (def_alt == NULL) { return false; } Ttcn::Reference* ttcn_ref = NULL; Template* temp = ti->get_Template(); switch (temp->get_templatetype()) { case Ttcn::Template::TEMPLATE_REFD: ttcn_ref = temp->get_reference(); break; case Ttcn::Template::SPECIFIC_VALUE: ttcn_ref = dynamic_cast<Ttcn::Reference*>(temp->get_specific_value()->get_reference()); break; default: break; } if (ttcn_ref != NULL) { Error_Context cntxt(ti, "Using default alternative `%s' in value or template of union type `%s'", def_alt->get_name().get_dispname().c_str(), ti_gov->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt->get_name()); if (u.expr.state != EXPR_CHECKING_ERR) { chk_expr_operands(refch, exp_val); } return true; } return false; } void Value::chk_expr_operands(ReferenceChain *refch, Type::expected_value_t exp_val) { const char *first="First", *second="Second", *third="Third", *fourth="Fourth", *the="The", *left="Left", *right="Right"; Value *v1, *v2, *v3; Type::typetype_t tt1, tt2, tt3; Type t_chk(Type::T_ERROR); const char *opname=get_opname(); // first classify the unchecked ischosen() operation if (u.expr.v_optype==OPTYPE_ISCHOSEN) chk_expr_ref_ischosen(); switch (u.expr.v_optype) { case OPTYPE_COMP_NULL: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: break; case OPTYPE_NOW: { Ttcn::StatementBlock* sb = my_scope->get_statementblock_scope(); if (sb == NULL || sb->get_my_def() == NULL) { error("Operation `%s' can only be used in testcases, functions or " "altsteps", opname); } break; } case OPTYPE_GET_PORT_REF: if (u.expr.type == NULL) { Ttcn::PortScope* port_scope = my_scope->get_scope_port(); if (port_scope == NULL) { error("Operation `%s' can only be used in a function with a port clause.", opname); set_valuetype(V_ERROR); break; } u.expr.type = port_scope->get_port_type(); if (u.expr.type == NULL) { FATAL_ERROR("Value::chk_expr_operands"); } if (my_governor != NULL && !u.expr.type->is_identical(my_governor)) { error("Type mismatch: A value of type `%s' was expected instead of `%s'", my_governor->get_typename().c_str(), u.expr.type->get_typename().c_str()); set_valuetype(V_ERROR); } } break; case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: chk_expr_comptype_compat(); break; case OPTYPE_RND: // - case OPTYPE_TMR_RUNNING_ANY: chk_expr_dynamic_part(exp_val, true); break; case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_GETVERDICT: chk_expr_dynamic_part(exp_val, false); break; case OPTYPE_COMP_SELF: chk_expr_comptype_compat(); chk_expr_dynamic_part(exp_val, false, true, false); break; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int_float(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_NOT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_bool(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_NOT4B: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_binstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_BIT2HEX: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_bstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_BIT2INT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_bstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); // Skip `chk_expr_val_bitstr_intsize(v1, the, opname);'. } break; case OPTYPE_CHAR2INT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_len1(v1, the, opname); } break; case OPTYPE_CHAR2OCT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_STR2INT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_int(v1, the, opname); } break; case OPTYPE_STR2FLOAT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_float(v1, the, opname); } break; case OPTYPE_STR2BIT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_bindigits(v1, the, opname); } break; case OPTYPE_STR2HEX: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_hexdigits(v1, the, opname); } break; case OPTYPE_STR2OCT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_len_even(v1, the, opname); chk_expr_val_str_hexdigits(v1, the, opname); } break; case OPTYPE_ENUM2INT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); // can only be reference to enum Type *t = v1->get_expr_governor(exp_val); if (v1->valuetype==V_ERROR) return; if (!t) { v1->error("Please use reference to an enumerated value as the operand of " "operation `%s'", get_opname()); set_valuetype(V_ERROR); return; } t = t->get_type_refd_last(); if (t->get_typetype() == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } if (t->get_typetype()!=Type::T_ENUM_A && t->get_typetype()!=Type::T_ENUM_T) { v1->error("The operand of operation `%s' should be enumerated value", opname); set_valuetype(V_ERROR); } if (v1->get_value_refd_last()->valuetype==V_OMIT) { v1->error("The operand of operation `%s' cannot be omit", opname); set_valuetype(V_ERROR); } chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_ENCODE: chk_expr_operand_encode(refch, exp_val); break; case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_float(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); if (u.expr.v_optype==OPTYPE_FLOAT2INT) chk_expr_operand_valid_float(v1, the, opname); } break; case OPTYPE_RNDWITHVAL: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_float(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_operand_valid_float(v1, the, opname); } chk_expr_dynamic_part(exp_val, true); break; case OPTYPE_HEX2BIT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_hstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_HEX2INT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_hstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); // Skip `chk_expr_val_hexstr_intsize(v1, the, opname);'. } break; case OPTYPE_INT2CHAR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_int_pos7bit(v1, the, opname); } break; case OPTYPE_INT2UNICHAR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_int_pos31bit(v1, first, opname); } break; case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_OCT2BIT: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_OCT2HEX: case OPTYPE_OCT2STR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_OCT2INT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); // Simply skip `chk_expr_val_hexstr_intsize(v1, the, opname);' for // now. } break; case OPTYPE_OCT2CHAR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_str_7bitoctets(v1, the, opname); } break; case OPTYPE_REMOVE_BOM: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_GET_STRINGENCODING: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_ENCODE_BASE64: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } v2=u.expr.v2 ? u.expr.v2 : 0; if (v2) { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_bool(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } break; case OPTYPE_DECODE_BASE64: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_UNICHAR2INT: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_len1(v1, the, opname); } break; case OPTYPE_UNICHAR2CHAR: v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_ustr_7bitchars(v1, the, opname); } break; case OPTYPE_HOSTID: v1=u.expr.v1 ? u.expr.v1 : 0; if (v1) { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt1, second, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: // v1 v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } break; case OPTYPE_UNICHAR2OCT: // v1 [v2] v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } v2=u.expr.v2 ? u.expr.v2 : 0; if (v2) { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } break; case OPTYPE_OCT2UNICHAR: // v1 [v2] v1=u.expr.v1; { Error_Context cntxt(this, "In the operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_ostr(tt1, the, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } v2=u.expr.v2 ? u.expr.v2 : 0; if (v2) { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } break; case OPTYPE_ISTEMPLATEKIND: { // ti1 v2 if (exp_val == Type::EXPECTED_DYNAMIC_VALUE) exp_val = Type::EXPECTED_TEMPLATE; { Error_Context cntxt(u.expr.ti1, "In the first operand of operation `%s'", opname); Type *governor = chk_expr_operands_ti(u.expr.ti1, exp_val); if (!governor) return; if (valuetype == V_ERROR) return; chk_expr_eval_ti(u.expr.ti1, governor, refch, exp_val); } Error_Context cntxt(u.expr.v2, "In the second operand of operation `%s'", opname); u.expr.v2->set_lowerid_to_ref(); tt2=u.expr.v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && u.expr.v2->is_ref() && chk_expr_operand_default_alternative(u.expr.v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt2, second, opname, u.expr.v2); chk_expr_eval_value(u.expr.v2, t_chk, refch, exp_val); if (!u.expr.v2->is_unfoldable()) { const string& type_param = u.expr.v2->get_val_str(); if (type_param != "value" && type_param != "list" && type_param != "complement" && type_param != "AnyValue" && type_param != "?" && type_param != "AnyValueOrNone" && type_param != "*" && type_param != "range" && type_param != "superset" && type_param != "subset" && type_param != "omit" && type_param != "decmatch" && type_param != "AnyElement" && type_param != "AnyElementsOrNone" && type_param != "permutation" && type_param != "length" && type_param != "ifpresent" && type_param != "pattern") { error("Incorrect second parameter (%s) was passed to istemplatekind.", type_param.c_str()); set_valuetype(V_ERROR); } } break; } case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] chk_expr_operand_encode(refch, exp_val); v2=u.expr.v2 ? u.expr.v2 : 0; if (v2) { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); if (!u.expr.v2->is_unfoldable()) { const string& type_param = u.expr.v2->get_val_str(); if (type_param != "UTF-8" && type_param != "UTF-16" && type_param != "UTF-16LE" && type_param != "UTF-16BE" && type_param != "UTF-32" && type_param != "UTF-32LE" && type_param != "UTF-32BE") { error("Incorrect second parameter (%s) was passed to encvalue_unichar.", type_param.c_str()); set_valuetype(V_ERROR); } } } break; case OPTYPE_DECVALUE_UNICHAR: chk_expr_operands_decode(refch, exp_val); v3=u.expr.v3 ? u.expr.v3 : 0; if (v3) { Error_Context cntxt(this, "In the thrid operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3=v3->get_expr_returntype(exp_val); if (tt3 == Type::T_CHOICE_T && v3->is_ref() && chk_expr_operand_default_alternative(v3, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_charstr(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); if (!u.expr.v3->is_unfoldable()) { const string& type_param = u.expr.v3->get_val_str(); if (type_param != "UTF-8" && type_param != "UTF-16" && type_param != "UTF-16LE" && type_param != "UTF-16BE" && type_param != "UTF-32" && type_param != "UTF-32LE" && type_param != "UTF-32BE") { error("Incorrect third parameter (%s) was passed to decvalue_unichar.", type_param.c_str()); set_valuetype(V_ERROR); } } } break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: { v1=u.expr.v1; v2=u.expr.v2; Error_Context cntxt(this, "In the operands of operation `%s'", opname); v1->set_lowerid_to_ref(); v2->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int_float(tt1, first, opname, v1); chk_expr_operandtype_int_float(tt2, second, opname, v2); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_eval_value(v2, t_chk, refch, exp_val); // No float checks needed, everything is allowed on -+infinity and not_a_number if(u.expr.v_optype==OPTYPE_DIVIDE) chk_expr_val_int_float_not0(v2, second, opname); chk_expr_operandtypes_same(tt1, tt2, opname); break; } case OPTYPE_MOD: case OPTYPE_REM: v1=u.expr.v1; { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } v2=u.expr.v2; { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_float_not0(v2, right, opname); } break; case OPTYPE_CONCAT: { v1=u.expr.v1; v2=u.expr.v2; v1->set_lowerid_to_ref(); v2->set_lowerid_to_ref(); if (v1->is_string_type(exp_val) || v2->is_string_type(exp_val)) { { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_str(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_str(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } if (!((tt1==Type::T_CSTR && tt2==Type::T_USTR) || (tt2==Type::T_CSTR && tt1==Type::T_USTR))) chk_expr_operandtypes_same(tt1, tt2, opname); } else { // other list types v1->get_value_refd_last(); v2->get_value_refd_last(); Type* v1_gov = v1->get_expr_governor(exp_val); Type* v2_gov = v2->get_expr_governor(exp_val); if (!v1_gov) { error("Cannot determine the type of the left operand of `%s' operation", opname); set_valuetype(V_ERROR); return; } else { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); if (v1->is_ref() && v1_gov->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } v1_gov->chk_this_value_ref(v1); (void)v1_gov->chk_this_value(v1, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); chk_expr_operandtype_list(v1_gov, left, opname, v1, false); } if (!v2_gov) { // for recof/setof literals set the type from v1 v2_gov = v1_gov; v2->set_my_governor(v1_gov); } { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); if (v2->is_ref() && v2_gov->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } v2_gov->chk_this_value_ref(v2); (void)v2_gov->chk_this_value(v2, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); chk_expr_operandtype_list(v2_gov, right, opname, v2, false); if (valuetype == V_ERROR) return; // 7.1.2 says that we shouldn't allow type compatibility. if (!v1_gov->is_compatible(v2_gov, NULL, this) && !v2_gov->is_compatible(v1_gov, NULL, NULL)) { error("The operands of operation `%s' should be of compatible " "types", get_opname()); } } } break; } case OPTYPE_EQ: case OPTYPE_NE: v1 = u.expr.v1; v2 = u.expr.v2; chk_expr_operandtypes_compat(exp_val, v1, v2); { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); chk_expr_eval_value(v1, t_chk, refch, exp_val); } { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); chk_expr_eval_value(v2, t_chk, refch, exp_val); /* According to the BNF v4.1.1, the "arguments" around ==/!= in an * EqualExpression are RelExpression-s, not NotExpression-s. This means: * "not a == b" is supposed to be equivalent to "not (a == b)", and * "a == not b" is not allowed. (HL69107) * The various *Expressions implement operator precedence in the std. * Titan's parser has only one Expression and relies on Bison * for operator precedence. The check below brings Titan in line * with the standard by explicitly making "a == not b" an error */ if (v2->get_valuetype() == V_EXPR && v2->u.expr.v_optype == OPTYPE_NOT) { error("The operation `%s' is not allowed to be " "the second operand of operation `%s'", v2->get_opname(), opname); set_valuetype(V_ERROR); } } break; case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_GE: case OPTYPE_LE: v1=u.expr.v1; v2=u.expr.v2; chk_expr_operandtypes_compat(exp_val, v1, v2); { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int_float_enum(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int_float_enum(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } break; case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: v1=u.expr.v1; { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_bool(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } v2=u.expr.v2; { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_bool(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } break; case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: v1=u.expr.v1; { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_binstr(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } v2=u.expr.v2; { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_binstr(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } chk_expr_operandtypes_same(tt1, tt2, opname); chk_expr_operands_str_samelen(); break; case OPTYPE_SHL: case OPTYPE_SHR: v1=u.expr.v1; { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_binstr(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } v2=u.expr.v2; { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_large_int(v2, right, opname); } break; case OPTYPE_ROTL: case OPTYPE_ROTR: v1=u.expr.v1; v1->set_lowerid_to_ref(); if (v1->is_string_type(exp_val)) { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_str(tt1, left, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); } else { // other list types v1->get_value_refd_last(); Type* v1_gov = v1->get_expr_governor(exp_val); if (!v1_gov) { // a recof/setof literal would be a syntax error here error("Cannot determine the type of the left operand of `%s' operation", opname); } else { Error_Context cntxt(this, "In the left operand of operation `%s'", opname); if (v1->is_ref() && v1_gov->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } v1_gov->chk_this_value_ref(v1); (void)v1_gov->chk_this_value(v1, 0, exp_val, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); chk_expr_operandtype_list(v1_gov, left, opname, v1, true); } } v2=u.expr.v2; { Error_Context cntxt(this, "In the right operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt2, right, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_large_int(v2, right, opname); } break; case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: v1=u.expr.v1; { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); v1->set_lowerid_to_ref(); tt1=v1->get_expr_returntype(exp_val); if (tt1 == Type::T_CHOICE_T && v1->is_ref() && chk_expr_operand_default_alternative(v1, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt1, first, opname, v1); chk_expr_eval_value(v1, t_chk, refch, exp_val); chk_expr_val_int_pos0(v1, first, opname); } v2=u.expr.v2; { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_pos0(v2, second, opname); } chk_expr_operands_int2binstr(); break; case OPTYPE_DECODE: chk_expr_operands_decode(refch, exp_val); break; case OPTYPE_SUBSTR: { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); Type::expected_value_t ti_exp_val = exp_val; if (ti_exp_val == Type::EXPECTED_DYNAMIC_VALUE) ti_exp_val = Type::EXPECTED_TEMPLATE; Type* governor = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (!governor) return; if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_eval_ti(u.expr.ti1, governor, refch, ti_exp_val); if (valuetype!=V_ERROR) u.expr.ti1->get_Template()->chk_specific_value(false); chk_expr_operandtype_list(governor, first, opname, u.expr.ti1, false); } v2=u.expr.v2; { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_pos0(v2, second, opname); } v3=u.expr.v3; { Error_Context cntxt(this, "In the third operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3=v3->get_expr_returntype(exp_val); if (tt3 == Type::T_CHOICE_T && v3->is_ref() && chk_expr_operand_default_alternative(v3, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); chk_expr_val_int_pos0(v3, third, opname); } chk_expr_operands_substr(); break; case OPTYPE_REGEXP: { Type::expected_value_t ti_exp_val = exp_val; if (ti_exp_val == Type::EXPECTED_DYNAMIC_VALUE) ti_exp_val = Type::EXPECTED_TEMPLATE; { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); Type* governor = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (!governor) return; if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_eval_ti(u.expr.ti1, governor, refch, ti_exp_val); if (valuetype!=V_ERROR) { u.expr.ti1->get_Template()->chk_specific_value(false); chk_expr_operandtype_charstr(governor->get_type_refd_last()-> get_typetype_ttcn3(), first, opname, u.expr.ti1); } } { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); Type* governor = chk_expr_operands_ti(u.expr.t2, ti_exp_val); if (!governor) return; if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(u.expr.t2, governor, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_eval_ti(u.expr.t2, governor, refch, ti_exp_val); chk_expr_operandtype_charstr(governor->get_type_refd_last()-> get_typetype_ttcn3(), second, opname, u.expr.t2); } v3=u.expr.v3; { Error_Context cntxt(this, "In the third operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3=v3->get_expr_returntype(exp_val); if (tt3 == Type::T_CHOICE_T && v3->is_ref() && chk_expr_operand_default_alternative(v3, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); chk_expr_val_int_pos0(v3, third, opname); } chk_expr_operands_regexp(); } break; case OPTYPE_ISCHOSEN: // do nothing: the operand is erroneous // the error was already reported in chk_expr_ref_ischosen() break; case OPTYPE_ISCHOSEN_V: // v1 i2 case OPTYPE_ISCHOSEN_T: // t1 i2 chk_expr_operands_ischosen(refch, exp_val); break; case OPTYPE_VALUEOF: { // ti1 [subrefs2] if (exp_val == Type::EXPECTED_DYNAMIC_VALUE) exp_val = Type::EXPECTED_TEMPLATE; Error_Context cntxt(this, "In the operand of operation `%s'", opname); Type *governor = (u.expr.subrefs2 == NULL) ? my_governor : NULL; if (!governor) governor = chk_expr_operands_ti(u.expr.ti1, exp_val); if (!governor) return; chk_expr_eval_ti(u.expr.ti1, governor, refch, exp_val); if (valuetype == V_ERROR) return; u.expr.ti1->get_Template()->chk_specific_value(false); // the subreferences have already been checked by get_expr_returntype break; } case OPTYPE_ISPRESENT: // TODO: rename UsedInIsbound to better name case OPTYPE_ISBOUND: { Template *templ = u.expr.ti1->get_Template(); switch (templ->get_templatetype()) { case Template::TEMPLATE_REFD: templ->get_reference()->setUsedInIsbound(); break; case Template::SPECIFIC_VALUE: { Value *value = templ->get_specific_value(); if (Value::V_REFD == value->get_valuetype()) { value->get_reference()->setUsedInIsbound(); } break; } default: break; } } // no break case OPTYPE_ISVALUE: {// ti1 // This code is almost, but not quite, the same as for OPTYPE_VALUEOF if (exp_val == Type::EXPECTED_DYNAMIC_VALUE) exp_val = Type::EXPECTED_TEMPLATE; Error_Context cntxt(this, "In the operand of operation `%s'", opname); Type *governor = chk_expr_operands_ti(u.expr.ti1, exp_val); if (!governor) return; tt1 = u.expr.ti1->get_expr_returntype(exp_val); chk_expr_eval_ti(u.expr.ti1, governor, refch, exp_val); break; } case OPTYPE_SIZEOF: // ti1 /* this checking is too complex, do the checking during eval... */ break; case OPTYPE_LENGTHOF: { // ti1 if (exp_val == Type::EXPECTED_DYNAMIC_VALUE) exp_val = Type::EXPECTED_TEMPLATE; Error_Context cntxt(this, "In the operand of operation `%s'", opname); Type *governor = chk_expr_operands_ti(u.expr.ti1, exp_val); if (!governor) return; if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_list(governor, the, opname, u.expr.ti1, true); if (valuetype == V_ERROR) return; chk_expr_eval_ti(u.expr.ti1, governor, refch, exp_val); break; } case OPTYPE_MATCH: // v1 t2 chk_expr_operands_match(exp_val); break; case OPTYPE_UNDEF_RUNNING: // r1 [r2] b4 chk_expr_operand_undef_running(exp_val, u.expr.r1, u.expr.b4, u.expr.r2, the, opname); break; case OPTYPE_COMP_ALIVE: case OPTYPE_COMP_RUNNING: { //v1 Type* ref_type = chk_expr_operand_compref(u.expr.v1, the, opname, u.expr.b4); chk_expr_dynamic_part(exp_val, false); if (u.expr.r2 != NULL && ref_type != NULL) { Ttcn::Reference* index_ref = dynamic_cast<Ttcn::Reference*>(u.expr.r2); if (index_ref == NULL) { FATAL_ERROR("Value::chk_expr_operand_undef_running"); } Ttcn::ArrayDimensions dummy; ref_type = ref_type->get_type_refd_last(); while (ref_type->get_typetype() == Type::T_ARRAY) { dummy.add(ref_type->get_dimension()->clone()); ref_type = ref_type->get_ofType()->get_type_refd_last(); } Ttcn::Statement::chk_index_redirect(index_ref, &dummy, u.expr.b4, "component"); } break; } case OPTYPE_TMR_READ: // r1 case OPTYPE_TMR_RUNNING: // r1 chk_expr_operand_tmrref(u.expr.r1, the, opname); chk_expr_dynamic_part(exp_val, true); break; case OPTYPE_EXECUTE: // r1 [v2] // testcase chk_expr_operand_execute(u.expr.r1, u.expr.v2, the, opname); chk_expr_dynamic_part(exp_val, true, false, false); break; case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4 case OPTYPE_CLASS_CREATE: { // r1 t_list2 Type* t = chk_expr_operand_undef_create(); if (u.expr.v_optype == OPTYPE_CLASS_CREATE) { Ttcn::ClassTypeBody* class_ = t->get_class_type_body(); if (class_->is_abstract()) { error("Cannot create an instance of abstract class type `%s'", class_->get_my_def()->get_Type()->get_typename().c_str()); } Common::Assignment* constructor = class_->get_constructor(); Ttcn::FormalParList* fp_list = (constructor != NULL) ? constructor->get_FormalParList() : NULL; Ttcn::ActualParList* parlist = new Ttcn::ActualParList; bool is_erroneous = (constructor != NULL) ? fp_list->chk_actual_parlist(u.expr.t_list2->get_tis(), parlist) : true; if (is_erroneous) { delete parlist; parlist = 0; set_valuetype(V_ERROR); } else { parlist->set_fullname(get_fullname()); parlist->set_my_scope(get_my_scope()); delete u.expr.t_list2; u.expr.ap_list2 = parlist; } chk_expr_dynamic_part(exp_val, true); my_scope->chk_runs_on_clause(t, *this, "create"); my_scope->chk_mtc_clause(t, *this); my_scope->chk_system_clause(t, *this); } if (u.expr.v_optype != OPTYPE_COMP_CREATE) { break; } } // else fall through case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 v2=u.expr.v2; if(v2) { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); chk_expr_operandtype_cstr(tt2, first, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } v3=u.expr.v3; if(v3) { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3=v3->get_expr_returntype(exp_val); chk_expr_operandtype_cstr(tt3, second, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); } chk_expr_dynamic_part(exp_val, false); break; case OPTYPE_ACTIVATE: // r1 // altstep chk_expr_operand_activate(u.expr.r1, the, opname); chk_expr_dynamic_part(exp_val, true); break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2 case OPTYPE_CHECKSTATE_ALL: chk_expr_dynamic_part(exp_val, false); v2=u.expr.v2; if(v2) { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2=v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_cstr(tt2, first, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); } break; case OPTYPE_ACTIVATE_REFD:{ //v1 t_list2 Ttcn::ActualParList *parlist = new Ttcn::ActualParList; chk_expr_operand_activate_refd(u.expr.v1,u.expr.t_list2->get_tis(), parlist, the, opname); delete u.expr.t_list2; u.expr.ap_list2 = parlist; chk_expr_dynamic_part(exp_val, true); break; } case OPTYPE_EXECUTE_REFD: {// v1 t_list2 [v3] Ttcn::ActualParList *parlist = new Ttcn::ActualParList; chk_expr_operand_execute_refd(u.expr.v1, u.expr.t_list2->get_tis(), parlist, u.expr.v3, the, opname); delete u.expr.t_list2; u.expr.ap_list2 = parlist; chk_expr_dynamic_part(exp_val, true); break; } case OPTYPE_DECOMP: error("Built-in function `%s' is not yet supported", opname); set_valuetype(V_ERROR); break; case OPTYPE_REPLACE: { Type::expected_value_t ti_exp_val = exp_val; if (ti_exp_val == Type::EXPECTED_DYNAMIC_VALUE) ti_exp_val = Type::EXPECTED_TEMPLATE; { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); Type* governor = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (!governor) return; if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(u.expr.ti1, governor, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_eval_ti(u.expr.ti1, governor, refch, ti_exp_val); if (valuetype != V_ERROR) u.expr.ti1->get_Template()->chk_specific_value(false); chk_expr_operandtype_list(governor, first, opname, u.expr.ti1, false); } v2 = u.expr.v2; { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); v2->set_lowerid_to_ref(); tt2 = v2->get_expr_returntype(exp_val); if (tt2 == Type::T_CHOICE_T && v2->is_ref() && chk_expr_operand_default_alternative(v2, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt2, second, opname, v2); chk_expr_eval_value(v2, t_chk, refch, exp_val); chk_expr_val_int_pos0(v2, second, opname); } v3 = u.expr.v3; { Error_Context cntxt(this, "In the third operand of operation `%s'", opname); v3->set_lowerid_to_ref(); tt3 = v3->get_expr_returntype(exp_val); if (tt3 == Type::T_CHOICE_T && v3->is_ref() && chk_expr_operand_default_alternative(v3, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_operandtype_int(tt3, third, opname, v3); chk_expr_eval_value(v3, t_chk, refch, exp_val); chk_expr_val_int_pos0(v3, third, opname); } { Error_Context cntxt(this, "In the fourth operand of operation `%s'", opname); Type* governor = chk_expr_operands_ti(u.expr.ti4, ti_exp_val); if (!governor) return; if (governor->get_type_refd_last()->get_typetype() == Type::T_CHOICE_T && chk_expr_operand_default_alternative(u.expr.ti4, governor, refch, exp_val)) { // this function was already re-called with the default alternative, abort this call return; } chk_expr_eval_ti(u.expr.ti4, governor, refch, ti_exp_val); if (valuetype != V_ERROR) u.expr.ti4->get_Template()->chk_specific_value(false); chk_expr_operandtype_list(governor, fourth, opname, u.expr.ti4, false); } chk_expr_operands_replace(); break; } case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: { Error_Context cntxt(this, "In the operand of operation `%s'", opname); u.expr.logargs->chk(); if (!semantic_check_only) u.expr.logargs->join_strings(); break; } case OPTYPE_TTCN2STRING: { Error_Context cntxt(this, "In the parameter of ttcn2string()"); Type::expected_value_t ti_exp_val = exp_val; if (ti_exp_val == Type::EXPECTED_DYNAMIC_VALUE) ti_exp_val = Type::EXPECTED_TEMPLATE; Type *governor = chk_expr_operands_ti(u.expr.ti1, ti_exp_val); if (!governor) return; chk_expr_eval_ti(u.expr.ti1, governor, refch, ti_exp_val); } break; case OPTYPE_CLASS_CASTING_REF: { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); Type* type = u.expr.r1->chk_variable_ref(); type = (type == NULL) ? new Type(Type::T_ERROR) : type->clone(); type->set_my_scope(my_scope); type->set_fullname(get_fullname() + ".<classtype>"); type->set_location(*u.expr.r1); delete u.expr.r1; u.expr.type = type; u.expr.v_optype = OPTYPE_CLASS_CASTING; } // no break case OPTYPE_CLASS_CASTING: case OPTYPE_OF_CLASS: { bool erroneous = false; Type* ref_type_last = NULL; { Error_Context cntxt(this, "In the first operand of operation `%s'", opname); Type* ref_type = u.expr.r2->chk_variable_ref(); if (ref_type != NULL) { ref_type_last = ref_type->get_type_refd_last(); if (ref_type_last->get_typetype() != Type::T_CLASS) { u.expr.r2->error("Reference to a class object was expected"); erroneous = true; } } else { erroneous = true; } } { Error_Context cntxt(this, "In the second operand of operation `%s'", opname); u.expr.type->chk(); Type* type_last = u.expr.type->get_type_refd_last(); if (type_last->get_typetype() != Type::T_CLASS) { if (type_last->get_typetype() != Type::T_ERROR) { u.expr.type->error("Class type was expected"); } erroneous = true; } else if (u.expr.v_optype == OPTYPE_CLASS_CASTING && !erroneous) { Ttcn::ClassTypeBody* new_class = type_last->get_class_type_body(); Ttcn::ClassTypeBody* old_class = ref_type_last->get_class_type_body(); if (!new_class->is_parent_class(old_class) && !old_class->is_parent_class(new_class)) { u.expr.type->error("Cannot cast an object of class type `%s' " "to class type `%s'", ref_type_last->get_typename().c_str(), u.expr.type->get_typename().c_str()); } } } if (erroneous) { set_valuetype(V_ERROR); } break; } default: FATAL_ERROR("chk_expr_operands()"); } // switch optype } // Compile-time evaluation. It may change the valuetype from V_EXPR to // the result of evaluating the expression. E.g. V_BOOL for // OPTYPE_ISCHOSEN. void Value::evaluate_value(ReferenceChain *refch, Type::expected_value_t exp_val) { if(valuetype!=V_EXPR) FATAL_ERROR("Value::evaluate_value()"); if(u.expr.state!=EXPR_NOT_CHECKED) return; u.expr.state=EXPR_CHECKING; get_expr_returntype(exp_val); // to report 'didyamean'-errors etc chk_expr_operands(refch, exp_val == Type::EXPECTED_TEMPLATE ? Type::EXPECTED_DYNAMIC_VALUE : exp_val); if(valuetype==V_ERROR) return; if(u.expr.state==EXPR_CHECKING_ERR) { u.expr.state=EXPR_CHECKED; set_valuetype(V_ERROR); return; } u.expr.state=EXPR_CHECKED; Value *v1, *v2, *v3, *v4; switch(u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_NULL: // the only foldable in this group case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_PROF_RUNNING: case OPTYPE_GET_PORT_REF: case OPTYPE_RNDWITHVAL: // v1 case OPTYPE_COMP_RUNNING: // v1 case OPTYPE_COMP_ALIVE: case OPTYPE_TMR_READ: case OPTYPE_TMR_RUNNING: case OPTYPE_ACTIVATE: case OPTYPE_ACTIVATE_REFD: case OPTYPE_EXECUTE: // r1 [v2] case OPTYPE_EXECUTE_REFD: // v1 t_list2 [v3] case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4 case OPTYPE_CLASS_CREATE: // r1 t_list2 case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 case OPTYPE_MATCH: // v1 t2 case OPTYPE_ISCHOSEN_T: case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: case OPTYPE_ENCODE: case OPTYPE_DECODE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: case OPTYPE_DECODE_BASE64: case OPTYPE_ENCVALUE_UNICHAR: case OPTYPE_DECVALUE_UNICHAR: case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: case OPTYPE_HOSTID: case OPTYPE_ISTEMPLATEKIND: // ti1 v2 case OPTYPE_CBOR2JSON: // v1 case OPTYPE_JSON2CBOR: // v1 case OPTYPE_BSON2JSON: // v1 case OPTYPE_JSON2BSON: // v1 case OPTYPE_NOW: break; case OPTYPE_TESTCASENAME: { // - if (!my_scope) FATAL_ERROR("Value::evaluate_value()"); Ttcn::StatementBlock *my_sb = dynamic_cast<Ttcn::StatementBlock *>(my_scope); if (!my_sb) break; Ttcn::Definition *my_def = my_sb->get_my_def(); if (!my_def) { // In control part. set_val_str(new string("")); valuetype = V_CSTR; } else if (my_def->get_asstype() == Assignment::A_TESTCASE) { set_val_str(new string(my_def->get_id().get_dispname())); valuetype = V_CSTR; } break; } case OPTYPE_UNARYPLUS: // v1 v1=u.expr.v1; u.expr.v1=0; copy_and_destroy(v1); break; case OPTYPE_UNARYMINUS: if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); switch (v1->valuetype) { case V_INT: { int_val_t *i = new int_val_t(-*(v1->get_val_Int())); if (!i) FATAL_ERROR("Value::evaluate_value()"); clean_up(); valuetype = V_INT; u.val_Int = i; break; } case V_REAL: { ttcn3float r = v1->get_val_Real(); clean_up(); valuetype = V_REAL; u.val_Real = -r; break; } default: FATAL_ERROR("Value::evaluate_value()"); } break; case OPTYPE_NOT: { if(is_unfoldable()) break; bool b=u.expr.v1->get_value_refd_last()->get_val_bool(); clean_up(); valuetype=V_BOOL; u.val_bool=!b; break;} case OPTYPE_NOT4B: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); valuetype_t vt=v1->valuetype; clean_up(); valuetype=vt; set_val_str(vt==V_BSTR?not4b_bit(s):not4b_hex(s)); break;} case OPTYPE_BIT2HEX: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_HSTR; set_val_str(bit2hex(s)); break;} case OPTYPE_BIT2OCT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_OSTR; set_val_str(bit2oct(s)); break;} case OPTYPE_BIT2STR: case OPTYPE_HEX2STR: case OPTYPE_OCT2STR: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_CSTR; set_val_str(new string(s)); break;} case OPTYPE_BIT2INT: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype = V_INT; u.val_Int = bit2int(s); break; } case OPTYPE_CHAR2INT: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); char c = v1->get_val_str()[0]; clean_up(); valuetype = V_INT; u.val_Int = new int_val_t((Int)c); break; } case OPTYPE_CHAR2OCT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_OSTR; set_val_str(char2oct(s)); break;} case OPTYPE_STR2INT: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); int_val_t *i = new int_val_t((v1->get_val_str()).c_str(), *u.expr.v1); clean_up(); valuetype = V_INT; u.val_Int = i; /** \todo hiba eseten lenyeli... */ break; } case OPTYPE_STR2FLOAT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); Real r; if (s.find("-infinity") != s.size()) { r = -REAL_INFINITY; } else if (s.find("infinity") != s.size()) { r = REAL_INFINITY; } else if (s.find("not_a_number") != s.size()) { r = REAL_NAN; } else { r = string2Real(s, *u.expr.v1); } clean_up(); valuetype=V_REAL; u.val_Real=r; /** \todo hiba eseten lenyeli... */ break;} case OPTYPE_STR2BIT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_BSTR; set_val_str(new string(s)); break;} case OPTYPE_STR2HEX: case OPTYPE_OCT2HEX: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_HSTR; set_val_str(to_uppercase(s)); break;} case OPTYPE_STR2OCT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_OSTR; set_val_str(to_uppercase(s)); break;} case OPTYPE_FLOAT2INT: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); ttcn3float r = v1->get_val_Real(); clean_up(); valuetype = V_INT; u.val_Int = float2int(r, *u.expr.v1); break;} case OPTYPE_FLOAT2STR: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); ttcn3float r=v1->get_val_Real(); clean_up(); valuetype=V_CSTR; set_val_str(float2str(r)); break;} case OPTYPE_HEX2BIT: case OPTYPE_OCT2BIT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_BSTR; set_val_str(hex2bit(s)); break;} case OPTYPE_HEX2INT: case OPTYPE_OCT2INT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_INT; u.val_Int=hex2int(s); break;} case OPTYPE_HEX2OCT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_OSTR; set_val_str(hex2oct(s)); break;} case OPTYPE_INT2CHAR: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); const int_val_t *c_int = v1->get_val_Int(); char c = static_cast<char>(c_int->get_val()); clean_up(); valuetype = V_CSTR; set_val_str(new string(1, &c)); break; } case OPTYPE_INT2UNICHAR: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); const int_val_t *i_int = v1->get_val_Int(); Int i = i_int->get_val(); clean_up(); valuetype = V_USTR; set_val_ustr(int2unichar(i)); u.ustr.convert_str = false; break; } case OPTYPE_INT2FLOAT: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); const int_val_t *i_int = v1->get_val_Int(); Real i_int_real = i_int->to_real(); clean_up(); valuetype = V_REAL; u.val_Real = i_int_real; break; } case OPTYPE_INT2STR: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); const int_val_t *i_int = v1->get_val_Int(); string *i_int_str = new string(i_int->t_str()); clean_up(); valuetype = V_CSTR; set_val_str(i_int_str); break; } case OPTYPE_OCT2CHAR: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); const string& s = v1->get_val_str(); clean_up(); valuetype=V_CSTR; set_val_str(oct2char(s)); break;} case OPTYPE_GET_STRINGENCODING: { if(is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); const string& s1 = v1->get_val_str(); clean_up(); valuetype = V_CSTR; set_val_str(get_stringencoding(s1)); break;} case OPTYPE_REMOVE_BOM: { if(is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); const string& s1 = v1->get_val_str(); clean_up(); valuetype = V_OSTR; set_val_str(remove_bom(s1)); break;} case OPTYPE_ENUM2INT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); Type* enum_type = v1->get_my_governor(); const Int& enum_val = enum_type->get_enum_val_byId(*(v1->u.val_id)); clean_up(); valuetype = V_INT; u.val_Int = new int_val_t(enum_val); break;} case OPTYPE_UNICHAR2INT: if (is_unfoldable()) { // replace the operation with char2int() if the operand is a charstring // value to avoid its unnecessary conversion to universal charstring if (u.expr.v1->get_expr_returntype(exp_val) == Type::T_CSTR) u.expr.v_optype = OPTYPE_CHAR2INT; } else { v1=u.expr.v1->get_value_refd_last(); const ustring& s = v1->get_val_ustr(); clean_up(); valuetype=V_INT; u.val_Int=new int_val_t(unichar2int(s)); } break; case OPTYPE_UNICHAR2CHAR: v1 = u.expr.v1; if (is_unfoldable()) { // replace the operation with its operand if it is a charstring // value to avoid its unnecessary conversion to universal charstring if (v1->get_expr_returntype(exp_val) == Type::T_CSTR) { u.expr.v1 = 0; copy_and_destroy(v1); } } else { v1 = v1->get_value_refd_last(); const ustring& s = v1->get_val_ustr(); clean_up(); valuetype = V_CSTR; set_val_str(new string(s)); } break; case OPTYPE_MULTIPLY: { // v1 v2 if (!is_unfoldable()) goto eval_arithmetic; v1 = u.expr.v1->get_value_refd_last(); v2 = u.expr.v2->get_value_refd_last(); if (v1->is_unfoldable()) v1 = v2; if (v1->is_unfoldable()) break; switch(v1->valuetype) { case V_INT: { if (*v1->get_val_Int() != 0) break; clean_up(); valuetype = V_INT; u.val_Int = new int_val_t((Int)0); break; } case V_REAL: { if (v1->get_val_Real() != 0.0) break; clean_up(); valuetype = V_REAL; u.val_Real = 0.0; break; } default: FATAL_ERROR("Value::evaluate_value()"); } break; } case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: { eval_arithmetic: if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); operationtype_t ot=u.expr.v_optype; switch (v1->valuetype) { case V_INT: { const int_val_t *i1 = new int_val_t(*(v1->get_val_Int())); const int_val_t *i2 = new int_val_t(*(v2->get_val_Int())); clean_up(); valuetype = V_INT; switch (ot) { case OPTYPE_ADD: u.val_Int = new int_val_t(*i1 + *i2); break; case OPTYPE_SUBTRACT: u.val_Int = new int_val_t(*i1 - *i2); break; case OPTYPE_MULTIPLY: u.val_Int = new int_val_t(*i1 * *i2); break; case OPTYPE_DIVIDE: u.val_Int = new int_val_t(*i1 / *i2); break; case OPTYPE_MOD: u.val_Int = new int_val_t(mod(*i1, *i2)); break; case OPTYPE_REM: u.val_Int = new int_val_t(rem(*i1, *i2)); break; default: FATAL_ERROR("Value::evaluate_value()"); } delete i1; delete i2; break; } case V_REAL: { ttcn3float r1=v1->get_val_Real(); ttcn3float r2=v2->get_val_Real(); clean_up(); valuetype=V_REAL; switch(ot) { case OPTYPE_ADD: u.val_Real=r1+r2; break; case OPTYPE_SUBTRACT: u.val_Real=r1-r2; break; case OPTYPE_MULTIPLY: u.val_Real=r1*r2; break; case OPTYPE_DIVIDE: u.val_Real=r1/r2; break; default: FATAL_ERROR("Value::evaluate_value()"); } break;} default: FATAL_ERROR("Value::evaluate_value()"); } break;} case OPTYPE_CONCAT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt = v1->valuetype; if (vt == V_USTR || v2->valuetype == V_USTR) { // V_USTR wins const ustring& s1 = v1->get_val_ustr(); const ustring& s2 = v2->get_val_ustr(); clean_up(); valuetype = V_USTR; set_val_ustr(new ustring(s1 + s2)); u.ustr.convert_str = false; } else { const string& s1 = v1->get_val_str(); const string& s2 = v2->get_val_str(); clean_up(); valuetype = vt; set_val_str(new string(s1 + s2)); } break;} case OPTYPE_EQ: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); bool b=*v1==*v2; clean_up(); valuetype=V_BOOL; u.val_bool=b; break;} case OPTYPE_NE: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); bool b=*v1==*v2; clean_up(); valuetype=V_BOOL; u.val_bool=!b; break;} case OPTYPE_LT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); bool b=*v1<*v2; clean_up(); valuetype=V_BOOL; u.val_bool=b; break;} case OPTYPE_GT: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); bool b=*v2<*v1; clean_up(); valuetype=V_BOOL; u.val_bool=b; break;} case OPTYPE_GE: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); bool b=*v1<*v2; clean_up(); valuetype=V_BOOL; u.val_bool=!b; break;} case OPTYPE_LE: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); bool b=*v2<*v1; clean_up(); valuetype=V_BOOL; u.val_bool=!b; break;} case OPTYPE_AND: v1 = u.expr.v1->get_value_refd_last(); if (v1->valuetype == V_BOOL) { if (v1->get_val_bool()) { // the left operand is a literal "true" // substitute the expression with the right operand v2 = u.expr.v2; u.expr.v2 = 0; copy_and_destroy(v2); } else { // the left operand is a literal "false" // the result must be false regardless the right operand // because of the short circuit evaluation rule clean_up(); valuetype = V_BOOL; u.val_bool = false; } } else { // we must keep the left operand because of the potential side effects // the right operand can only be eliminated if it is a literal "true" v2 = u.expr.v2->get_value_refd_last(); if (v2->valuetype == V_BOOL && v2->get_val_bool()) { v1 = u.expr.v1; u.expr.v1 = 0; copy_and_destroy(v1); } } break; case OPTYPE_OR: v1 = u.expr.v1->get_value_refd_last(); if (v1->valuetype == V_BOOL) { if (v1->get_val_bool()) { // the left operand is a literal "true" // the result must be true regardless the right operand // because of the short circuit evaluation rule clean_up(); valuetype = V_BOOL; u.val_bool = true; } else { // the left operand is a literal "false" // substitute the expression with the right operand v2 = u.expr.v2; u.expr.v2 = 0; copy_and_destroy(v2); } } else { // we must keep the left operand because of the potential side effects // the right operand can only be eliminated if it is a literal "false" v2 = u.expr.v2->get_value_refd_last(); if (v2->valuetype == V_BOOL && !v2->get_val_bool()) { v1 = u.expr.v1; u.expr.v1 = 0; copy_and_destroy(v1); } } break; case OPTYPE_XOR: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); bool b=v1->get_val_bool() ^ v2->get_val_bool(); clean_up(); valuetype=V_BOOL; u.val_bool=b; break;} case OPTYPE_AND4B: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt=v1->valuetype; const string& s1 = v1->get_val_str(); const string& s2 = v2->get_val_str(); clean_up(); valuetype=vt; set_val_str(and4b(s1, s2)); break;} case OPTYPE_OR4B: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt=v1->valuetype; const string& s1 = v1->get_val_str(); const string& s2 = v2->get_val_str(); clean_up(); valuetype=vt; set_val_str(or4b(s1, s2)); break;} case OPTYPE_XOR4B: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt=v1->valuetype; const string& s1 = v1->get_val_str(); const string& s2 = v2->get_val_str(); clean_up(); valuetype=vt; set_val_str(xor4b(s1, s2)); break;} case OPTYPE_SHL: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt=v1->valuetype; const string& s = v1->get_val_str(); const int_val_t *i_int = v2->get_val_Int(); Int i=i_int->get_val(); if(vt==V_OSTR) i*=2; clean_up(); valuetype=vt; set_val_str(shift_left(s, i)); break;} case OPTYPE_SHR: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt=v1->valuetype; const string& s = v1->get_val_str(); const int_val_t *i_int = v2->get_val_Int(); Int i=i_int->get_val(); if(vt==V_OSTR) i*=2; clean_up(); valuetype=vt; set_val_str(shift_right(s, i)); break;} case OPTYPE_ROTL: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt=v1->valuetype; const int_val_t *i_int=v2->get_val_Int(); Int i=i_int->get_val(); if(vt==V_USTR) { const ustring& s = v1->get_val_ustr(); clean_up(); valuetype=vt; set_val_ustr(rotate_left(s, i)); u.ustr.convert_str = false; } else { if(vt==V_OSTR) i*=2; const string& s = v1->get_val_str(); clean_up(); valuetype=vt; set_val_str(rotate_left(s, i)); } break;} case OPTYPE_ROTR: { if(is_unfoldable()) break; v1=u.expr.v1->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); valuetype_t vt=v1->valuetype; const int_val_t *i_int=v2->get_val_Int(); Int i=i_int->get_val(); if(vt==V_USTR) { const ustring& s = v1->get_val_ustr(); clean_up(); valuetype=vt; set_val_ustr(rotate_right(s, i)); u.ustr.convert_str = false; } else { if(vt==V_OSTR) i*=2; const string& s = v1->get_val_str(); clean_up(); valuetype=vt; set_val_str(rotate_right(s, i)); } break;} case OPTYPE_INT2BIT: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); v2 = u.expr.v2->get_value_refd_last(); const int_val_t *i1_int = v1->get_val_Int(); const int_val_t *i2_int = v2->get_val_Int(); string *val = int2bit(*i1_int, i2_int->get_val()); clean_up(); valuetype = V_BSTR; set_val_str(val); break; } case OPTYPE_INT2HEX: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); v2 = u.expr.v2->get_value_refd_last(); const int_val_t *i1_int = v1->get_val_Int(); const int_val_t *i2_int = v2->get_val_Int(); // Do it before the `clean_up'. i2_int is already checked. string *val = int2hex(*i1_int, i2_int->get_val()); clean_up(); valuetype = V_HSTR; set_val_str(val); break; } case OPTYPE_INT2OCT: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); v2 = u.expr.v2->get_value_refd_last(); const int_val_t i1_int(*v1->get_val_Int()); // `v2' is a native integer. Int i2_int = v2->get_val_Int()->get_val() * 2; clean_up(); valuetype = V_OSTR; set_val_str(int2hex(i1_int, i2_int)); break; } case OPTYPE_SUBSTR: { if(is_unfoldable()) break; v1=u.expr.ti1->get_specific_value()->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); v3=u.expr.v3->get_value_refd_last(); valuetype_t vt=v1->valuetype; const int_val_t *i2_int=v2->get_val_Int(); const int_val_t *i3_int=v3->get_val_Int(); Int i2=i2_int->get_val(); Int i3=i3_int->get_val(); if(vt==V_USTR) { const ustring& s = v1->get_val_ustr(); clean_up(); valuetype=vt; set_val_ustr(new ustring(s.substr(i2, i3))); u.ustr.convert_str = false; } else { if(vt==V_OSTR) { i2*=2; i3*=2; } const string& s = v1->get_val_str(); clean_up(); valuetype=vt; set_val_str(new string(s.substr(i2, i3))); } break;} case OPTYPE_REPLACE: { if(is_unfoldable()) break; v1=u.expr.ti1->get_specific_value()->get_value_refd_last(); v2=u.expr.v2->get_value_refd_last(); v3=u.expr.v3->get_value_refd_last(); v4=u.expr.ti4->get_specific_value()->get_value_refd_last(); valuetype_t vt=v1->valuetype; const int_val_t *i2_int=v2->get_val_Int(); const int_val_t *i3_int=v3->get_val_Int(); Int i2=i2_int->get_val(); Int i3=i3_int->get_val(); switch(vt) { case V_BSTR: { string *s1 = new string(v1->get_val_str()); const string& s2 = v4->get_val_str(); clean_up(); valuetype=vt; s1->replace(i2, i3, s2); set_val_str(s1); break;} case V_HSTR: { string *s1 = new string(v1->get_val_str()); const string& s2 = v4->get_val_str(); clean_up(); valuetype=vt; s1->replace(i2, i3, s2); set_val_str(s1); break;} case V_OSTR: { i2*=2; i3*=2; string *s1 = new string(v1->get_val_str()); const string& s2 = v4->get_val_str(); clean_up(); valuetype=vt; s1->replace(i2, i3, s2); set_val_str(s1); break;} case V_CSTR: { string *s1 = new string(v1->get_val_str()); const string& s2 = v4->get_val_str(); clean_up(); valuetype=vt; s1->replace(i2, i3, s2); set_val_str(s1); break;} case V_USTR: { ustring *s1 = new ustring(v1->get_val_ustr()); const ustring& s2 = v4->get_val_ustr(); clean_up(); valuetype=vt; s1->replace(i2, i3, s2); set_val_ustr(s1); u.ustr.convert_str = false; break;} default: FATAL_ERROR("Value::evaluate_value()"); } break; } case OPTYPE_REGEXP: { if (is_unfoldable()) break; v1=u.expr.ti1->get_specific_value()->get_value_refd_last(); v2=u.expr.t2->get_specific_value()->get_value_refd_last(); v3=u.expr.v3->get_value_refd_last(); const int_val_t *i3_int = v3->get_val_Int(); Int i3 = i3_int->get_val(); if (v1->valuetype == V_CSTR) { const string& s1 = v1->get_val_str(); const string& s2 = v2->get_val_str(); string *result = regexp(s1, s2, i3, u.expr.b4); clean_up(); valuetype = V_CSTR; set_val_str(result); } if (v1->valuetype == V_USTR) { const ustring& s1 = v1->get_val_ustr(); const ustring& s2 = v2->get_val_ustr(); ustring *result = regexp(s1, s2, i3, u.expr.b4); clean_up(); valuetype = V_USTR; set_val_ustr(result); u.ustr.convert_str = false; } break; } case OPTYPE_LENGTHOF:{ if(is_unfoldable()) break; v1=u.expr.ti1->get_Template()->get_specific_value() ->get_value_refd_last(); size_t i; if(v1->is_string_type(exp_val)) { i=v1->get_val_strlen(); } else { // v1 is be seq/set of or array switch (v1->valuetype) { case V_SEQOF: case V_SETOF: case V_ARRAY: { if(v1->u.val_vs->is_indexed()) { i = v1->u.val_vs->get_nof_ivs();} else { i = v1->u.val_vs->get_nof_vs();} break; } default: FATAL_ERROR("Value::evaluate_value()"); } } clean_up(); valuetype=V_INT; u.val_Int=new int_val_t(i); break;} case OPTYPE_SIZEOF: { Int i=chk_eval_expr_sizeof(refch, exp_val); if(i!=-1) { clean_up(); valuetype=V_INT; u.val_Int=new int_val_t(i); } break;} case OPTYPE_ISVALUE: { if(is_unfoldable()) break; bool is_singleval = !u.expr.ti1->get_DerivedRef() && u.expr.ti1->get_Template()->is_Value(); if (is_singleval) { Value * other_val = u.expr.ti1->get_Template()->get_Value(); is_singleval = other_val->evaluate_isvalue(false); // is_singleval now contains the compile-time result of isvalue delete other_val; } clean_up(); valuetype = V_BOOL; u.val_bool = is_singleval; break;} case OPTYPE_ISCHOSEN_V: { if (is_unfoldable()) break; v1 = u.expr.v1->get_value_refd_last(); bool b = v1->field_is_chosen(*u.expr.i2); clean_up(); valuetype = V_BOOL; u.val_bool = b; break; } case OPTYPE_VALUEOF: // ti1 [subrefs2] if (!u.expr.ti1->get_DerivedRef() && u.expr.ti1->get_Template()->is_Value() && !u.expr.ti1->get_Type()) { // FIXME actually if the template instance has a type // it might still be foldable. // the argument is a single specific value v1 = u.expr.ti1->get_Template()->get_Value()-> get_refd_sub_value(u.expr.subrefs2, 0, false, refch); Type *governor = my_governor; if (governor == NULL) { governor = u.expr.ti1->get_expr_governor(exp_val); if (governor != NULL) governor = governor->get_type_refd_last()-> get_field_type(u.expr.subrefs2, exp_val); if (governor != NULL) governor = governor->get_type_refd_last(); } if (governor == NULL) governor = v1->get_my_governor()->get_type_refd_last(); if (governor == NULL) FATAL_ERROR("Value::evaluate_value()"); clean_up(); valuetype = v1->valuetype; u = v1->u; set_my_governor(governor); if (valuetype == V_REFD && u.ref.refd_last == v1) u.ref.refd_last = this; v1->valuetype = V_ERROR; delete v1; } break; case OPTYPE_OF_CLASS: if (!is_unfoldable()) { clean_up(); valuetype = V_BOOL; u.val_bool = false; } break; case OPTYPE_CLASS_CASTING: if (!is_unfoldable()) { Type* type = u.expr.type; Reference* ref = u.expr.r2; valuetype = V_REFD; u.ref.ref = ref; u.ref.refd_last = this; set_my_governor(type->get_type_refd_last()); delete type; } break; case OPTYPE_CLASS_CASTING_REF: case OPTYPE_UNDEF_RUNNING: default: FATAL_ERROR("Value::evaluate_value()"); } // switch optype } bool Value::evaluate_isvalue(bool from_sequence) { switch (valuetype) { case V_OMIT: // Omit is not a value unless a member of a sequence or set return from_sequence; case V_NOTUSED: return false; case V_NULL: /**< NULL (for ASN.1 NULL type, also in TTCN-3) */ case V_BOOL: /**< boolean */ case V_NAMEDINT: /**< integer / named number */ case V_NAMEDBITS: /**< named bits (identifiers) */ case V_INT: /**< integer */ case V_REAL: /**< real/float */ case V_ENUM: /**< enumerated */ case V_BSTR: /**< bitstring */ case V_HSTR: /**< hexstring */ case V_OSTR: /**< octetstring */ case V_CSTR: /**< charstring */ case V_USTR: /**< universal charstring */ case V_ISO2022STR: /**< ISO-2022 string (treat as octetstring) */ case V_CHARSYMS: /**< parsed ASN.1 universal string notation */ case V_OID: /**< object identifier */ case V_ROID: /**< relative object identifier */ case V_VERDICT: /**< all verdicts */ return true; // values of built-in types return true // Code below was adapted from is_unfoldable(), false returned early. case V_CHOICE: return u.choice.alt_value->evaluate_isvalue(false); case V_SEQOF: case V_SETOF: case V_ARRAY: for (size_t i = 0; i < u.val_vs->get_nof_vs(); i++) { if (!u.val_vs->get_v_byIndex(i)->evaluate_isvalue(false)) { return false; } } return true; case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); i++) { if (!u.val_nvs->get_nv_byIndex(i)->get_value() ->evaluate_isvalue(true)) return false; } return true; case V_REFD: // alas, get_value_refd_last prevents this function from const return get_value_refd_last()->evaluate_isvalue(false); case V_EXPR: switch (u.expr.v_optype) { // A constant null component reference is a corner case: it is foldable // but escapes unmodified from evaluate_value. // A V_EXPR with any other OPTYPE_ is either unfoldable, // or is transformed into some other valuetype in evaluate_value. case OPTYPE_COMP_NULL: return false; default: break; // and fall through to the FATAL_ERROR } // no break default: FATAL_ERROR("Value::evaluate_isvalue()"); break; } return true; } void Value::evaluate_macro(Type::expected_value_t exp_val) { switch (u.macro) { case MACRO_MODULEID: if (!my_scope) FATAL_ERROR("Value::evaluate_macro(): my_scope is not set"); set_val_str(new string(my_scope->get_scope_mod() ->get_modid().get_dispname())); valuetype = V_CSTR; break; case MACRO_FILENAME: case MACRO_BFILENAME: { const char *t_filename = get_filename(); if (!t_filename) FATAL_ERROR("Value::evaluate_macro(): file name is not set"); set_val_str(new string(t_filename)); valuetype = V_CSTR; break; } case MACRO_FILEPATH: { const char *t_filename = get_filename(); if (!t_filename) FATAL_ERROR("Value::evaluate_macro(): file name is not set"); char *t_filepath = canonize_input_file(t_filename); if (!t_filepath) FATAL_ERROR("Value::evaluate_macro(): file path cannot be determined"); set_val_str(new string(t_filepath)); valuetype = V_CSTR; Free(t_filepath); break; } case MACRO_LINENUMBER: { size_t t_lineno = get_first_line(); if (t_lineno <= 0) FATAL_ERROR("Value::evaluate_macro(): line number is not set"); set_val_str(new string(Int2string(t_lineno))); valuetype = V_CSTR; break; } case MACRO_LINENUMBER_C: { size_t t_lineno = get_first_line(); if (t_lineno <= 0) FATAL_ERROR("Value::evaluate_macro(): line number is not set"); u.val_Int = new int_val_t(t_lineno); valuetype = V_INT; break; } case MACRO_DEFINITIONID: { // cut the second part from the fullname separated by dots const string& t_fullname = get_fullname(); size_t first_char = t_fullname.find('.') + 1; if (first_char >= t_fullname.size()) FATAL_ERROR("Value::evaluate_macro(): malformed fullname: `%s'", \ t_fullname.c_str()); set_val_str(new string(t_fullname.substr(first_char, t_fullname.find('.', first_char) - first_char))); valuetype = V_CSTR; break; } case MACRO_SCOPE: { if (!my_scope) FATAL_ERROR("Value::evaluate_macro(): scope is not set"); set_val_str(new string(my_scope->get_scopeMacro_name())); valuetype = V_CSTR; break; } case MACRO_TESTCASEID: { if (exp_val == Type::EXPECTED_CONSTANT || exp_val == Type::EXPECTED_STATIC_VALUE) { error("A %s value was expected instead of macro `%%testcaseId', " "which is evaluated at runtime", exp_val == Type::EXPECTED_CONSTANT ? "constant" : "static"); goto error; } if (!my_scope) FATAL_ERROR("Value::evaluate_macro(): my_scope is not set"); Ttcn::StatementBlock *my_sb = dynamic_cast<Ttcn::StatementBlock*>(my_scope); if (!my_sb) { error("Usage of macro %%testcaseId is allowed only within the " "statement blocks of functions, altsteps and testcases"); goto error; } Ttcn::Definition *my_def = my_sb->get_my_def(); if (!my_def) { error("Macro %%testcaseId cannot be used in the control part. " "It is allowed only within the statement blocks of functions, " "altsteps and testcases"); goto error; } if (my_def->get_asstype() == Assignment::A_TESTCASE) { // folding is possible only within testcases set_val_str(new string(my_def->get_id().get_dispname())); valuetype = V_CSTR; } break; } default: FATAL_ERROR("Value::evaluate_macro()"); } return; error: set_valuetype(V_ERROR); } void Value::add_id(Identifier *p_id) { switch(valuetype) { case V_NAMEDBITS: if(u.ids->has_key(p_id->get_name())) { error("Duplicate named bit `%s'", p_id->get_dispname().c_str()); // The Value does not take ownership for the identifier, // so it must be deleted (add_is acts as a sink). delete p_id; } else u.ids->add(p_id->get_name(), p_id); break; default: FATAL_ERROR("Value::add_id()"); } // switch } void Value::use_default_alternative(Type* p_union_type) { if (valuetype == V_ERROR) { return; } CompField* def_alt = p_union_type->get_default_alternative(); if (def_alt == NULL) { FATAL_ERROR("Value::use_default_alternative"); } Value* def_val = clone(); def_val->my_governor = def_alt->get_type(); def_val->set_my_scope(my_scope); def_val->set_fullname(get_fullname() + ".<default_alternative>"); clean_up(); valuetype = V_CHOICE; u.choice.alt_name = def_alt->get_name().clone(); u.choice.alt_value = def_val; my_governor = p_union_type; } Value* Value::get_value_refd_last(ReferenceChain *refch, Type::expected_value_t exp_val) { set_lowerid_to_ref(); switch (valuetype) { case V_INVOKE: // there might be a better place for this chk_invoke(exp_val); return this; case V_REFD: // use the cache if available if (u.ref.refd_last) return u.ref.refd_last; else { Assignment *ass = u.ref.ref->get_refd_assignment(); if (!ass) { // the referred definition is not found set_valuetype(V_ERROR); } else { switch (ass->get_asstype()) { case Assignment::A_OBJECT: case Assignment::A_OS: { // the referred definition is an ASN.1 object or object set Setting *setting = u.ref.ref->get_refd_setting(); if (!setting || setting->get_st() == S_ERROR) { // remain silent, the error has been already reported set_valuetype(V_ERROR); break; } else if (setting->get_st() != S_V) { u.ref.ref->error("InformationFromObjects construct `%s' does not" " refer to a value", u.ref.ref->get_dispname().c_str()); set_valuetype(V_ERROR); break; } bool destroy_refch; if (refch) { refch->mark_state(); destroy_refch = false; } else { refch = new ReferenceChain(this, "While searching referenced value"); destroy_refch = true; } if (refch->add(get_fullname())) { Value *v_refd = dynamic_cast<Value*>(setting); Value *v_last = v_refd->get_value_refd_last(refch); // in case of circular recursion the valuetype is already set // to V_ERROR, so don't set the cache if (valuetype == V_REFD) u.ref.refd_last = v_last; } else { // a circular recursion was detected set_valuetype(V_ERROR); } if (destroy_refch) delete refch; else refch->prev_state(); break; } case Assignment::A_CONST: { // the referred definition is a constant bool destroy_refch; if (refch) { refch->mark_state(); destroy_refch = false; } else { refch = new ReferenceChain(this, "While searching referenced value"); destroy_refch = true; } if (refch->add(get_fullname())) { if (ass->get_my_scope()->get_parent_scope()->is_class_scope()) { // class members are considered unfoldable, because their initial // values can be changed in the constructor u.ref.refd_last = this; } else { Ttcn::FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs(); Value *v_refd = ass->get_Value() ->get_refd_sub_value(subrefs, 0, u.ref.ref->getUsedInIsbound(), refch); if (v_refd) { Value *v_last = v_refd->get_value_refd_last(refch); // in case of circular recursion the valuetype is already set // to V_ERROR, so don't set the cache if (valuetype == V_REFD) u.ref.refd_last = v_last; } else if (subrefs && subrefs->has_unfoldable_index()) { u.ref.refd_last = this; } else if (u.ref.ref->getUsedInIsbound()) { u.ref.refd_last = this; } else { // the sub-reference points to a non-existent field set_valuetype(V_ERROR); } } } else { // a circular recursion was detected set_valuetype(V_ERROR); } if (destroy_refch) delete refch; else refch->prev_state(); break; } case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: // the referred definition is not a constant u.ref.refd_last = this; break; case Assignment::A_FUNCTION: case Assignment::A_EXT_FUNCTION: u.ref.ref->error("Reference to a value was expected instead of a " "call of %s, which does not have return type", ass->get_description().c_str()); set_valuetype(V_ERROR); break; case Assignment::A_FUNCTION_RTEMP: case Assignment::A_EXT_FUNCTION_RTEMP: u.ref.ref->error("Reference to a value was expected instead of a " "call of %s, which returns a template", ass->get_description().c_str()); set_valuetype(V_ERROR); break; case Assignment::A_TYPE: if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) { Ttcn::Reference* ttcn_ref = static_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref->get_reftype() == Ref_simple::REF_THIS) { u.ref.refd_last = this; break; } } // else fall through default: u.ref.ref->error("Reference to a value was expected instead of %s", ass->get_description().c_str()); set_valuetype(V_ERROR); } // switch asstype } if (valuetype == V_REFD) return u.ref.refd_last; else return this; } case V_EXPR: { // try to evaluate the expression bool destroy_refch; if(refch) { refch->mark_state(); destroy_refch=false; } else { refch=new ReferenceChain(this, "While evaluating expression"); destroy_refch=true; } if(refch->add(get_fullname())) evaluate_value(refch, exp_val); else set_valuetype(V_ERROR); if(destroy_refch) delete refch; else refch->prev_state(); return this; } case V_MACRO: evaluate_macro(exp_val); // no break default: // return this for all other value types return this; } // switch } map<Value*, void> Value::UnfoldabilityCheck::running; /* Note that the logic here needs to be in sync with evaluate_value, * and possibly others, i.e. if evaluate_value is called for a Value * for which is_unfoldable returns false, FATAL_ERROR might happen. */ bool Value::is_unfoldable(ReferenceChain *refch, Type::expected_value_t exp_val) { if (UnfoldabilityCheck::is_running(this)) { // This function is already running on this value => infinite recursion return true; } UnfoldabilityCheck checker(this); if (get_needs_conversion()) return true; switch (valuetype) { case V_NAMEDINT: case V_NAMEDBITS: case V_OPENTYPE: case V_UNDEF_LOWERID: case V_UNDEF_BLOCK: case V_REFER: // these value types are eliminated during semantic analysis FATAL_ERROR("Value::is_unfoldable()"); case V_ERROR: case V_INVOKE: case V_TTCN3_NULL: return true; case V_CHOICE: return u.choice.alt_value->is_unfoldable(refch, exp_val); case V_SEQOF: case V_SETOF: case V_ARRAY: if (!is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_vs(); i++) { if (u.val_vs->get_v_byIndex(i)->is_unfoldable(refch, exp_val)) return true; } } else { for(size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { if (u.val_vs->get_iv_byIndex(i)->is_unfoldable(refch, exp_val)) return true; } } return false; case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); i++) { if (u.val_nvs->get_nv_byIndex(i)->get_value() ->is_unfoldable(refch, exp_val)) return true; } return false; case V_OID: case V_ROID: chk(); for (size_t i = 0; i < u.oid_comps->size(); ++i) { if ((*u.oid_comps)[i]->is_variable()) return true; } return false; case V_REFD: { Value *v_last=get_value_refd_last(refch, exp_val); if(v_last==this) return true; // there weren't any references to chase else return v_last->is_unfoldable(refch, exp_val); } case V_EXPR: // classify the unchecked ischosen() operation, if it was not done so far if (u.expr.v_optype==OPTYPE_ISCHOSEN) chk_expr_ref_ischosen(); if(u.expr.state==EXPR_CHECKING_ERR) return true; switch (u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_GET_PORT_REF: case OPTYPE_RNDWITHVAL: // v1 case OPTYPE_MATCH: // v1 t2 case OPTYPE_UNDEF_RUNNING: // v1 case OPTYPE_COMP_RUNNING: case OPTYPE_COMP_ALIVE: case OPTYPE_TMR_READ: case OPTYPE_TMR_RUNNING: case OPTYPE_ACTIVATE: case OPTYPE_ACTIVATE_REFD: case OPTYPE_EXECUTE: // r1 [v2] case OPTYPE_EXECUTE_REFD: case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4 case OPTYPE_CLASS_CREATE: // r1 t_list2 case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 case OPTYPE_ISCHOSEN: case OPTYPE_ISCHOSEN_T: case OPTYPE_SIZEOF: // ti1 case OPTYPE_DECODE: case OPTYPE_ENCODE: case OPTYPE_OCT2UNICHAR: case OPTYPE_UNICHAR2OCT: case OPTYPE_ENCODE_BASE64: case OPTYPE_DECODE_BASE64: case OPTYPE_ENCVALUE_UNICHAR: case OPTYPE_DECVALUE_UNICHAR: case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: case OPTYPE_HOSTID: case OPTYPE_ISTEMPLATEKIND: // ti1 v2 case OPTYPE_CBOR2JSON: case OPTYPE_JSON2CBOR: case OPTYPE_BSON2JSON: case OPTYPE_JSON2BSON: case OPTYPE_NOW: return true; case OPTYPE_COMP_NULL: // - return false; case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: return u.expr.v1->is_unfoldable(refch, exp_val); case OPTYPE_ISBOUND: /*{ //TODO once we have the time for it make isbound foldable. if (u.expr.ti1->get_DerivedRef() != 0) return true; Template* temp = u.expr.ti1->get_Template(); if (temp->get_templatetype() == Template::SPECIFIC_VALUE) { Value* specificValue = temp->get_specific_value(); if (specificValue->get_valuetype() == Value::V_REFD) { //FIXME implement } return specificValue->is_unfoldable(refch, exp_val); } else if (temp->get_templatetype() == Template::TEMPLATE_REFD) { //FIXME implement } }*/ return true; case OPTYPE_ISPRESENT: // TODO: "if you have motivation" return true; case OPTYPE_ISVALUE: // ti1 // fallthrough case OPTYPE_LENGTHOF: // ti1 return u.expr.ti1->get_DerivedRef() != 0 || u.expr.ti1->get_Template()->get_templatetype() != Template::SPECIFIC_VALUE || u.expr.ti1->get_Template()->get_specific_value() ->is_unfoldable(refch, exp_val); case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_CONCAT: if (!u.expr.v1->is_string_type(exp_val)) return true; // no break case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: return u.expr.v1->is_unfoldable(refch, exp_val) || u.expr.v2->is_unfoldable(refch, exp_val); case OPTYPE_AND: // short-circuit evaluation return u.expr.v1->is_unfoldable(refch, exp_val) || (u.expr.v1->get_val_bool() && u.expr.v2->is_unfoldable(refch, exp_val)); case OPTYPE_OR: // short-circuit evaluation return u.expr.v1->is_unfoldable(refch, exp_val) || (!u.expr.v1->get_val_bool() && u.expr.v2->is_unfoldable(refch, exp_val)); case OPTYPE_SUBSTR: if (!u.expr.ti1->get_specific_value()) return true; if (!u.expr.ti1->is_string_type(exp_val)) return true; return u.expr.ti1->get_specific_value()->is_unfoldable(refch, exp_val) || u.expr.v2->is_unfoldable(refch, exp_val) || u.expr.v3->is_unfoldable(refch, exp_val); case OPTYPE_REGEXP: if (!u.expr.ti1->get_specific_value() || !u.expr.t2->get_specific_value()) return true; return u.expr.ti1->get_specific_value()->is_unfoldable(refch, exp_val) || u.expr.t2->get_specific_value()->is_unfoldable(refch, exp_val) || u.expr.v3->is_unfoldable(refch, exp_val); case OPTYPE_DECOMP: return u.expr.v1->is_unfoldable(refch, exp_val) || u.expr.v2->is_unfoldable(refch, exp_val) || u.expr.v3->is_unfoldable(refch, exp_val); case OPTYPE_REPLACE: { if (!u.expr.ti1->get_specific_value() || !u.expr.ti4->get_specific_value()) return true; if (!u.expr.ti1->is_string_type(exp_val)) return true; return u.expr.ti1->get_specific_value()->is_unfoldable(refch, exp_val) || u.expr.v2->is_unfoldable(refch, exp_val) || u.expr.v3->is_unfoldable(refch, exp_val) || u.expr.ti4->get_specific_value()->is_unfoldable(refch, exp_val); } case OPTYPE_VALUEOF: // ti1 [subrefs2] /* \todo if you have motivation to implement the eval function for valueof()... */ return true; case OPTYPE_ISCHOSEN_V: return true; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: case OPTYPE_TTCN2STRING: return true; case OPTYPE_OF_CLASS: { // class of object reference Ttcn::ClassTypeBody* ref_class = u.expr.r2->chk_variable_ref()-> get_type_refd_last()->get_class_type_body(); // expected class Ttcn::ClassTypeBody* exp_class = u.expr.type->get_type_refd_last()-> get_class_type_body(); // the result is always false if the classes are not related to each other, // otherwise a runtime check is required return ref_class->is_parent_class(exp_class) || exp_class->is_parent_class(ref_class); } case OPTYPE_CLASS_CASTING: return !u.expr.type->is_identical(u.expr.r2->chk_variable_ref()); default: FATAL_ERROR("Value::is_unfoldable()"); } // switch FATAL_ERROR("Value::is_unfoldable()"); break; // should never get here case V_MACRO: switch (u.macro) { case MACRO_TESTCASEID: // this is known only at runtime return true; default: return false; } default: // all literal values are foldable return false; } } Value* Value::get_refd_sub_value(Ttcn::FieldOrArrayRefs *subrefs, size_t start_i, bool usedInIsbound, ReferenceChain *refch, bool silent) { if (!subrefs) return this; Value *v = this; for (size_t i = start_i; i < subrefs->get_nof_refs(); i++) { if (!v) break; v = v->get_value_refd_last(refch); switch(v->valuetype) { case V_ERROR: return v; case V_REFD: // unfoldable stuff return this; default: break; } // switch Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i); if (ref->get_type() == Ttcn::FieldOrArrayRef::FIELD_REF) { if (v->get_my_governor()->get_type_refd_last()->get_typetype() == Type::T_OPENTYPE) { // allow the alternatives of open types as both lower and upper identifiers ref->set_field_name_to_lowercase(); } v = v->get_refd_field_value(*ref->get_id(), usedInIsbound, *ref, silent); } else v = v->get_refd_array_value(ref->get_val(), usedInIsbound, refch, silent); } return v; } Value *Value::get_refd_field_value(const Identifier& field_id, bool usedInIsbound, const Location& loc, bool silent) { if (valuetype == V_OMIT) { if (!silent) { loc.error("Reference to field `%s' of omit value `%s'", field_id.get_dispname().c_str(), get_fullname().c_str()); } return 0; } if (!my_governor) FATAL_ERROR("Value::get_refd_field_value()"); Type *t = my_governor->get_type_refd_last(); switch (t->get_typetype()) { case Type::T_ERROR: // remain silent return 0; case Type::T_CHOICE_A: case Type::T_CHOICE_T: case Type::T_OPENTYPE: case Type::T_ANYTYPE: if (!t->has_comp_withName(field_id)) { if (!silent) { loc.error("Reference to non-existent union field `%s' in type `%s'", field_id.get_dispname().c_str(), t->get_typename().c_str()); } return 0; } else if (valuetype != V_CHOICE) { // remain silent, the error is already reported return 0; } else if (*u.choice.alt_name == field_id) { // everything is OK return u.choice.alt_value; }else { if (!usedInIsbound && !silent) { loc.error("Reference to inactive field `%s' in a value of union type " "`%s'. The active field is `%s'", field_id.get_dispname().c_str(), t->get_typename().c_str(), u.choice.alt_name->get_dispname().c_str()); } return 0; } case Type::T_SEQ_A: case Type::T_SEQ_T: if (!t->has_comp_withName(field_id)) { if (!silent) { loc.error("Reference to non-existent record field `%s' in type `%s'", field_id.get_dispname().c_str(), t->get_typename().c_str()); } return 0; } else if (valuetype != V_SEQ) { // remain silent, the error has been already reported return 0; } else break; case Type::T_SET_A: case Type::T_SET_T: if (!t->has_comp_withName(field_id)) { if (!silent) { loc.error("Reference to non-existent set field `%s' in type `%s'", field_id.get_dispname().c_str(), t->get_typename().c_str()); } return 0; } else if (valuetype != V_SET) { // remain silent, the error has been already reported return 0; } else break; default: if (!silent) { loc.error("Invalid field reference `%s': type `%s' " "does not have fields", field_id.get_dispname().c_str(), t->get_typename().c_str()); } return 0; } // the common end for record & set types if (u.val_nvs->has_nv_withName(field_id)) { // everything is OK return u.val_nvs->get_nv_byName(field_id)->get_value(); } else if (!is_asn1()) { if (!usedInIsbound && !silent) { loc.error("Reference to unbound field `%s'", field_id.get_dispname().c_str()); // this is an error in TTCN-3, which has been already reported } return 0; } else { CompField *cf = t->get_comp_byName(field_id); if (cf->get_is_optional()) { // creating an explicit omit value Value *v = new Value(V_OMIT); v->set_fullname(get_fullname() + "." + field_id.get_dispname()); v->set_my_scope(get_my_scope()); u.val_nvs->add_nv(new NamedValue(field_id.clone(), v)); return v; } else if (cf->has_default()) { // returning the component's default value return cf->get_defval(); } else { // this is an error in ASN.1, which has been already reported return 0; } } } Value *Value::get_refd_array_value(Value *array_index, bool usedInIsbound, ReferenceChain *refch, bool silent) { Value *v_index = array_index->get_value_refd_last(refch); if (!my_governor) FATAL_ERROR("Value::get_refd_field_value()"); Type *t = my_governor->get_type_refd_last(); Int index = 0; bool index_available = false; if (!v_index->is_unfoldable()) { if (v_index->valuetype == V_INT) { index = v_index->get_val_Int()->get_val(); index_available = true; } else if (v_index->valuetype == V_ARRAY || v_index->valuetype == V_SEQOF) { Value *v = this; size_t comps = v_index->get_nof_comps(); for (size_t i = 0; i < comps; i++) { Value *comp = v_index->get_comp_byIndex(i); v = v->get_refd_array_value(comp, usedInIsbound, refch, silent); if (v == NULL) { // error reported already return 0; } } return v; } else if (!silent) { array_index->error("An integer value or a fixed length array or record of integer value was expected as index"); } } if (valuetype == V_OMIT) { if (!silent) { array_index->error("Accessing an element with index of omit value `%s'", get_fullname().c_str()); } return 0; } switch (t->get_typetype()) { case Type::T_ERROR: // remain silent return 0; case Type::T_SEQOF: if (index_available) { if (index < 0) { if (!silent) { array_index->error("A non-negative integer value was expected " "instead of %s for indexing a value of `record " "of' type `%s'", Int2string(index).c_str(), t->get_typename().c_str()); } return 0; } switch (valuetype) { case V_SEQOF: if (!is_indexed()) { if (index >= static_cast<Int>(u.val_vs->get_nof_vs())) { if (!usedInIsbound && !silent) { array_index->error("Index overflow in a value of `record of' " "type `%s': the index is %s, but the value " "has only %lu elements", t->get_typename().c_str(), Int2string(index).c_str(), (unsigned long)u.val_vs->get_nof_vs()); } return 0; } else { Value* temp = u.val_vs->get_v_byIndex((size_t)index); if(!silent && temp->get_value_refd_last()->get_valuetype() == V_NOTUSED) temp->error("Not used symbol is not allowed in this context"); return u.val_vs->get_v_byIndex((size_t)index); } } else { // Search the appropriate constant index. for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) { Value *iv_index = u.val_vs->get_iv_byIndex(i)->get_index() ->get_value_refd_last(); if (iv_index->get_valuetype() != V_INT) continue; if (iv_index->get_val_Int()->get_val() == index) return u.val_vs->get_iv_byIndex(i)->get_value(); } return 0; } break; default: // remain silent, the error has been already reported return 0; } } else { // the error has been reported above return 0; } case Type::T_SETOF: if (index_available) { if (index < 0) { if (!silent) { array_index->error("A non-negative integer value was expected " "instead of %s for indexing a value of `set of' type `%s'", Int2string(index).c_str(), t->get_typename().c_str()); } return 0; } switch (valuetype) { case V_SETOF: if (!is_indexed()) { if (index >= static_cast<Int>(u.val_vs->get_nof_vs())) { if (!usedInIsbound && !silent) { array_index->error("Index overflow in a value of `set of' type " "`%s': the index is %s, but the value has " "only %lu elements", t->get_typename().c_str(), Int2string(index).c_str(), (unsigned long)u.val_vs->get_nof_vs()); } return 0; } else { Value* temp = u.val_vs->get_v_byIndex((size_t)index); if(!silent && temp->get_value_refd_last()->get_valuetype() == V_NOTUSED) temp->error("Not used symbol is not allowed in this context"); return temp; } } else { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) { Value *iv_index = u.val_vs->get_iv_byIndex(i)->get_index() ->get_value_refd_last(); if (iv_index->get_valuetype() != V_INT) continue; if (iv_index->get_val_Int()->get_val() == index) return u.val_vs->get_iv_byIndex(i)->get_value(); } return 0; } break; default: // remain silent, the error has been already reported return 0; } } else { // the error has been reported above return 0; } case Type::T_ARRAY: if (index_available) { Ttcn::ArrayDimension *dim = t->get_dimension(); dim->chk_index(v_index, Type::EXPECTED_CONSTANT); if (valuetype == V_ARRAY && !dim->get_has_error()) { // perform the index transformation index -= dim->get_offset(); if (!is_indexed()) { // check for index underflow/overflow or too few elements in the // value if (index < 0 || index >= static_cast<Int>(u.val_vs->get_nof_vs())) return 0; else return u.val_vs->get_v_byIndex((size_t)index); } else { if (index < 0) return 0; for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) { Value *iv_index = u.val_vs->get_iv_byIndex(i)->get_index() ->get_value_refd_last(); if (iv_index->get_valuetype() != V_INT) continue; if (iv_index->get_val_Int()->get_val() == index) return u.val_vs->get_iv_byIndex((size_t)index)->get_value(); } return 0; } } else { // remain silent, the error has been already reported return 0; } } else { // the error has been reported above return 0; } case Type::T_BSTR: case Type::T_BSTR_A: case Type::T_HSTR: case Type::T_OSTR: case Type::T_CSTR: case Type::T_USTR: case Type::T_UTF8STRING: case Type::T_NUMERICSTRING: case Type::T_PRINTABLESTRING: case Type::T_TELETEXSTRING: case Type::T_VIDEOTEXSTRING: case Type::T_IA5STRING: case Type::T_GRAPHICSTRING: case Type::T_VISIBLESTRING: case Type::T_GENERALSTRING: case Type::T_UNIVERSALSTRING: case Type::T_BMPSTRING: case Type::T_UTCTIME: case Type::T_GENERALIZEDTIME: case Type::T_OBJECTDESCRIPTOR: if (index_available) return get_string_element(index, *array_index); else return 0; default: if (!silent) { array_index->error("Invalid array element reference: type `%s' cannot " "be indexed", t->get_typename().c_str()); } return 0; } } Value *Value::get_string_element(const Int& index, const Location& loc) { if (index < 0) { loc.error("A non-negative integer value was expected instead of %s " "for indexing a string element", Int2string(index).c_str()); return 0; } size_t string_length; switch (valuetype) { case V_BSTR: case V_HSTR: case V_CSTR: case V_ISO2022STR: string_length = u.str.val_str->size(); break; case V_OSTR: string_length = u.str.val_str->size() / 2; break; case V_USTR: string_length = u.ustr.val_ustr->size(); break; default: // remain silent, the error has been already reported return 0; } if (index >= static_cast<Int>(string_length)) { loc.error("Index overflow when accessing a string element: " "the index is %s, but the string has only %lu elements", Int2string(index).c_str(), (unsigned long) string_length); return 0; } switch (valuetype) { case V_BSTR: case V_HSTR: case V_CSTR: case V_ISO2022STR: if (u.str.str_elements && u.str.str_elements->has_key(index)) return (*u.str.str_elements)[index]; else { Value *t_val = new Value(valuetype, new string(u.str.val_str->substr(index, 1))); add_string_element(index, t_val, u.str.str_elements); return t_val; } case V_OSTR: if (u.str.str_elements && u.str.str_elements->has_key(index)) return (*u.str.str_elements)[index]; else { Value *t_val = new Value(V_OSTR, new string(u.str.val_str->substr(2 * index, 2))); add_string_element(index, t_val, u.str.str_elements); return t_val; } case V_USTR: if (u.ustr.ustr_elements && u.ustr.ustr_elements->has_key(index)) return (*u.ustr.ustr_elements)[index]; else { Value *t_val = new Value(V_USTR, new ustring(u.ustr.val_ustr->substr(index, 1))); add_string_element(index, t_val, u.ustr.ustr_elements); return t_val; } default: FATAL_ERROR("Value::get_string_element()"); return 0; } } void Value::chk_expr_type(Type::typetype_t p_tt, const char *type_name, Type::expected_value_t exp_val) { set_lowerid_to_ref(); Type::typetype_t r_tt = get_expr_returntype(exp_val); bool error_flag = r_tt != Type::T_ERROR && r_tt != p_tt; if (error_flag) { if (is_ref() && r_tt == Type::T_CHOICE_T) { Type* t = get_expr_governor(exp_val); if (t != NULL) { CompField* def_alt = t->get_default_alternative(); Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(get_reference()); if (def_alt != NULL && ttcn_ref != NULL) { Error_Context cntxt(this, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), t->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt->get_name()); chk_expr_type(p_tt, type_name, exp_val); return; } } } error("A value or expression of type %s was expected", type_name); } if (valuetype == V_REFD) { Type *t_chk = Type::get_pooltype(Type::T_ERROR); t_chk->chk_this_refd_value(this, 0, exp_val); } get_value_refd_last(0, exp_val); if (error_flag) set_valuetype(V_ERROR); else if (!my_governor) set_my_governor(Type::get_pooltype(p_tt)); } bool Value::chk_string_encoding(Common::Assignment* lhs) { Error_Context cntxt(this, "In encoding format"); set_lowerid_to_ref(); bool self_ref = Type::get_pooltype(Type::T_CSTR)->chk_this_value(this, lhs, Type::EXPECTED_DYNAMIC_VALUE, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); if (!is_unfoldable()) { string enc_name = 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") { error("'%s' is not a valid encoding format", enc_name.c_str()); } } return self_ref; } int Value::is_parsed_infinity() { if ( (get_valuetype()==V_REAL) && (get_val_Real()==REAL_INFINITY) ) return 1; if ( (get_valuetype()==V_EXPR) && (get_optype()==OPTYPE_UNARYMINUS) && (u.expr.v1->get_valuetype()==V_REAL) && (u.expr.v1->get_val_Real()==REAL_INFINITY) ) return -1; return 0; } bool Value::get_val_bool() { Value *v; if (valuetype == V_REFD) v = get_value_refd_last(); else v = this; if (v->valuetype != V_BOOL) FATAL_ERROR("Value::get_val_bool()"); return v->u.val_bool; } int_val_t* Value::get_val_Int() { Value *v; if (valuetype == V_REFD) v = get_value_refd_last(); else v = this; switch (v->valuetype) { case V_INT: break; case V_UNDEF_LOWERID: FATAL_ERROR("Cannot use this value (here) as an integer: " \ "`%s'", (*u.val_id).get_dispname().c_str()); default: FATAL_ERROR("Value::get_val_Int()"); } // switch return v->u.val_Int; } const Identifier* Value::get_val_id() { switch(valuetype) { case V_NAMEDINT: case V_ENUM: case V_UNDEF_LOWERID: return u.val_id; default: FATAL_ERROR("Value::get_val_id()"); return 0; } // switch } const ttcn3float& Value::get_val_Real() { Value *v; if (valuetype == V_REFD) v = get_value_refd_last(); else v = this; if (v->valuetype != V_REAL) FATAL_ERROR("Value::get_val_Real()"); return v->u.val_Real; } string Value::get_val_str() { Value *v = get_value_refd_last(); switch (v->valuetype) { case V_BSTR: case V_HSTR: case V_OSTR: case V_CSTR: return *v->u.str.val_str; case V_CHARSYMS: return v->u.char_syms->get_string(); case V_USTR: error("Cannot use ISO-10646 string value in string context"); return string(); case V_ISO2022STR: error("Cannot use ISO-2022 string value in string context"); // no break case V_ERROR: return string(); default: error("Cannot use this value in charstring value context"); return string(); } // switch } ustring Value::get_val_ustr() { Value *v = get_value_refd_last(); switch (v->valuetype) { case V_CSTR: return ustring(*v->u.str.val_str); case V_USTR: return *v->u.ustr.val_ustr; case V_CHARSYMS: return v->u.char_syms->get_ustring(); case V_ISO2022STR: error("Cannot use ISO-2022 string value in ISO-10646 string context"); // no break case V_ERROR: return ustring(); default: error("Cannot use this value in ISO-10646 string context"); return ustring(); } // switch } string Value::get_val_iso2022str() { Value *v = get_value_refd_last(); switch (v->valuetype) { case V_CSTR: case V_ISO2022STR: return *v->u.str.val_str; case V_CHARSYMS: return v->u.char_syms->get_iso2022string(); case V_USTR: error("Cannot use ISO-10646 string value in ISO-2022 string context"); // no break case V_ERROR: return string(); default: error("Cannot use this value in ISO-2022 string context"); return string(); } // switch } size_t Value::get_val_strlen() { Value *v = get_value_refd_last(); switch (v->valuetype) { case V_BSTR: case V_HSTR: case V_CSTR: case V_ISO2022STR: return v->u.str.val_str->size(); case V_OSTR: return v->u.str.val_str->size()/2; case V_CHARSYMS: return v->u.char_syms->get_len(); case V_USTR: return v->u.ustr.val_ustr->size(); case V_ERROR: return 0; default: error("Cannot use this value in string value context"); return 0; } // switch } Value::verdict_t Value::get_val_verdict() { switch(valuetype) { case V_VERDICT: return u.verdict; default: FATAL_ERROR("Value::get_val_verdict()"); return u.verdict; } // switch } size_t Value::get_nof_comps() { switch (valuetype) { case V_OID: case V_ROID: chk(); return u.oid_comps->size(); case V_SEQOF: case V_SETOF: case V_ARRAY: if (u.val_vs->is_indexed()) return u.val_vs->get_nof_ivs(); else return u.val_vs->get_nof_vs(); case V_SEQ: case V_SET: return u.val_nvs->get_nof_nvs(); case V_BSTR: case V_HSTR: case V_CSTR: case V_ISO2022STR: return u.str.val_str->size(); case V_OSTR: return u.str.val_str->size()/2; case V_USTR: return u.ustr.val_ustr->size(); default: FATAL_ERROR("Value::get_nof_comps()"); return 0; } // switch } bool Value::is_indexed() const { switch (valuetype) { case V_SEQOF: case V_SETOF: case V_ARRAY: // Applicable only for list-types. Assigning a record/SEQUENCE or // set/SET with indexed notation is not supported. return u.val_vs->is_indexed(); default: FATAL_ERROR("Value::is_indexed()"); break; } return false; } const Identifier& Value::get_alt_name() { if (valuetype != V_CHOICE) FATAL_ERROR("Value::get_alt_name()"); return *u.choice.alt_name; } Value *Value::get_alt_value() { if (valuetype != V_CHOICE) FATAL_ERROR("Value::get_alt_value()"); return u.choice.alt_value; } void Value::set_alt_name_to_lowercase() { if (valuetype != V_CHOICE) FATAL_ERROR("Value::set_alt_name_to_lowercase()"); string new_name = u.choice.alt_name->get_name(); if (isupper(new_name[0])) { new_name[0] = (char)tolower(new_name[0]); if (new_name[new_name.size() - 1] == '_') { // an underscore is inserted at the end of the alternative name if it's // a basic type's name (since it would conflict with the class generated // for that type) // remove the underscore, it won't conflict with anything if its name // starts with a lowercase letter new_name.replace(new_name.size() - 1, 1, ""); } delete u.choice.alt_name; u.choice.alt_name = new Identifier(Identifier::ID_NAME, new_name); } } bool Value::has_oid_error() { Value *v; if (valuetype == V_REFD) v = get_value_refd_last(); else v = this; switch (valuetype) { case V_OID: case V_ROID: for (size_t i = 0; i < v->u.oid_comps->size(); i++) if ((*v->u.oid_comps)[i]->has_error()) return true; return false; default: return true; } } bool Value::get_oid_comps(vector<string>& comps) { bool ret_val = true; Value *v = this; switch (valuetype) { case V_REFD: v = get_value_refd_last(); // no break case V_OID: case V_ROID: for (size_t i = 0; i < v->u.oid_comps->size(); i++) { (*v->u.oid_comps)[i]->get_comps(comps); if ((*v->u.oid_comps)[i]->is_variable()) { // not all components can be calculated in compile-time ret_val = false; } } break; default: FATAL_ERROR("Value::get_oid_comps()"); } return ret_val; } void Value::add_se_comp(NamedValue* nv) { switch (valuetype) { case V_SEQ: case V_SET: if (!u.val_nvs) u.val_nvs = new NamedValues(); u.val_nvs->add_nv(nv); break; default: FATAL_ERROR("Value::add_se_comp()"); } } NamedValue* Value::get_se_comp_byIndex(size_t n) { switch(valuetype) { case V_SEQ: case V_SET: return u.val_nvs->get_nv_byIndex(n); default: FATAL_ERROR("Value::get_se_comp_byIndex()"); return 0; } // switch } Value *Value::get_comp_byIndex(size_t n) { switch (valuetype) { case V_SEQOF: case V_SETOF: case V_ARRAY: if (!is_indexed()) return u.val_vs->get_v_byIndex(n); return u.val_vs->get_iv_byIndex(n)->get_value(); default: FATAL_ERROR("Value::get_comp_byIndex()"); return 0; } // switch } Value *Value::get_index_byIndex(size_t n) { switch (valuetype) { case V_SEQOF: case V_SETOF: case V_ARRAY: if (!is_indexed()) FATAL_ERROR("Value::get_index_byIndex()"); return u.val_vs->get_iv_byIndex(n)->get_index(); default: FATAL_ERROR("Value::get_index_byIndex()"); return 0; } // switch } bool Value::has_comp_withName(const Identifier& p_name) { switch(valuetype) { case V_SEQ: case V_SET: return u.val_nvs->has_nv_withName(p_name); case V_CHOICE: return u.choice.alt_name->get_dispname() == p_name.get_dispname(); default: FATAL_ERROR("Value::get_has_comp_withName()"); return false; } // switch } bool Value::field_is_chosen(const Identifier& p_name) { Value *v=get_value_refd_last(); if(v->valuetype!=V_CHOICE) FATAL_ERROR("Value::field_is_chosen()"); return *v->u.choice.alt_name==p_name; } bool Value::field_is_present(const Identifier& p_name) { Value *v=get_value_refd_last(); if(!(v->valuetype==V_SEQ || v->valuetype==V_SET)) FATAL_ERROR("Value::field_is_present()"); return v->u.val_nvs->has_nv_withName(p_name) && v->u.val_nvs->get_nv_byName(p_name)->get_value() ->get_value_refd_last()->valuetype != V_OMIT; } NamedValue* Value::get_se_comp_byName(const Identifier& p_name) { switch(valuetype) { case V_SEQ: case V_SET: return u.val_nvs->get_nv_byName(p_name); default: FATAL_ERROR("Value::get_se_comp_byName()"); return 0; } // switch } Value* Value::get_comp_value_byName(const Identifier& p_name) { switch(valuetype) { case V_SEQ: case V_SET: return u.val_nvs->get_nv_byName(p_name)->get_value(); case V_CHOICE: if(u.choice.alt_name->get_dispname() == p_name.get_dispname()) return u.choice.alt_value; else return NULL; default: FATAL_ERROR("Value::get_se_comp_byName()"); return 0; } // switch } void Value::chk_dupl_id() { switch(valuetype) { case V_SEQ: case V_SET: u.val_nvs->chk_dupl_id(); break; default: FATAL_ERROR("Value::chk_dupl_id()"); } // switch } size_t Value::get_nof_ids() const { switch(valuetype) { case V_NAMEDBITS: return u.ids->size(); break; default: FATAL_ERROR("Value::get_nof_ids()"); return 0; } // switch } Identifier* Value::get_id_byIndex(size_t p_i) { switch(valuetype) { case V_NAMEDBITS: return u.ids->get_nth_elem(p_i); break; default: FATAL_ERROR("Value::get_id_byIndex()"); return 0; } // switch } bool Value::has_id(const Identifier& p_id) { switch(valuetype) { case V_NAMEDBITS: return u.ids->has_key(p_id.get_name()); break; default: FATAL_ERROR("Value::has_id()"); return false; } // switch } Reference *Value::get_reference() const { if (valuetype != V_REFD) FATAL_ERROR("Value::get_reference()"); return u.ref.ref; } Reference *Value::get_refered() const { if (valuetype != V_REFER) FATAL_ERROR("Value::get_referred()"); return u.refered; } Common::Assignment *Value::get_refd_fat() const { switch(valuetype){ case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: return u.refd_fat; default: FATAL_ERROR("Value::get_refd_fat()"); } } Ttcn::Reference* Value::steal_ttcn_ref() { Ttcn::Reference *t_ref; if(valuetype==V_REFD) { t_ref=dynamic_cast<Ttcn::Reference*>(u.ref.ref); if(!t_ref) FATAL_ERROR("Value::steal_ttcn_ref()"); u.ref.ref=0; } else if(valuetype==V_UNDEF_LOWERID) { t_ref=new Ttcn::Reference(u.val_id); t_ref->set_location(*this); t_ref->set_fullname(get_fullname()); t_ref->set_my_scope(get_my_scope()); u.val_id=0; } else { FATAL_ERROR("Value::steal_ttcn_ref()"); t_ref = 0; } set_valuetype(V_ERROR); return t_ref; } void Value::steal_invoke_data(Value*& p_v, Ttcn::ParsedActualParameters*& p_ti, Ttcn::ActualParList*& p_ap) { if(valuetype != V_INVOKE) FATAL_ERROR("Value::steal_invoke_data()"); p_v = u.invoke.v; u.invoke.v = 0; p_ti = u.invoke.t_list; u.invoke.t_list = 0; p_ap = u.invoke.ap_list; u.invoke.ap_list = 0; set_valuetype(V_ERROR); } Common::Assignment* Value::get_refd_assignment() { switch(valuetype) { case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: return u.refd_fat; break; default: FATAL_ERROR("Value::get_refd_assignment()"); return 0; } } void Value::chk() { if(checked) return; switch(valuetype) { case V_OID: { ReferenceChain refch(this, "While checking OBJECT IDENTIFIER" " components"); chk_OID(refch); break; } case V_ROID: { ReferenceChain refch(this, "While checking RELATIVE-OID components"); chk_ROID(refch); break; } default: break; } // switch checked=true; } void Value::chk_OID(ReferenceChain& refch) { if (checked) return; if (valuetype != V_OID || u.oid_comps->size() < 1) FATAL_ERROR("Value::chk_OID()"); if (!refch.add(get_fullname())) { checked = true; return; } OID_comp::oidstate_t state = OID_comp::START; for (size_t i = 0; i < u.oid_comps->size(); i++) { refch.mark_state(); (*u.oid_comps)[i]->chk_OID(refch, this, i, state); refch.prev_state(); } if (state != OID_comp::LATER && state != OID_comp::ITU_REC) error("An OBJECT IDENTIFIER value must have at least " "two components"); // X.680 (07/2002) 31.10 } void Value::chk_ROID(ReferenceChain& refch) { if (checked) return; if (valuetype != V_ROID || u.oid_comps->size() < 1) FATAL_ERROR("Value::chk_ROID()"); if (!refch.add(get_fullname())) { checked = true; return; } for (size_t i = 0; i < u.oid_comps->size(); i++) { refch.mark_state(); (*u.oid_comps)[i]->chk_ROID(refch, i); refch.prev_state(); } } void Value::chk_recursions(ReferenceChain& refch) { if (recurs_checked) return; Value *v = get_value_refd_last(); if (refch.add(v->get_fullname())) { switch (v->valuetype) { case V_CHOICE: v->u.choice.alt_value->chk_recursions(refch); break; case V_SEQOF: case V_SETOF: case V_ARRAY: if (!v->is_indexed()) { for (size_t i = 0; i < v->u.val_vs->get_nof_vs(); i++) { refch.mark_state(); v->u.val_vs->get_v_byIndex(i)->chk_recursions(refch); refch.prev_state(); } } else { for (size_t i = 0; i < v->u.val_vs->get_nof_ivs(); i++) { refch.mark_state(); v->u.val_vs->get_iv_byIndex(i)->get_value() ->chk_recursions(refch); refch.prev_state(); } } break; case V_SEQ: case V_SET: for (size_t i = 0; i < v->u.val_nvs->get_nof_nvs(); i++) { refch.mark_state(); v->u.val_nvs->get_nv_byIndex(i)->get_value()->chk_recursions(refch); refch.prev_state(); } break; case V_EXPR: chk_recursions_expr(refch); break; default: break; } if (v->err_descrs) { // FIXME: make this work v->err_descrs->chk_recursions(refch); } } recurs_checked = true; } void Value::chk_recursions_expr(ReferenceChain& refch) { // first classify the unchecked ischosen() operation if (u.expr.v_optype==OPTYPE_ISCHOSEN) chk_expr_ref_ischosen(); switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_ENUM2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_RNDWITHVAL: case OPTYPE_ISCHOSEN_V: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: refch.mark_state(); u.expr.v1->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_ISCHOSEN_T: refch.mark_state(); u.expr.t1->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_HOSTID: // [v1] if (u.expr.v1) { refch.mark_state(); u.expr.v1->chk_recursions(refch); refch.prev_state(); } break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: refch.mark_state(); u.expr.v1->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.v2->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: refch.mark_state(); u.expr.v1->chk_recursions(refch); refch.prev_state(); if (u.expr.v2) { refch.mark_state(); u.expr.v2->chk_recursions(refch); refch.prev_state(); } break; case OPTYPE_DECODE: chk_recursions_expr_decode(u.expr.r1, refch); chk_recursions_expr_decode(u.expr.r2, refch); if (u.expr.v3 != NULL) { refch.mark_state(); u.expr.v3->chk_recursions(refch); refch.prev_state(); } if (u.expr.v4 != NULL) { refch.mark_state(); u.expr.v4->chk_recursions(refch); refch.prev_state(); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: refch.mark_state(); u.expr.ti1->chk_recursions(refch); refch.prev_state(); if (u.expr.v2 != NULL) { refch.mark_state(); u.expr.v2->chk_recursions(refch); refch.prev_state(); } if (u.expr.v3 != NULL) { refch.mark_state(); u.expr.v3->chk_recursions(refch); refch.prev_state(); } break; case OPTYPE_REGEXP: refch.mark_state(); u.expr.ti1->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.t2->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.v3->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_DECOMP: // v1 v2 v3 refch.mark_state(); u.expr.v1->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.v2->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.v3->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_REPLACE: refch.mark_state(); u.expr.ti1->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.v2->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.v3->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.ti4->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_VALUEOF: // ti1 [subrefs2] if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { refch.mark_state(); subref->get_val()->chk_recursions(refch); refch.prev_state(); } } } // fall through case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: refch.mark_state(); u.expr.ti1->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] refch.mark_state(); u.expr.ti1->chk_recursions(refch); refch.prev_state(); if (u.expr.v2){ refch.mark_state(); u.expr.v2->chk_recursions(refch); refch.prev_state(); } if (u.expr.v3 != NULL) { refch.mark_state(); u.expr.v3->chk_recursions(refch); refch.prev_state(); } if (u.expr.v4 != NULL) { refch.mark_state(); u.expr.v4->chk_recursions(refch); refch.prev_state(); } break; case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] chk_recursions_expr_decode(u.expr.r1, refch); chk_recursions_expr_decode(u.expr.r2, refch); if (u.expr.v3 != NULL) { refch.mark_state(); u.expr.v3->chk_recursions(refch); refch.prev_state(); } if (u.expr.v4 != NULL) { refch.mark_state(); u.expr.v4->chk_recursions(refch); refch.prev_state(); } if (u.expr.v5 != NULL) { refch.mark_state(); u.expr.v5->chk_recursions(refch); refch.prev_state(); } break; case OPTYPE_MATCH: // v1 t2 refch.mark_state(); u.expr.v1->chk_recursions(refch); refch.prev_state(); refch.mark_state(); u.expr.t2->chk_recursions(refch); refch.prev_state(); break; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: u.expr.logargs->chk_recursions(refch); break; default: break; } // switch } void Value::chk_recursions_expr_decode(Ttcn::Reference* ref, ReferenceChain& refch) { Error_Context cntxt(this, "In the operand of operation `%s'", get_opname()); Assignment *ass = ref->get_refd_assignment(); if (!ass) { set_valuetype(V_ERROR); return; } switch (ass->get_asstype()) { case Assignment::A_CONST: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: { Value* v = new Value(V_REFD, ref); v->set_location(*ref); v->set_my_scope(get_my_scope()); v->set_fullname(get_fullname()+".<operand>"); refch.mark_state(); v->chk_recursions(refch); refch.prev_state(); delete v; break; } case Assignment::A_MODULEPAR_TEMP: case Assignment::A_TEMPLATE: case Assignment::A_VAR_TEMPLATE: case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: { Template* t = new Template(Template::TEMPLATE_REFD, ref->clone()); t->set_location(*ref); t->set_my_scope(get_my_scope()); t->set_fullname(get_fullname()+".<operand>"); refch.mark_state(); t->chk_recursions(refch); refch.prev_state(); delete t; break; } default: // remain silent, the error has been already reported set_valuetype(V_ERROR); break; } // switch } bool Value::chk_expr_self_ref_templ(Ttcn::Template *t, Common::Assignment *lhs, namedbool class_member_init) { bool self_ref = false; switch (t->get_templatetype()) { case Ttcn::Template::SPECIFIC_VALUE: { Value *v = t->get_specific_value(); self_ref |= v->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE) ->chk_this_value(v, lhs, Type::EXPECTED_DYNAMIC_VALUE, INCOMPLETE_NOT_ALLOWED, OMIT_ALLOWED, NO_SUB_CHK, NOT_IMPLICIT_OMIT, NOT_STR_ELEM, class_member_init); break; } case Ttcn::Template::TEMPLATE_REFD: { if (lhs != NULL) { Ttcn::Reference *refb = t->get_reference(); Common::Assignment *ass = refb->get_refd_assignment(); self_ref |= (ass == lhs); } break; } case Ttcn::Template::ALL_FROM: self_ref |= chk_expr_self_ref_templ(t->get_all_from(), lhs, class_member_init); break; case Ttcn::Template::TEMPLATE_LIST: case Ttcn::Template::SUPERSET_MATCH: case Ttcn::Template::SUBSET_MATCH: case Ttcn::Template::PERMUTATION_MATCH: case Ttcn::Template::COMPLEMENTED_LIST: case Ttcn::Template::VALUE_LIST: { size_t num = t->get_nof_comps(); for (size_t i = 0; i < num; ++i) { self_ref |= chk_expr_self_ref_templ(t->get_temp_byIndex(i), lhs, class_member_init); } break; } // not yet clear whether we should use this or the above for TEMPLATE_LIST // case Ttcn::Template::TEMPLATE_LIST: { // size_t num = t->get_nof_listitems(); // for (size_t i=0; i < num; ++i) { // self_ref |= chk_expr_self_ref_templ(t->get_listitem_byIndex(i), lhs); // } // break; } case Ttcn::Template::NAMED_TEMPLATE_LIST: { size_t nnt = t->get_nof_comps(); for (size_t i=0; i < nnt; ++i) { Ttcn::NamedTemplate *nt = t->get_namedtemp_byIndex(i); self_ref |= chk_expr_self_ref_templ(nt->get_template(), lhs, class_member_init); } break; } case Ttcn::Template::INDEXED_TEMPLATE_LIST: { size_t nnt = t->get_nof_comps(); for (size_t i=0; i < nnt; ++i) { Ttcn::IndexedTemplate *it = t->get_indexedtemp_byIndex(i); self_ref |= chk_expr_self_ref_templ(it->get_template(), lhs, class_member_init); } break; } case Ttcn::Template::VALUE_RANGE: { Ttcn::ValueRange *vr = t->get_value_range(); Common::Value *v = vr->get_min_v(); if (v) self_ref |= chk_expr_self_ref_val(v, lhs, class_member_init); v = vr->get_max_v(); if (v) self_ref |= chk_expr_self_ref_val(v, lhs, class_member_init); break; } case Ttcn::Template::CSTR_PATTERN: case Ttcn::Template::USTR_PATTERN: { Ttcn::PatternString *ps = t->get_cstr_pattern(); self_ref |= ps->chk_self_ref(lhs); break; } case Ttcn::Template::BSTR_PATTERN: case Ttcn::Template::HSTR_PATTERN: case Ttcn::Template::OSTR_PATTERN: { // FIXME: cannot access u.pattern break; } case Ttcn::Template::ANY_VALUE: case Ttcn::Template::ANY_OR_OMIT: case Ttcn::Template::OMIT_VALUE: case Ttcn::Template::TEMPLATE_NOTUSED: 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, class_member_init); break; case Ttcn::Template::TEMPLATE_ERROR: //FATAL_ERROR("Value::chk_expr_self_ref_templ()"); break; case Ttcn::Template::TEMPLATE_CONCAT: self_ref |= chk_expr_self_ref_templ(t->get_concat_operand(true), lhs, class_member_init); self_ref |= chk_expr_self_ref_templ(t->get_concat_operand(false), lhs, class_member_init); break; // default: // FATAL_ERROR("todo ttype %d", t->get_templatetype()); // break; // and hope for the best } return self_ref; } bool Value::chk_expr_self_ref_val(Common::Value *v, Common::Assignment *lhs, namedbool class_member_init) { Common::Type *gov = v->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE); namedbool is_str_elem = NOT_STR_ELEM; if (v->valuetype == V_REFD) { Reference *ref = v->get_reference(); Ttcn::FieldOrArrayRefs *subrefs = ref->get_subrefs(); if (subrefs && subrefs->refers_to_string_element()) { is_str_elem = IS_STR_ELEM; } } return gov->chk_this_value(v, lhs, Type::EXPECTED_DYNAMIC_VALUE, INCOMPLETE_NOT_ALLOWED, OMIT_ALLOWED, NO_SUB_CHK, NOT_IMPLICIT_OMIT, is_str_elem, class_member_init); } bool Value::chk_expr_self_ref(Common::Assignment *lhs, namedbool class_member_init) { if (valuetype != V_EXPR) FATAL_ERROR("Value::chk_expr_self_ref"); bool self_ref = false; switch (u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_TESTCASENAME: // - case OPTYPE_COMP_NULL: // - (from V_TTCN3_NULL) case OPTYPE_COMP_MTC: // - case OPTYPE_COMP_SYSTEM: // - case OPTYPE_COMP_SELF: // - case OPTYPE_COMP_RUNNING_ANY: // - case OPTYPE_COMP_RUNNING_ALL: // - case OPTYPE_COMP_ALIVE_ANY: // - case OPTYPE_COMP_ALIVE_ALL: // - case OPTYPE_TMR_RUNNING_ANY: // - case OPTYPE_GETVERDICT: // - case OPTYPE_PROF_RUNNING: // - case OPTYPE_GET_PORT_REF: // - case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: case OPTYPE_NOW: // - break; // nothing to do case OPTYPE_MATCH: // v1 t2 self_ref |= chk_expr_self_ref_templ(u.expr.t2->get_Template(), lhs, class_member_init); // no break case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: // v1 case OPTYPE_NOT: // v1 case OPTYPE_NOT4B: // v1 case OPTYPE_BIT2HEX: // v1 case OPTYPE_BIT2INT: // v1 case OPTYPE_BIT2OCT: // v1 case OPTYPE_BIT2STR: // v1 case OPTYPE_BSON2JSON: // v1 case OPTYPE_CBOR2JSON: // v1 case OPTYPE_CHAR2INT: // v1 case OPTYPE_CHAR2OCT: // v1 case OPTYPE_FLOAT2INT: // v1 case OPTYPE_FLOAT2STR: // v1 case OPTYPE_HEX2BIT: // v1 case OPTYPE_HEX2INT: // v1 case OPTYPE_HEX2OCT: // v1 case OPTYPE_HEX2STR: // v1 case OPTYPE_INT2CHAR: // v1 case OPTYPE_INT2FLOAT: // v1 case OPTYPE_INT2STR: // v1 case OPTYPE_INT2UNICHAR: // v1 case OPTYPE_JSON2BSON: // v1 case OPTYPE_JSON2CBOR: // v1 case OPTYPE_OCT2BIT: // v1 case OPTYPE_OCT2CHAR: // v1 case OPTYPE_OCT2HEX: // v1 case OPTYPE_OCT2INT: // v1 case OPTYPE_OCT2STR: // v1 case OPTYPE_STR2BIT: // v1 case OPTYPE_STR2FLOAT: // v1 case OPTYPE_STR2HEX: // v1 case OPTYPE_STR2INT: // v1 case OPTYPE_STR2OCT: // v1 case OPTYPE_UNICHAR2INT: // v1 case OPTYPE_UNICHAR2CHAR: // v1 case OPTYPE_ENUM2INT: // v1 case OPTYPE_RNDWITHVAL: // v1 case OPTYPE_ISCHOSEN_V: // v1 i2; ignore the identifier case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: case OPTYPE_REMOVE_BOM: self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: // v1 [r2] b4 self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); if (u.expr.r2 != NULL && lhs != NULL) { Common::Assignment *ass = u.expr.r2->get_refd_assignment(); self_ref |= (ass == lhs); } break; case OPTYPE_HOSTID: // [v1] if (u.expr.v1) self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: // v1 v2 case OPTYPE_MULTIPLY: // v1 v2 case OPTYPE_DIVIDE: // v1 v2 case OPTYPE_MOD: // v1 v2 case OPTYPE_REM: // v1 v2 case OPTYPE_CONCAT: // v1 v2 case OPTYPE_EQ: // v1 v2 case OPTYPE_LT: // v1 v2 case OPTYPE_GT: // v1 v2 case OPTYPE_NE: // v1 v2 case OPTYPE_GE: // v1 v2 case OPTYPE_LE: // v1 v2 case OPTYPE_AND: // v1 v2 case OPTYPE_OR: // v1 v2 case OPTYPE_XOR: // v1 v2 case OPTYPE_AND4B: // v1 v2 case OPTYPE_OR4B: // v1 v2 case OPTYPE_XOR4B: // v1 v2 case OPTYPE_SHL: // v1 v2 case OPTYPE_SHR: // v1 v2 case OPTYPE_ROTL: // v1 v2 case OPTYPE_ROTR: // v1 v2 case OPTYPE_INT2BIT: // v1 v2 case OPTYPE_INT2HEX: // v1 v2 case OPTYPE_INT2OCT: // v1 v2 self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); if (u.expr.v2) self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); break; case OPTYPE_DECOMP: // v1 v2 v3 self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); break; case OPTYPE_REPLACE: // ti1 v2 v3 ti4 self_ref |= chk_expr_self_ref_templ(u.expr.ti4->get_Template(), lhs, class_member_init); // no break case OPTYPE_SUBSTR: // ti1 v2 v3 case OPTYPE_ENCODE: // ti1 [v2] [v3] self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); if (u.expr.v2 != NULL) { self_ref |= chk_expr_self_ref_val (u.expr.v2, lhs, class_member_init); } if (u.expr.v3 != NULL) { self_ref |= chk_expr_self_ref_val (u.expr.v3, lhs, class_member_init); } break; case OPTYPE_REGEXP: // ti1 t2 v3 self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); self_ref |= chk_expr_self_ref_templ(u.expr.t2 ->get_Template(), lhs, class_member_init); break; case OPTYPE_VALUEOF: // ti1 [subrefs2] if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { self_ref |= chk_expr_self_ref_val(subref->get_val(), lhs, class_member_init); } } } // fall through case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_TTCN2STRING: self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); if (u.expr.v2 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); } if (u.expr.v3 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } if (u.expr.v4 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs, class_member_init); } break; case OPTYPE_DECVALUE_UNICHAR: { // r1 r2 [v3] [v4] [v5] if (lhs != NULL) { Common::Assignment *ass = u.expr.r2->get_refd_assignment(); self_ref |= (ass == lhs); } if (u.expr.v3 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } if (u.expr.v4 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs, class_member_init); } if (u.expr.v5 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v5, lhs, class_member_init); } goto label_r1; break; } case OPTYPE_UNDEF_CREATE: // r1 t_list2 b4 case OPTYPE_CLASS_CREATE: // r1 t_list2 // no self-ref? case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 // component.create -- assume no self-ref case OPTYPE_ACTIVATE: // r1 // defaultref := activate(altstep) -- assume no self-ref case OPTYPE_TMR_RUNNING: // r1 // boolvar := a_timer.running -- assume no self-ref break; case OPTYPE_ANY2UNISTR: case OPTYPE_LOG2STR: {// logargs for (size_t i = 0, e = u.expr.logargs->get_nof_logargs(); i < e; ++i) { const Ttcn::LogArgument *la = u.expr.logargs->get_logarg_byIndex(i); switch (la->get_type()) { case Ttcn::LogArgument::L_UNDEF: case Ttcn::LogArgument::L_ERROR: case Ttcn::LogArgument::L_MACRO: case Ttcn::LogArgument::L_STR: break; // self reference not possible case Ttcn::LogArgument::L_VAL: case Ttcn::LogArgument::L_MATCH: self_ref |= chk_expr_self_ref_val(la->get_val(), lhs, class_member_init); break; case Ttcn::LogArgument::L_REF: { if (lhs != NULL) { Ttcn::Reference *ref = la->get_ref(); Common::Assignment *ass = ref->get_refd_assignment(); self_ref |= (ass == lhs); } break; } case Ttcn::LogArgument::L_TI: { Ttcn::TemplateInstance *ti = la->get_ti(); Ttcn::Template *t = ti->get_Template(); self_ref |= chk_expr_self_ref_templ(t, lhs, class_member_init); break; } // no default please } // switch la->logargtype } break; } case OPTYPE_DECODE: { // r1 r2 if (lhs != NULL) { Common::Assignment *ass = u.expr.r2->get_refd_assignment(); self_ref |= (ass == lhs); } if (u.expr.v3 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } if (u.expr.v4 != NULL) { self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs, class_member_init); } goto label_r1; } case OPTYPE_EXECUTE: // r1 [v2] if (u.expr.v2) { self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); } label_r1: // no break case OPTYPE_TMR_READ: { // r1 if (lhs != NULL) { Common::Assignment *ass = u.expr.r1->get_refd_assignment(); self_ref |= (ass == lhs); } break; } case OPTYPE_UNDEF_RUNNING: { // r1 [r2] b4 if (lhs != NULL) { if (u.expr.r2 != NULL) { Common::Assignment *ass2 = u.expr.r2->get_refd_assignment(); self_ref |= (ass2 == lhs); } Common::Assignment *ass = u.expr.r1->get_refd_assignment(); self_ref |= (ass == lhs); } break; } case OPTYPE_ISCHOSEN_T: // t1 i2 case OPTYPE_ISBOUND: // ti1 case OPTYPE_ISVALUE: // ti1 case OPTYPE_ISPRESENT: { // ti1 Ttcn::Template *t; if (u.expr.v_optype == OPTYPE_ISCHOSEN_T) t = u.expr.t1; else t = u.expr.ti1->get_Template(); self_ref |= chk_expr_self_ref_templ(t, lhs, class_member_init); break; } case OPTYPE_ISTEMPLATEKIND: // ti1 v2 self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); break; case OPTYPE_EXECUTE_REFD: // v1 t_list2 [v3] if (u.expr.v3) { self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } // no break case OPTYPE_ACTIVATE_REFD: // v1 t_list2 self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); // TODO t_list2 break; case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: { if (lhs != NULL) { Common::Assignment *ass = u.expr.r2->get_refd_assignment(); self_ref |= (ass == lhs); } break; } case NUMBER_OF_OPTYPES: // can never happen case OPTYPE_ISCHOSEN: // r1 i2, should have been classified as _T or _V case OPTYPE_CLASS_CASTING_REF: FATAL_ERROR("Value::chk_expr_self_ref(%d)", u.expr.v_optype); break; } // switch u.expr.v_optype return self_ref; } string Value::create_stringRepr() { // note: cannot call is_asn1() when only parsing (scopes are not properly set) switch (valuetype) { case V_ERROR: return string("<erroneous>"); case V_NULL: return string("NULL"); case V_BOOL: if (!parse_only && is_asn1()) { if (u.val_bool) return string("TRUE"); else return string("FALSE"); } else { if (u.val_bool) return string("true"); else return string("false"); } case V_INT: return u.val_Int->t_str(); case V_REAL: return Real2string(u.val_Real); case V_ENUM: case V_NAMEDINT: case V_UNDEF_LOWERID: return u.val_id->get_name(); case V_NAMEDBITS: { string ret_val("{ "); for (size_t i = 0; i < u.ids->size(); i++) { if (i>0) ret_val += ' '; ret_val += u.ids->get_nth_elem(i)->get_dispname(); } ret_val += '}'; return ret_val; } case V_BSTR: { string ret_val('\''); ret_val += *u.str.val_str; ret_val += "'B"; return ret_val; } case V_HSTR: { string ret_val('\''); ret_val += *u.str.val_str; ret_val += "'H"; return ret_val; } case V_OSTR: { string ret_val('\''); ret_val += *u.str.val_str; ret_val += "'O"; return ret_val; } case V_CSTR: case V_ISO2022STR: return u.str.val_str->get_stringRepr(); case V_USTR: return u.ustr.val_ustr->get_stringRepr(); case V_CHARSYMS: /** \todo stringrepr of V_CHARSYMS */ return string("<sorry, string representation of charsyms " "not implemented>"); case V_OID: case V_ROID: { string ret_val; if (parse_only || !is_asn1()) ret_val += "objid "; ret_val += "{ "; for (size_t i = 0; i < u.oid_comps->size(); i++) { if (i>0) ret_val += ' '; (*u.oid_comps)[i]->append_stringRepr(ret_val); } ret_val += " }"; return ret_val; } case V_CHOICE: if (!parse_only && is_asn1()) { string ret_val(u.choice.alt_name->get_dispname()); ret_val += " : "; ret_val += u.choice.alt_value->get_stringRepr(); return ret_val; } else { string ret_val("{ "); ret_val += u.choice.alt_name->get_dispname(); ret_val += " := "; ret_val += u.choice.alt_value->get_stringRepr(); ret_val += " }"; return ret_val; } case V_SEQOF: case V_SETOF: case V_ARRAY: { string ret_val("{ "); if (!is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_vs(); i++) { if (i > 0) ret_val += ", "; ret_val += u.val_vs->get_v_byIndex(i)->get_stringRepr(); } } else { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) { if (i > 0) ret_val += ", "; ret_val += u.val_vs->get_iv_byIndex(i)->get_value()->get_stringRepr(); } } ret_val += " }"; return ret_val; } case V_SEQ: case V_SET: { string ret_val("{ "); bool asn1_flag = !parse_only && is_asn1(); for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); i++) { if (i > 0) ret_val += ", "; NamedValue *nv = u.val_nvs->get_nv_byIndex(i); ret_val += nv->get_name().get_dispname(); if (asn1_flag) ret_val += ' '; else ret_val += " := "; ret_val += nv->get_value()->get_stringRepr(); } ret_val += " }"; return ret_val; } case V_REFD: { // do not evaluate the reference if it is not done so far // (e.g. in parse-only mode) Value *t_val = u.ref.refd_last ? u.ref.refd_last : this; if (t_val->valuetype == V_REFD) return t_val->u.ref.ref->get_dispname(); else return t_val->get_stringRepr(); } case V_OMIT: return string("omit"); case V_VERDICT: switch (u.verdict) { case Verdict_NONE: return string("none"); case Verdict_PASS: return string("pass"); case Verdict_INCONC: return string("inconc"); case Verdict_FAIL: return string("fail"); case Verdict_ERROR: return string("error"); default: return string("<unknown verdict value>"); } case V_DEFAULT_NULL: case V_FAT_NULL: return string("null"); case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_RND: return string("rnd()"); case OPTYPE_TESTCASENAME: return string("testcasename()"); case OPTYPE_NOW: return string("now"); case OPTYPE_UNARYPLUS: return create_stringRepr_unary("+"); case OPTYPE_UNARYMINUS: return create_stringRepr_unary("-"); case OPTYPE_NOT: return create_stringRepr_unary("not"); case OPTYPE_NOT4B: return create_stringRepr_unary("not4b"); case OPTYPE_BIT2HEX: return create_stringRepr_predef1("bit2hex"); case OPTYPE_BIT2INT: return create_stringRepr_predef1("bit2int"); case OPTYPE_BIT2OCT: return create_stringRepr_predef1("bit2oct"); case OPTYPE_BIT2STR: return create_stringRepr_predef1("bit2str"); case OPTYPE_BSON2JSON: return create_stringRepr_predef1("bson2json"); case OPTYPE_CBOR2JSON: return create_stringRepr_predef1("cbor2json"); case OPTYPE_CHAR2INT: return create_stringRepr_predef1("char2int"); case OPTYPE_CHAR2OCT: return create_stringRepr_predef1("char2oct"); case OPTYPE_FLOAT2INT: return create_stringRepr_predef1("float2int"); case OPTYPE_FLOAT2STR: return create_stringRepr_predef1("float2str"); case OPTYPE_HEX2BIT: return create_stringRepr_predef1("hex2bit"); case OPTYPE_HEX2INT: return create_stringRepr_predef1("hex2int"); case OPTYPE_HEX2OCT: return create_stringRepr_predef1("hex2oct"); case OPTYPE_HEX2STR: return create_stringRepr_predef1("hex2str"); case OPTYPE_INT2CHAR: return create_stringRepr_predef1("int2char"); case OPTYPE_INT2FLOAT: return create_stringRepr_predef1("int2float"); case OPTYPE_INT2STR: return create_stringRepr_predef1("int2str"); case OPTYPE_JSON2BSON: return create_stringRepr_predef1("json2bson"); case OPTYPE_JSON2CBOR: return create_stringRepr_predef1("json2cbor"); case OPTYPE_INT2UNICHAR: return create_stringRepr_predef1("int2unichar"); case OPTYPE_OCT2BIT: return create_stringRepr_predef1("oct2bit"); case OPTYPE_OCT2CHAR: return create_stringRepr_predef1("oct2char"); case OPTYPE_OCT2HEX: return create_stringRepr_predef1("oct2hex"); case OPTYPE_OCT2INT: return create_stringRepr_predef1("oct2int"); case OPTYPE_OCT2STR: return create_stringRepr_predef1("oct2str"); case OPTYPE_GET_STRINGENCODING: return create_stringRepr_predef1("get_stringencoding"); case OPTYPE_REMOVE_BOM: return create_stringRepr_predef1("remove_bom"); case OPTYPE_ENCODE_BASE64: { if (u.expr.v2) return create_stringRepr_predef2("encode_base64"); else return create_stringRepr_predef1("encode_base64"); } case OPTYPE_DECODE_BASE64: return create_stringRepr_predef1("decode_base64"); case OPTYPE_OCT2UNICHAR:{ if (u.expr.v2) return create_stringRepr_predef2("oct2unichar"); else return create_stringRepr_predef1("oct2unichar"); } case OPTYPE_UNICHAR2OCT: { if (u.expr.v2) return create_stringRepr_predef2("unichar2oct"); else return create_stringRepr_predef1("unichar2oct"); } case OPTYPE_ENCVALUE_UNICHAR: { string ret_val("encvalue_unichar("); u.expr.ti1->append_stringRepr(ret_val); if (u.expr.v2 != NULL) { ret_val += ", "; ret_val += u.expr.v2->get_stringRepr(); if (u.expr.v3 != NULL) { ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); if (u.expr.v4 != NULL) { ret_val += ", "; ret_val += u.expr.v4->get_stringRepr(); } } } ret_val += ')'; return ret_val; } case OPTYPE_HOSTID: { if (u.expr.v1) return create_stringRepr_predef1("hostid"); else return string("hostid()"); } case OPTYPE_DECVALUE_UNICHAR: { string ret_val("decvalue_unichar("); ret_val += u.expr.r1->get_dispname(); ret_val += ", "; ret_val += u.expr.r2->get_dispname(); if (u.expr.v3 != NULL) { ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); if (u.expr.v4 != NULL) { ret_val += ", "; ret_val += u.expr.v4->get_stringRepr(); if (u.expr.v5 != NULL) { ret_val += ", "; ret_val += u.expr.v5->get_stringRepr(); } } } ret_val += ')'; return ret_val; } case OPTYPE_STR2BIT: return create_stringRepr_predef1("str2bit"); case OPTYPE_STR2FLOAT: return create_stringRepr_predef1("str2float"); case OPTYPE_STR2HEX: return create_stringRepr_predef1("str2hex"); case OPTYPE_STR2INT: return create_stringRepr_predef1("str2int"); case OPTYPE_STR2OCT: return create_stringRepr_predef1("str2oct"); case OPTYPE_UNICHAR2INT: return create_stringRepr_predef1("unichar2int"); case OPTYPE_UNICHAR2CHAR: return create_stringRepr_predef1("unichar2char"); case OPTYPE_ENUM2INT: return create_stringRepr_predef1("enum2int"); case OPTYPE_ENCODE: { string ret_val("encvalue("); u.expr.ti1->append_stringRepr(ret_val); if (u.expr.v2 != NULL) { ret_val += ", "; ret_val += u.expr.v2->get_stringRepr(); if (u.expr.v3 != NULL) { ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); } } ret_val += ')'; return ret_val; } case OPTYPE_DECODE: { string ret_val("decvalue("); ret_val += u.expr.r1->get_dispname(); ret_val += ", "; ret_val += u.expr.r2->get_dispname(); if (u.expr.v3 != NULL) { ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); if (u.expr.v4 != NULL) { ret_val += ", "; ret_val += u.expr.v4->get_stringRepr(); } } ret_val += ')'; return ret_val; } case OPTYPE_RNDWITHVAL: return create_stringRepr_predef1("rnd"); case OPTYPE_ADD: return create_stringRepr_infix("+"); case OPTYPE_SUBTRACT: return create_stringRepr_infix("-"); case OPTYPE_MULTIPLY: return create_stringRepr_infix("*"); case OPTYPE_DIVIDE: return create_stringRepr_infix("/"); case OPTYPE_MOD: return create_stringRepr_infix("mod"); case OPTYPE_REM: return create_stringRepr_infix("rem"); case OPTYPE_CONCAT: return create_stringRepr_infix("&"); case OPTYPE_EQ: return create_stringRepr_infix("=="); case OPTYPE_LT: return create_stringRepr_infix("<"); case OPTYPE_GT: return create_stringRepr_infix(">"); case OPTYPE_NE: return create_stringRepr_infix("!="); case OPTYPE_GE: return create_stringRepr_infix(">="); case OPTYPE_LE: return create_stringRepr_infix("<="); case OPTYPE_AND: return create_stringRepr_infix("and"); case OPTYPE_OR: return create_stringRepr_infix("or"); case OPTYPE_XOR: return create_stringRepr_infix("xor"); case OPTYPE_AND4B: return create_stringRepr_infix("and4b"); case OPTYPE_OR4B: return create_stringRepr_infix("or4b"); case OPTYPE_XOR4B: return create_stringRepr_infix("xor4b"); case OPTYPE_SHL: return create_stringRepr_infix("<<"); case OPTYPE_SHR: return create_stringRepr_infix(">>"); case OPTYPE_ROTL: return create_stringRepr_infix("<@"); case OPTYPE_ROTR: return create_stringRepr_infix("@>"); case OPTYPE_INT2BIT: return create_stringRepr_predef2("int2bit"); case OPTYPE_INT2HEX: return create_stringRepr_predef2("int2hex"); case OPTYPE_INT2OCT: return create_stringRepr_predef2("int2oct"); case OPTYPE_SUBSTR: { string ret_val("substr("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ", "; ret_val += u.expr.v2->get_stringRepr(); ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); ret_val += ')'; return ret_val; } case OPTYPE_REGEXP: { string ret_val("regexp"); if (u.expr.b4) { ret_val += " @nocase "; } ret_val += "("; u.expr.ti1->append_stringRepr(ret_val); ret_val += ", "; u.expr.t2->append_stringRepr(ret_val); ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); ret_val += ')'; return ret_val; } case OPTYPE_DECOMP: { string ret_val("decomp("); ret_val += u.expr.v1->get_stringRepr(); ret_val += ", "; ret_val += u.expr.v2->get_stringRepr(); ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); ret_val += ')'; return ret_val; } case OPTYPE_REPLACE: { string ret_val("replace("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ", "; ret_val += u.expr.v2->get_stringRepr(); ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); ret_val += ", "; u.expr.ti4->append_stringRepr(ret_val); ret_val += ')'; return ret_val; } case OPTYPE_ISPRESENT: { string ret_val("ispresent("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ')'; return ret_val; } case OPTYPE_ISCHOSEN: { string ret_val("ischosen("); ret_val += u.expr.r1->get_dispname(); ret_val += '.'; ret_val += u.expr.i2->get_dispname(); ret_val += ')'; return ret_val; } case OPTYPE_ISCHOSEN_V: { string ret_val("ischosen("); ret_val += u.expr.v1->get_stringRepr(); ret_val += '.'; ret_val += u.expr.i2->get_dispname(); ret_val += ')'; return ret_val; } case OPTYPE_ISCHOSEN_T: { string ret_val("ischosen("); ret_val += u.expr.t1->get_stringRepr(); ret_val += '.'; ret_val += u.expr.i2->get_dispname(); ret_val += ')'; return ret_val; } case OPTYPE_LENGTHOF: { string ret_val("lengthof("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ')'; return ret_val; } case OPTYPE_SIZEOF: { string ret_val("sizeof("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ')'; return ret_val; } case OPTYPE_ISVALUE: { string ret_val("isvalue("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ')'; return ret_val; } case OPTYPE_VALUEOF: { string ret_val("valueof("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ')'; if (u.expr.subrefs2 != NULL) { u.expr.subrefs2->append_stringRepr(ret_val); } return ret_val; } case OPTYPE_LOG2STR: return string("log2str(...)"); case OPTYPE_ANY2UNISTR: return string("any2unistr(...)"); case OPTYPE_MATCH: { string ret_val("match("); ret_val += u.expr.v1->get_stringRepr(); ret_val += ", "; u.expr.t2->append_stringRepr(ret_val); ret_val += ')'; return ret_val; } case OPTYPE_TTCN2STRING: { string ret_val("ttcn2string("); u.expr.ti1->append_stringRepr(ret_val); ret_val += ')'; return ret_val; } case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_UNDEF_RUNNING: // r1 [r2] b4 case OPTYPE_TMR_RUNNING: // r1 [r2] b4 case OPTYPE_COMP_ALIVE: { // v1 [r2] b4 string ret_val; if (u.expr.b4) { ret_val = "any from "; } ret_val += (u.expr.v_optype == OPTYPE_COMP_RUNNING || u.expr.v_optype == OPTYPE_COMP_ALIVE) ? u.expr.v1->get_stringRepr() : u.expr.r1->get_dispname(); ret_val += u.expr.v_optype == OPTYPE_COMP_ALIVE ? ".alive" : ".running"; if (u.expr.r2 != NULL) { ret_val += " -> @index value " + u.expr.r2->get_dispname(); } return ret_val; } case OPTYPE_COMP_NULL: return string("null"); case OPTYPE_COMP_MTC: return string("mtc"); case OPTYPE_COMP_SYSTEM: return string("system"); case OPTYPE_COMP_SELF: return string("self"); case OPTYPE_UNDEF_CREATE: case OPTYPE_CLASS_CREATE: { string ret_val(u.expr.r1->get_dispname()); ret_val += ".create"; if (u.expr.t_list2->get_nof_tis() != 0) { ret_val += '('; for (size_t i = 0; i < u.expr.t_list2->get_nof_tis(); ++i) { if (i > 0) { ret_val += ", "; } u.expr.t_list2->get_ti_byIndex(i)->append_stringRepr(ret_val); } ret_val += ')'; } if (u.expr.v_optype == OPTYPE_UNDEF_CREATE && u.expr.b4) { ret_val += " alive"; } return ret_val; } case OPTYPE_COMP_CREATE: { string ret_val(u.expr.r1->get_dispname()); ret_val += ".create"; if (u.expr.v2 || u.expr.v3) { ret_val += '('; if (u.expr.v2) ret_val += u.expr.v2->get_stringRepr(); else ret_val += '-'; if (u.expr.v3) { ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); } ret_val += ')'; } if (u.expr.b4) ret_val += " alive"; return ret_val; } case OPTYPE_COMP_RUNNING_ANY: return string("any component.running"); case OPTYPE_COMP_RUNNING_ALL: return string("all component.running"); case OPTYPE_COMP_ALIVE_ANY: return string("any component.alive"); case OPTYPE_COMP_ALIVE_ALL: return string("all component.alive"); case OPTYPE_TMR_READ: return u.expr.r1->get_dispname() + ".read"; case OPTYPE_TMR_RUNNING_ANY: return string("any timer.running"); case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: { string ret_val(""); if (u.expr.r1) { ret_val += u.expr.r1->get_dispname(); } else { if (u.expr.v_optype == OPTYPE_CHECKSTATE_ANY) { ret_val += "any port"; } else if (u.expr.v_optype == OPTYPE_CHECKSTATE_ALL) { ret_val += "all port"; } } ret_val += "checkstate("; ret_val += u.expr.v2->get_stringRepr(); ret_val += ")"; return ret_val; } case OPTYPE_GETVERDICT: return string("getverdict"); case OPTYPE_ACTIVATE: { string ret_val("activate("); ret_val += u.expr.r1->get_dispname(); ret_val += ')'; return ret_val; } case OPTYPE_ACTIVATE_REFD: { string ret_val("activate(derefer("); ret_val += u.expr.v1->get_stringRepr(); ret_val += ")("; if (u.expr.state == EXPR_CHECKED) { if (u.expr.ap_list2) { size_t nof_pars = u.expr.ap_list2->get_nof_pars(); for (size_t i = 0; i < nof_pars; i++) { if (i > 0) ret_val += ", "; u.expr.ap_list2->get_par(i)->append_stringRepr(ret_val); } } } else { if (u.expr.t_list2) { size_t nof_pars = u.expr.t_list2->get_nof_tis(); for (size_t i = 0; i < nof_pars; i++) { if (i > 0) ret_val += ", "; u.expr.t_list2->get_ti_byIndex(i)->append_stringRepr(ret_val); } } } ret_val += "))"; return ret_val; } case OPTYPE_EXECUTE: { string ret_val("execute("); ret_val += u.expr.r1->get_dispname(); if (u.expr.v2) { ret_val += ", "; ret_val += u.expr.v2->get_stringRepr(); } ret_val += ')'; return ret_val; } case OPTYPE_EXECUTE_REFD: { string ret_val("execute(derefers("); ret_val += u.expr.v1->get_stringRepr(); ret_val += ")("; if (u.expr.state == EXPR_CHECKED) { if (u.expr.ap_list2) { size_t nof_pars = u.expr.ap_list2->get_nof_pars(); for (size_t i = 0; i < nof_pars; i++) { if (i > 0) ret_val += ", "; u.expr.ap_list2->get_par(i)->append_stringRepr(ret_val); } } } else { if (u.expr.t_list2) { size_t nof_pars = u.expr.t_list2->get_nof_tis(); for (size_t i = 0; i < nof_pars; i++) { if (i > 0) ret_val += ", "; u.expr.t_list2->get_ti_byIndex(i)->append_stringRepr(ret_val); } } } ret_val += ')'; if(u.expr.v3) { ret_val += ", "; ret_val += u.expr.v3->get_stringRepr(); } ret_val += ')'; return ret_val; } case OPTYPE_PROF_RUNNING: return string("@profiler.running"); case OPTYPE_GET_PORT_REF: return string("port.getref()"); case OPTYPE_OF_CLASS: return u.expr.r2->get_dispname() + string(" of ") + u.expr.type->get_typename(); case OPTYPE_CLASS_CASTING: return u.expr.r2->get_dispname() + string(" => ") + u.expr.type->get_typename(); case OPTYPE_CLASS_CASTING_REF: return u.expr.r2->get_dispname() + string(" => (") + u.expr.r1->get_dispname() + string(")"); default: return string("<unsupported optype>"); } // switch u.expr.v_optype case V_MACRO: switch (u.macro) { case MACRO_MODULEID: return string("%moduleId"); case MACRO_FILENAME: return string("%fileName"); case MACRO_BFILENAME: return string("__BFILE__"); case MACRO_FILEPATH: return string("__FILE__"); case MACRO_LINENUMBER: return string("%lineNumber"); case MACRO_LINENUMBER_C: return string("__LINE__"); case MACRO_DEFINITIONID: return string("%definitionId"); case MACRO_SCOPE: return string("__SCOPE__"); case MACRO_TESTCASEID: return string("%testcaseId"); default: return string("<unknown macro>"); } // switch u.macro case V_NOTUSED: return string('-'); case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: { string ret_val("refers("); ret_val += u.refd_fat->get_assname(); ret_val += ')'; return ret_val; } case V_INVOKE: { string ret_val; ret_val += u.invoke.v->get_stringRepr(); ret_val += ".apply("; if (u.invoke.ap_list) { size_t nof_pars = u.invoke.ap_list->get_nof_pars(); for (size_t i = 0; i < nof_pars; i++) { if (i > 0) ret_val += ", "; u.invoke.ap_list->get_par(i)->append_stringRepr(ret_val); } } else if (u.invoke.t_list) { size_t nof_pars = u.invoke.t_list->get_nof_tis(); for (size_t i = 0; i < nof_pars; i++) { if (i > 0) ret_val += ", "; u.invoke.t_list->get_ti_byIndex(i)->append_stringRepr(ret_val); } } ret_val += ')'; return ret_val; } case V_REFER: { string ret_val("refers("); ret_val += u.refered->get_dispname(); ret_val += ')'; return ret_val; } default: return string("<unsupported valuetype>"); } // switch valuetype } string Value::create_stringRepr_unary(const char *operator_str) { string ret_val(operator_str); ret_val += '('; ret_val += u.expr.v1->get_stringRepr(); ret_val += ')'; return ret_val; } string Value::create_stringRepr_infix(const char *operator_str) { string ret_val('('); ret_val += u.expr.v1->get_stringRepr(); ret_val += ' '; ret_val += operator_str; ret_val += ' '; ret_val += u.expr.v2->get_stringRepr(); ret_val += ')'; return ret_val; } string Value::create_stringRepr_predef1(const char *function_name) { string ret_val(function_name); ret_val += '('; ret_val += u.expr.v1->get_stringRepr(); ret_val += ')'; return ret_val; } string Value::create_stringRepr_predef2(const char *function_name) { string ret_val(function_name); ret_val += '('; ret_val += u.expr.v1->get_stringRepr(); ret_val += ", "; ret_val += u.expr.v2->get_stringRepr(); ret_val += ')'; return ret_val; } bool Value::operator==(Value& val) { Value *left = get_value_refd_last(); Type *left_governor = left->get_my_governor(); if (left_governor) left_governor = left_governor->get_type_refd_last(); Value *right = val.get_value_refd_last(); Type *right_governor = right->get_my_governor(); if (right_governor) right_governor = right_governor->get_type_refd_last(); if (left_governor && right_governor && !left_governor->is_compatible(right_governor, NULL, NULL) && !right_governor->is_compatible(left_governor, NULL, NULL)) FATAL_ERROR("Value::operator=="); // Not-A-Value is not equal to anything (NaN analogy:) if ( (left->valuetype==V_ERROR) || (right->valuetype==V_ERROR) ) return false; switch (left->valuetype) { case V_NULL: case V_OMIT: case V_DEFAULT_NULL: case V_FAT_NULL: case V_NOTUSED: return left->valuetype == right->valuetype; case V_BOOL: return right->valuetype == V_BOOL && left->get_val_bool() == right->get_val_bool(); case V_INT: return right->valuetype == V_INT && *left->get_val_Int() == *right->get_val_Int(); case V_REAL: return right->valuetype == V_REAL && left->get_val_Real() == right->get_val_Real(); case V_CSTR: switch (right->valuetype) { case V_CSTR: return left->get_val_str() == right->get_val_str(); case V_USTR: return right->get_val_ustr() == left->get_val_str(); case V_ISO2022STR: return right->get_val_iso2022str() == left->get_val_str(); default: return false; } case V_BSTR: case V_HSTR: case V_OSTR: return left->valuetype == right->valuetype && left->get_val_str() == right->get_val_str(); case V_USTR: switch (right->valuetype) { case V_CSTR: return left->get_val_ustr() == right->get_val_str(); case V_USTR: return left->get_val_ustr() == right->get_val_ustr(); case V_ISO2022STR: return left->get_val_ustr() == right->get_val_iso2022str(); default: return false; } case V_ISO2022STR: switch (right->valuetype) { case V_CSTR: return left->get_val_iso2022str() == right->get_val_str(); case V_USTR: // The appropriate operator==() is missing. The operands are swapped, // but it shouldn't be a problem. return right->get_val_ustr() == left->get_val_iso2022str(); case V_ISO2022STR: return left->get_val_iso2022str() == right->get_val_iso2022str(); default: return false; } case V_ENUM: return right->valuetype == V_ENUM && left->get_val_id()->get_name() == right->get_val_id()->get_name(); case V_OID: case V_ROID: if (right->valuetype == V_OID || right->valuetype == V_ROID) { vector<string> act, other; get_oid_comps(act); val.get_oid_comps(other); size_t act_size = act.size(), other_size = other.size(); bool ret_val; if (act_size == other_size) { ret_val = true; for (size_t i = 0; i < act_size; i++) if (*act[i] != *other[i]) { ret_val = false; break; } } else ret_val = false; for (size_t i = 0; i < act_size; i++) delete act[i]; act.clear(); for (size_t i = 0; i < other_size; i++) delete other[i]; other.clear(); return ret_val; } else return false; case V_CHOICE: return right->valuetype == V_CHOICE && left->get_alt_name().get_name() == right->get_alt_name().get_name() && *(left->get_alt_value()) == *(right->get_alt_value()); case V_SEQ: case V_SET: { if (!left_governor) FATAL_ERROR("Value::operator=="); if (left->valuetype != right->valuetype) return false; size_t nof_comps = left_governor->get_nof_comps(); for (size_t i = 0; i < nof_comps; i++) { Value *lval = NULL, *rval = NULL; CompField* cfl = left_governor->get_comp_byIndex(i); const Identifier& field_name = cfl->get_name(); if (left->has_comp_withName(field_name)) { lval = left->get_comp_value_byName(field_name); if (right->has_comp_withName(field_name)) { rval = right->get_comp_value_byName(field_name); if ((lval->valuetype == V_OMIT && rval->valuetype != V_OMIT) || (rval->valuetype == V_OMIT && lval->valuetype!=V_OMIT)) return false; else if (!(*lval == *rval)) return false; } else { if (cfl->has_default()) { if (!(*lval == *cfl->get_defval())) return false; } else { if (lval->valuetype != V_OMIT) return false; } } } else { if(right->has_comp_withName(field_name)) { rval = right->get_comp_value_byName(field_name); if(cfl->has_default()) { if(rval->valuetype==V_OMIT) return false; else { lval = cfl->get_defval(); if (!(*lval==*rval)) return false; } } } } } return true; } case V_SEQOF: case V_ARRAY: { if (left->valuetype != right->valuetype) return false; size_t ncomps = get_nof_comps(); if (ncomps != right->get_nof_comps()) return false; if (left->is_indexed() && right->is_indexed()) { //both of them are indexed bool found = false; map<IndexedValue*, void> uncovered; for (size_t i = 0; i < left->get_nof_comps(); ++i) uncovered.add(left->u.val_vs->get_iv_byIndex(i),0); for (size_t i = 0; i < right->get_nof_comps(); ++i) { found = false; for (size_t j = 0; j < uncovered.size(); ++j) { if (*(uncovered.get_nth_key(j)->get_value()) == *(right->get_comp_byIndex(i)) && *(uncovered.get_nth_key(j)->get_index()) == *(right->get_index_byIndex(i))) { found = true; uncovered.erase(uncovered.get_nth_key(j)); break; } } if (!found) break; } uncovered.clear(); return found; } else if (left->is_indexed() || right->is_indexed()) { Value* indexed_one = 0; Value* not_indexed_one = 0; if(left->is_indexed()) { // left is indexed, right is not indexed_one = left; not_indexed_one = right; } else { // right indexed, left is not indexed_one = right; not_indexed_one = left; } for(size_t i = 0; i < ncomps; ++i) { Value* ind = indexed_one->get_index_byIndex(i)->get_value_refd_last(); if(!(ind->valuetype == V_INT && *(not_indexed_one->get_comp_byIndex(ind->u.val_Int->get_val())) == *(indexed_one->get_comp_byIndex(i)))) { return false; } } return true; } else { // none of them is indexed for (size_t i = 0; i < ncomps; i++) { if (!(*(left->get_comp_byIndex(i)) == *(right->get_comp_byIndex(i)))) return false; } return true; } } case V_SETOF: { if (right->valuetype != V_SETOF) return false; size_t ncomps = get_nof_comps(); if (ncomps != right->get_nof_comps()) return false; if (ncomps == 0) return true; map<size_t, void> uncovered; for (size_t i = 0; i < ncomps; i++) uncovered.add(i, 0); for (size_t i = 0; i < ncomps; i++) { Value *left_item = left->get_comp_byIndex(i); bool pair_found = false; for (size_t j = 0; j < ncomps - i; j++) { size_t right_index = uncovered.get_nth_key(j); if (*left_item == *right->get_comp_byIndex(right_index)) { uncovered.erase(right_index); pair_found = true; break; } } if (!pair_found) { uncovered.clear(); return false; } } return true; } case V_VERDICT: return right->valuetype == V_VERDICT && left->get_val_verdict() == right->get_val_verdict(); case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: return left->valuetype == right->valuetype && left->get_refd_assignment() == right->get_refd_assignment(); default: FATAL_ERROR("Value::operator=="); } return true; } bool Value::operator<(Value& val) { Value *left = get_value_refd_last(); Type *left_governor = left->get_my_governor(); if(left_governor) left_governor=left_governor->get_type_refd_last(); Value *right = val.get_value_refd_last(); Type *right_governor = right->get_my_governor(); if(right_governor) right_governor=right_governor->get_type_refd_last(); if (left->get_valuetype() != right->get_valuetype()) FATAL_ERROR("Value::operator<"); switch(valuetype){ case V_INT: return *left->get_val_Int() < *right->get_val_Int(); case V_REAL: return (left->get_val_Real() < right->get_val_Real()); case V_ENUM: if(!left_governor || !right_governor) FATAL_ERROR("Value::operator<"); if(left_governor!=right_governor) FATAL_ERROR("Value::operator<"); return (left_governor->get_enum_val_byId(*left->get_val_id()) < right_governor->get_enum_val_byId(*right->get_val_id())); default: FATAL_ERROR("Value::operator<"); } return true; } bool Value::is_string_type(Type::expected_value_t exp_val) { switch (get_expr_returntype(exp_val, true)) { case Type::T_CSTR: case Type::T_USTR: case Type::T_BSTR: case Type::T_HSTR: case Type::T_OSTR: return true; default: return false; } } void Value::reset_code_generated() { // this is currently only used for default values of template parameters, // so it only checks the values that can appear in default values if (!get_code_generated()) { return; } GovernedSimple::reset_code_generated(); switch (valuetype) { case V_SEQOF: case V_SETOF: case V_ARRAY: if (is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { u.val_vs->get_iv_byIndex(i)->get_value()->reset_code_generated(); } } else { for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { u.val_vs->get_v_byIndex(i)->reset_code_generated(); } } break; case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { u.val_nvs->get_nv_byIndex(i)->get_value()->reset_code_generated(); } break; case V_CHOICE: case V_OPENTYPE: u.choice.alt_value->reset_code_generated(); break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_REMOVE_BOM: case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: case OPTYPE_HOSTID: u.expr.v1->reset_code_generated(); break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->reset_code_generated(); u.expr.v2->reset_code_generated(); break; case OPTYPE_DECODE: // r1 r2 [v3] [v4] u.expr.v3->reset_code_generated(); u.expr.v4->reset_code_generated(); break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->get_Template()->reset_code_generated(); u.expr.v2->reset_code_generated(); u.expr.v3->reset_code_generated(); break; case OPTYPE_REGEXP: u.expr.ti1->get_Template()->reset_code_generated(); u.expr.t2->get_Template()->reset_code_generated(); u.expr.v3->reset_code_generated(); break; case OPTYPE_DECOMP: // v1 v2 v3 u.expr.v1->reset_code_generated(); u.expr.v2->reset_code_generated(); u.expr.v3->reset_code_generated(); break; case OPTYPE_REPLACE: u.expr.ti1->get_Template()->reset_code_generated(); u.expr.v2->reset_code_generated(); u.expr.v3->reset_code_generated(); u.expr.ti4->get_Template()->reset_code_generated(); break; case OPTYPE_VALUEOF: // ti1 [subrefs2] case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_ISVALUE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->get_Template()->reset_code_generated(); break; case OPTYPE_ISTEMPLATEKIND: // ti1 v2 u.expr.ti1->get_Template()->reset_code_generated(); u.expr.v2->reset_code_generated(); break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] u.expr.ti1->get_Template()->reset_code_generated(); u.expr.v2->reset_code_generated(); u.expr.v3->reset_code_generated(); u.expr.v4->reset_code_generated(); break; case OPTYPE_DECVALUE_UNICHAR: // r1 r2 [v3] [v4] [v5] u.expr.v3->reset_code_generated(); u.expr.v4->reset_code_generated(); u.expr.v5->reset_code_generated(); break; case OPTYPE_MATCH: // v1 t2 u.expr.v1->reset_code_generated(); u.expr.t2->get_Template()->reset_code_generated(); break; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: // TODO if needed break; default: break; } break; default: break; } } void Value::generate_code_expr(expression_struct *expr) { if (has_single_expr()) { expr->expr = mputstr(expr->expr, get_single_expr().c_str()); } else { switch (valuetype) { case V_EXPR: generate_code_expr_expr(expr); break; case V_CHOICE: case V_SEQOF: case V_SETOF: case V_ARRAY: case V_SEQ: case V_SET: { const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); expr->preamble = mputprintf(expr->preamble, "%s %s;\n", my_governor->get_genname_value(my_scope).c_str(), tmp_id_str); set_genname_recursive(tmp_id); expr->preamble = generate_code_init(expr->preamble, tmp_id_str); expr->expr = mputstr(expr->expr, tmp_id_str); break; } case V_INT: { const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); expr->preamble = mputprintf(expr->preamble, "INTEGER %s;\n", tmp_id_str); set_genname_recursive(tmp_id); expr->preamble = generate_code_init(expr->preamble, tmp_id_str); expr->expr = mputstr(expr->expr, tmp_id_str); break; } case V_REFD: { if (!get_needs_conversion()) { u.ref.ref->generate_code_const_ref(expr); } else { Type *my_gov = my_governor != NULL ? my_governor->get_type_refd_last() : get_expr_governor_last(); Type *refd_gov = u.ref.ref->get_refd_assignment()->get_Type() ->get_field_type(u.ref.ref->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE)->get_type_refd_last(); // Make sure that nothing goes wrong. if (!my_gov || !refd_gov || my_gov == refd_gov) FATAL_ERROR("Value::generate_code_expr()"); expression_struct expr_tmp; Code::init_expr(&expr_tmp); const string& tmp_id1 = get_temporary_id(); const char *tmp_id_str1 = tmp_id1.c_str(); const string& tmp_id2 = get_temporary_id(); const char *tmp_id_str2 = tmp_id2.c_str(); expr->preamble = mputprintf(expr->preamble, "%s %s;\n", refd_gov->get_genname_value(my_scope).c_str(), tmp_id_str1); expr_tmp.expr = mputprintf(expr_tmp.expr, "%s = ", tmp_id_str1); u.ref.ref->generate_code_const_ref(&expr_tmp); expr->preamble = Code::merge_free_expr(expr->preamble, &expr_tmp); expr->preamble = mputprintf(expr->preamble, "%s %s;\n" "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' " "and `%s' are not compatible at run-time\");\n", my_gov->get_genname_value(my_scope).c_str(), tmp_id_str2, TypeConv::get_conv_func(refd_gov, my_gov, get_my_scope() ->get_scope_mod()).c_str(), tmp_id_str2, tmp_id_str1, my_gov ->get_typename().c_str(), refd_gov->get_typename().c_str()); expr->expr = mputprintf(expr->expr, "%s", tmp_id_str2); } break; } case V_INVOKE: generate_code_expr_invoke(expr); break; default: FATAL_ERROR("Value::generate_code_expr(%d)", valuetype); } } } void Value::generate_code_expr_mandatory(expression_struct *expr) { generate_code_expr(expr); if (valuetype == V_REFD && get_value_refd_last()->valuetype == V_REFD && u.ref.ref->get_refd_assignment()->get_Type()->get_type_refd_last()->get_typetype() != Type::T_CLASS) generate_code_expr_optional_field_ref(expr, u.ref.ref); } bool Value::can_use_increment(Reference *ref) const { if (valuetype != V_EXPR) { return false; } switch (u.expr.v_optype) { case OPTYPE_ADD: case OPTYPE_SUBTRACT: break; default: return false; } bool v1_one = u.expr.v1->get_valuetype() == V_INT && *u.expr.v1->get_val_Int() == 1; bool v2_one = u.expr.v2->get_valuetype() == V_INT && *u.expr.v2->get_val_Int() == 1; if ((v1_one && u.expr.v2->get_valuetype() == V_REFD && u.expr.v2->get_reference()->get_refd_assignment()->get_id() == ref->get_refd_assignment()->get_id()) || (v2_one && u.expr.v1->get_valuetype() == V_REFD && u.expr.v1->get_reference()->get_refd_assignment()->get_id() == ref->get_refd_assignment()->get_id())) { return true; } return false; } char *Value::generate_code_init(char *str, const char *name) { if (get_code_generated()) return str; if (err_descrs != NULL && err_descrs->has_descr(NULL)) { str = err_descrs->generate_code_init_str(NULL, str, string(name)); } switch (valuetype) { case V_NULL: case V_BOOL: case V_REAL: case V_ENUM: case V_BSTR: case V_HSTR: case V_OSTR: case V_CSTR: case V_USTR: case V_ISO2022STR: case V_OID: case V_ROID: case V_VERDICT: case V_DEFAULT_NULL: case V_FAT_NULL: case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: // These values have a single string equivalent. str = mputprintf(str, "%s = %s;\n", name, get_single_expr().c_str()); break; case V_INT: if (u.val_Int->is_native_fit()) str = mputprintf(str, "%s = %s;\n", name, get_single_expr().c_str()); else // It's always an INTEGER. str = mputprintf(str, "{ INTEGER INTEGER_tmp(%s);\n%s = INTEGER_tmp; " "}\n", get_single_expr().c_str(), name); break; case V_EXPR: case V_INVOKE: { expression_struct expr; Code::init_expr(&expr); expr.expr = mputprintf(expr.expr, "%s = ", name); generate_code_expr(&expr); str = Code::merge_free_expr(str, &expr); break; } case V_CHOICE: str = generate_code_init_choice(str, name); break; case V_SEQOF: case V_SETOF: if (!is_indexed()) str = generate_code_init_seof(str, name); else str = generate_code_init_indexed(str, name); break; case V_ARRAY: if (!is_indexed()) str = generate_code_init_array(str, name); else str = generate_code_init_indexed(str, name); break; case V_SEQ: case V_SET: str = generate_code_init_se(str, name); break; case V_REFD: str = generate_code_init_refd(str, name); break; case V_MACRO: switch (u.macro) { case MACRO_TESTCASEID: str = mputprintf(str, "%s = TTCN_Runtime::get_testcase_id_macro();\n", name); break; default: // all others must already be evaluated away FATAL_ERROR("Value::generate_code_init()"); } break; case V_TTCN3_NULL: str = mputprintf(str, "%s = NULL_VALUE;\n", name); break; case V_NOTUSED: // unbound value, don't generate anything break; default: FATAL_ERROR("Value::generate_code_init()"); } if (err_descrs != NULL && err_descrs->has_descr(NULL)) { str = mputprintf(str, "%s.set_err_descr(&%s_%lu_err_descr);\n", name, name, (unsigned long) err_descrs->get_descr_index(NULL)); } set_code_generated(); return str; } char *Value::rearrange_init_code(char *str, Common::Module* usage_mod) { switch (valuetype) { case V_REFD: { Ttcn::ActualParList *parlist = u.ref.ref->get_parlist(); if (parlist) { str = parlist->rearrange_init_code(str, usage_mod); } if (get_code_section() == CS_INIT_CLASS && get_value_refd_last() == this) { str = rearrange_init_code_refd(str); } break; } case V_INVOKE: { str = u.invoke.v->rearrange_init_code(str, usage_mod); str = u.invoke.ap_list->rearrange_init_code(str, usage_mod); break; } case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_ISCHOSEN_V: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: str = u.expr.v1->rearrange_init_code(str, usage_mod); break; case OPTYPE_DECODE: { Ttcn::ActualParList *parlist = u.expr.r1->get_parlist(); if (parlist) str = parlist->rearrange_init_code(str, usage_mod); parlist = u.expr.r2->get_parlist(); if (parlist) str = parlist->rearrange_init_code(str, usage_mod); if (u.expr.v3 != NULL) { str = u.expr.v3->rearrange_init_code(str, usage_mod); } if (u.expr.v4 != NULL) { str = u.expr.v4->rearrange_init_code(str, usage_mod); } break; } case OPTYPE_HOSTID: if (u.expr.v1) str = u.expr.v1->rearrange_init_code(str, usage_mod); break; case OPTYPE_ADD: case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: str = u.expr.v1->rearrange_init_code(str, usage_mod); str = u.expr.v2->rearrange_init_code(str, usage_mod); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: str = u.expr.v1->rearrange_init_code(str, usage_mod); if (u.expr.v2) str = u.expr.v2->rearrange_init_code(str, usage_mod); break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: str = u.expr.ti1->rearrange_init_code(str, usage_mod); if (u.expr.v2 != NULL) { str = u.expr.v2->rearrange_init_code(str, usage_mod); } if (u.expr.v3 != NULL) { str = u.expr.v3->rearrange_init_code(str, usage_mod); } break; case OPTYPE_REGEXP: str = u.expr.ti1->rearrange_init_code(str, usage_mod); str = u.expr.t2->rearrange_init_code(str, usage_mod); str = u.expr.v3->rearrange_init_code(str, usage_mod); break; case OPTYPE_DECOMP: str = u.expr.v1->rearrange_init_code(str, usage_mod); str = u.expr.v2->rearrange_init_code(str, usage_mod); str = u.expr.v3->rearrange_init_code(str, usage_mod); break; case OPTYPE_REPLACE: str = u.expr.ti1->rearrange_init_code(str, usage_mod); str = u.expr.v2->rearrange_init_code(str, usage_mod); str = u.expr.v3->rearrange_init_code(str, usage_mod); str = u.expr.ti4->rearrange_init_code(str, usage_mod); break; case OPTYPE_ISTEMPLATEKIND: str = u.expr.ti1->rearrange_init_code(str, usage_mod); str = u.expr.v2->rearrange_init_code(str, usage_mod); break; case OPTYPE_VALUEOF: if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { str = subref->get_val()->rearrange_init_code(str, usage_mod); } } } // fall through case OPTYPE_LENGTHOF: case OPTYPE_SIZEOF: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: str = u.expr.ti1->rearrange_init_code(str, usage_mod); break; case OPTYPE_ENCVALUE_UNICHAR: str = u.expr.ti1->rearrange_init_code(str, usage_mod); if (u.expr.v2 != NULL) { str = u.expr.v2->rearrange_init_code(str, usage_mod); } if (u.expr.v3 != NULL) { str = u.expr.v3->rearrange_init_code(str, usage_mod); } if (u.expr.v4 != NULL) { str = u.expr.v4->rearrange_init_code(str, usage_mod); } break; case OPTYPE_DECVALUE_UNICHAR: { Ttcn::ActualParList *parlist = u.expr.r1->get_parlist(); Common::Assignment *ass = u.expr.r1->get_refd_assignment(); if (parlist) str = parlist->rearrange_init_code(str, usage_mod); (void)ass; // eliminate assigned but not used warning parlist = u.expr.r2->get_parlist(); ass = u.expr.r2->get_refd_assignment(); if (parlist) str = parlist->rearrange_init_code(str, usage_mod); if (u.expr.v3 != NULL) { str = u.expr.v3->rearrange_init_code(str, usage_mod); } if (u.expr.v4 != NULL) { str = u.expr.v4->rearrange_init_code(str, usage_mod); } if (u.expr.v5 != NULL) { str = u.expr.v5->rearrange_init_code(str, usage_mod); } break; } case OPTYPE_ISCHOSEN_T: case OPTYPE_ISVALUE: str = u.expr.t1->rearrange_init_code(str, usage_mod); break; case OPTYPE_MATCH: str = u.expr.v1->rearrange_init_code(str, usage_mod); str = u.expr.t2->rearrange_init_code(str, usage_mod); break; default: // other kinds of expressions cannot appear within templates break; } break; default: break; } return str; } char* Value::rearrange_init_code_refd(char* str) { Assignment* refd_ass = u.ref.ref->get_refd_assignment(); if ((refd_ass->get_asstype() == Assignment::A_CONST || refd_ass->get_asstype() == Assignment::A_VAR) && refd_ass->get_my_scope()->get_parent_scope()->is_class_scope()) { Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref == NULL) { FATAL_ERROR("Value::generate_code_init_refd"); } Value* v2 = refd_ass->get_Value(); if (!ttcn_ref->is_gen_class_defpar_prefix() && v2 != NULL && needs_init_precede(v2)) { string lhs = v2->get_lhs_name(); if (refd_ass->get_asstype() == Assignment::A_VAR) { lhs = string("this->") + lhs; } str = v2->generate_code_init(str, lhs.c_str()); } } return str; } char* Value::generate_code_tmp(char *str, const char *prefix, size_t& blockcount) { char *s2 = memptystr(); char *s1 = generate_code_tmp(NULL, s2); if (s2[0]) { if (blockcount == 0) { str = mputstr(str, "{\n"); blockcount++; } str = mputstr(str, s2); } Free(s2); str=mputstr(str, prefix); str=mputstr(str, s1); Free(s1); return str; } char *Value::generate_code_tmp(char *str, char*& init) { expression_struct expr; Code::init_expr(&expr); generate_code_expr_mandatory(&expr); if (expr.preamble || expr.postamble) { if (valuetype == V_EXPR && (u.expr.v_optype == OPTYPE_AND || u.expr.v_optype == OPTYPE_OR)) { // a temporary variable is already introduced if (expr.preamble) init = mputstr(init, expr.preamble); if (expr.postamble) init = mputstr(init, expr.postamble); str = mputstr(str, expr.expr); } else { const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); init = mputprintf(init, "%s %s;\n" "{\n", my_governor->get_type_refd_last()->get_typetype() == Type::T_BOOL ? "boolean" : my_governor->get_genname_value(my_scope).c_str(), tmp_id_str); if (expr.preamble) init = mputstr(init, expr.preamble); init = mputprintf(init, "%s = %s;\n", tmp_id_str, expr.expr); if (expr.postamble) init = mputstr(init, expr.postamble); init = mputstr(init, "}\n"); str = mputstr(str, tmp_id_str); } } else str = mputstr(str, expr.expr); Code::free_expr(&expr); return str; } void Value::generate_code_log(expression_struct *expr) { if (explicit_cast_needed()) { char *expr_backup = expr->expr; expr->expr = NULL; generate_code_expr(expr); const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); // We have to create a temporary object, because the parser of GCC // earlier than 3.4.x (e.g. 3.0.4) in some cases cannot recognize the // constructor call that is, this does not work: type(...).log(); but // this works: type tmp(...); tmp.log();. expr->preamble = mputprintf(expr->preamble, "%s %s(%s);\n", my_governor->get_genname_value(my_scope).c_str(), tmp_id_str, expr->expr); Free(expr->expr); expr->expr = mputstr(expr_backup, tmp_id_str); } else { generate_code_expr(expr); } expr->expr = mputstr(expr->expr, ".log()"); } void Value::generate_code_log_match(expression_struct *expr) { if (valuetype != V_EXPR || u.expr.v_optype != OPTYPE_MATCH) FATAL_ERROR("Value::generate_code_log_match()"); // Maybe, it's a more general problem, but for complete GCC 3.0.4 // compliance the whole code-generation should be checked. Standalone // constructs like: "A(a[0].f());" should be avoided. The current // solution for HK38721 uses an additional assignment to overcome the // issue. The generated code will be slower, but it's needed for old GCC // versions in specific circumstances. if (u.expr.t2->needs_temp_ref()) { char *expr_backup = expr->expr; expr->expr = NULL; u.expr.t2->generate_code(expr); const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); expr->preamble = mputprintf(expr->preamble, "%s %s = %s;\n", u.expr.t2->get_expr_governor(Type::EXPECTED_TEMPLATE) ->get_genname_template(my_scope).c_str(), tmp_id_str, expr->expr); Free(expr->expr); expr->expr = mputstr(expr_backup, tmp_id_str); } else { // Workaround for "A(NS::B).a(C);" like constructs for GCC 3.0.4. For // some reason "(A(NS::B)).a(C);" compiles fine. expr->expr = mputc(expr->expr, '('); u.expr.t2->generate_code(expr); expr->expr = mputc(expr->expr, ')'); } expr->expr = mputstr(expr->expr, ".log_match("); u.expr.v1->generate_code_expr(expr); expr->expr = mputprintf(expr->expr, "%s)", omit_in_value_list ? ", TRUE" : ""); } void Value::generate_code_expr_expr(expression_struct *expr) { switch (u.expr.v_optype) { case OPTYPE_RND: generate_code_expr_rnd(expr, 0); break; case OPTYPE_UNARYPLUS: // same as without the '+' operator u.expr.v1->generate_code_expr(expr); break; case OPTYPE_UNARYMINUS: generate_code_expr_unary(expr, "-", u.expr.v1); break; case OPTYPE_NOT: generate_code_expr_unary(expr, "!", u.expr.v1); break; case OPTYPE_NOT4B: generate_code_expr_unary(expr, "~", u.expr.v1); break; case OPTYPE_BIT2HEX: generate_code_expr_predef1(expr, "bit2hex", u.expr.v1); break; case OPTYPE_BIT2INT: generate_code_expr_predef1(expr, "bit2int", u.expr.v1); break; case OPTYPE_BIT2OCT: generate_code_expr_predef1(expr, "bit2oct", u.expr.v1); break; case OPTYPE_BIT2STR: generate_code_expr_predef1(expr, "bit2str", u.expr.v1); break; case OPTYPE_BSON2JSON: generate_code_expr_predef1(expr, "bson2json", u.expr.v1); break; case OPTYPE_CBOR2JSON: generate_code_expr_predef1(expr, "cbor2json", u.expr.v1); break; case OPTYPE_CHAR2INT: generate_code_expr_predef1(expr, "char2int", u.expr.v1); break; case OPTYPE_CHAR2OCT: generate_code_expr_predef1(expr, "char2oct", u.expr.v1); break; case OPTYPE_FLOAT2INT: generate_code_expr_predef1(expr, "float2int", u.expr.v1); break; case OPTYPE_FLOAT2STR: generate_code_expr_predef1(expr, "float2str", u.expr.v1); break; case OPTYPE_HEX2BIT: generate_code_expr_predef1(expr, "hex2bit", u.expr.v1); break; case OPTYPE_HEX2INT: generate_code_expr_predef1(expr, "hex2int", u.expr.v1); break; case OPTYPE_HEX2OCT: generate_code_expr_predef1(expr, "hex2oct", u.expr.v1); break; case OPTYPE_HEX2STR: generate_code_expr_predef1(expr, "hex2str", u.expr.v1); break; case OPTYPE_INT2CHAR: generate_code_expr_predef1(expr, "int2char", u.expr.v1); break; case OPTYPE_INT2FLOAT: generate_code_expr_predef1(expr, "int2float", u.expr.v1); break; case OPTYPE_INT2STR: generate_code_expr_predef1(expr, "int2str", u.expr.v1); break; case OPTYPE_INT2UNICHAR: generate_code_expr_predef1(expr, "int2unichar", u.expr.v1); break; case OPTYPE_JSON2BSON: generate_code_expr_predef1(expr, "json2bson", u.expr.v1); break; case OPTYPE_JSON2CBOR: generate_code_expr_predef1(expr, "json2cbor", u.expr.v1); break; case OPTYPE_OCT2BIT: generate_code_expr_predef1(expr, "oct2bit", u.expr.v1); break; case OPTYPE_OCT2CHAR: generate_code_expr_predef1(expr, "oct2char", u.expr.v1); break; case OPTYPE_GET_STRINGENCODING: generate_code_expr_predef1(expr, "get_stringencoding", u.expr.v1); break; case OPTYPE_REMOVE_BOM: generate_code_expr_predef1(expr, "remove_bom", u.expr.v1); break; case OPTYPE_ENCODE_BASE64: if (u.expr.v2) generate_code_expr_predef2(expr, "encode_base64", u.expr.v1, u.expr.v2); else generate_code_expr_predef1(expr, "encode_base64", u.expr.v1); break; case OPTYPE_DECODE_BASE64: generate_code_expr_predef1(expr, "decode_base64", u.expr.v1); break; case OPTYPE_OCT2UNICHAR: if (u.expr.v2) generate_code_expr_predef2(expr, "oct2unichar", u.expr.v1, u.expr.v2); else generate_code_expr_predef1(expr, "oct2unichar", u.expr.v1); break; case OPTYPE_UNICHAR2OCT: if (u.expr.v2) generate_code_expr_predef2(expr, "unichar2oct", u.expr.v1, u.expr.v2); else generate_code_expr_predef1(expr, "unichar2oct", u.expr.v1); break; case OPTYPE_ENCVALUE_UNICHAR: generate_code_expr_encvalue_unichar(expr); break; case OPTYPE_DECVALUE_UNICHAR: generate_code_expr_decvalue_unichar(expr); break; case OPTYPE_HOSTID: generate_code_expr_hostid(expr); break; case OPTYPE_OCT2HEX: generate_code_expr_predef1(expr, "oct2hex", u.expr.v1); break; case OPTYPE_OCT2INT: generate_code_expr_predef1(expr, "oct2int", u.expr.v1); break; case OPTYPE_OCT2STR: generate_code_expr_predef1(expr, "oct2str", u.expr.v1); break; case OPTYPE_STR2BIT: generate_code_expr_predef1(expr, "str2bit", u.expr.v1); break; case OPTYPE_STR2FLOAT: generate_code_expr_predef1(expr, "str2float", u.expr.v1); break; case OPTYPE_STR2HEX: generate_code_expr_predef1(expr, "str2hex", u.expr.v1); break; case OPTYPE_STR2INT: generate_code_expr_predef1(expr, "str2int", u.expr.v1); break; case OPTYPE_STR2OCT: generate_code_expr_predef1(expr, "str2oct", u.expr.v1); break; case OPTYPE_UNICHAR2INT: generate_code_expr_predef1(expr, "unichar2int", u.expr.v1); break; case OPTYPE_UNICHAR2CHAR: generate_code_expr_predef1(expr, "unichar2char", u.expr.v1); break; case OPTYPE_ENUM2INT: { Type* enum_type = u.expr.v1->get_expr_governor_last(); if (!enum_type) FATAL_ERROR("Value::generate_code_expr_expr(): enum2int"); expr->expr = mputprintf(expr->expr, "%s::enum2int(", enum_type->get_genname_value(my_scope).c_str()); u.expr.v1->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); break;} case OPTYPE_ENCODE: generate_code_expr_encode(expr); break; case OPTYPE_DECODE: generate_code_expr_decode(expr); break; case OPTYPE_RNDWITHVAL: generate_code_expr_rnd(expr, u.expr.v1); break; case OPTYPE_ADD: generate_code_expr_infix(expr, "+", u.expr.v1, u.expr.v2, false); break; case OPTYPE_SUBTRACT: generate_code_expr_infix(expr, "-", u.expr.v1, u.expr.v2, false); break; case OPTYPE_MULTIPLY: generate_code_expr_infix(expr, "*", u.expr.v1, u.expr.v2, false); break; case OPTYPE_DIVIDE: generate_code_expr_infix(expr, "/", u.expr.v1, u.expr.v2, false); break; case OPTYPE_MOD: generate_code_expr_predef2(expr, "mod", u.expr.v1, u.expr.v2); break; case OPTYPE_REM: generate_code_expr_predef2(expr, "rem", u.expr.v1, u.expr.v2); break; case OPTYPE_CONCAT: generate_code_expr_infix(expr, "+", u.expr.v1, u.expr.v2, false); break; case OPTYPE_EQ: generate_code_expr_infix(expr, "==", u.expr.v1, u.expr.v2, true); break; case OPTYPE_LT: generate_code_expr_infix(expr, "<", u.expr.v1, u.expr.v2, false); break; case OPTYPE_GT: generate_code_expr_infix(expr, ">", u.expr.v1, u.expr.v2, false); break; case OPTYPE_NE: generate_code_expr_infix(expr, "!=", u.expr.v1, u.expr.v2, true); break; case OPTYPE_GE: generate_code_expr_infix(expr, ">=", u.expr.v1, u.expr.v2, false); break; case OPTYPE_LE: generate_code_expr_infix(expr, "<=", u.expr.v1, u.expr.v2, false); break; case OPTYPE_AND: case OPTYPE_OR: generate_code_expr_and_or(expr); break; case OPTYPE_XOR: generate_code_expr_infix(expr, "^", u.expr.v1, u.expr.v2, false); break; case OPTYPE_AND4B: generate_code_expr_infix(expr, "&", u.expr.v1, u.expr.v2, false); break; case OPTYPE_OR4B: generate_code_expr_infix(expr, "|", u.expr.v1, u.expr.v2, false); break; case OPTYPE_XOR4B: generate_code_expr_infix(expr, "^", u.expr.v1, u.expr.v2, false); break; case OPTYPE_SHL: generate_code_expr_infix(expr, "<<", u.expr.v1, u.expr.v2, false); break; case OPTYPE_SHR: generate_code_expr_infix(expr, ">>", u.expr.v1, u.expr.v2, false); break; case OPTYPE_ROTL: generate_code_expr_infix(expr, "<<=", u.expr.v1, u.expr.v2, false); break; case OPTYPE_ROTR: generate_code_expr_infix(expr, ">>=", u.expr.v1, u.expr.v2, false); break; case OPTYPE_INT2BIT: generate_code_expr_predef2(expr, "int2bit", u.expr.v1, u.expr.v2); break; case OPTYPE_INT2HEX: generate_code_expr_predef2(expr, "int2hex", u.expr.v1, u.expr.v2); break; case OPTYPE_INT2OCT: generate_code_expr_predef2(expr, "int2oct", u.expr.v1, u.expr.v2); break; case OPTYPE_SUBSTR: if (!get_needs_conversion()) generate_code_expr_substr(expr); else generate_code_expr_substr_replace_compat(expr); break; case OPTYPE_REGEXP: generate_code_expr_regexp(expr); break; case OPTYPE_DECOMP: generate_code_expr_predef3(expr, "decomp", u.expr.v1, u.expr.v2, u.expr.v3); break; case OPTYPE_REPLACE: if (!get_needs_conversion()) generate_code_expr_replace(expr); else generate_code_expr_substr_replace_compat(expr); break; case OPTYPE_ISCHOSEN: // r1 i2 FATAL_ERROR("Value::generate_code_expr_expr()"); break; case OPTYPE_ISCHOSEN_V: { // v1 i2 char* field = mprintf("%s::ALT_%s", u.expr.v1->get_my_governor()->get_genname_value(my_scope).c_str(), u.expr.i2->get_name().c_str()); if (u.expr.v1->get_valuetype() == Value::V_REFD) { Ttcn::Reference* reference = dynamic_cast<Ttcn::Reference*>(u.expr.v1->get_reference()); if (reference) { reference->generate_code_ispresentboundchosen(expr, false, u.expr.v_optype, field); } } Free(field); break; } case OPTYPE_ISCHOSEN_T: { // t1 i2 char* field = mprintf("%s::ALT_%s", u.expr.t1->get_my_governor()->get_genname_value(my_scope).c_str(), u.expr.i2->get_name().c_str()); Template::templatetype_t temp = u.expr.t1->get_templatetype(); if (temp == Template::SPECIFIC_VALUE) { Value* specific_value = u.expr.t1->get_specific_value(); if (specific_value->get_valuetype() == Value::V_REFD) { Ttcn::Reference* reference = dynamic_cast<Ttcn::Reference*>(specific_value->get_reference()); if (reference) { reference->generate_code_ispresentboundchosen(expr, false, u.expr.v_optype, field); } } } else if (temp == Template::TEMPLATE_REFD) { Ttcn::Reference* reference = dynamic_cast<Ttcn::Reference*>(u.expr.t1->get_reference()); if (reference) { reference->generate_code_ispresentboundchosen(expr, true, u.expr.v_optype, field); } } Free(field); break; } case OPTYPE_ISVALUE: // ti1 case OPTYPE_ISPRESENT: case OPTYPE_ISBOUND: { Template::templatetype_t temp = u.expr.ti1->get_Template() ->get_templatetype(); // TODO: use get_refd_assignment instead to determine whether it's a template? if (temp == Template::SPECIFIC_VALUE) { Value* specific_value = u.expr.ti1->get_Template() ->get_specific_value(); if (specific_value->get_valuetype() == Value::V_REFD) { Ttcn::Reference* reference = dynamic_cast<Ttcn::Reference*>(specific_value->get_reference()); if (reference != NULL && !reference->has_parameters()) { reference->generate_code_ispresentboundchosen(expr, false, u.expr.v_optype, NULL); break; } } } else if (temp == Template::TEMPLATE_REFD) { Ttcn::Reference* reference = dynamic_cast<Ttcn::Reference*>(u.expr.ti1->get_Template() ->get_reference()); if (reference != NULL && !reference->has_parameters()) { reference->generate_code_ispresentboundchosen(expr, true, u.expr.v_optype, NULL); break; } } } // no break case OPTYPE_LENGTHOF: // ti1 // fall through, separated later case OPTYPE_SIZEOF: { // ti1 if (u.expr.ti1->is_only_specific_value()) { Value *t_val=u.expr.ti1->get_Template()->get_specific_value(); bool cast_needed = t_val->explicit_cast_needed( u.expr.v_optype != OPTYPE_LENGTHOF); if(cast_needed) { // the ambiguous C++ expression is converted to the value class expr->expr = mputprintf(expr->expr, "%s(", t_val->get_my_governor()->get_genname_value(my_scope).c_str()); } if (u.expr.v_optype != OPTYPE_LENGTHOF && u.expr.v_optype != OPTYPE_SIZEOF) { t_val->generate_code_expr(expr); } else { t_val->generate_code_expr_mandatory(expr); } if(cast_needed) expr->expr=mputc(expr->expr, ')'); } else u.expr.ti1->generate_code(expr); switch (u.expr.v_optype) { case OPTYPE_ISBOUND: expr->expr=mputstr(expr->expr, ".is_bound()"); break; case OPTYPE_ISPRESENT: expr->expr=mputprintf(expr->expr, ".is_present(%s)", !u.expr.ti1->is_only_specific_value() && omit_in_value_list ? "TRUE" : ""); break; case OPTYPE_SIZEOF: expr->expr=mputstr(expr->expr, ".size_of()"); break; case OPTYPE_LENGTHOF: expr->expr=mputstr(expr->expr, ".lengthof()"); break; case OPTYPE_ISVALUE: expr->expr=mputstr(expr->expr, ".is_value()"); break; default: FATAL_ERROR("Value::generate_code_expr_expr()"); } break; } case OPTYPE_VALUEOF: // ti1 [subrefs2] u.expr.ti1->generate_code(expr); expr->expr = mputstr(expr->expr, ".valueof()"); if (u.expr.subrefs2 != NULL) { u.expr.subrefs2->generate_code(expr, u.expr.ti1->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE), my_scope); } break; case OPTYPE_ISTEMPLATEKIND: // ti1 v2 u.expr.ti1->generate_code(expr); expr->expr = mputstr(expr->expr, ".get_istemplate_kind((const char*)"); u.expr.v2->generate_code_expr(expr); expr->expr = mputstr(expr->expr, ")"); break; case OPTYPE_MATCH: // v1 t2 u.expr.t2->generate_code(expr); expr->expr = mputstr(expr->expr, ".match("); u.expr.v1->generate_code_expr(expr); expr->expr = mputprintf(expr->expr, "%s)", omit_in_value_list ? ", TRUE" : ""); break; case OPTYPE_UNDEF_RUNNING: // it is resolved during semantic check FATAL_ERROR("Value::generate_code_expr_expr(): undef running"); break; case OPTYPE_COMP_NULL: // - expr->expr=mputstr(expr->expr, "NULL_COMPREF"); break; case OPTYPE_COMP_MTC: // - expr->expr=mputstr(expr->expr, "MTC_COMPREF"); break; case OPTYPE_COMP_SYSTEM: // - expr->expr=mputstr(expr->expr, "SYSTEM_COMPREF"); break; case OPTYPE_COMP_SELF: // - expr->expr=mputstr(expr->expr, "self"); break; case OPTYPE_CLASS_CREATE: // r1 ap_list2 generate_code_expr_class_create(expr, u.expr.r1, u.expr.ap_list2); break; case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 generate_code_expr_comp_create(expr, u.expr.r1, u.expr.v2, u.expr.v3, u.expr.b4); break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: u.expr.v1->generate_code_expr(expr); if(u.expr.v1->get_valuetype() == V_REFD) generate_code_expr_optional_field_ref(expr, u.expr.v1->get_reference()); expr->expr = mputstr(expr->expr, u.expr.v_optype == OPTYPE_COMP_ALIVE ? ".alive(" : ".running("); if (u.expr.r2 != NULL) { Ttcn::Reference* index_ref = dynamic_cast<Ttcn::Reference*>(u.expr.r2); if (index_ref == NULL) { FATAL_ERROR("Value::generate_code_expr_expr"); } Ttcn::Statement::generate_code_index_redirect(expr, index_ref, my_scope); } else { expr->expr=mputstr(expr->expr, "NULL"); } expr->expr = mputc(expr->expr, ')'); break; case OPTYPE_COMP_RUNNING_ANY: // - expr->expr=mputstr(expr->expr, "TTCN_Runtime::component_running(ANY_COMPREF)"); break; case OPTYPE_COMP_RUNNING_ALL: // - expr->expr=mputstr(expr->expr, "TTCN_Runtime::component_running(ALL_COMPREF)"); break; // v1 u.expr.v1->generate_code_expr(expr); if(u.expr.v1->get_valuetype() == V_REFD) generate_code_expr_optional_field_ref(expr, u.expr.v1->get_reference()); expr->expr = mputstr(expr->expr, ".alive()"); break; case OPTYPE_COMP_ALIVE_ANY: // - expr->expr = mputstr(expr->expr, "TTCN_Runtime::component_alive(ANY_COMPREF)"); break; case OPTYPE_COMP_ALIVE_ALL: // - expr->expr = mputstr(expr->expr, "TTCN_Runtime::component_alive(ALL_COMPREF)"); break; case OPTYPE_TMR_READ: // r1 u.expr.r1->generate_code(expr); expr->expr = mputstr(expr->expr, ".read()"); break; case OPTYPE_TMR_RUNNING: // r1 u.expr.r1->generate_code(expr); expr->expr = mputstr(expr->expr, ".running("); if (u.expr.r2 != NULL) { Ttcn::Reference* index_ref = dynamic_cast<Ttcn::Reference*>(u.expr.r2); if (index_ref == NULL) { FATAL_ERROR("Value::generate_code_expr_expr"); } Ttcn::Statement::generate_code_index_redirect(expr, index_ref, my_scope); } else { expr->expr=mputstr(expr->expr, "NULL"); } expr->expr = mputc(expr->expr, ')'); break; case OPTYPE_TMR_RUNNING_ANY: // - expr->expr=mputstr(expr->expr, "TIMER::any_running()"); break; case OPTYPE_GETVERDICT: // - expr->expr=mputstr(expr->expr, "TTCN_Runtime::getverdict()"); break; case OPTYPE_TESTCASENAME: // - expr->expr = mputstr(expr->expr, "TTCN_Runtime::get_testcasename()"); break; case OPTYPE_NOW: expr->expr = mputstr(expr->expr, "TTCN_Runtime::now()"); break; case OPTYPE_ACTIVATE: // r1 generate_code_expr_activate(expr); break; case OPTYPE_CHECKSTATE_ANY: // [r1] v2 case OPTYPE_CHECKSTATE_ALL: generate_code_expr_checkstate(expr); break; case OPTYPE_ACTIVATE_REFD: // v1 ap_list2 generate_code_expr_activate_refd(expr); break; case OPTYPE_EXECUTE: // r1 [v2] generate_code_expr_execute(expr); break; case OPTYPE_EXECUTE_REFD: //v1 ap_list2 [v3] generate_code_expr_execute_refd(expr); break; case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: u.expr.logargs->generate_code_expr(expr); break; case OPTYPE_TTCN2STRING: { Type* param_governor = u.expr.ti1->get_Template()->get_template_refd_last()->get_my_governor(); if (param_governor==NULL) FATAL_ERROR("Value::generate_code_expr_expr()"); param_governor = param_governor->get_type_refd_last(); expr->expr = mputstr(expr->expr, "ttcn_to_string("); if (!u.expr.ti1->get_DerivedRef() && !u.expr.ti1->get_Type() && u.expr.ti1->get_Template()->is_Value()) { Value* v = u.expr.ti1->get_Template()->get_Value(); delete u.expr.ti1; u.expr.ti1 = NULL; bool cast_needed = v->explicit_cast_needed(); if (cast_needed) { expr->expr = mputprintf(expr->expr, "%s(", param_governor->get_genname_value(my_scope).c_str()); } v->generate_code_expr(expr); if (cast_needed) { expr->expr = mputstr(expr->expr, ")"); } delete v; } else { u.expr.ti1->generate_code(expr); } expr->expr = mputstr(expr->expr, ")"); } break; case OPTYPE_PROF_RUNNING: expr->expr = mputstr(expr->expr, "ttcn3_prof.is_running()"); break; case OPTYPE_GET_PORT_REF: { string tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "%s* %s = dynamic_cast<%s*>(TTCN_Runtime::get_translation_port());\n" "if (%s == NULL) TTCN_error(\"Internal error: Conversion of port " "reference to type `%s' failed.\");\n", u.expr.type->get_genname_value(my_scope).c_str(), tmp_id.c_str(), u.expr.type->get_genname_value(my_scope).c_str(), tmp_id.c_str(), u.expr.type->get_typename().c_str()); expr->expr = mputprintf(expr->expr, "(*%s)", tmp_id.c_str()); break; } case OPTYPE_OF_CLASS: { Ttcn::ClassTypeBody* exp_class = u.expr.type->get_type_refd_last()-> get_class_type_body(); expression_struct_t ref_expr; Code::init_expr(&ref_expr); u.expr.r2->generate_code(&ref_expr); if (ref_expr.preamble != NULL) { expr->preamble = mputstr(expr->preamble, ref_expr.preamble); } expr->expr = mputprintf(expr->expr, "%s != NULL_VALUE && dynamic_cast<%s*>(*%s) != NULL", ref_expr.expr, exp_class->is_built_in() ? "OBJECT" : u.expr.type->get_type_refd_last()->get_genname_own(my_scope).c_str(), ref_expr.expr); if (ref_expr.postamble != NULL) { expr->postamble = mputstr(expr->postamble, ref_expr.postamble); } Code::free_expr(&ref_expr); break; } case OPTYPE_CLASS_CASTING: { Ttcn::ClassTypeBody* exp_class = u.expr.type->get_type_refd_last()-> get_class_type_body(); expression_struct_t ref_expr; Code::init_expr(&ref_expr); u.expr.r2->generate_code(&ref_expr); if (ref_expr.preamble != NULL) { expr->preamble = mputstr(expr->preamble, ref_expr.preamble); } expr->expr = mputprintf(expr->expr, "%s.cast_to<%s>()", ref_expr.expr, exp_class->is_built_in() ? "OBJECT" : u.expr.type->get_type_refd_last()->get_genname_own(my_scope).c_str()); if (ref_expr.postamble != NULL) { expr->postamble = mputstr(expr->postamble, ref_expr.postamble); } Code::free_expr(&ref_expr); break; } default: FATAL_ERROR("Value::generate_code_expr_expr()"); } } void Value::generate_code_expr_unary(expression_struct *expr, const char *operator_str, Value *v1) { expr->expr = mputprintf(expr->expr, "(%s(", operator_str); v1->generate_code_expr_mandatory(expr); expr->expr = mputstrn(expr->expr, "))", 2); } void Value::generate_code_expr_infix(expression_struct *expr, const char *operator_str, Value *v1, Value *v2, bool optional_allowed) { if (!get_needs_conversion()) { expr->expr = mputc(expr->expr, '('); if (optional_allowed) v1->generate_code_expr(expr); else v1->generate_code_expr_mandatory(expr); expr->expr = mputprintf(expr->expr, " %s ", operator_str); if (optional_allowed) v2->generate_code_expr(expr); else v2->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } else { // Temporary variable for the converted value. const string& tmp_id1 = get_temporary_id(); const char *tmp_id_str1 = tmp_id1.c_str(); expression_struct expr_tmp; Code::init_expr(&expr_tmp); switch (u.expr.v_optype) { case OPTYPE_EQ: case OPTYPE_NE: { // Always "v1 -> v2". Type *t1 = v1->get_expr_governor_last(); Type *t2 = v2->get_expr_governor_last(); if (t1 == t2) FATAL_ERROR("Value::generate_code_expr_infix()"); if (optional_allowed) v2->generate_code_expr(&expr_tmp); else v2->generate_code_expr_mandatory(&expr_tmp); if (expr_tmp.preamble) expr->preamble = mputstr(expr->preamble, expr_tmp.preamble); expr->preamble = mputprintf(expr->preamble, "%s %s;\n" "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' " "and `%s' are not compatible at run-time\");\n", t1->get_genname_value(v1->get_my_scope()).c_str(), tmp_id_str1, TypeConv::get_conv_func(t2, t1, get_my_scope() ->get_scope_mod()).c_str(), tmp_id_str1, expr_tmp.expr, t2->get_typename().c_str(), t1->get_typename().c_str()); Code::free_expr(&expr_tmp); if (optional_allowed) v1->generate_code_expr(expr); else v1->generate_code_expr_mandatory(expr); expr->expr = mputprintf(expr->expr, " %s %s", operator_str, tmp_id_str1); break; } // OPTYPE_{REPLACE,SUBSTR} are handled in their own code generation // functions. The governors of all operands must exist at this point. case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_CONCAT: { const string& tmp_id2 = get_temporary_id(); const char *tmp_id_str2 = tmp_id2.c_str(); if (!my_governor) FATAL_ERROR("Value::generate_code_expr_infix()"); Type *my_gov = my_governor->get_type_refd_last(); Type *t1_gov = v1->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE) ->get_type_refd_last(); if (!t1_gov || my_gov == t1_gov) FATAL_ERROR("Value::generate_code_expr_infix()"); expr->preamble = mputprintf(expr->preamble, "%s %s;\n", t1_gov->get_genname_value(my_scope).c_str(), tmp_id_str1); expr_tmp.expr = mputprintf(expr_tmp.expr, "%s = ", tmp_id_str1); if (optional_allowed) v1->generate_code_expr(&expr_tmp); else v1->generate_code_expr_mandatory(&expr_tmp); expr_tmp.expr = mputprintf(expr_tmp.expr, " %s ", operator_str); if (optional_allowed) v2->generate_code_expr(&expr_tmp); else v2->generate_code_expr_mandatory(&expr_tmp); expr->preamble = Code::merge_free_expr(expr->preamble, &expr_tmp); expr->preamble = mputprintf(expr->preamble, "%s %s;\n" "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' " "and `%s' are not compatible at run-time\");\n", my_gov->get_genname_value(my_scope).c_str(), tmp_id_str2, TypeConv::get_conv_func(t1_gov, my_gov, get_my_scope() ->get_scope_mod()).c_str(), tmp_id_str2, tmp_id_str1, my_gov->get_typename().c_str(), t1_gov->get_typename().c_str()); expr->expr = mputprintf(expr->expr, "%s", tmp_id_str2); break; } default: FATAL_ERROR("Value::generate_code_expr_infix()"); break; } } } void Value::generate_code_expr_and_or(expression_struct *expr) { if (u.expr.v2->needs_short_circuit()) { // introduce a temporary variable to store the result of the operation const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); expr->preamble = mputprintf(expr->preamble, "boolean %s;\n", tmp_id_str); expression_struct expr2; // the left operand must be evaluated anyway Code::init_expr(&expr2); expr2.expr = mputprintf(expr2.expr, "%s = ", tmp_id_str); u.expr.v1->generate_code_expr_mandatory(&expr2); expr->preamble = Code::merge_free_expr(expr->preamble, &expr2); expr->preamble = mputprintf(expr->preamble, "if (%s%s) ", u.expr.v_optype == OPTYPE_AND ? "" : "!", tmp_id_str); // evaluate the right operand only when necessary // in this case the final result will be the right operand Code::init_expr(&expr2); expr2.expr = mputprintf(expr2.expr, "%s = ", tmp_id_str); u.expr.v2->generate_code_expr_mandatory(&expr2); expr->preamble = Code::merge_free_expr(expr->preamble, &expr2); // the result is now in the temporary variable expr->expr = mputstr(expr->expr, tmp_id_str); } else { // use the overloaded operator to get better error messages generate_code_expr_infix(expr, u.expr.v_optype == OPTYPE_AND ? "&&" : "||", u.expr.v1, u.expr.v2, false); } } void Value::generate_code_expr_predef1(expression_struct *expr, const char *function_name, Value *v1) { expr->expr = mputprintf(expr->expr, "%s(", function_name); v1->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_predef2(expression_struct *expr, const char *function_name, Value *v1, Value *v2) { expr->expr = mputprintf(expr->expr, "%s(", function_name); v1->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ", "); v2->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_predef3(expression_struct *expr, const char *function_name, Value *v1, Value *v2, Value *v3) { expr->expr = mputprintf(expr->expr, "%s(", function_name); v1->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ", "); v2->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ", "); v3->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_substr(expression_struct *expr) { bool par1_is_str; Value* v1 = u.expr.ti1->get_specific_value(); if (v1) par1_is_str = v1->is_string_type(Type::EXPECTED_TEMPLATE); else par1_is_str = u.expr.ti1->is_string_type(Type::EXPECTED_TEMPLATE); if (par1_is_str) expr->expr = mputstr(expr->expr, "substr("); if (v1) v1->generate_code_expr_mandatory(expr); else u.expr.ti1->generate_code(expr); if (par1_is_str) expr->expr = mputstr(expr->expr, ", "); else expr->expr = mputstr(expr->expr, ".substr("); if (!par1_is_str && u.expr.v2->is_unfoldable()) expr->expr = mputstr(expr->expr, "(int)"); u.expr.v2->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ", "); if (!par1_is_str && u.expr.v3->is_unfoldable()) expr->expr = mputstr(expr->expr, "(int)"); u.expr.v3->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_substr_replace_compat(expression_struct *expr) { expression_struct expr_tmp; Code::init_expr(&expr_tmp); Type *t1 = u.expr.ti1->get_expr_governor(Type::EXPECTED_TEMPLATE) ->get_type_refd_last(); if (!t1 || t1 == my_governor->get_type_refd_last()) FATAL_ERROR("Value::generate_code_expr_substr_replace_compat()"); if (u.expr.v_optype == OPTYPE_SUBSTR) { generate_code_expr_substr(&expr_tmp); } else if (u.expr.v_optype == OPTYPE_REPLACE) { generate_code_expr_replace(&expr_tmp); } else { FATAL_ERROR("Value::generate_code_expr_substr_replace_compat()"); } // Two temporaries to store the result of substr() or replace() and to // store the converted value. const string& tmp_id1 = get_temporary_id(); const char *tmp_id_str1 = tmp_id1.c_str(); const string& tmp_id2 = get_temporary_id(); const char *tmp_id_str2 = tmp_id2.c_str(); if (expr_tmp.preamble) expr->preamble = mputstr(expr->preamble, expr_tmp.preamble); expr->preamble = mputprintf(expr->preamble, "%s %s;\n%s %s = %s;\n", my_governor->get_genname_value(my_scope).c_str(), tmp_id_str1, t1->get_genname_value(my_scope).c_str(), tmp_id_str2, expr_tmp.expr); if (expr_tmp.postamble) expr->preamble = mputstr(expr->preamble, expr_tmp.postamble); Code::free_expr(&expr_tmp); expr->preamble = mputprintf(expr->preamble, "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' and " "`%s' are not compatible at run-time\");\n", TypeConv::get_conv_func(t1, my_governor->get_type_refd_last(), my_scope->get_scope_mod()).c_str(), tmp_id_str1, tmp_id_str2, my_governor->get_typename().c_str(), t1->get_typename().c_str()); expr->expr = mputprintf(expr->expr, "%s", tmp_id_str1); } void Value::generate_code_expr_regexp(expression_struct *expr) { Value* v1 = u.expr.ti1->get_specific_value(); Value* v2 = u.expr.t2->get_specific_value(); expr->expr = mputstr(expr->expr, "regexp("); if (v1) v1->generate_code_expr_mandatory(expr); else u.expr.ti1->generate_code(expr); expr->expr = mputstr(expr->expr, ", "); if (v2) v2->generate_code_expr_mandatory(expr); else u.expr.t2->generate_code(expr); expr->expr = mputstr(expr->expr, ", "); u.expr.v3->generate_code_expr_mandatory(expr); expr->expr = mputprintf(expr->expr, ", %s)", u.expr.b4 ? "TRUE" : "FALSE"); } void Value::generate_code_expr_replace(expression_struct *expr) { Value* v1 = u.expr.ti1->get_specific_value(); Value* v4 = u.expr.ti4->get_specific_value(); bool par1_is_str; if (v1) par1_is_str = v1->is_string_type(Type::EXPECTED_TEMPLATE); else par1_is_str = u.expr.ti1->is_string_type(Type::EXPECTED_TEMPLATE); if (par1_is_str) expr->expr = mputstr(expr->expr, "replace("); if (v1) v1->generate_code_expr_mandatory(expr); else u.expr.ti1->generate_code(expr); if (par1_is_str) expr->expr = mputstr(expr->expr, ", "); else expr->expr = mputstr(expr->expr, ".replace("); if (!par1_is_str && u.expr.v2->is_unfoldable()) expr->expr = mputstr(expr->expr, "(int)"); u.expr.v2->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ", "); if (!par1_is_str && u.expr.v3->is_unfoldable()) expr->expr = mputstr(expr->expr, "(int)"); u.expr.v3->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ", "); if (v4) { // if v4 is an empty record of constant (NULL_VALUE), the C++ compiler won't know // which replace function to call (replace(int,int,X) or replace(int,int,X_template)) Value* v4_last = v4->get_value_refd_last(); if ((v4_last->valuetype == V_SEQOF || v4_last->valuetype == V_SETOF) && !v4_last->u.val_vs->is_indexed() && v4_last->u.val_vs->get_nof_vs() == 0) { expr->expr = mputprintf(expr->expr, "(%s)", v4->my_governor->get_genname_value(my_scope).c_str()); } v4->generate_code_expr_mandatory(expr); } else u.expr.ti4->generate_code(expr); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_rnd(expression_struct *expr, Value *v1) { if(!v1) // simple random generation expr->expr = mputstr(expr->expr, "rnd()"); else { // random generation with seeding expr->expr = mputstr(expr->expr, "rnd("); v1->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } } void Value::generate_code_expr_class_create(expression_struct* expr, Ttcn::Reference* type, Ttcn::ActualParList* ap_list) { expr->expr = mputstr(expr->expr, "new "); type->generate_code(expr); expr->expr = mputc(expr->expr, '('); Assignment* t_ass = type->get_refd_assignment(); if (t_ass == NULL || t_ass->get_asstype() != Assignment::A_TYPE) { FATAL_ERROR("Value::generate_code_expr_class_create()"); } ap_list->generate_code_noalias(expr, t_ass->get_Type()->get_class_type_body()->get_constructor()->get_FormalParList()); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_comp_create(expression_struct *expr, Ttcn::Reference *type, Value *name, Value *location, bool alive) { expr->expr = mputstr(expr->expr, "TTCN_Runtime::create_component("); // first two arguments: component type Assignment *t_ass = type->get_refd_assignment(); if (!t_ass || t_ass->get_asstype() != Assignment::A_TYPE) FATAL_ERROR("Value::generate_code_expr_comp_create()"); Type *comptype = t_ass->get_Type()->get_field_type(type->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE); if (!comptype) FATAL_ERROR("Value::generate_code_expr_comp_create()"); comptype = comptype->get_type_refd_last(); expr->expr = comptype->get_CompBody() ->generate_code_comptype_name(expr->expr); expr->expr = mputstr(expr->expr, ", "); // third argument: component name if (name) { Value *t_val = name->get_value_refd_last(); if (t_val->valuetype == V_CSTR) { // the argument is foldable to a string literal size_t str_len = t_val->u.str.val_str->size(); const char *str_ptr = t_val->u.str.val_str->c_str(); expr->expr = mputc(expr->expr, '"'); for (size_t i = 0; i < str_len; i++) expr->expr = Code::translate_character(expr->expr, str_ptr[i], true); expr->expr = mputc(expr->expr, '"'); } else name->generate_code_expr_mandatory(expr); } else expr->expr = mputstr(expr->expr, "NULL"); expr->expr = mputstr(expr->expr, ", "); // fourth argument: location if (location) { Value *t_val = location->get_value_refd_last(); if (t_val->valuetype == V_CSTR) { // the argument is foldable to a string literal size_t str_len = t_val->u.str.val_str->size(); const char *str_ptr = t_val->u.str.val_str->c_str(); expr->expr = mputc(expr->expr, '"'); for (size_t i = 0; i < str_len; i++) expr->expr = Code::translate_character(expr->expr, str_ptr[i], true); expr->expr = mputc(expr->expr, '"'); } else location->generate_code_expr_mandatory(expr); } else expr->expr = mputstr(expr->expr, "NULL"); // fifth argument: alive flag expr->expr = mputprintf(expr->expr, ", %s)", alive ? "TRUE" : "FALSE"); } void Value::generate_code_expr_activate(expression_struct *expr) { Assignment *t_ass = u.expr.r1->get_refd_assignment(); if (!t_ass || t_ass->get_asstype() != Assignment::A_ALTSTEP) FATAL_ERROR("Value::generate_code_expr_activate()"); expr->expr = mputprintf(expr->expr, "%s(", t_ass->get_genname_from_scope(my_scope, "activate_").c_str()); u.expr.r1->get_parlist()->generate_code_noalias(expr, t_ass->get_FormalParList()); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_activate_refd(expression_struct *expr) { Value *v_last = u.expr.v1->get_value_refd_last(); if (v_last->valuetype == V_ALTSTEP) { // the referred altstep is known expr->expr = mputprintf(expr->expr, "%s(", v_last->get_refd_fat() ->get_genname_from_scope(my_scope, "activate_").c_str()); } else { // the referred altstep is unknown u.expr.v1->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr,".activate("); } u.expr.ap_list2->generate_code_noalias(expr, NULL); expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_execute(expression_struct *expr) { Assignment *testcase = u.expr.r1->get_refd_assignment(); expr->expr = mputprintf(expr->expr, "%s(", testcase->get_genname_from_scope(my_scope, "testcase_").c_str()); Ttcn::ActualParList *parlist = u.expr.r1->get_parlist(); if (parlist->get_nof_pars() > 0) { parlist->generate_code_alias(expr, testcase->get_FormalParList(), 0, false); expr->expr = mputstr(expr->expr, ", "); } if (u.expr.v2) { expr->expr = mputstr(expr->expr, "TRUE, "); u.expr.v2->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } else expr->expr = mputstr(expr->expr, "FALSE, 0.0)"); } void Value::generate_code_expr_execute_refd(expression_struct *expr) { Value *v_last = u.expr.v1->get_value_refd_last(); if (v_last->valuetype == V_TESTCASE) { // the referred testcase is known Assignment *testcase = v_last->get_refd_fat(); expr->expr = mputprintf(expr->expr, "%s(", testcase->get_genname_from_scope(my_scope, "testcase_").c_str()); u.expr.ap_list2->generate_code_alias(expr, testcase->get_FormalParList(), 0, false); } else { // the referred testcase is unknown u.expr.v1->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr,".execute("); u.expr.ap_list2->generate_code_alias(expr, 0, 0, false); } if (u.expr.ap_list2->get_nof_pars() > 0) expr->expr = mputstr(expr->expr, ", "); if (u.expr.v3) { expr->expr = mputstr(expr->expr, "TRUE, "); u.expr.v3->generate_code_expr_mandatory(expr); expr->expr = mputc(expr->expr, ')'); } else expr->expr = mputstr(expr->expr, "FALSE, 0.0)"); } void Value::generate_code_expr_invoke(expression_struct *expr) { Value *last_v = u.invoke.v->get_value_refd_last(); if (last_v->get_valuetype() == V_FUNCTION) { // the referred function is known Assignment *function = last_v->get_refd_fat(); expr->expr = mputprintf(expr->expr, "%s(", function->get_genname_from_scope(my_scope).c_str()); u.invoke.ap_list->generate_code_alias(expr, function->get_FormalParList(), function->get_RunsOnType(), false); } else { // the referred function is unknown u.invoke.v->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ".invoke("); Type* gov_last = last_v->get_expr_governor_last(); u.invoke.ap_list->generate_code_alias(expr, 0, gov_last->get_fat_runs_on_type(), gov_last->get_fat_runs_on_self()); } expr->expr = mputc(expr->expr, ')'); } void Value::generate_code_expr_optional_field_ref(expression_struct *expr, Reference *ref) { // if the referenced value points to an optional value field the // generated code has to be corrected at the end: // `fieldid()' => `fieldid()()' Assignment *ass = ref->get_refd_assignment(); if (!ass) FATAL_ERROR("Value::generate_code_expr_optional_field_ref()"); switch (ass->get_asstype()) { case Assignment::A_CONST: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: // only these are mapped to value objects if (ass->get_Type()->field_is_optional(ref->get_subrefs())) expr->expr = mputstr(expr->expr, "()"); break; default: break; } } void Value::generate_code_expr_encode(expression_struct *expr) { Value* v1 = 0; Template* templ = u.expr.ti1->get_Template()->get_template_refd_last(); if (templ->get_templatetype() == Template::SPECIFIC_VALUE) v1 = templ->get_specific_value(); Type* gov_last = templ->get_my_governor()->get_type_refd_last(); expression_struct expr2; Code::init_expr(&expr2); bool is_templ = false; switch (templ->get_templatetype()) { case Template::SPECIFIC_VALUE: v1->generate_code_expr_mandatory(&expr2); break; default: u.expr.ti1->generate_code(&expr2); is_templ = true; break; } Scope* scope = u.expr.ti1->get_Template()->get_my_scope(); if (legacy_codec_handling) { if (!gov_last->is_coding_by_function(true)) { const string& tmp_id = get_temporary_id(); const string& tmp_buf_id = get_temporary_id(); const string& tmp_ref_id = get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "OCTETSTRING %s;\n", tmp_id.c_str()); expr->preamble = mputprintf(expr->preamble, "TTCN_Buffer %s;\n", tmp_buf_id.c_str()); if (expr2.preamble) { // copy preamble setting up the argument, if any expr->preamble = mputstr(expr->preamble, expr2.preamble); expr->preamble = mputc (expr->preamble, '\n'); } expr->preamble = mputprintf(expr->preamble, "%s const& %s = %s", 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 expr->preamble = mputprintf(expr->preamble, ".valueof()"); 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(scope).c_str(), tmp_buf_id.c_str(), gov_last->get_coding(true).c_str() ); expr->preamble = mputstr(expr->preamble, ");\n"); expr->preamble = mputprintf(expr->preamble, "%s.get_string(%s);\n", tmp_buf_id.c_str(), tmp_id.c_str() ); expr->expr = mputprintf(expr->expr, "oct2bit(%s)", tmp_id.c_str()); if (expr2.postamble) expr->postamble = mputstr(expr->postamble, expr2.postamble); } else { if (expr2.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr2.preamble); } expr->expr = mputprintf(expr->expr, "%s(%s%s)", gov_last->get_legacy_coding_function(true)->get_genname_from_scope(scope).c_str(), expr2.expr, is_templ ? ".valueof()" : ""); } } else { // new codec handling Type* gov = templ->get_my_governor(); if (expr2.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr2.preamble); } expression_struct expr3; Code::init_expr(&expr3); if (u.expr.v3 != NULL) { u.expr.v3->generate_code_expr(&expr3); if (expr3.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr3.preamble); } } else { expr3.expr = mprintf("%s_default_coding", gov->get_genname_default_coding(scope).c_str()); } const string& tmp_id = get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "OCTETSTRING %s;\n" "%s_encoder(%s%s, %s, %s);\n", tmp_id.c_str(), gov->get_genname_coder(scope).c_str(), expr2.expr, is_templ ? ".valueof()" : "", tmp_id.c_str(), expr3.expr); expr->expr = mputprintf(expr->expr, "oct2bit(%s)", tmp_id.c_str()); if (expr2.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr2.postamble); } if (expr3.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr3.postamble); } Code::free_expr(&expr3); } Code::free_expr(&expr2); } void Value::generate_code_expr_decode(expression_struct *expr) { expression_struct expr1, expr2; Code::init_expr(&expr1); Code::init_expr(&expr2); u.expr.r1->generate_code(&expr1); u.expr.r2->generate_code(&expr2); Type* _type = u.expr.r2->get_refd_assignment()->get_Type()-> get_field_type(u.expr.r2->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE); Type* _type_last = _type->get_type_refd_last(); if (expr1.preamble) expr->preamble = mputprintf(expr->preamble, "%s", expr1.preamble); if (expr2.preamble) expr->preamble = mputprintf(expr->preamble, "%s", expr2.preamble); Scope* scope = u.expr.r2->get_my_scope(); const bool optional = u.expr.r2->get_refd_assignment()->get_Type()-> field_is_optional(u.expr.r2->get_subrefs()); if (legacy_codec_handling) { if (!_type_last->is_coding_by_function(false)) { const string& tmp_id = get_temporary_id(); const string& buffer_id = get_temporary_id(); const string& retval_id = get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "TTCN_Buffer %s(bit2oct(%s));\n" "INTEGER %s;\n" "TTCN_EncDec::set_error_behavior(" "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);\n" "TTCN_EncDec::clear_error();\n", buffer_id.c_str(), expr1.expr, retval_id.c_str() ); expr->preamble = mputprintf(expr->preamble, "%s%s.decode(%s_descr_, %s, TTCN_EncDec::CT_%s);\n", expr2.expr, optional ? "()" : "", _type_last->get_genname_typedescriptor(scope).c_str(), buffer_id.c_str(), _type_last->get_coding(false).c_str() ); expr->preamble = mputprintf(expr->preamble, "switch (TTCN_EncDec::get_last_error_type()) {\n" "case TTCN_EncDec::ET_NONE: {\n" "%s.cut();\n" "OCTETSTRING %s;\n" "%s.get_string(%s);\n" "%s = oct2bit(%s);\n" "%s = 0;\n" "}break;\n" "case TTCN_EncDec::ET_INCOMPL_MSG:\n" "case TTCN_EncDec::ET_LEN_ERR:\n" "%s = 2;\n" "break;\n" "default:\n" "%s = 1;\n" "}\n" "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL," "TTCN_EncDec::EB_DEFAULT);\n" "TTCN_EncDec::clear_error();\n", buffer_id.c_str(), tmp_id.c_str(), buffer_id.c_str(), tmp_id.c_str(), expr1.expr, tmp_id.c_str(), retval_id.c_str(), retval_id.c_str(), retval_id.c_str() ); expr->expr = mputprintf(expr->expr, "%s", retval_id.c_str()); } else expr->expr = mputprintf(expr->expr, "%s(%s, %s)", _type_last->get_legacy_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) expr->postamble = mputprintf(expr->postamble, "%s", expr2.postamble); } else { // new codec handling if (expr1.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr1.preamble); } if (expr2.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr2.preamble); } expression_struct expr3; Code::init_expr(&expr3); if (u.expr.v4 != NULL) { u.expr.v4->generate_code_expr(&expr3); if (expr3.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr3.preamble); } } else { expr3.expr = mprintf("%s_default_coding", _type->get_genname_default_coding(scope).c_str()); } const string& buff_id = get_temporary_id(); const string& retval_id = get_temporary_id(); if (_type->has_built_in_encoding()) { expr->preamble = mputstr(expr->preamble, "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, " "TTCN_EncDec::EB_WARNING);\n" "TTCN_EncDec::clear_error();\n"); } expr->preamble = mputprintf(expr->preamble, "OCTETSTRING %s(bit2oct(%s));\n" "INTEGER %s(%s_decoder(%s, %s%s, %s));\n" "if (%s == 0) {\n" "%s = oct2bit(%s);\n" "}\n", buff_id.c_str(), expr1.expr, retval_id.c_str(), _type->get_genname_coder(scope).c_str(), buff_id.c_str(), expr2.expr, optional ? "()" : "", expr3.expr, retval_id.c_str(), expr1.expr, buff_id.c_str()); if (_type->has_built_in_encoding()) { expr->preamble = mputstr(expr->preamble, "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, " "TTCN_EncDec::EB_DEFAULT);\n" "TTCN_EncDec::clear_error();\n"); } expr->expr = mputprintf(expr->expr, "%s", retval_id.c_str()); if (expr1.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr1.postamble); } if (expr2.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr2.postamble); } if (expr3.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr3.postamble); } Code::free_expr(&expr3); } Code::free_expr(&expr1); Code::free_expr(&expr2); } void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) { Value* v1 = 0; Template* templ = u.expr.ti1->get_Template()->get_template_refd_last(); if (templ->get_templatetype() == Template::SPECIFIC_VALUE) v1 = templ->get_specific_value(); Type* gov_last = templ->get_my_governor()->get_type_refd_last(); expression_struct expr2; Code::init_expr(&expr2); bool is_templ = false; switch (templ->get_templatetype()) { case Template::SPECIFIC_VALUE: v1->generate_code_expr_mandatory(&expr2); break; default: u.expr.ti1->generate_code(&expr2); is_templ = true; break; } char * v2_code = NULL; if(u.expr.v2) { v2_code = generate_code_char_coding_check(expr, u.expr.v2, "encvalue_unichar"); } else { v2_code = mcopystr("\"UTF-8\""); } Scope* scope = u.expr.ti1->get_Template()->get_my_scope(); if (legacy_codec_handling) { if (!gov_last->is_coding_by_function(true)) { const string& tmp_id = get_temporary_id(); const string& tmp_buf_id = get_temporary_id(); const string& tmp_ref_id = get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "OCTETSTRING %s;\n", tmp_id.c_str()); expr->preamble = mputprintf(expr->preamble, "TTCN_Buffer %s;\n", tmp_buf_id.c_str()); if (expr2.preamble) { // copy preamble setting up the argument, if any expr->preamble = mputstr(expr->preamble, expr2.preamble); expr->preamble = mputc (expr->preamble, '\n'); } expr->preamble = mputprintf(expr->preamble, "%s const& %s = %s", 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 expr->preamble = mputprintf(expr->preamble, ".valueof()"); 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(scope).c_str(), tmp_buf_id.c_str(), gov_last->get_coding(true).c_str() ); expr->preamble = mputstr(expr->preamble, ");\n"); expr->preamble = mputprintf(expr->preamble, "%s.get_string(%s);\n", tmp_buf_id.c_str(), tmp_id.c_str() ); expr->expr = mputprintf(expr->expr, "oct2unichar(%s, %s)", tmp_id.c_str(), v2_code); if (expr2.postamble) expr->postamble = mputstr(expr->postamble, expr2.postamble); } else { if (expr2.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr2.preamble); } expr->expr = mputprintf(expr->expr, "oct2unichar(bit2oct(%s(%s%s)), %s)", gov_last->get_legacy_coding_function(true)->get_genname_from_scope(scope).c_str(), expr2.expr, is_templ ? ".valueof()" : "", v2_code); } } else { // new codec handling Type* gov = templ->get_my_governor(); if (expr2.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr2.preamble); } expression_struct expr3; Code::init_expr(&expr3); if (u.expr.v4 != NULL) { u.expr.v4->generate_code_expr(&expr3); if (expr3.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr3.preamble); } } else { expr3.expr = mprintf("%s_default_coding", gov->get_genname_default_coding(scope).c_str()); } const string& tmp_id = get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "OCTETSTRING %s;\n" "%s_encoder(%s%s, %s, %s);\n", tmp_id.c_str(), gov->get_genname_coder(scope).c_str(), expr2.expr, is_templ ? ".valueof()" : "", tmp_id.c_str(), expr3.expr); expr->expr = mputprintf(expr->expr, "oct2unichar(%s, %s)", tmp_id.c_str(), v2_code); if (expr2.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr2.postamble); } if (expr3.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr3.postamble); } Code::free_expr(&expr3); } Code::free_expr(&expr2); Free(v2_code); } void Value::generate_code_expr_decvalue_unichar(expression_struct *expr) { expression_struct expr1, expr2; Code::init_expr(&expr1); Code::init_expr(&expr2); u.expr.r1->generate_code(&expr1); u.expr.r2->generate_code(&expr2); Type* _type = u.expr.r2->get_refd_assignment()->get_Type()-> get_field_type(u.expr.r2->get_subrefs(), Type::EXPECTED_DYNAMIC_VALUE); Type* _type_last = _type->get_type_refd_last(); if (expr1.preamble) expr->preamble = mputprintf(expr->preamble, "%s", expr1.preamble); if (expr2.preamble) expr->preamble = mputprintf(expr->preamble, "%s", expr2.preamble); char* v3_code = NULL; if(u.expr.v3) { v3_code = generate_code_char_coding_check(expr, u.expr.v3, "decvalue_unichar"); } else { v3_code = mcopystr("\"UTF-8\""); } Scope* scope = u.expr.r2->get_my_scope(); const bool optional = u.expr.r2->get_refd_assignment()->get_Type()-> field_is_optional(u.expr.r2->get_subrefs()); if (legacy_codec_handling) { if (!_type_last->is_coding_by_function(false)) { const string& tmp_id = get_temporary_id(); const string& buffer_id = get_temporary_id(); const string& retval_id = get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "TTCN_Buffer %s(unichar2oct(%s, %s));\n" "INTEGER %s;\n" "TTCN_EncDec::set_error_behavior(" "TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);\n" "TTCN_EncDec::clear_error();\n", buffer_id.c_str(), expr1.expr, v3_code, retval_id.c_str() ); expr->preamble = mputprintf(expr->preamble, "%s%s.decode(%s_descr_, %s, TTCN_EncDec::CT_%s);\n", expr2.expr, optional ? "()" : "", _type_last->get_genname_typedescriptor(scope).c_str(), buffer_id.c_str(), _type_last->get_coding(false).c_str() ); expr->preamble = mputprintf(expr->preamble, "switch (TTCN_EncDec::get_last_error_type()) {\n" "case TTCN_EncDec::ET_NONE: {\n" "%s.cut();\n" "OCTETSTRING %s;\n" "%s.get_string(%s);\n" "%s = oct2unichar(%s, %s);\n" "%s = 0;\n" "}break;\n" "case TTCN_EncDec::ET_INCOMPL_MSG:\n" "case TTCN_EncDec::ET_LEN_ERR:\n" "%s = 2;\n" "break;\n" "default:\n" "%s = 1;\n" "}\n" "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL," "TTCN_EncDec::EB_DEFAULT);\n" "TTCN_EncDec::clear_error();\n", buffer_id.c_str(), tmp_id.c_str(), buffer_id.c_str(), tmp_id.c_str(), expr1.expr, tmp_id.c_str(), v3_code, retval_id.c_str(), retval_id.c_str(), retval_id.c_str() ); expr->expr = mputprintf(expr->expr, "%s", retval_id.c_str()); } else { const string& ustr_ref_id = get_temporary_id(); const string& bstr_id = get_temporary_id(); const string& ret_val_id = get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "UNIVERSAL_CHARSTRING& %s = %s;\n" "BITSTRING %s(oct2bit(unichar2oct(%s, %s)));\n" "INTEGER %s(%s(%s, %s));\n" "%s = oct2unichar(bit2oct(%s), %s);\n", ustr_ref_id.c_str(), expr1.expr, bstr_id.c_str(), ustr_ref_id.c_str(), v3_code, ret_val_id.c_str(), _type_last->get_legacy_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(), v3_code); expr->expr = mputprintf(expr->expr, "%s", ret_val_id.c_str()); } if (expr1.postamble) expr->postamble = mputprintf(expr->postamble, "%s", expr1.postamble); if (expr2.postamble) expr->postamble = mputprintf(expr->postamble, "%s", expr2.postamble); } else { // new codec handling if (expr1.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr1.preamble); } if (expr2.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr2.preamble); } expression_struct expr3; Code::init_expr(&expr3); if (u.expr.v5 != NULL) { u.expr.v5->generate_code_expr(&expr3); if (expr3.preamble != NULL) { expr->preamble = mputstr(expr->preamble, expr3.preamble); } } else { expr3.expr = mprintf("%s_default_coding", _type->get_genname_default_coding(scope).c_str()); } const string& buff_id = get_temporary_id(); const string& retval_id = get_temporary_id(); if (_type->has_built_in_encoding()) { expr->preamble = mputstr(expr->preamble, "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, " "TTCN_EncDec::EB_WARNING);\n" "TTCN_EncDec::clear_error();\n"); } expr->preamble = mputprintf(expr->preamble, "OCTETSTRING %s(unichar2oct(%s, %s));\n" "INTEGER %s(%s_decoder(%s, %s%s, %s));\n" "if (%s == 0) {\n" "%s = oct2unichar(%s, %s);\n" "}\n", buff_id.c_str(), expr1.expr, v3_code, retval_id.c_str(), _type->get_genname_coder(scope).c_str(), buff_id.c_str(), expr2.expr, optional ? "()" : "", expr3.expr, retval_id.c_str(), expr1.expr, buff_id.c_str(), v3_code); if (_type->has_built_in_encoding()) { expr->preamble = mputstr(expr->preamble, "TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, " "TTCN_EncDec::EB_DEFAULT);\n" "TTCN_EncDec::clear_error();\n"); } expr->expr = mputprintf(expr->expr, "%s", retval_id.c_str()); if (expr1.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr1.postamble); } if (expr2.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr2.postamble); } if (expr3.postamble != NULL) { expr->postamble = mputstr(expr->postamble, expr3.postamble); } Code::free_expr(&expr3); } Code::free_expr(&expr1); Code::free_expr(&expr2); Free(v3_code); } void Value::generate_code_expr_checkstate(expression_struct *expr) { if (u.expr.r1) { // It is a port if r1 is not null u.expr.r1->generate_code_const_ref(expr); expr->expr = mputstr(expr->expr, "."); } else { // it is an any or all port if r1 is null if (u.expr.v_optype == OPTYPE_CHECKSTATE_ANY) { expr->expr = mputstr(expr->expr, "PORT::any_"); } else if (u.expr.v_optype == OPTYPE_CHECKSTATE_ALL) { expr->expr = mputstr(expr->expr, "PORT::all_"); } else { FATAL_ERROR("Value::generate_code_expr_checkstate()"); } } expr->expr = mputstr(expr->expr, "check_port_state("); u.expr.v2->generate_code_expr_mandatory(expr); expr->expr = mputstr(expr->expr, ")"); } void Value::generate_code_expr_hostid(expression_struct *expr) { expr->expr = mputstr(expr->expr, "TTCN_Runtime::get_host_address("); if (u.expr.v1) u.expr.v1->generate_code_expr_mandatory(expr); else expr->expr = mputstr(expr->expr, "CHARSTRING(\"Ipv4orIpv6\")"); expr->expr = mputstr(expr->expr, ")"); } char* Value::generate_code_char_coding_check(expression_struct *expr, Value *v, const char *name) { expression_struct expr2; Code::init_expr(&expr2); v->generate_code_expr_mandatory(&expr2); expr->preamble = mputprintf(expr->preamble, "if (\"UTF-8\" != %s && \"UTF-16\" != %s && \"UTF-16LE\" != %s && \n" " \"UTF-16BE\" != %s && \"UTF-32\" != %s && \"UTF-32LE\" != %s && \n" " \"UTF-32BE\" != %s) {\n" " TTCN_error(\"%s: Invalid encoding parameter: %%s\", (const char*)%s);\n" "}\n", //todo errorbehaviour? expr2.expr, expr2.expr, expr2.expr, expr2.expr, expr2.expr, expr2.expr, expr2.expr, name, expr2.expr); return expr2.expr; } char *Value::generate_code_init_choice(char *str, const char *name) { const char *alt_name = u.choice.alt_name->get_name().c_str(); // Safe as long as get_name() returns a const string&, not a temporary. const char *alt_prefix = (my_governor->get_type_refd_last()->get_typetype()==Type::T_ANYTYPE) ? "AT_" : ""; if (u.choice.alt_value->needs_temp_ref()) { const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); str = mputprintf(str, "{\n" "%s& %s = %s.%s%s();\n", my_governor->get_comp_byName(*u.choice.alt_name) ->get_type()->get_genname_value(my_scope).c_str(), tmp_id_str, name, alt_prefix, alt_name); str = u.choice.alt_value->generate_code_init(str, tmp_id_str); str = mputstr(str, "}\n"); } else { char *embedded_name = mprintf("%s.%s%s()", name, alt_prefix, alt_name); str = u.choice.alt_value->generate_code_init(str, embedded_name); Free(embedded_name); } return str; } char *Value::generate_code_init_seof(char *str, const char *name) { size_t nof_vs = u.val_vs->get_nof_vs(); if (nof_vs > 0) { str = mputprintf(str, "%s.set_size(%lu);\n", name, (unsigned long)nof_vs); const string& embedded_type = my_governor->get_ofType()->get_genname_value(my_scope); const char *embedded_type_str = embedded_type.c_str(); for (size_t i = 0; i < nof_vs; i++) { Value *comp_v = u.val_vs->get_v_byIndex(i); if (comp_v->valuetype == V_NOTUSED) continue; else if (comp_v->needs_temp_ref()) { const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); str = mputprintf(str, "{\n" "%s& %s = %s[%lu];\n", embedded_type_str, tmp_id_str, name, (unsigned long) i); str = comp_v->generate_code_init(str, tmp_id_str); str = mputstr(str, "}\n"); } else { char *embedded_name = mprintf("%s[%lu]", name, (unsigned long) i); str = comp_v->generate_code_init(str, embedded_name); Free(embedded_name); } } } else { str = mputprintf(str, "%s = NULL_VALUE;\n", name); } return str; } char *Value::generate_code_init_indexed(char *str, const char *name) { size_t nof_ivs = u.val_vs->get_nof_ivs(); if (nof_ivs > 0) { // Previous values can be truncated. The concept is similar to // templates. Type *t_last = my_governor->get_type_refd_last(); const string& oftype_name = t_last->get_ofType()->get_genname_value(my_scope); const char *oftype_name_str = oftype_name.c_str(); for (size_t i = 0; i < nof_ivs; i++) { IndexedValue *iv = u.val_vs->get_iv_byIndex(i); const string& tmp_id_1 = get_temporary_id(); str = mputstr(str, "{\n"); Value *index = iv->get_index(); if (index->get_valuetype() != V_INT) { const string& tmp_id_2 = get_temporary_id(); str = mputprintf(str, "int %s;\n", tmp_id_2.c_str()); str = index->generate_code_init(str, tmp_id_2.c_str()); str = mputprintf(str, "%s& %s = %s[%s];\n", oftype_name_str, tmp_id_1.c_str(), name, tmp_id_2.c_str()); } else { str = mputprintf(str, "%s& %s = %s[%s];\n", oftype_name_str, tmp_id_1.c_str(), name, (index->get_val_Int()->t_str()).c_str()); } str = iv->get_value()->generate_code_init(str, tmp_id_1.c_str()); str = mputstr(str, "}\n"); } } else { str = mputprintf(str, "%s = NULL_VALUE;\n", name); } return str; } char *Value::generate_code_init_array(char *str, const char *name) { size_t nof_vs = u.val_vs->get_nof_vs(); Type *t_last = my_governor->get_type_refd_last(); Int index_offset = t_last->get_dimension()->get_offset(); const string& embedded_type = t_last->get_ofType()->get_genname_value(my_scope); const char *embedded_type_str = embedded_type.c_str(); for (size_t i = 0; i < nof_vs; i++) { Value *comp_v = u.val_vs->get_v_byIndex(i); if (comp_v->valuetype == V_NOTUSED) continue; else if (comp_v->needs_temp_ref()) { const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); str = mputprintf(str, "{\n" "%s& %s = %s[%s];\n", embedded_type_str, tmp_id_str, name, Int2string(index_offset + i).c_str()); str = comp_v->generate_code_init(str, tmp_id_str); str = mputstr(str, "}\n"); } else { char *embedded_name = mprintf("%s[%s]", name, Int2string(index_offset + i).c_str()); str = comp_v->generate_code_init(str, embedded_name); Free(embedded_name); } } return str; } char *Value::generate_code_init_se(char *str, const char *name) { Type *type = my_governor->get_type_refd_last(); size_t nof_comps = type->get_nof_comps(); if (nof_comps > 0) { for (size_t i = 0; i < nof_comps; i++) { CompField *cf = type->get_comp_byIndex(i); const Identifier& field_id = cf->get_name(); const char *field_name = field_id.get_name().c_str(); Value *field_v; if (u.val_nvs->has_nv_withName(field_id)) { field_v = u.val_nvs->get_nv_byName(field_id)->get_value(); if (field_v->valuetype == V_NOTUSED) continue; if (field_v->valuetype == V_OMIT) field_v = 0; } else if (is_asn1()) { if (cf->has_default()) { // handle like a referenced value Value *defval = cf->get_defval(); if (needs_init_precede(defval)) { str = defval->generate_code_init(str, defval->get_lhs_name().c_str()); } str = mputprintf(str, "%s.%s() = %s;\n", name, field_name, defval->get_genname_own(my_scope).c_str()); continue; } else { if (!cf->get_is_optional()) FATAL_ERROR("Value::generate_code_init()"); field_v = 0; } } else { continue; } if (field_v) { // the value is not omit if (field_v->needs_temp_ref()) { const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); str = mputprintf(str, "{\n" "%s& %s = %s.%s();\n", type->get_comp_byName(field_id)->get_type() ->get_genname_value(my_scope).c_str(), tmp_id_str, name, field_name); str = field_v->generate_code_init(str, tmp_id_str); str = mputstr(str, "}\n"); } else { char *embedded_name = mprintf("%s.%s()", name, field_name); if (cf->get_is_optional() && field_v->is_compound()) embedded_name = mputstr(embedded_name, "()"); str = field_v->generate_code_init(str, embedded_name); Free(embedded_name); } } else { // the value is omit str = mputprintf(str, "%s.%s() = OMIT_VALUE;\n", name, field_name); } } } else { str = mputprintf(str, "%s = NULL_VALUE;\n", name); } return str; } char *Value::generate_code_init_refd(char *str, const char *name) { Value *v = get_value_refd_last(); if (v == this) { if (get_code_section() == CS_INIT_CLASS) { str = rearrange_init_code_refd(str); } // the referred value is not available at compile time // the code generation is based on the reference if (use_runtime_2 && TypeConv::needs_conv_refd(v)) { str = TypeConv::gen_conv_code_refd(str, name, v); } else { expression_struct expr; Code::init_expr(&expr); expr.expr = mputprintf(expr.expr, "%s = ", name); u.ref.ref->generate_code_const_ref(&expr); str = Code::merge_free_expr(str, &expr); } } else { // the referred value is available at compile time // the code generation is based on the referred value if (v->has_single_expr() && my_scope->get_scope_mod_gen() == v->my_scope->get_scope_mod_gen()) { // simple substitution for in-line values within the same module str = mputprintf(str, "%s = %s;\n", name, v->get_single_expr().c_str()); } else { // use a simple reference to reduce code size if (needs_init_precede(v)) { // the referred value must be initialized first if (!v->is_toplevel() && v->needs_temp_ref()) { // temporary id should be introduced for the lhs const string& tmp_id = get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); str = mputprintf(str, "{\n" "%s& %s = %s;\n", v->get_my_governor()->get_genname_value(my_scope).c_str(), tmp_id_str, v->get_lhs_name().c_str()); str = v->generate_code_init(str, tmp_id_str); str = mputstr(str, "}\n"); } else { str = v->generate_code_init(str, v->get_lhs_name().c_str()); } } str = mputprintf(str, "%s = %s;\n", name, v->get_genname_own(my_scope).c_str()); } } return str; } void Value::generate_json_value(JSON_Tokenizer& json, bool allow_special_float, /* = true */ bool union_value_list, /* = false */ Ttcn::JsonOmitCombination* omit_combo /* = NULL */) { switch (valuetype) { case V_INT: json.put_next_token(JSON_TOKEN_NUMBER, get_val_Int()->t_str().c_str()); break; case V_REAL: { Real r = get_val_Real(); if (r == REAL_INFINITY) { if (allow_special_float) { json.put_next_token(JSON_TOKEN_STRING, "\"infinity\""); } } else if (r == -REAL_INFINITY) { if (allow_special_float) { json.put_next_token(JSON_TOKEN_STRING, "\"-infinity\""); } } else if (r != r) { if (allow_special_float) { json.put_next_token(JSON_TOKEN_STRING, "\"not_a_number\""); } } else { // true if decimal representation possible (use %f format) bool decimal_repr = (r == 0.0) || (r > -MAX_DECIMAL_FLOAT && r <= -MIN_DECIMAL_FLOAT) || (r >= MIN_DECIMAL_FLOAT && r < MAX_DECIMAL_FLOAT); char* number_str = mprintf(decimal_repr ? "%f" : "%e", r); json.put_next_token(JSON_TOKEN_NUMBER, number_str); Free(number_str); } break; } case V_BOOL: json.put_next_token(get_val_bool() ? JSON_TOKEN_LITERAL_TRUE : JSON_TOKEN_LITERAL_FALSE); break; case V_BSTR: case V_HSTR: case V_OSTR: case V_CSTR: { char* str = convert_to_json_string(get_val_str().c_str()); json.put_next_token(JSON_TOKEN_STRING, str); Free(str); break; } case V_USTR: { char* str = convert_to_json_string(ustring_to_uft8(get_val_ustr()).c_str()); json.put_next_token(JSON_TOKEN_STRING, str); Free(str); break; } case V_VERDICT: case V_ENUM: json.put_next_token(JSON_TOKEN_STRING, (string('\"') + create_stringRepr() + string('\"')).c_str()); break; case V_SEQOF: case V_SETOF: json.put_next_token(JSON_TOKEN_ARRAY_START); if (!u.val_vs->is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { u.val_vs->get_v_byIndex(i)->generate_json_value(json, allow_special_float, union_value_list, omit_combo); } } else { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { // look for the entry with index equal to i for (size_t j = 0; j < u.val_vs->get_nof_ivs(); ++j) { if (u.val_vs->get_iv_byIndex(j)->get_index()->get_val_Int()->get_val() == (Int)i) { u.val_vs->get_iv_byIndex(j)->get_value()->generate_json_value(json, allow_special_float, union_value_list, omit_combo); break; } } } } json.put_next_token(JSON_TOKEN_ARRAY_END); break; case V_SEQ: case V_SET: { // omitted fields have 2 possible JSON values (the field is absent, or it's // present with value 'null'), each combination of omitted values must be // generated if (omit_combo == NULL) { FATAL_ERROR("Value::generate_json_value - no combo"); } size_t len = get_nof_comps(); // generate the JSON object from the present combination json.put_next_token(JSON_TOKEN_OBJECT_START); for (size_t i = 0; i < len; ++i) { Ttcn::JsonOmitCombination::omit_state_t state = omit_combo->get_state(this, i); if (state == Ttcn::JsonOmitCombination::OMITTED_ABSENT) { // the field is absent, don't insert anything continue; } // use the field's alias, if it has one const char* alias = NULL; if (my_governor != NULL) { JsonAST* field_attrib = my_governor->get_comp_byName( get_se_comp_byIndex(i)->get_name())->get_type()->get_json_attributes(); if (field_attrib != NULL) { alias = field_attrib->alias; } } json.put_next_token(JSON_TOKEN_NAME, (alias != NULL) ? alias : get_se_comp_byIndex(i)->get_name().get_ttcnname().c_str()); if (state == Ttcn::JsonOmitCombination::OMITTED_NULL) { json.put_next_token(JSON_TOKEN_LITERAL_NULL); } else { get_se_comp_byIndex(i)->get_value()->generate_json_value(json, allow_special_float, union_value_list, omit_combo); } } json.put_next_token(JSON_TOKEN_OBJECT_END); break; } case V_CHOICE: { bool as_value = !union_value_list && my_governor != NULL && my_governor->get_type_refd_last()->get_json_attributes() != NULL && my_governor->get_type_refd_last()->get_json_attributes()->as_value; if (!as_value) { // no 'as value' coding instruction, insert an object with one field json.put_next_token(JSON_TOKEN_OBJECT_START); // use the field's alias, if it has one const char* alias = NULL; if (my_governor != NULL) { JsonAST* field_attrib = my_governor->get_comp_byName( get_alt_name())->get_type()->get_json_attributes(); if (field_attrib != NULL) { alias = field_attrib->alias; } } json.put_next_token(JSON_TOKEN_NAME, (alias != NULL) ? alias : get_alt_name().get_ttcnname().c_str()); } get_alt_value()->generate_json_value(json, allow_special_float, union_value_list, omit_combo); if (!as_value) { json.put_next_token(JSON_TOKEN_OBJECT_END); } break; } case V_REFD: { Value* v = get_value_refd_last(); if (this != v) { v->generate_json_value(json, allow_special_float, union_value_list, omit_combo); return; } } // no break default: FATAL_ERROR("Value::generate_json_value - %d", valuetype); } } bool Value::explicit_cast_needed(bool forIsValue) { Value *v_last = get_value_refd_last(); if (v_last != this) { // this is a foldable referenced value // if the reference points to an imported or compound value the code // generation will be based on the reference so cast is not needed if (v_last->my_scope->get_scope_mod_gen() != my_scope->get_scope_mod_gen() || !v_last->has_single_expr()) return false; } else if (v_last->valuetype == V_REFD) { // this is an unfoldable reference (v_last==this) // explicit cast is needed only for string element references if (forIsValue) return false; Ttcn::FieldOrArrayRefs *t_subrefs = v_last->u.ref.ref->get_subrefs(); return t_subrefs && t_subrefs->refers_to_string_element(); } if (!v_last->my_governor) FATAL_ERROR("Value::explicit_cast_needed()"); Type *t_governor = v_last->my_governor->get_type_refd_last(); switch (t_governor->get_typetype()) { case Type::T_NULL: case Type::T_BOOL: case Type::T_INT: case Type::T_INT_A: case Type::T_REAL: case Type::T_ENUM_A: case Type::T_ENUM_T: case Type::T_VERDICT: case Type::T_COMPONENT: // these are mapped to built-in C/C++ types return true; case Type::T_SEQ_A: case Type::T_SEQ_T: case Type::T_SET_A: case Type::T_SET_T: // the C++ equivalent of empty record/set value (i.e. {}) is ambiguous return t_governor->get_nof_comps() == 0; case Type::T_SEQOF: case Type::T_SETOF: // the C++ equivalent of value {} is ambiguous // tr926 return true; case Type::T_FUNCTION: case Type::T_ALTSTEP: case Type::T_TESTCASE: return true; default: return false; } } bool Value::has_single_expr() { if (get_needs_conversion()) return false; switch (valuetype) { case V_EXPR: return has_single_expr_expr(); case V_CHOICE: case V_ARRAY: // a union or array value cannot be represented as an in-line expression return false; case V_SEQOF: case V_SETOF: // only an empty record/set of value can be represented as an in-line // expression if (!is_indexed()) return u.val_vs->get_nof_vs() == 0; else return u.val_vs->get_nof_ivs() == 0; case V_SEQ: case V_SET: { // only a value for an empty record/set type can be represented as an // in-line expression if (!my_governor) FATAL_ERROR("Value::has_single_expr()"); Type *type = my_governor->get_type_refd_last(); return type->get_nof_comps() == 0; } case V_REFD: { Value *v_last = get_value_refd_last(); // If the above call hit an error and set_valuetype(V_ERROR), // then u.ref.ref has been freed. Avoid the segfault. if (valuetype == V_ERROR) return false; if (v_last != this && v_last->has_single_expr() && v_last->my_scope->get_scope_mod_gen() == my_scope->get_scope_mod_gen()) return true; else return u.ref.ref->has_single_expr(); } case V_INVOKE: return has_single_expr_invoke(u.invoke.v, u.invoke.ap_list); case V_ERROR: case V_NAMEDINT: case V_NAMEDBITS: case V_UNDEF_LOWERID: case V_UNDEF_BLOCK: case V_REFER: // these values cannot occur during code generation FATAL_ERROR("Value::has_single_expr()"); case V_INT: return u.val_Int->is_native_fit() && u.val_Int->get_val() != -2147483648; case V_NOTUSED: // should only happen when generating code for an unbound record/set value return false; default: // other value types (literal values) do not need temporary reference return true; } } string Value::get_single_expr() { switch (valuetype) { case V_NULL: return string("ASN_NULL_VALUE"); case V_BOOL: return string(u.val_bool ? "TRUE" : "FALSE"); case V_INT: if (u.val_Int->is_native_fit()) { // Be sure. return u.val_Int->t_str(); } else { // get_single_expr may be called only if has_single_expr() is true. // The only exception is V_INT, where get_single_expr may be called // even if is_native_fit (which is used to implement has_single_expr) // returns false. string ret_val('"'); ret_val += u.val_Int->t_str(); ret_val += '"'; return ret_val; } case V_REAL: return Real2code(u.val_Real); case V_ENUM: return get_single_expr_enum(); case V_BSTR: return get_my_scope()->get_scope_mod_gen() ->add_bitstring_literal(*u.str.val_str); case V_HSTR: return get_my_scope()->get_scope_mod_gen() ->add_hexstring_literal(*u.str.val_str); case V_OSTR: return get_my_scope()->get_scope_mod_gen() ->add_octetstring_literal(*u.str.val_str); case V_CSTR: return get_my_scope()->get_scope_mod_gen() ->add_charstring_literal(*u.str.val_str); case V_USTR: if (u.ustr.convert_str) { set_valuetype(V_CSTR); return get_my_scope()->get_scope_mod_gen() ->add_charstring_literal(*u.str.val_str); } else return get_my_scope()->get_scope_mod_gen() ->add_ustring_literal(*u.ustr.val_ustr); case V_ISO2022STR: return get_single_expr_iso2022str(); case V_OID: case V_ROID: { vector<string> comps; bool is_constant = get_oid_comps(comps); size_t nof_comps = comps.size(); string oi_str; for (size_t i = 0; i < nof_comps; i++) { if (i > 0) oi_str += ", "; oi_str += *(comps[i]); } for (size_t i = 0; i < nof_comps; i++) delete comps[i]; comps.clear(); if (is_constant) { // the objid only contains constants // => create a literal and return its name return get_my_scope()->get_scope_mod_gen()->add_objid_literal(oi_str, nof_comps); } // the objid contains at least one variable // => append the number of components before the component values in the string and return it return "OBJID(" + Int2string(nof_comps) + ", " + oi_str + ")"; } case V_SEQOF: case V_SETOF: if (u.val_vs->get_nof_vs() > 0) FATAL_ERROR("Value::get_single_expr()"); return string("NULL_VALUE"); case V_SEQ: case V_SET: if (u.val_nvs->get_nof_nvs() > 0) FATAL_ERROR("Value::get_single_expr()"); return string("NULL_VALUE"); case V_REFD: { Value *v_last = get_value_refd_last(); if (v_last != this && v_last->has_single_expr() && v_last->my_scope->get_scope_mod_gen() == my_scope->get_scope_mod_gen()) { // the reference points to another single value in the same module return v_last->get_single_expr(); } else { // convert the reference to a single expression expression_struct expr; Code::init_expr(&expr); u.ref.ref->generate_code_const_ref(&expr); if (expr.preamble || expr.postamble) FATAL_ERROR("Value::get_single_expr()"); string ret_val(expr.expr); Code::free_expr(&expr); return ret_val; } } case V_OMIT: return string("OMIT_VALUE"); case V_VERDICT: switch (u.verdict) { case Verdict_NONE: return string("NONE"); case Verdict_PASS: return string("PASS"); case Verdict_INCONC: return string("INCONC"); case Verdict_FAIL: return string("FAIL"); case Verdict_ERROR: return string("ERROR"); default: FATAL_ERROR("Value::get_single_expr()"); return string(); } case V_DEFAULT_NULL: return string("NULL_COMPREF"); case V_FAT_NULL: { string ret_val('('); ret_val += my_governor->get_genname_value(my_scope); ret_val += "::function_pointer)Module_List::get_fat_null()"; return ret_val; } case V_EXPR: case V_INVOKE: { expression_struct expr; Code::init_expr(&expr); if (valuetype == V_EXPR) generate_code_expr_expr(&expr); else generate_code_expr_invoke(&expr); if (expr.preamble || expr.postamble) FATAL_ERROR("Value::get_single_expr()"); string ret_val(expr.expr); Code::free_expr(&expr); return ret_val; } case V_MACRO: switch (u.macro) { case MACRO_TESTCASEID: return string("TTCN_Runtime::get_testcase_id_macro()"); default: FATAL_ERROR("Value::get_single_expr(): invalid macrotype"); return string(); } case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: return get_single_expr_fat(); case V_TTCN3_NULL: return string("NULL_VALUE"); default: FATAL_ERROR("Value::get_single_expr()"); return string(); } } bool Value::has_single_expr_expr() { switch (u.expr.v_optype) { case OPTYPE_RND: // - case OPTYPE_COMP_NULL: case OPTYPE_COMP_MTC: case OPTYPE_COMP_SYSTEM: case OPTYPE_COMP_SELF: case OPTYPE_COMP_RUNNING_ANY: case OPTYPE_COMP_RUNNING_ALL: case OPTYPE_COMP_ALIVE_ANY: case OPTYPE_COMP_ALIVE_ALL: case OPTYPE_TMR_RUNNING_ANY: case OPTYPE_GETVERDICT: case OPTYPE_TESTCASENAME: case OPTYPE_PROF_RUNNING: case OPTYPE_CHECKSTATE_ANY: case OPTYPE_CHECKSTATE_ALL: case OPTYPE_HOSTID: case OPTYPE_NOW: return true; case OPTYPE_ENCODE: case OPTYPE_DECODE: case OPTYPE_ISBOUND: case OPTYPE_ISPRESENT: case OPTYPE_ISCHOSEN_T: case OPTYPE_ISCHOSEN_V: // v1 i2 case OPTYPE_ISVALUE: // ti1 case OPTYPE_TTCN2STRING: case OPTYPE_ENCVALUE_UNICHAR: case OPTYPE_DECVALUE_UNICHAR: case OPTYPE_GET_PORT_REF: return false; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: if (u.expr.r2 != NULL) { return false; } // no break case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_RNDWITHVAL: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: return u.expr.v1->has_single_expr(); case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: return u.expr.v1->has_single_expr() && u.expr.v2->has_single_expr(); case OPTYPE_UNICHAR2OCT: case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: return u.expr.v1->has_single_expr() && (!u.expr.v2 || u.expr.v2->has_single_expr()); case OPTYPE_AND: case OPTYPE_OR: return u.expr.v1->has_single_expr() && u.expr.v2->has_single_expr() && !u.expr.v2->needs_short_circuit(); case OPTYPE_SUBSTR: return u.expr.ti1->has_single_expr() && u.expr.v2->has_single_expr() && u.expr.v3->has_single_expr(); case OPTYPE_REGEXP: return u.expr.ti1->has_single_expr() && u.expr.t2->has_single_expr() && u.expr.v3->has_single_expr(); case OPTYPE_DECOMP: // v1 v2 v3 return u.expr.v1->has_single_expr() && u.expr.v2->has_single_expr() && u.expr.v3->has_single_expr(); case OPTYPE_REPLACE: return u.expr.ti1->has_single_expr() && u.expr.v2->has_single_expr() && u.expr.v3->has_single_expr() && u.expr.ti4->has_single_expr(); case OPTYPE_VALUEOF: // ti1 [subrefs2] if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF && !subref->get_val()->has_single_expr()) { return false; } } } // fall through case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 return u.expr.ti1->has_single_expr(); case OPTYPE_LOG2STR: case OPTYPE_ANY2UNISTR: return u.expr.logargs->has_single_expr(); case OPTYPE_ISTEMPLATEKIND: return u.expr.ti1->has_single_expr() && u.expr.v2->has_single_expr(); case OPTYPE_MATCH: // v1 t2 return u.expr.v1->has_single_expr() && u.expr.t2->has_single_expr(); case OPTYPE_CLASS_CREATE: { // r1 ap_list2 Type* t = u.expr.r1->get_refd_assignment()->get_Type()->get_field_type( u.expr.r1->get_subrefs(), Type::EXPECTED_CONSTANT)->get_type_refd_last(); Ttcn::FormalParList* fp_list = t->get_class_type_body()->get_constructor() ->get_FormalParList(); for (size_t i = 0; i < u.expr.ap_list2->get_nof_pars(); ++i) { if (!u.expr.ap_list2->get_par(i)->has_single_expr(fp_list->get_fp_byIndex(i))) { return false; } } return true; } case OPTYPE_COMP_CREATE: // r1 [v2] [v3] b4 return (!u.expr.v2 || u.expr.v2->has_single_expr()) && (!u.expr.v3 || u.expr.v3->has_single_expr()); case OPTYPE_TMR_RUNNING: // r1 [r2] b4 if (u.expr.r2 != NULL) { return false; } // no break case OPTYPE_TMR_READ: // r1 case OPTYPE_ACTIVATE: return u.expr.r1->has_single_expr(); case OPTYPE_EXECUTE: // r1 [v2] return u.expr.r1->has_single_expr() && (!u.expr.v2 || u.expr.v2->has_single_expr()); case OPTYPE_ACTIVATE_REFD: // v1 ap_list2 return has_single_expr_invoke(u.expr.v1, u.expr.ap_list2); case OPTYPE_EXECUTE_REFD: // v1 ap_list2 [v3] return has_single_expr_invoke(u.expr.v1, u.expr.ap_list2) && (!u.expr.v3 || u.expr.v3->has_single_expr()); case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: return u.expr.r2->has_single_expr(); default: FATAL_ERROR("Value::has_single_expr_expr()"); } // switch } bool Value::has_single_expr_invoke(Value *v, Ttcn::ActualParList *ap_list) { if (!v->has_single_expr()) return false; Value* last_v = v->get_value_refd_last(); const Ttcn::FormalParList* fplist = (last_v->get_valuetype() == V_FUNCTION) ? last_v->get_refd_fat()->get_FormalParList() : NULL; for (size_t i = 0; i < ap_list->get_nof_pars(); i++) if (!ap_list->get_par(i)->has_single_expr( fplist != NULL ? fplist->get_fp_byIndex(i) : NULL)) return false; return true; } string Value::get_single_expr_enum() { string ret_val(my_governor->get_genname_value(my_scope)); ret_val += "::"; ret_val += u.val_id->get_name(); return ret_val; } string Value::get_single_expr_iso2022str() { string ret_val; Type *type = get_my_governor()->get_type_refd_last(); switch (type->get_typetype()) { case Type::T_TELETEXSTRING: ret_val += "TTCN_ISO2022_2_TeletexString"; break; case Type::T_VIDEOTEXSTRING: ret_val += "TTCN_ISO2022_2_VideotexString"; break; case Type::T_GRAPHICSTRING: case Type::T_OBJECTDESCRIPTOR: ret_val += "TTCN_ISO2022_2_GraphicString"; break; case Type::T_GENERALSTRING: ret_val += "TTCN_ISO2022_2_GeneralString"; break; default: FATAL_ERROR("Value::get_single_expr_iso2022str()"); } // switch ret_val += '('; string *ostr = char2oct(*u.str.val_str); ret_val += get_my_scope()->get_scope_mod_gen() ->add_octetstring_literal(*ostr); delete ostr; ret_val += ')'; return ret_val; } string Value::get_single_expr_fat() { if (!my_governor) FATAL_ERROR("Value::get_single_expr_fat()"); // the ampersand operator is not really necessary to obtain the function // pointer, but some older versions of GCC cannot instantiate the // appropriate operator=() member of class OPTIONAL when necessary // if only the function name is given string ret_val('&'); switch (valuetype) { case V_FUNCTION: ret_val += u.refd_fat->get_genname_from_scope(my_scope); break; case V_ALTSTEP: ret_val += u.refd_fat->get_genname_from_scope(my_scope); ret_val += "_instance"; break; case V_TESTCASE: ret_val += u.refd_fat->get_genname_from_scope(my_scope, "testcase_"); break; default: FATAL_ERROR("Value::get_single_expr_fat()"); } return ret_val; } bool Value::is_compound() { switch (valuetype) { case V_CHOICE: case V_SEQOF: case V_SETOF: case V_ARRAY: case V_SEQ: case V_SET: return true; default: return false; } } bool Value::needs_temp_ref() { switch (valuetype) { case V_SEQOF: case V_SETOF: if (!is_indexed()) { // Temporary reference is needed if the value has at least one real // element (i.e. it is not empty or contains only not used symbols). for (size_t i = 0; i < u.val_vs->get_nof_vs(); i++) { if (u.val_vs->get_v_byIndex(i)->valuetype != V_NOTUSED) return true; } } else { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) { if (u.val_vs->get_iv_byIndex(i)->get_value() ->valuetype != V_NOTUSED) return true; } } return false; case V_ARRAY: { size_t nof_real_vs = 0; if (!is_indexed()) { // Temporary reference is needed if the array value has at least two // real elements (excluding not used symbols). for (size_t i = 0; i < u.val_vs->get_nof_vs(); i++) { if (u.val_vs->get_v_byIndex(i)->valuetype != V_NOTUSED) { nof_real_vs++; if (nof_real_vs > 1) return true; } } } else { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); i++) { if (u.val_vs->get_iv_byIndex(i)->get_value() ->valuetype != V_NOTUSED) { nof_real_vs++; if (nof_real_vs > 1) return true; } } } return false; } case V_SEQ: case V_SET: if (is_asn1()) { // it depends on the type since fields with omit or default value // may not be present return my_governor->get_type_refd_last()->get_nof_comps() > 1; } else { // incomplete values are allowed in TTCN-3 // we should check the number of value components return u.val_nvs->get_nof_nvs() > 1; } case V_ERROR: case V_NAMEDINT: case V_NAMEDBITS: case V_UNDEF_LOWERID: case V_UNDEF_BLOCK: case V_TTCN3_NULL: // these values cannot occur during code generation FATAL_ERROR("Value::needs_temp_ref()"); case V_INT: return !u.val_Int->is_native(); default: // other value types (literal values) do not need temporary reference return false; } } bool Value::needs_short_circuit() { switch (valuetype) { case V_BOOL: return false; case V_REFD: // examined below break; case V_EXPR: case V_INVOKE: // sub-expressions should be evaluated only if necessary return true; default: FATAL_ERROR("Value::needs_short_circuit()"); } Assignment *t_ass = u.ref.ref->get_refd_assignment(); if (!t_ass) FATAL_ERROR("Value::needs_short_circuit()"); switch (t_ass->get_asstype()) { case Assignment::A_FUNCTION_RVAL: case Assignment::A_EXT_FUNCTION_RVAL: // avoid unnecessary call of a function return true; case Assignment::A_CONST: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_VAL_OUT: case Assignment::A_PAR_VAL_INOUT: // depends on field/array sub-references, which is examined below break; default: FATAL_ERROR("Value::needs_short_circuit()"); } Ttcn::FieldOrArrayRefs *t_subrefs = u.ref.ref->get_subrefs(); if (t_subrefs) { // the evaluation of the reference does not have side effects // (i.e. false shall be returned) only if all sub-references point to // mandatory fields of record/set types, and neither sub-reference points // to a field of a union type Type *t_type = t_ass->get_Type(); for (size_t i = 0; i < t_subrefs->get_nof_refs(); i++) { Ttcn::FieldOrArrayRef *t_fieldref = t_subrefs->get_ref(i); if (t_fieldref->get_type() == Ttcn::FieldOrArrayRef::FIELD_REF) { CompField *t_cf = t_type->get_comp_byName(*t_fieldref->get_id()); if (Type::T_CHOICE_T == t_type->get_type_refd_last()->get_typetype() || Type::T_CHOICE_A == t_type->get_type_refd_last()->get_typetype() || t_cf->get_is_optional()) return true; t_type = t_cf->get_type(); } else return true; } } return false; } void Value::dump(unsigned level) const { switch (valuetype) { case V_ERROR: case V_NULL: case V_BOOL: case V_INT: case V_NAMEDINT: case V_NAMEDBITS: case V_REAL: case V_ENUM: case V_BSTR: case V_HSTR: case V_OSTR: case V_CSTR: case V_ISO2022STR: case V_OID: case V_ROID: case V_CHOICE: case V_SEQOF: case V_SETOF: case V_ARRAY: case V_SEQ: case V_SET: case V_OMIT: case V_VERDICT: case V_DEFAULT_NULL: case V_FAT_NULL: case V_EXPR: case V_MACRO: case V_NOTUSED: case V_FUNCTION: case V_ALTSTEP: case V_TESTCASE: DEBUG(level, "Value: %s", const_cast<Value*>(this)->get_stringRepr().c_str()); break; case V_REFD: case V_REFER: DEBUG(level, "Value: reference"); u.ref.ref->dump(level + 1); break; case V_UNDEF_LOWERID: DEBUG(level, "Value: identifier: %s", u.val_id->get_dispname().c_str()); break; case V_UNDEF_BLOCK: DEBUG(level, "Value: {block}"); break; case V_TTCN3_NULL: DEBUG(level, "Value: null"); break; case V_INVOKE: DEBUG(level, "Value: invoke"); u.invoke.v->dump(level + 1); if (u.invoke.ap_list) u.invoke.ap_list->dump(level + 1); else if (u.invoke.t_list) u.invoke.t_list->dump(level + 1); break; default: DEBUG(level, "Value: unknown type: %d", valuetype); } // switch } void Value::set_is_in_brackets() { in_brackets = true; } bool Value::get_is_in_brackets() const { return in_brackets; } void Value::chk_ctor_defpar(bool default_ctor, bool in_base_call) { switch (valuetype) { case V_REFD: { Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref != NULL) { ttcn_ref->chk_ctor_defpar(default_ctor, in_base_call); if (ttcn_ref->has_parameters()) { ttcn_ref->get_parlist()->chk_ctor_defpar(default_ctor, in_base_call); } } break; } case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { u.val_nvs->get_nv_byIndex(i)->get_value()->chk_ctor_defpar(default_ctor, in_base_call); } break; case V_SEQOF: case V_SETOF: case V_ARRAY: if (u.val_vs->is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { u.val_vs->get_iv_byIndex(i)->get_value()->chk_ctor_defpar(default_ctor, in_base_call); } } else { for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { u.val_vs->get_v_byIndex(i)->chk_ctor_defpar(default_ctor, in_base_call); } } break; case V_CHOICE: u.choice.alt_value->chk_ctor_defpar(default_ctor, in_base_call); break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_ISCHOSEN_V: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: u.expr.v1->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_DECODE: { if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->chk_ctor_defpar(default_ctor, in_base_call); } else { u.expr.r1->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->chk_ctor_defpar(default_ctor, in_base_call); } else { u.expr.r2->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v3 != NULL) { u.expr.v3->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v4 != NULL) { u.expr.v4->chk_ctor_defpar(default_ctor, in_base_call); } break; } case OPTYPE_HOSTID: if (u.expr.v1 != NULL) { u.expr.v1->chk_ctor_defpar(default_ctor, in_base_call); } break; case OPTYPE_ADD: case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1->chk_ctor_defpar(default_ctor, in_base_call); u.expr.v2->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->chk_ctor_defpar(default_ctor, in_base_call); if (u.expr.v2 != NULL) { u.expr.v2->chk_ctor_defpar(default_ctor, in_base_call); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->chk_ctor_defpar(default_ctor, in_base_call); if (u.expr.v2 != NULL) { u.expr.v2->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v3 != NULL) { u.expr.v3->chk_ctor_defpar(default_ctor, in_base_call); } break; case OPTYPE_REGEXP: u.expr.ti1->chk_ctor_defpar(default_ctor, in_base_call); u.expr.t2->chk_ctor_defpar(default_ctor, in_base_call); u.expr.v3->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_DECOMP: u.expr.v1->chk_ctor_defpar(default_ctor, in_base_call); u.expr.v2->chk_ctor_defpar(default_ctor, in_base_call); u.expr.v3->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_REPLACE: u.expr.ti1->chk_ctor_defpar(default_ctor, in_base_call); u.expr.v2->chk_ctor_defpar(default_ctor, in_base_call); u.expr.v3->chk_ctor_defpar(default_ctor, in_base_call); u.expr.ti4->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_ISTEMPLATEKIND: u.expr.ti1->chk_ctor_defpar(default_ctor, in_base_call); u.expr.v2->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_VALUEOF: if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { subref->get_val()->chk_ctor_defpar(default_ctor, in_base_call); } } } // fall through case OPTYPE_LENGTHOF: case OPTYPE_SIZEOF: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_ENCVALUE_UNICHAR: u.expr.ti1->chk_ctor_defpar(default_ctor, in_base_call); if (u.expr.v2 != NULL) { u.expr.v2->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v3 != NULL) { u.expr.v3->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v4 != NULL) { u.expr.v4->chk_ctor_defpar(default_ctor, in_base_call); } break; case OPTYPE_DECVALUE_UNICHAR: { if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->chk_ctor_defpar(default_ctor, in_base_call); } else { u.expr.r1->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->chk_ctor_defpar(default_ctor, in_base_call); } else { u.expr.r2->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v3 != NULL) { u.expr.v3->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v4 != NULL) { u.expr.v4->chk_ctor_defpar(default_ctor, in_base_call); } if (u.expr.v5 != NULL) { u.expr.v5->chk_ctor_defpar(default_ctor, in_base_call); } break; } case OPTYPE_ISCHOSEN_T: case OPTYPE_ISVALUE: u.expr.t1->chk_ctor_defpar(default_ctor, in_base_call); break; case OPTYPE_MATCH: u.expr.v1->chk_ctor_defpar(default_ctor, in_base_call); u.expr.t2->chk_ctor_defpar(default_ctor, in_base_call); break; default: break; } break; default: break; } } void Value::chk_class_member(Ttcn::ClassTypeBody* p_class) { switch (valuetype) { case V_REFD: { Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref != NULL) { ttcn_ref->chk_class_member(p_class); if (ttcn_ref->has_parameters()) { ttcn_ref->get_parlist()->chk_class_member(p_class); } } break; } case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { u.val_nvs->get_nv_byIndex(i)->get_value()->chk_class_member(p_class); } break; case V_SEQOF: case V_SETOF: case V_ARRAY: if (u.val_vs->is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { u.val_vs->get_iv_byIndex(i)->get_value()->chk_class_member(p_class); } } else { for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { u.val_vs->get_v_byIndex(i)->chk_class_member(p_class); } } break; case V_CHOICE: u.choice.alt_value->chk_class_member(p_class); break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_ISCHOSEN_V: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: u.expr.v1->chk_class_member(p_class); break; case OPTYPE_DECODE: { if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->chk_class_member(p_class); } else { u.expr.r1->chk_class_member(p_class); } if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->chk_class_member(p_class); } else { u.expr.r2->chk_class_member(p_class); } if (u.expr.v3 != NULL) { u.expr.v3->chk_class_member(p_class); } if (u.expr.v4 != NULL) { u.expr.v4->chk_class_member(p_class); } break; } case OPTYPE_HOSTID: if (u.expr.v1 != NULL) { u.expr.v1->chk_class_member(p_class); } break; case OPTYPE_ADD: case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1->chk_class_member(p_class); u.expr.v2->chk_class_member(p_class); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->chk_class_member(p_class); if (u.expr.v2 != NULL) { u.expr.v2->chk_class_member(p_class); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->chk_class_member(p_class); if (u.expr.v2 != NULL) { u.expr.v2->chk_class_member(p_class); } if (u.expr.v3 != NULL) { u.expr.v3->chk_class_member(p_class); } break; case OPTYPE_REGEXP: u.expr.ti1->chk_class_member(p_class); u.expr.t2->chk_class_member(p_class); u.expr.v3->chk_class_member(p_class); break; case OPTYPE_DECOMP: u.expr.v1->chk_class_member(p_class); u.expr.v2->chk_class_member(p_class); u.expr.v3->chk_class_member(p_class); break; case OPTYPE_REPLACE: u.expr.ti1->chk_class_member(p_class); u.expr.v2->chk_class_member(p_class); u.expr.v3->chk_class_member(p_class); u.expr.ti4->chk_class_member(p_class); break; case OPTYPE_ISTEMPLATEKIND: u.expr.ti1->chk_class_member(p_class); u.expr.v2->chk_class_member(p_class); break; case OPTYPE_VALUEOF: if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { subref->get_val()->chk_class_member(p_class); } } } // fall through case OPTYPE_LENGTHOF: case OPTYPE_SIZEOF: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->chk_class_member(p_class); break; case OPTYPE_ENCVALUE_UNICHAR: u.expr.ti1->chk_class_member(p_class); if (u.expr.v2 != NULL) { u.expr.v2->chk_class_member(p_class); } if (u.expr.v3 != NULL) { u.expr.v3->chk_class_member(p_class); } if (u.expr.v4 != NULL) { u.expr.v4->chk_class_member(p_class); } break; case OPTYPE_DECVALUE_UNICHAR: { if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->chk_class_member(p_class); } else { u.expr.r1->chk_class_member(p_class); } if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->chk_class_member(p_class); } else { u.expr.r2->chk_class_member(p_class); } if (u.expr.v3 != NULL) { u.expr.v3->chk_class_member(p_class); } if (u.expr.v4 != NULL) { u.expr.v4->chk_class_member(p_class); } if (u.expr.v5 != NULL) { u.expr.v5->chk_class_member(p_class); } break; } case OPTYPE_ISCHOSEN_T: case OPTYPE_ISVALUE: u.expr.t1->chk_class_member(p_class); break; case OPTYPE_MATCH: u.expr.v1->chk_class_member(p_class); u.expr.t2->chk_class_member(p_class); break; default: break; } break; default: break; } } void Value::set_gen_class_defpar_prefix() { switch (valuetype) { case V_REFD: { Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref != NULL) { ttcn_ref->set_gen_class_defpar_prefix(); if (ttcn_ref->has_parameters()) { ttcn_ref->get_parlist()->set_gen_class_defpar_prefix(); } } break; } case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { u.val_nvs->get_nv_byIndex(i)->get_value()->set_gen_class_defpar_prefix(); } break; case V_SEQOF: case V_SETOF: case V_ARRAY: if (u.val_vs->is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { u.val_vs->get_iv_byIndex(i)->get_value()->set_gen_class_defpar_prefix(); } } else { for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { u.val_vs->get_v_byIndex(i)->set_gen_class_defpar_prefix(); } } break; case V_CHOICE: u.choice.alt_value->set_gen_class_defpar_prefix(); break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_ISCHOSEN_V: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: u.expr.v1->set_gen_class_defpar_prefix(); break; case OPTYPE_DECODE: { u.expr.r1->set_gen_class_defpar_prefix(); if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->set_gen_class_defpar_prefix(); } u.expr.r2->set_gen_class_defpar_prefix(); if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->set_gen_class_defpar_prefix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_defpar_prefix(); } if (u.expr.v4 != NULL) { u.expr.v4->set_gen_class_defpar_prefix(); } break; } case OPTYPE_HOSTID: if (u.expr.v1 != NULL) { u.expr.v1->set_gen_class_defpar_prefix(); } break; case OPTYPE_ADD: case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1->set_gen_class_defpar_prefix(); u.expr.v2->set_gen_class_defpar_prefix(); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->set_gen_class_defpar_prefix(); if (u.expr.v2 != NULL) { u.expr.v2->set_gen_class_defpar_prefix(); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->set_gen_class_defpar_prefix(); if (u.expr.v2 != NULL) { u.expr.v2->set_gen_class_defpar_prefix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_defpar_prefix(); } break; case OPTYPE_REGEXP: u.expr.ti1->set_gen_class_defpar_prefix(); u.expr.t2->set_gen_class_defpar_prefix(); u.expr.v3->set_gen_class_defpar_prefix(); break; case OPTYPE_DECOMP: u.expr.v1->set_gen_class_defpar_prefix(); u.expr.v2->set_gen_class_defpar_prefix(); u.expr.v3->set_gen_class_defpar_prefix(); break; case OPTYPE_REPLACE: u.expr.ti1->set_gen_class_defpar_prefix(); u.expr.v2->set_gen_class_defpar_prefix(); u.expr.v3->set_gen_class_defpar_prefix(); u.expr.ti4->set_gen_class_defpar_prefix(); break; case OPTYPE_ISTEMPLATEKIND: u.expr.ti1->set_gen_class_defpar_prefix(); u.expr.v2->set_gen_class_defpar_prefix(); break; case OPTYPE_VALUEOF: if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { subref->get_val()->set_gen_class_defpar_prefix(); } } } // fall through case OPTYPE_LENGTHOF: case OPTYPE_SIZEOF: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->set_gen_class_defpar_prefix(); break; case OPTYPE_ENCVALUE_UNICHAR: u.expr.ti1->set_gen_class_defpar_prefix(); if (u.expr.v2 != NULL) { u.expr.v2->set_gen_class_defpar_prefix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_defpar_prefix(); } if (u.expr.v4 != NULL) { u.expr.v4->set_gen_class_defpar_prefix(); } break; case OPTYPE_DECVALUE_UNICHAR: { u.expr.r1->set_gen_class_defpar_prefix(); if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->set_gen_class_defpar_prefix(); } u.expr.r2->set_gen_class_defpar_prefix(); if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->set_gen_class_defpar_prefix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_defpar_prefix(); } if (u.expr.v4 != NULL) { u.expr.v4->set_gen_class_defpar_prefix(); } if (u.expr.v5 != NULL) { u.expr.v5->set_gen_class_defpar_prefix(); } break; } case OPTYPE_ISCHOSEN_T: case OPTYPE_ISVALUE: u.expr.t1->set_gen_class_defpar_prefix(); break; case OPTYPE_MATCH: u.expr.v1->set_gen_class_defpar_prefix(); u.expr.t2->set_gen_class_defpar_prefix(); break; default: break; } break; default: break; } } void Value::set_gen_class_base_call_postfix() { switch (valuetype) { case V_REFD: { Ttcn::Reference* ttcn_ref = dynamic_cast<Ttcn::Reference*>(u.ref.ref); if (ttcn_ref != NULL) { if (ttcn_ref->has_parameters()) { ttcn_ref->get_parlist()->set_gen_class_base_call_postfix(); } else { ttcn_ref->set_gen_class_base_call_postfix(); } } break; } case V_SEQ: case V_SET: for (size_t i = 0; i < u.val_nvs->get_nof_nvs(); ++i) { u.val_nvs->get_nv_byIndex(i)->get_value()->set_gen_class_base_call_postfix(); } break; case V_SEQOF: case V_SETOF: case V_ARRAY: if (u.val_vs->is_indexed()) { for (size_t i = 0; i < u.val_vs->get_nof_ivs(); ++i) { u.val_vs->get_iv_byIndex(i)->get_value()->set_gen_class_base_call_postfix(); } } else { for (size_t i = 0; i < u.val_vs->get_nof_vs(); ++i) { u.val_vs->get_v_byIndex(i)->set_gen_class_base_call_postfix(); } } break; case V_CHOICE: u.choice.alt_value->set_gen_class_base_call_postfix(); break; case V_EXPR: switch (u.expr.v_optype) { case OPTYPE_UNARYPLUS: case OPTYPE_UNARYMINUS: case OPTYPE_NOT: case OPTYPE_NOT4B: case OPTYPE_BIT2HEX: case OPTYPE_BIT2INT: case OPTYPE_BIT2OCT: case OPTYPE_BIT2STR: case OPTYPE_BSON2JSON: case OPTYPE_CBOR2JSON: case OPTYPE_CHAR2INT: case OPTYPE_CHAR2OCT: case OPTYPE_FLOAT2INT: case OPTYPE_FLOAT2STR: case OPTYPE_HEX2BIT: case OPTYPE_HEX2INT: case OPTYPE_HEX2OCT: case OPTYPE_HEX2STR: case OPTYPE_INT2CHAR: case OPTYPE_INT2FLOAT: case OPTYPE_INT2STR: case OPTYPE_INT2UNICHAR: case OPTYPE_JSON2BSON: case OPTYPE_JSON2CBOR: case OPTYPE_OCT2BIT: case OPTYPE_OCT2CHAR: case OPTYPE_OCT2HEX: case OPTYPE_OCT2INT: case OPTYPE_OCT2STR: case OPTYPE_STR2BIT: case OPTYPE_STR2FLOAT: case OPTYPE_STR2HEX: case OPTYPE_STR2INT: case OPTYPE_STR2OCT: case OPTYPE_UNICHAR2INT: case OPTYPE_UNICHAR2CHAR: case OPTYPE_ENUM2INT: case OPTYPE_ISCHOSEN_V: case OPTYPE_GET_STRINGENCODING: case OPTYPE_REMOVE_BOM: case OPTYPE_DECODE_BASE64: u.expr.v1->set_gen_class_base_call_postfix(); break; case OPTYPE_DECODE: { if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->set_gen_class_base_call_postfix(); } else { u.expr.r1->set_gen_class_base_call_postfix(); } if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->set_gen_class_base_call_postfix(); } else { u.expr.r2->set_gen_class_base_call_postfix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_base_call_postfix(); } if (u.expr.v4 != NULL) { u.expr.v4->set_gen_class_base_call_postfix(); } break; } case OPTYPE_HOSTID: if (u.expr.v1 != NULL) { u.expr.v1->set_gen_class_base_call_postfix(); } break; case OPTYPE_ADD: case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: case OPTYPE_DIVIDE: case OPTYPE_MOD: case OPTYPE_REM: case OPTYPE_CONCAT: case OPTYPE_EQ: case OPTYPE_LT: case OPTYPE_GT: case OPTYPE_NE: case OPTYPE_GE: case OPTYPE_LE: case OPTYPE_AND: case OPTYPE_OR: case OPTYPE_XOR: case OPTYPE_AND4B: case OPTYPE_OR4B: case OPTYPE_XOR4B: case OPTYPE_SHL: case OPTYPE_SHR: case OPTYPE_ROTL: case OPTYPE_ROTR: case OPTYPE_INT2BIT: case OPTYPE_INT2HEX: case OPTYPE_INT2OCT: u.expr.v1->set_gen_class_base_call_postfix(); u.expr.v2->set_gen_class_base_call_postfix(); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: u.expr.v1->set_gen_class_base_call_postfix(); if (u.expr.v2 != NULL) { u.expr.v2->set_gen_class_base_call_postfix(); } break; case OPTYPE_SUBSTR: case OPTYPE_ENCODE: u.expr.ti1->set_gen_class_base_call_postfix(); if (u.expr.v2 != NULL) { u.expr.v2->set_gen_class_base_call_postfix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_base_call_postfix(); } break; case OPTYPE_REGEXP: u.expr.ti1->set_gen_class_base_call_postfix(); u.expr.t2->set_gen_class_base_call_postfix(); u.expr.v3->set_gen_class_base_call_postfix(); break; case OPTYPE_DECOMP: u.expr.v1->set_gen_class_base_call_postfix(); u.expr.v2->set_gen_class_base_call_postfix(); u.expr.v3->set_gen_class_base_call_postfix(); break; case OPTYPE_REPLACE: u.expr.ti1->set_gen_class_base_call_postfix(); u.expr.v2->set_gen_class_base_call_postfix(); u.expr.v3->set_gen_class_base_call_postfix(); u.expr.ti4->set_gen_class_base_call_postfix(); break; case OPTYPE_ISTEMPLATEKIND: u.expr.ti1->set_gen_class_base_call_postfix(); u.expr.v2->set_gen_class_base_call_postfix(); break; case OPTYPE_VALUEOF: if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { subref->get_val()->set_gen_class_base_call_postfix(); } } } // fall through case OPTYPE_LENGTHOF: case OPTYPE_SIZEOF: case OPTYPE_ISPRESENT: case OPTYPE_TTCN2STRING: u.expr.ti1->set_gen_class_base_call_postfix(); break; case OPTYPE_ENCVALUE_UNICHAR: u.expr.ti1->set_gen_class_base_call_postfix(); if (u.expr.v2 != NULL) { u.expr.v2->set_gen_class_base_call_postfix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_base_call_postfix(); } if (u.expr.v4 != NULL) { u.expr.v4->set_gen_class_base_call_postfix(); } break; case OPTYPE_DECVALUE_UNICHAR: { if (u.expr.r1->has_parameters()) { u.expr.r1->get_parlist()->set_gen_class_base_call_postfix(); } else { u.expr.r1->set_gen_class_base_call_postfix(); } if (u.expr.r2->has_parameters()) { u.expr.r2->get_parlist()->set_gen_class_base_call_postfix(); } else { u.expr.r2->set_gen_class_base_call_postfix(); } if (u.expr.v3 != NULL) { u.expr.v3->set_gen_class_base_call_postfix(); } if (u.expr.v4 != NULL) { u.expr.v4->set_gen_class_base_call_postfix(); } if (u.expr.v5 != NULL) { u.expr.v5->set_gen_class_base_call_postfix(); } break; } case OPTYPE_ISCHOSEN_T: case OPTYPE_ISVALUE: u.expr.t1->set_gen_class_base_call_postfix(); break; case OPTYPE_MATCH: u.expr.v1->set_gen_class_base_call_postfix(); u.expr.t2->set_gen_class_base_call_postfix(); break; default: break; } break; default: break; } } void Value::add_string_element(size_t index, Value *v_element, map<size_t, Value>*& string_elements) { v_element->set_my_scope(get_my_scope()); v_element->set_my_governor(get_my_governor()); v_element->set_fullname(get_fullname() + "[" + Int2string(index) + "]"); v_element->set_location(*this); if (!string_elements) string_elements = new map<size_t, Value>; string_elements->add(index, v_element); } /////////////////////////////////////////////////////////////////////////////// // class LazyFuzzyParamData int LazyFuzzyParamData::depth = 0; bool LazyFuzzyParamData::used_as_lvalue = false; vector<string>* LazyFuzzyParamData::type_vec = NULL; vector<string>* LazyFuzzyParamData::refd_vec = NULL; void LazyFuzzyParamData::init(bool p_used_as_lvalue) { if (depth<0) FATAL_ERROR("LazyFuzzyParamData::init()"); if (depth==0) { if (type_vec || refd_vec) FATAL_ERROR("LazyFuzzyParamData::init()"); used_as_lvalue = p_used_as_lvalue; type_vec = new vector<string>; refd_vec = new vector<string>; } depth++; } void LazyFuzzyParamData::clean() { if (depth<=0) FATAL_ERROR("LazyFuzzyParamData::clean()"); if (!type_vec || !refd_vec) FATAL_ERROR("LazyFuzzyParamData::clean()"); if (depth==1) { // type_vec for (size_t i=0; i<type_vec->size(); i++) delete (*type_vec)[i]; type_vec->clear(); delete type_vec; type_vec = NULL; // refd_vec for (size_t i=0; i<refd_vec->size(); i++) delete (*refd_vec)[i]; refd_vec->clear(); delete refd_vec; refd_vec = NULL; } depth--; } bool LazyFuzzyParamData::in_lazy_or_fuzzy() { if (depth<0) FATAL_ERROR("LazyFuzzyParamData::in_lazy_or_fuzzy()"); return depth>0; } // returns a temporary id instead of the C++ reference to a definition // stores in vectors the C++ type of the definiton, the C++ reference to the // definition and whether it refers to a lazy/fuzzy formal parameter string LazyFuzzyParamData::add_ref_genname(Assignment* ass, Scope* scope) { if (!ass || !scope) FATAL_ERROR("LazyFuzzyParamData::add_ref_genname()"); if (!type_vec || !refd_vec) FATAL_ERROR("LazyFuzzyParamData::add_ref_genname()"); if (type_vec->size()!=refd_vec->size()) FATAL_ERROR("LazyFuzzyParamData::add_ref_genname()"); // store the type of the assignment string* type_str = new string; switch (ass->get_asstype()) { case Assignment::A_MODULEPAR_TEMP: case Assignment::A_TEMPLATE: case Assignment::A_VAR_TEMPLATE: case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: *type_str = ass->get_Type()->get_genname_template(scope); break; default: *type_str = ass->get_Type()->get_genname_value(scope); } // add the Lazy_Fuzzy_Expr<> part if the referenced assignment is a FormalPar lazy or fuzzy bool refd_ass_is_lazy_or_fuzzy_fpar = false; switch (ass->get_asstype()) { case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_TEMPL_IN: refd_ass_is_lazy_or_fuzzy_fpar = ass->get_eval_type() != NORMAL_EVAL; if (refd_ass_is_lazy_or_fuzzy_fpar) { *type_str = string("Lazy_Fuzzy_Expr<") + *type_str + string(">"); } break; default: break; } // add the "const" part if the referenced assignment is a constant thing if (!refd_ass_is_lazy_or_fuzzy_fpar) { switch (ass->get_asstype()) { case Assignment::A_CONST: case Assignment::A_OC: case Assignment::A_OBJECT: case Assignment::A_OS: case Assignment::A_VS: case Assignment::A_EXT_CONST: case Assignment::A_MODULEPAR: case Assignment::A_MODULEPAR_TEMP: case Assignment::A_TEMPLATE: case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_TEMPL_IN: *type_str = string("const ") + *type_str; break; default: // nothing to do break; } } // type_vec->add(type_str); // store the C++ reference string refd_vec->add(new string(ass->get_genname_from_scope(scope,""))); // the "" parameter makes sure that no casting to type is generated into the string if (refd_ass_is_lazy_or_fuzzy_fpar) { Type* refd_ass_type = ass->get_Type(); string refd_ass_type_genname = (ass->get_asstype()==Assignment::A_PAR_TEMPL_IN) ? refd_ass_type->get_genname_template(scope) : refd_ass_type->get_genname_value(scope); return string("((") + refd_ass_type_genname + string("&)") + get_member_name(refd_vec->size()-1) + string(")"); } else { return get_member_name(refd_vec->size()-1); } } string LazyFuzzyParamData::get_member_name(size_t idx) { return string("lpm_") + Int2string(idx); } string LazyFuzzyParamData::get_constr_param_name(size_t idx) { return string("lpp_") + Int2string(idx); } void LazyFuzzyParamData::generate_code_for_value(expression_struct* expr, Value* val, Scope* my_scope) { // copied from ActualPar::generate_code(), TODO: remove duplication by refactoring if (use_runtime_2 && TypeConv::needs_conv_refd(val)) { const string& tmp_id = val->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); expr->preamble = mputprintf(expr->preamble, "%s %s;\n", val->get_my_governor()->get_genname_value(my_scope).c_str(), tmp_id_str); expr->preamble = TypeConv::gen_conv_code_refd(expr->preamble, tmp_id_str, val); expr->expr = mputstr(expr->expr, tmp_id_str); } else { val->generate_code_expr(expr); } } void LazyFuzzyParamData::generate_code_for_template(expression_struct* expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* my_scope) { // copied from ActualPar::generate_code(), TODO: remove duplication by refactoring if (use_runtime_2 && TypeConv::needs_conv_refd(temp->get_Template())) { const string& tmp_id = temp->get_Template()->get_temporary_id(); const char *tmp_id_str = tmp_id.c_str(); expr->preamble = mputprintf(expr->preamble, "%s %s;\n", temp->get_Template()->get_my_governor() ->get_genname_template(my_scope).c_str(), tmp_id_str); expr->preamble = TypeConv::gen_conv_code_refd(expr->preamble, tmp_id_str, temp->get_Template()); // Not incorporated into gen_conv_code() yet. if (gen_restriction_check != TR_NONE) expr->preamble = Template::generate_restriction_check_code( expr->preamble, tmp_id_str, gen_restriction_check); expr->expr = mputstr(expr->expr, tmp_id_str); } else temp->generate_code(expr, gen_restriction_check); } void LazyFuzzyParamData::generate_code(expression_struct *expr, Value* value, Scope* scope, boolean lazy) { if (depth<=0) FATAL_ERROR("LazyFuzzyParamData::generate_code()"); if (depth>1) { // if a function with lazy parameter(s) was called inside a lazy parameter then don't generate code for // lazy parameter inside a lazy parameter, call the function as a normal call // wrap the calculated parameter value inside a special constructor which calculates the value of its cache immediately expression_struct value_expr; Code::init_expr(&value_expr); generate_code_for_value(&value_expr, value, scope); // the id of the instance of Lazy_Fuzzy_Expr, which will be used as the actual parameter const string& param_id = value->get_temporary_id(); if (value_expr.preamble) { expr->preamble = mputstr(expr->preamble, value_expr.preamble); } expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", value->get_my_governor()->get_genname_value(scope).c_str(), param_id.c_str(), lazy ? "FALSE" : "TRUE", value->get_my_governor()->get_genname_value(scope).c_str(), value_expr.expr); Code::free_expr(&value_expr); expr->expr = mputstr(expr->expr, param_id.c_str()); return; } // only if the formal parameter is *not* used as lvalue if (!used_as_lvalue && value->get_valuetype()==Value::V_REFD && value->get_reference()->get_subrefs()==NULL) { Assignment* refd_ass = value->get_reference()->get_refd_assignment(); if (refd_ass) { bool refd_ass_is_lazy_or_fuzzy_fpar = false; switch (refd_ass->get_asstype()) { case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_TEMPL_IN: refd_ass_is_lazy_or_fuzzy_fpar = refd_ass->get_eval_type() != NORMAL_EVAL; break; default: break; } if (refd_ass_is_lazy_or_fuzzy_fpar) { string refd_str = refd_ass->get_genname_from_scope(scope, ""); if ((refd_ass->get_eval_type() == LAZY_EVAL && !lazy) || (refd_ass->get_eval_type() == FUZZY_EVAL && lazy)) { expr->preamble = mputprintf(expr->preamble, "%s.change();\n", refd_str.c_str()); expr->postamble = mputprintf(expr->postamble, "%s.revert();\n", refd_str.c_str()); } expr->expr = mputprintf(expr->expr, "%s", refd_str.c_str()); return; } } } // generate the code for value in a temporary expr structure, this code is put inside the ::eval() member function expression_struct value_expr; Code::init_expr(&value_expr); generate_code_for_value(&value_expr, value, scope); // the id of the instance of Lazy_Fuzzy_Expr, which will be used as the actual parameter string param_id = value->get_temporary_id(); string type_name = value->get_my_governor()->get_genname_value(scope); generate_code_param_class(expr, value_expr, param_id, type_name, lazy); } void LazyFuzzyParamData::generate_code(expression_struct *expr, TemplateInstance* temp, template_restriction_t gen_restriction_check, Scope* scope, boolean lazy) { if (depth<=0) FATAL_ERROR("LazyFuzzyParamData::generate_code()"); if (depth>1) { // if a function with lazy parameter(s) was called inside a lazy parameter then don't generate code for // lazy parameter inside a lazy parameter, call the function as a normal call // wrap the calculated parameter value inside a special constructor which calculates the value of its cache immediately expression_struct tmpl_expr; Code::init_expr(&tmpl_expr); generate_code_for_template(&tmpl_expr, temp, gen_restriction_check, scope); // the id of the instance of Lazy_Fuzzy_Expr which will be used as the actual parameter const string& param_id = temp->get_Template()->get_temporary_id(); if (tmpl_expr.preamble) { expr->preamble = mputstr(expr->preamble, tmpl_expr.preamble); } expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", temp->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), param_id.c_str(), lazy ? "FALSE" : "TRUE", temp->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), tmpl_expr.expr); Code::free_expr(&tmpl_expr); expr->expr = mputstr(expr->expr, param_id.c_str()); return; } // only if the formal parameter is *not* used as lvalue if (!used_as_lvalue && temp->get_Template()->get_templatetype()==Template::TEMPLATE_REFD && temp->get_Template()->get_reference()->get_subrefs()==NULL) { Assignment* refd_ass = temp->get_Template()->get_reference()->get_refd_assignment(); if (refd_ass) { bool refd_ass_is_lazy_or_fuzzy_fpar = false; switch (refd_ass->get_asstype()) { case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: case Assignment::A_PAR_TEMPL_IN: refd_ass_is_lazy_or_fuzzy_fpar = refd_ass->get_eval_type() != NORMAL_EVAL; break; default: break; } if (refd_ass_is_lazy_or_fuzzy_fpar) { string refd_str = refd_ass->get_genname_from_scope(scope, ""); if ((refd_ass->get_eval_type() == LAZY_EVAL && !lazy) || (refd_ass->get_eval_type() == FUZZY_EVAL && lazy)) { expr->preamble = mputprintf(expr->preamble, "%s.change();\n", refd_str.c_str()); expr->postamble = mputprintf(expr->postamble, "%s.revert();\n", refd_str.c_str()); } expr->expr = mputprintf(expr->expr, "%s", refd_str.c_str()); return; } } } // generate the code for template in a temporary expr structure, this code is put inside the ::eval_expr() member function expression_struct tmpl_expr; Code::init_expr(&tmpl_expr); generate_code_for_template(&tmpl_expr, temp, gen_restriction_check, scope); // the id of the instance of Lazy_Fuzzy_Expr which will be used as the actual parameter string param_id = temp->get_Template()->get_temporary_id(); string type_name = temp->get_Template()->get_my_governor()->get_genname_template(scope); generate_code_param_class(expr, tmpl_expr, param_id, type_name, lazy); } void LazyFuzzyParamData::generate_code_param_class(expression_struct *expr, expression_struct& param_expr, const string& param_id, const string& type_name, boolean lazy) { expr->preamble = mputprintf(expr->preamble, "class Lazy_Fuzzy_Expr_%s : public Lazy_Fuzzy_Expr<%s> {\n", param_id.c_str(), type_name.c_str()); // private members of the local class will be const references to the objects referenced by the expression for (size_t i=0; i<type_vec->size(); i++) { expr->preamble = mputprintf(expr->preamble, "%s& %s;\n", (*type_vec)[i]->c_str(), get_member_name(i).c_str()); } expr->preamble = mputstr(expr->preamble, "public:\n"); expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr_%s(", param_id.c_str()); for (size_t i=0; i<type_vec->size(); i++) { if (i>0) expr->preamble = mputstr(expr->preamble, ", "); expr->preamble = mputprintf(expr->preamble, "%s& %s", (*type_vec)[i]->c_str(), get_constr_param_name(i).c_str()); } expr->preamble = mputprintf(expr->preamble, "): Lazy_Fuzzy_Expr<%s>(%s)", type_name.c_str(), lazy ? "FALSE" : "TRUE"); for (size_t i=0; i<type_vec->size(); i++) { expr->preamble = mputprintf(expr->preamble, ", %s(%s)", get_member_name(i).c_str(), get_constr_param_name(i).c_str()); } expr->preamble = mputstr(expr->preamble, " {}\n"); expr->preamble = mputstr(expr->preamble, "private:\n"); expr->preamble = mputstr(expr->preamble, "virtual void eval_expr() {\n"); // use the temporary expr structure to fill the body of the eval_expr() function if (param_expr.preamble) { expr->preamble = mputstr(expr->preamble, param_expr.preamble); } expr->preamble = mputprintf(expr->preamble, "expr_cache = %s;\n", param_expr.expr); if (param_expr.postamble) { expr->preamble = mputstr(expr->preamble, param_expr.postamble); } Code::free_expr(¶m_expr); expr->preamble = mputstr(expr->preamble, "}\n" "};\n" // end of local class definition ); expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr_%s %s", param_id.c_str(), param_id.c_str()); if (type_vec->size()>0) { expr->preamble = mputc(expr->preamble, '('); // paramteres of the constructor are references to the objects used in the expression for (size_t i=0; i<refd_vec->size(); i++) { if (i>0) expr->preamble = mputstr(expr->preamble, ", "); expr->preamble = mputprintf(expr->preamble, "%s", (*refd_vec)[i]->c_str()); } expr->preamble = mputc(expr->preamble, ')'); } expr->preamble = mputstr(expr->preamble, ";\n"); // the instance of the local class Lazy_Fuzzy_Expr_tmp_xxx is used as the actual parameter expr->expr = mputprintf(expr->expr, "%s", param_id.c_str()); } void LazyFuzzyParamData::generate_code_ap_default_ref(expression_struct *expr, Ttcn::Reference* ref, Scope* scope, boolean lazy) { expression_struct ref_expr; Code::init_expr(&ref_expr); ref->generate_code(&ref_expr); const string& param_id = scope->get_scope_mod_gen()->get_temporary_id(); if (ref_expr.preamble) { expr->preamble = mputstr(expr->preamble, ref_expr.preamble); } Assignment* ass = ref->get_refd_assignment(); // determine C++ type of the assignment string type_str; switch (ass->get_asstype()) { case Assignment::A_MODULEPAR_TEMP: case Assignment::A_TEMPLATE: case Assignment::A_VAR_TEMPLATE: case Assignment::A_PAR_TEMPL_IN: case Assignment::A_PAR_TEMPL_OUT: case Assignment::A_PAR_TEMPL_INOUT: type_str = ass->get_Type()->get_genname_template(scope); break; default: type_str = ass->get_Type()->get_genname_value(scope); } expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", type_str.c_str(), param_id.c_str(), lazy ? "FALSE" : "TRUE", type_str.c_str(), ref_expr.expr); if (ref_expr.postamble) { expr->postamble = mputstr(expr->postamble, ref_expr.postamble); } Code::free_expr(&ref_expr); expr->expr = mputstr(expr->expr, param_id.c_str()); } void LazyFuzzyParamData::generate_code_ap_default_value(expression_struct *expr, Value* value, Scope* scope, boolean lazy) { const string& param_id = value->get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", value->get_my_governor()->get_genname_value(scope).c_str(), param_id.c_str(), lazy ? "FALSE" : "TRUE", value->get_my_governor()->get_genname_value(scope).c_str(), value->get_genname_own(scope).c_str()); expr->expr = mputstr(expr->expr, param_id.c_str()); } void LazyFuzzyParamData::generate_code_ap_default_ti(expression_struct *expr, TemplateInstance* ti, Scope* scope, boolean lazy) { const string& param_id = ti->get_Template()->get_temporary_id(); expr->preamble = mputprintf(expr->preamble, "Lazy_Fuzzy_Expr<%s> %s(%s, Lazy_Fuzzy_Expr<%s>::EXPR_EVALED, %s);\n", ti->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), param_id.c_str(), lazy ? "FALSE" : "TRUE", ti->get_Template()->get_my_governor()->get_genname_template(scope).c_str(), ti->get_Template()->get_genname_own(scope).c_str()); expr->expr = mputstr(expr->expr, param_id.c_str()); } } // namespace Common