diff --git a/compiler2/Real.cc b/compiler2/Real.cc index c9f5a8179783037f979b0a426e4085f1a5b19b4c..87632b85ff2327659d2a9e38c755ab561a2be545 100644 --- a/compiler2/Real.cc +++ b/compiler2/Real.cc @@ -32,6 +32,11 @@ namespace Common { { return ((r!=r) || (r==REAL_INFINITY) || (r==-REAL_INFINITY)); } + + bool isNaN(const Real& r) + { + return r!=r; + } string Real2string(const Real& r) { diff --git a/compiler2/Real.hh b/compiler2/Real.hh index 1d6ebcf35df7634ade3edc84ff2281d6bdce42e0..2259d1eca31f3e742011fb8ba0a5cca24b415132 100644 --- a/compiler2/Real.hh +++ b/compiler2/Real.hh @@ -55,6 +55,7 @@ namespace Common { /** +/- infinity and not_a_number are non-numeric float values in ttcn-3, these special values cannot be used in some places */ bool isSpecialFloatValue(const Real& r); + bool isNaN(const Real& r); /** * Converts the Common::Real value to string. diff --git a/compiler2/Value.cc b/compiler2/Value.cc index acc618b7b6dafa1a36ce168b33f2213236a85d32..6d3efe51df92f0305263221c1d573c3fff516c12 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -6396,6 +6396,47 @@ error: set_valuetype(V_ERROR); } } + + void Value::chk_expr_operand_valid_float(Value* v1, Value* v2, const char *opnum1, const char *opnum2, const char *opname) + { + ttcn3float r1, r2; + boolean r1_is_set = FALSE, r2_is_set = FALSE; + if(valuetype!=V_ERROR) { + if(u.expr.state!=EXPR_CHECKING_ERR) { + if(!v1->is_unfoldable()) { + if(v1->get_expr_returntype()==Type::T_REAL) { + r1 = v1->get_val_Real(); + r1_is_set = TRUE; + } + } + if(!v2->is_unfoldable()) { + if(v2->get_expr_returntype()==Type::T_REAL) { + r2 = v2->get_val_Real(); + r2_is_set = TRUE; + } + } + if (r1_is_set && r2_is_set) { + if ((isSpecialFloatValue(r1) && isSpecialFloatValue(r2)) || isNaN(r1) || isNaN(r2)) { + error("Invalid operands of float %s: %s operand is %s, %s operand is %s", + opname, opnum1, Real2string(r1).c_str(), opnum2, Real2string(r2).c_str()); + set_valuetype(V_ERROR); + } + } else if (r1_is_set) { + if (isNaN(r1)) { + v1->error("%s operand of operation `%s' cannot be %s, it must be a numeric value", + opnum1, opname, Real2string(r1).c_str()); + set_valuetype(V_ERROR); + } + } else if (r2_is_set) { + if (isNaN(r2)) { + v2->error("%s operand of operation `%s' cannot be %s, it must be a numeric value", + opnum2, opname, Real2string(r2).c_str()); + set_valuetype(V_ERROR); + } + } + } + } + } void Value::chk_expr_operands(ReferenceChain *refch, Type::expected_value_t exp_val) @@ -6890,29 +6931,23 @@ error: case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: case OPTYPE_MULTIPLY: - case OPTYPE_DIVIDE: + case OPTYPE_DIVIDE: { 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); - chk_expr_operandtype_int_float(tt1, first, opname, v1); - chk_expr_eval_value(v1, t_chk, refch, exp_val); - chk_expr_operand_valid_float(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); - chk_expr_operandtype_int_float(tt2, second, opname, v2); - chk_expr_eval_value(v2, t_chk, refch, exp_val); - chk_expr_operand_valid_float(v2, second, opname); - if(u.expr.v_optype==OPTYPE_DIVIDE) - chk_expr_val_int_float_not0(v2, second, opname); - } + 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); + tt2=v2->get_expr_returntype(exp_val); + 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); + chk_expr_operand_valid_float(v1, v2, first, second, opname); + if(u.expr.v_optype==OPTYPE_DIVIDE) + chk_expr_val_int_float_not0(v2, second, opname); chk_expr_operandtypes_same(tt1, tt2, opname); - break; + break; } case OPTYPE_MOD: case OPTYPE_REM: v1=u.expr.v1; diff --git a/compiler2/Value.hh b/compiler2/Value.hh index ba32dd28e34a2779829313b276e62afe4a99e6f9..b53051033579e477b4cffb95d896494e3ff3cf2c 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -668,6 +668,7 @@ namespace Common { void chk_expr_operands(ReferenceChain *refch, Type::expected_value_t exp_val); void chk_expr_operand_valid_float(Value* v, const char *opnum, const char *opname); + void chk_expr_operand_valid_float(Value* v1, Value* v2, const char *opnum1, const char *opnum2, const char *opname); /** Evaluate... * Called by Value::get_value_refd_last() for V_EXPR */ void evaluate_value(ReferenceChain *refch, Type::expected_value_t exp_val); diff --git a/compiler2/ttcn3/compiler.c b/compiler2/ttcn3/compiler.c index aec9a10cadf91a8bf19351998eab012ee5a6d9e9..5228b99d6f43d804cf2522a36dd9201a84c58a8b 100644 --- a/compiler2/ttcn3/compiler.c +++ b/compiler2/ttcn3/compiler.c @@ -18,6 +18,7 @@ * Raduly, Csaba * Szabados, Kristof * Szabo, Janos Zoltan – initial implementation + * Szabo, Bence Janos * Zalanyi, Balazs Andor * Pandi, Krisztian * diff --git a/core/Float.cc b/core/Float.cc index 79331f91aa19747065e07a252484650eeb53da29..c0e5211353554c2bd9f983316390426ca94e44be 100644 --- a/core/Float.cc +++ b/core/Float.cc @@ -130,6 +130,11 @@ boolean FLOAT::is_special(double flt_val) return ( (flt_val!=flt_val) || (flt_val==INFINITY) || (flt_val==-INFINITY) ); } +boolean FLOAT::is_nan(double flt_val) +{ + return flt_val!=flt_val; +} + void FLOAT::check_numeric(double flt_val, const char *err_msg_begin) { if (is_special(flt_val)) { @@ -141,8 +146,10 @@ void FLOAT::check_numeric(double flt_val, const char *err_msg_begin) double FLOAT::operator+(double other_value) const { must_bound("Unbound left operand of float addition."); - check_numeric(float_value, "Left operand of float addition"); - check_numeric(other_value, "Right operand of float addition"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) { + TTCN_error("Invalid operands of float addition: Left operand is %g, right operand is %g", (double)float_value, other_value); + } return float_value + other_value; } @@ -150,16 +157,20 @@ double FLOAT::operator+(const FLOAT& other_value) const { must_bound("Unbound left operand of float addition."); other_value.must_bound("Unbound right operand of float addition."); - check_numeric(float_value, "Left operand of float addition"); - check_numeric(other_value.float_value, "Right operand of float addition"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float addition: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value); + } return float_value + other_value.float_value; } double FLOAT::operator-(double other_value) const { must_bound("Unbound left operand of float subtraction."); - check_numeric(float_value, "Left operand of float subtraction"); - check_numeric(other_value, "Right operand of float subtraction"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) { + TTCN_error("Invalid operands of float subtraction: Left operand is %g, right operand is %g", (double)float_value, other_value); + } return float_value - other_value; } @@ -167,16 +178,20 @@ double FLOAT::operator-(const FLOAT& other_value) const { must_bound("Unbound left operand of float subtraction."); other_value.must_bound("Unbound right operand of float subtraction."); - check_numeric(float_value, "Left operand of float subtraction"); - check_numeric(other_value.float_value, "Right operand of float subtraction"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float subtraction: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value); + } return float_value - other_value.float_value; } double FLOAT::operator*(double other_value) const { must_bound("Unbound left operand of float multiplication."); - check_numeric(float_value, "Left operand of float multiplication"); - check_numeric(other_value, "Right operand of float multiplication"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) { + TTCN_error("Invalid operands of float multiplication: Left operand is %g, right operand is %g", (double)float_value, other_value); + } return float_value * other_value; } @@ -184,16 +199,20 @@ double FLOAT::operator*(const FLOAT& other_value) const { must_bound("Unbound left operand of float multiplication."); other_value.must_bound("Unbound right operand of float multiplication."); - check_numeric(float_value, "Left operand of float multiplication"); - check_numeric(other_value.float_value, "Right operand of float multiplication"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float multiplication: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value); + } return float_value * other_value.float_value; } double FLOAT::operator/(double other_value) const { must_bound("Unbound left operand of float division."); - check_numeric(float_value, "Left operand of float division"); - check_numeric(other_value, "Right operand of float division"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value)) || is_nan(float_value) || is_nan(other_value)) { + TTCN_error("Invalid operands of float division: Left operand is %g, right operand is %g", (double)float_value, other_value); + } if (other_value == 0.0) TTCN_error("Float division by zero."); return float_value / other_value; } @@ -202,8 +221,10 @@ double FLOAT::operator/(const FLOAT& other_value) const { must_bound("Unbound left operand of float division."); other_value.must_bound("Unbound right operand of float division."); - check_numeric(float_value, "Left operand of float division"); - check_numeric(other_value.float_value, "Right operand of float division"); + // Both of them are +-infinity or one of them is nan + if ((is_special(float_value) && is_special(other_value.float_value)) || is_nan(float_value) || is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float division: Left operand is %g, right operand is %g", (double)float_value, (double)other_value.float_value); + } if (other_value.float_value == 0.0) TTCN_error("Float division by zero."); return float_value / other_value.float_value; } @@ -1174,32 +1195,40 @@ int FLOAT::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, double operator+(double double_value, const FLOAT& other_value) { other_value.must_bound("Unbound right operand of float addition."); - FLOAT::check_numeric(double_value, "Left operand of float addition"); - FLOAT::check_numeric(other_value.float_value, "Right operand of float addition"); + // Both of them are +-infinity or one of them is nan + if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float addition: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value); + } return double_value + other_value.float_value; } double operator-(double double_value, const FLOAT& other_value) { other_value.must_bound("Unbound right operand of float subtraction."); - FLOAT::check_numeric(double_value, "Left operand of float subtraction"); - FLOAT::check_numeric(other_value.float_value, "Right operand of float subtraction"); + // Both of them are +-infinity or one of them is nan + if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float subtraction: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value); + } return double_value - other_value.float_value; } double operator*(double double_value, const FLOAT& other_value) { other_value.must_bound("Unbound right operand of float multiplication."); - FLOAT::check_numeric(double_value, "Left operand of float multiplication"); - FLOAT::check_numeric(other_value.float_value, "Right operand of float multiplication"); + // Both of them are +-infinity or one of them is nan + if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float multiplication: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value); + } return double_value * other_value.float_value; } double operator/(double double_value, const FLOAT& other_value) { other_value.must_bound("Unbound right operand of float division."); - FLOAT::check_numeric(double_value, "Left operand of float division"); - FLOAT::check_numeric(other_value.float_value, "Right operand of float division"); + // Both of them are +-infinity or one of them is nan + if ((FLOAT::is_special(double_value) && FLOAT::is_special(other_value.float_value)) || FLOAT::is_nan(double_value) || FLOAT::is_nan(other_value.float_value)) { + TTCN_error("Invalid operands of float division: Left operand is %g, right operand is %g", double_value, (double)other_value.float_value); + } if (other_value.float_value == 0.0) TTCN_error("Float division by zero."); return double_value / other_value.float_value; } diff --git a/core/Float.hh b/core/Float.hh index 9755e7f5ad92930885497ca397ac16b38bcdfe59..c4d9e1a77a10593a783b5f397e782383f59dfb60 100644 --- a/core/Float.hh +++ b/core/Float.hh @@ -106,6 +106,7 @@ public: /** special TTCN-3 float values are not_a_number and +/- infinity */ static boolean is_special(double flt_val); + static boolean is_nan(double flt_val); static void check_numeric(double flt_val, const char *err_msg_begin); void log() const; diff --git a/function_test/Semantic_Analyser/Makefile.semantic b/function_test/Semantic_Analyser/Makefile.semantic index acfcce783b3a0bb2b98aa5ec659ea52ed9c2374f..da579923da1a258d05d89bf93d9e58dc5846d33d 100644 --- a/function_test/Semantic_Analyser/Makefile.semantic +++ b/function_test/Semantic_Analyser/Makefile.semantic @@ -9,9 +9,10 @@ # Balasko, Jeno # Baranyi, Botond # Ormandi, Matyas +# Szabo, Bence Janos # ############################################################################## -SADIRS := ver xer encode param template any_from pattern_ref +SADIRS := ver xer encode param template any_from pattern_ref float ifeq ($(RT2), yes) SADIRS += deprecated endif diff --git a/function_test/Semantic_Analyser/float/special_SE.ttcn b/function_test/Semantic_Analyser/float/special_SE.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..1a04be104c9f52f9ee2ad50c9a1b97893d057dda --- /dev/null +++ b/function_test/Semantic_Analyser/float/special_SE.ttcn @@ -0,0 +1,56 @@ +/****************************************************************************** + * Copyright (c) 2000-2016 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bence Janos Szabo + * + ******************************************************************************/ +module special_SE { //^In TTCN-3 module// + +const float err1 := infinity + infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is INF\, Second operand is INF// +const float err2 := infinity + -infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is INF\, Second operand is -INF// +const float err3 := -infinity + -infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is -INF\, Second operand is -INF// + + +const float err4 := infinity - infinity; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is INF\, Second operand is INF// +const float err5 := infinity - -infinity; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is INF\, Second operand is -INF// +const float err6 := -infinity - -infinity; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is -INF\, Second operand is -INF// + +const float err7 := infinity * infinity; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is INF\, Second operand is INF// +const float err8 := infinity * -infinity; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is INF\, Second operand is -INF// +const float err9 := -infinity * -infinity; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is -INF\, Second operand is -INF// + + +const float err10 := infinity / infinity; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is INF\, Second operand is INF// +const float err11 := infinity / -infinity; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is INF\, Second operand is -INF// +const float err12 := -infinity / -infinity; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is -INF\, Second operand is -INF// + +const float err13 := not_a_number + 2.0; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is NaN\, Second operand is 2\.0e0// +const float err14 := not_a_number - 2.0; //^In constant definition// //^In the operands of operation \`\-\'// //^error: Invalid operands of float \-\: First operand is NaN\, Second operand is 2\.0e0// +const float err15 := not_a_number * 2.0; //^In constant definition// //^In the operands of operation \`\*\'// //^error: Invalid operands of float \*\: First operand is NaN\, Second operand is 2\.0e0// +const float err16 := not_a_number / 2.0; //^In constant definition// //^In the operands of operation \`\/\'// //^error: Invalid operands of float \/\: First operand is NaN\, Second operand is 2\.0e0// +const float err17 := not_a_number + infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is NaN\, Second operand is INF// +const float err18 := not_a_number + -infinity; //^In constant definition// //^In the operands of operation \`\+\'// //^error: Invalid operands of float \+\: First operand is NaN\, Second operand is -INF// + +function fun() { //^In function definition// + var float f := 2.0; + var float f2 := f + not_a_number; //^In variable definition// //^In the operands of operation \`\+\'// //^error: Second operand of operation \`\+\' cannot be NaN\, it must be a numeric value// + f2 := not_a_number + f; //^In variable assignment// //^In the operands of operation \`\+\'// //^error: First operand of operation \`\+\' cannot be NaN\, it must be a numeric value// + + f2 := not_a_number - f; //^In variable assignment// //^In the operands of operation \`\-\'// //^error: First operand of operation \`\-\' cannot be NaN\, it must be a numeric value// + f2 := f - not_a_number; //^In variable assignment// //^In the operands of operation \`\-\'// //^error: Second operand of operation \`\-\' cannot be NaN\, it must be a numeric value// + + f2 := not_a_number * f; //^In variable assignment// //^In the operands of operation \`\*\'// //^error: First operand of operation \`\*\' cannot be NaN\, it must be a numeric value// + f2 := f * not_a_number; //^In variable assignment// //^In the operands of operation \`\*\'// //^error: Second operand of operation \`\*\' cannot be NaN\, it must be a numeric value// + + f2 := not_a_number / f; //^In variable assignment// //^In the operands of operation \`\/\'// //^error: First operand of operation \`\/\' cannot be NaN\, it must be a numeric value// + f2 := f / not_a_number; //^In variable assignment// //^In the operands of operation \`\/\'// //^error: Second operand of operation \`\/\' cannot be NaN\, it must be a numeric value// + +} + + +} diff --git a/function_test/Semantic_Analyser/float/subtype_SE.ttcn b/function_test/Semantic_Analyser/float/subtype_SE.ttcn index f273a1248364acbcd53d6436329cd54d1d712177..e7d76523632f0802b1383946f0eab0205d421b52 100644 --- a/function_test/Semantic_Analyser/float/subtype_SE.ttcn +++ b/function_test/Semantic_Analyser/float/subtype_SE.ttcn @@ -8,15 +8,29 @@ * Contributors: * Balasko, Jeno * Raduly, Csaba + * Szabo, Bence Janos * ******************************************************************************/ module subtype_SE { //^In TTCN-3 module// -import from subtype_OK all; type component floater {} -type myf123 su2 (3.14); //^In type definition// //^error: The subtype restriction is not a subset of the restriction on the parent type\. Subtype \(3\.14e0\) is not subset of subtype \(1\.0e0,2\.0e0,3\.0e0\)$// -type minf_to_zero su3 (!6.0 .. 10.0); //^In type definition// //^error: The subtype restriction is not a subset of the restriction on the parent type\. Subtype \(!6\.0e0\.\.1\.0e1\) is not subset of subtype \(-INF\.\.0\.0e0\)$// +type float myf123 (1.0, 2.0, 3.0) +type float minf_to_zero (-infinity..0.0) +type float minf_to_mzero (-infinity..-0.0) +type float reals (-infinity..infinity) +type float reals_and_some (-infinity..infinity, 0.0, 1.0, 2.0, 3.0) +//type myf5 myf6 + +type float pow2 (2147483648.0, 4294967296.0, 8589934592.0) +type float two31_32 (2147483648.0..8589934592.0) +type float myf9 (myf123, minf_to_zero) + +type myf9 myf10 (myf123) +type two31_32 myf11 (2147483648.0..4294967296.0, 4294967296.0..4294967300.0) + +type myf123 su2 (3.14); //^In type definition// //^error\: The subtype restriction is not a subset of the restriction on the parent type\. Subtype \(3\.14e0\) is not subset of subtype \(1\.0e0,2\.0e0,3\.0e0\)$// +type minf_to_zero su3 (!6.0 .. 10.0); //^In type definition// //^error\: The subtype restriction is not a subset of the restriction on the parent type\. Subtype \(\!6\.0e0\.\.1\.0e1\) is not subset of subtype \(\-INF\.\.0\.0e0\)$// type float buzz_lightyear (infinity .. not_a_number) //^In type definition// //^error: upper boundary cannot be not_a_number in float subtype range$// // to infinity and beyond diff --git a/regression_test/floatOper/Makefile b/regression_test/floatOper/Makefile index fc26c4fdca0ca0b9e4036d24583218ebeeca2a8d..bf011f158a85a5ce2f76178d7b7956fcdc3052b3 100644 --- a/regression_test/floatOper/Makefile +++ b/regression_test/floatOper/Makefile @@ -23,7 +23,7 @@ include $(TOPDIR)/Makefile.regression TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) -TTCN3_MODULES = TfloatOper.ttcn +TTCN3_MODULES = TfloatOper.ttcn TfloatOperSpecial.ttcn GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) GENERATED_HEADERS = $(GENERATED_SOURCES:.cc=.hh) @@ -38,7 +38,7 @@ endif OBJECTS = $(GENERATED_SOURCES:.cc=.o) -TARGET = TfloatOper$(EXESUFFIX) +TARGET = TfloatOperTests$(EXESUFFIX) all: $(TARGET) diff --git a/regression_test/floatOper/TfloatOperSpecial.ttcn b/regression_test/floatOper/TfloatOperSpecial.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..fc96ebef677ce9acbf7b97a089b979645f0a47f6 --- /dev/null +++ b/regression_test/floatOper/TfloatOperSpecial.ttcn @@ -0,0 +1,757 @@ +/****************************************************************************** + * Copyright (c) 2000-2016 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Szabo, Bence Janos + * + ******************************************************************************/ +module TfloatOperSpecial { + +type component EmptyCT {} + + +testcase tc_addition() runs on EmptyCT { + + var float f := infinity; + var float f2 := 1.0; + f := f + 1.0; + if (f != infinity) { + setverdict(fail); + } + f := f + f2; + if (f != infinity) { + setverdict(fail); + } + + f := -infinity; + f := f + 1.0; + if (f != -infinity) { + setverdict(fail); + } + f := f + f2; + if (f != -infinity) { + setverdict(fail); + } + + // Checked at compile time + f := infinity + 1.0; + if (f != infinity) { + setverdict(fail); + } + + f := -infinity + 1.0; + if (f != -infinity) { + setverdict(fail); + } + + + var charstring dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is inf, right operand is inf"; + @try { + f := infinity; + f2 := infinity; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is inf, right operand is -inf"; + @try { + f := infinity; + f2 := -infinity; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is -inf, right operand is inf"; + @try { + f := -infinity; + f2 := infinity; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is -inf, right operand is -inf"; + @try { + f := -infinity; + f2 := -infinity; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is nan, right operand is inf"; + @try { + f := not_a_number; + f2 := infinity; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is inf, right operand is nan"; + @try { + f := infinity; + f2 := not_a_number; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is nan, right operand is nan"; + @try { + f := not_a_number; + f2 := not_a_number; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float addition: Left operand is nan, right operand is 1"; + @try { + f := not_a_number; + f2 := 1.0; + f := f + f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + setverdict(pass); +} + +testcase tc_subtraction() runs on EmptyCT { + + var float f := infinity; + var float f2 := 1.0; + f := f - 1.0; + if (f != infinity) { + setverdict(fail); + } + f := f - f2; + if (f != infinity) { + setverdict(fail); + } + + + f := -infinity; + f := f - 1.0; + if (f != -infinity) { + setverdict(fail); + } + f := f - f2; + if (f != -infinity) { + setverdict(fail); + } + + // Checked at compile time + f := infinity - 1.0; + if (f != infinity) { + setverdict(fail); + } + + f := -infinity - 1.0; + if (f != -infinity) { + setverdict(fail); + } + + + var charstring dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is inf, right operand is inf"; + @try { + f := infinity; + f2 := infinity; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is inf, right operand is -inf"; + @try { + f := infinity; + f2 := -infinity; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is -inf, right operand is inf"; + @try { + f := -infinity; + f2 := infinity; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is -inf, right operand is -inf"; + @try { + f := -infinity; + f2 := -infinity; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is nan, right operand is inf"; + @try { + f := not_a_number; + f2 := infinity; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is inf, right operand is nan"; + @try { + f := infinity; + f2 := not_a_number; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is nan, right operand is nan"; + @try { + f := not_a_number; + f2 := not_a_number; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float subtraction: Left operand is nan, right operand is 1"; + @try { + f := not_a_number; + f2 := 1.0; + f := f - f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + setverdict(pass); +} + + +testcase tc_multiplication() runs on EmptyCT { + var float f := infinity; + var float f2 := 2.0; + var float f3 := -2.0; + f := f * 2.0; + if (f != infinity) { + setverdict(fail); + } + f := f * f2; + if (f != infinity) { + setverdict(fail); + } + f := f * f3; + if (f != -infinity) { + setverdict(fail); + } + + f := -infinity; + f := f * 2.0; + if (f != -infinity) { + setverdict(fail); + } + f := f * f2; + if (f != -infinity) { + setverdict(fail); + } + f := f * f3; + if (f != infinity) { + setverdict(fail); + } + + // Checked at compile time + f := infinity * 1.0; + if (f != infinity) { + setverdict(fail); + } + + f := -infinity * 1.0; + if (f != -infinity) { + setverdict(fail); + } + + + var charstring dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is inf, right operand is inf"; + @try { + f := infinity; + f2 := infinity; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is inf, right operand is -inf"; + @try { + f := infinity; + f2 := -infinity; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is -inf, right operand is inf"; + @try { + f := -infinity; + f2 := infinity; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is -inf, right operand is -inf"; + @try { + f := -infinity; + f2 := -infinity; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is nan, right operand is inf"; + @try { + f := not_a_number; + f2 := infinity; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is inf, right operand is nan"; + @try { + f := infinity; + f2 := not_a_number; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is nan, right operand is nan"; + @try { + f := not_a_number; + f2 := not_a_number; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float multiplication: Left operand is nan, right operand is 2"; + @try { + f := not_a_number; + f2 := 2.0; + f := f * f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + setverdict(pass); +} + + +testcase tc_division() runs on EmptyCT { + var float f := infinity; + var float f2 := 2.0; + var float f3 := -2.0; + f := f / 2.0; + if (f != infinity) { + setverdict(fail); + } + f := f / f2; + if (f != infinity) { + setverdict(fail); + } + f := f / f3; + if (f != -infinity) { + setverdict(fail); + } + + f := -infinity; + f := f / 2.0; + if (f != -infinity) { + setverdict(fail); + } + f := f / f2; + if (f != -infinity) { + setverdict(fail); + } + f := f / f3; + if (f != infinity) { + setverdict(fail); + } + + f := f2 / f; + if (f != 0.000000) { + setverdict(fail); + } + + f := infinity; + f := f3 / f; + if (f != -0.000000) { + setverdict(fail); + } + + f := -infinity; + f := f2 / f; + if (f != -0.000000) { + setverdict(fail); + } + + f := -infinity; + f := f3 / f; + if (f != 0.000000) { + setverdict(fail); + } + + + // Checked at compile time + f := infinity / 2.0; + if (f != infinity) { + setverdict(fail); + } + + f := -infinity / 2.0; + if (f != -infinity) { + setverdict(fail); + } + + + var charstring dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is inf, right operand is inf"; + @try { + f := infinity; + f2 := infinity; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is inf, right operand is -inf"; + @try { + f := infinity; + f2 := -infinity; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is -inf, right operand is inf"; + @try { + f := -infinity; + f2 := infinity; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is -inf, right operand is -inf"; + @try { + f := -infinity; + f2 := -infinity; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is nan, right operand is inf"; + @try { + f := not_a_number; + f2 := infinity; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is inf, right operand is nan"; + @try { + f := infinity; + f2 := not_a_number; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is nan, right operand is nan"; + @try { + f := not_a_number; + f2 := not_a_number; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + dte_message := "Dynamic test case error: Invalid operands of float division: Left operand is nan, right operand is 2"; + @try { + f := not_a_number; + f2 := 2.0; + f := f / f2; + setverdict(fail, "Expected dynamic test case error"); + } + @catch (msg) { + if (not match(msg, dte_message)) { + setverdict(fail, "Expected error: ", dte_message, ", got: ", msg); + } + } + + setverdict(pass); +} + + +//===========================================================================// + + +const float inf := infinity; +const float neginf := -infinity; +const float two := 2.0; +const float negtwo := -2.0; + +// All of theese are infinity +const float c_f1 := inf + two; +const float c_f2 := inf + negtwo; +const float c_f3 := inf - two; +const float c_f4 := inf - negtwo; +const float c_f5 := inf * two; +const float c_f6 := inf / two; +const float c_f7 := neginf * negtwo; +const float c_f8 := neginf / negtwo; + +// All of theese are -infinity +const float c_f9 := neginf + two; +const float c_f10 := neginf + negtwo; +const float c_f11 := neginf - two; +const float c_f12 := neginf - negtwo; +const float c_f13 := neginf * two; +const float c_f14 := neginf / two; +const float c_f15 := inf * negtwo; +const float c_f16 := inf / negtwo; + + +// All of theese are 0.000000 +const float c_f17 := two / inf; + +// All of theese are -0.000000 +const float c_f18 := two / neginf; + +// All of theese are not_a_number + +const float c_f19 := inf * 0.0; +const float c_f20 := neginf * 0.0; + +testcase tc_compile_time() runs on EmptyCT { + + // Infinities + if (c_f1 != infinity) { + setverdict(fail); + } + if (c_f2 != infinity) { + setverdict(fail); + } + if (c_f3 != infinity) { + setverdict(fail); + } + if (c_f4 != infinity) { + setverdict(fail); + } + if (c_f5 != infinity) { + setverdict(fail); + } + if (c_f6 != infinity) { + setverdict(fail); + } + if (c_f7 != infinity) { + setverdict(fail); + } + if (c_f8 != infinity) { + setverdict(fail); + } + + + // Negative infinities + if (c_f9 != -infinity) { + setverdict(fail); + } + if (c_f10 != -infinity) { + setverdict(fail); + } + if (c_f11 != -infinity) { + setverdict(fail); + } + if (c_f12 != -infinity) { + setverdict(fail); + } + if (c_f13 != -infinity) { + setverdict(fail); + } + if (c_f14 != -infinity) { + setverdict(fail); + } + if (c_f15 != -infinity) { + setverdict(fail); + } + if (c_f16 != -infinity) { + setverdict(fail); + } + + + // 0.000000 + if (c_f17 != 0.000000) { + setverdict(fail); + } + + // -0.000000 + if (c_f18 != -0.000000) { + setverdict(fail); + } + + + // Not a number + if (c_f19 != not_a_number) { + setverdict(fail); + } + if (c_f20 != not_a_number) { + setverdict(fail); + } + + setverdict(pass); +} + +//===========================================================================// + +control { + execute(tc_addition()); + execute(tc_subtraction()); + execute(tc_multiplication()); + execute(tc_division()); + execute(tc_compile_time()); +} + +} \ No newline at end of file diff --git a/regression_test/floatOper/config.cfg b/regression_test/floatOper/config.cfg index 706cca3fb8e994514f06549c16e6db9af14d1e05..7aa249ae8b4852d9c76b89b3fa4fc1a8fed105e2 100644 --- a/regression_test/floatOper/config.cfg +++ b/regression_test/floatOper/config.cfg @@ -8,6 +8,7 @@ # Contributors: # Balasko, Jeno # Szabo, Janos Zoltan – initial implementation +# Szabo, Bence Janos # ############################################################################### [MODULE_PARAMETERS] @@ -17,3 +18,4 @@ FileMask := LOG_ALL ConsoleMask := TTCN_WARNING | TTCN_ERROR | TTCN_TESTCASE | TTCN_STATISTICS [EXECUTE] TfloatOper +TfloatOperSpecial diff --git a/usrguide/referenceguide.doc b/usrguide/referenceguide.doc index 846c7c9efd3d8a3ccdfca4156dc1fa00afcfbb5c..de38655f6afcf8b59f7af6b889ef673009d16d09 100644 Binary files a/usrguide/referenceguide.doc and b/usrguide/referenceguide.doc differ