diff --git a/exprtk.hpp b/exprtk.hpp index f942a2c..746a1e4 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -2344,7 +2344,7 @@ namespace exprtk else if ('~' == (*s_itr_)) { token_t t; - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); token_list_.push_back(t); ++s_itr_; return; @@ -2352,7 +2352,7 @@ namespace exprtk else { token_t t; - t.set_error(token::e_error,s_itr_,s_itr_ + 2,base_itr_); + t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); token_list_.push_back(t); ++s_itr_; } @@ -2374,7 +2374,7 @@ namespace exprtk if ((c0 == '<') && (c1 == '=') && (c2 == '>')) { - t.set_operator(token_t::e_swap,s_itr_,s_itr_ + 3,base_itr_); + t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_); token_list_.push_back(t); s_itr_ += 3; return; @@ -2399,7 +2399,7 @@ namespace exprtk if (token_t::e_none != ttype) { - t.set_operator(ttype,s_itr_,s_itr_ + 2,base_itr_); + t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); token_list_.push_back(t); s_itr_ += 2; return; @@ -2407,17 +2407,17 @@ namespace exprtk } if ('<' == c0) - t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_lt ,s_itr_, s_itr_ + 1, base_itr_); else if ('>' == c0) - t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_gt ,s_itr_, s_itr_ + 1, base_itr_); else if (';' == c0) - t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_eof,s_itr_, s_itr_ + 1, base_itr_); else if ('&' == c0) - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); else if ('|' == c0) - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); else - t.set_operator(token_t::token_type(c0),s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_); token_list_.push_back(t); ++s_itr_; @@ -2489,7 +2489,7 @@ namespace exprtk { if (dot_found) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; } @@ -2505,7 +2505,7 @@ namespace exprtk if (is_end(s_itr_ + 1)) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2516,7 +2516,7 @@ namespace exprtk !details::is_digit(c) ) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2531,7 +2531,7 @@ namespace exprtk { if (post_e_sign_found) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2555,7 +2555,7 @@ namespace exprtk ++s_itr_; } - t.set_numeric(initial_itr,s_itr_,base_itr_); + t.set_numeric(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2569,7 +2569,7 @@ namespace exprtk // $fdd(x,x,x) = at least 11 chars if (std::distance(s_itr_,s_end_) < 11) { - t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_sfunc, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2582,7 +2582,7 @@ namespace exprtk (details::is_digit(*(s_itr_ + 3)))) ) { - t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_sfunc, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2590,7 +2590,7 @@ namespace exprtk s_itr_ += 4; // $fdd = 4chars - t.set_symbol(initial_itr,s_itr_,base_itr_); + t.set_symbol(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2604,7 +2604,7 @@ namespace exprtk if (std::distance(s_itr_,s_end_) < 2) { - t.set_error(token::e_err_string,s_itr_,s_end_,base_itr_); + t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); token_list_.push_back(t); return; } @@ -2654,7 +2654,7 @@ namespace exprtk if (!within_range || !x_seperator || !both_digits) { - t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2671,14 +2671,14 @@ namespace exprtk if (is_end(s_itr_)) { - t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; } if (!escaped_found) - t.set_string(initial_itr,s_itr_,base_itr_); + t.set_string(initial_itr, s_itr_, base_itr_); else { std::string parsed_string(initial_itr,s_itr_); @@ -2878,16 +2878,16 @@ namespace exprtk case 1 : insert_index = insert(g.token_list_[i],t); break; - case 2 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],t); + case 2 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], t); break; - case 3 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t); + case 3 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], t); break; - case 4 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],t); + case 4 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], t); break; - case 5 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],g.token_list_[i + 4],t); + case 5 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], g.token_list_[i + 4], t); break; } @@ -4295,7 +4295,8 @@ namespace exprtk e_erf , e_erfc , e_ncdf , e_frac , e_trunc , e_assign , e_addass , e_subass , e_mulass , e_divass , e_modass , e_in , - e_like , e_ilike , e_multi , e_swap , + e_like , e_ilike , e_multi , e_smulti , + e_swap , // Do not add new functions/operators after this point. e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, @@ -4784,36 +4785,37 @@ namespace exprtk e_for , e_switch , e_mswitch , e_return , e_retenv , e_variable , e_stringvar , e_stringconst , e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , - e_stringvarsize, e_strswap , e_stringsize , e_function , - e_vafunction , e_genfunction , e_strfunction , e_strcondition , - e_strccondition, e_add , e_sub , e_mul , - e_div , e_mod , e_pow , e_lt , - e_lte , e_gt , e_gte , e_eq , - e_ne , e_and , e_nand , e_or , - e_nor , e_xor , e_xnor , e_in , - e_like , e_ilike , e_inranges , e_ipow , - e_ipowinv , e_abs , e_acos , e_acosh , - e_asin , e_asinh , e_atan , e_atanh , - e_ceil , e_cos , e_cosh , e_exp , - e_expm1 , e_floor , e_log , e_log10 , - e_log2 , e_log1p , e_neg , e_pos , - e_round , e_sin , e_sinc , e_sinh , - e_sqrt , e_tan , e_tanh , e_cot , - e_sec , e_csc , e_r2d , e_d2r , - e_d2g , e_g2d , e_notl , e_sgn , - e_erf , e_erfc , e_ncdf , e_frac , - e_trunc , e_uvouv , e_vov , e_cov , - e_voc , e_vob , e_bov , e_cob , - e_boc , e_vovov , e_vovoc , e_vocov , - e_covov , e_covoc , e_vovovov , e_vovovoc , - e_vovocov , e_vocovov , e_covovov , e_covocov , - e_vocovoc , e_covovoc , e_vococov , e_sf3ext , - e_sf4ext , e_nulleq , e_strass , e_vector , - e_vecelem , e_rbvecelem , e_rbveccelem , e_vecdefass , - e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass , - e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq , - e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith , - e_vecunaryop , e_break , e_continue , e_swap + e_stringvarsize, e_strswap , e_stringsize , e_stringvararg , + e_function , e_vafunction , e_genfunction , e_strfunction , + e_strcondition , e_strccondition, e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_lt , e_lte , e_gt , e_gte , + e_eq , e_ne , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_in , e_like , e_ilike , e_inranges , + e_ipow , e_ipowinv , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_neg , + e_pos , e_round , e_sin , e_sinc , + e_sinh , e_sqrt , e_tan , e_tanh , + e_cot , e_sec , e_csc , e_r2d , + e_d2r , e_d2g , e_g2d , e_notl , + e_sgn , e_erf , e_erfc , e_ncdf , + e_frac , e_trunc , e_uvouv , e_vov , + e_cov , e_voc , e_vob , e_bov , + e_cob , e_boc , e_vovov , e_vovoc , + e_vocov , e_covov , e_covoc , e_vovovov , + e_vovovoc , e_vovocov , e_vocovov , e_covovov , + e_covocov , e_vocovoc , e_covovoc , e_vococov , + e_sf3ext , e_sf4ext , e_nulleq , e_strass , + e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , + e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , + e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , + e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , + e_valvecarith , e_vecunaryop , e_break , e_continue , + e_swap }; typedef T value_type; @@ -8728,6 +8730,141 @@ namespace exprtk expression_ptr test_; expression_ptr consequent_; }; + + template + class str_vararg_node : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + template class Sequence> + str_vararg_node(const Sequence& arg_list) + : final_node_(arg_list.back()), + final_deletable_(branch_deletable(final_node_)), + initialised_(false), + str_base_ptr_ (0), + str_range_ptr_(0) + { + if (0 == final_node_) + return; + else if (!is_generally_string_node(final_node_)) + return; + + str_base_ptr_ = dynamic_cast(final_node_); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(final_node_); + + if (0 == str_range_ptr_) + return; + + initialised_ = str_base_ptr_ && str_range_ptr_; + + if (arg_list.size() > 1) + { + const std::size_t arg_list_size = arg_list.size() - 1; + + arg_list_.resize(arg_list_size); + delete_branch_.resize(arg_list_size); + + for (std::size_t i = 0; i < arg_list_size; ++i) + { + if (arg_list[i]) + { + arg_list_[i] = arg_list[i]; + delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); + } + else + { + arg_list_.clear(); + delete_branch_.clear(); + return; + } + } + } + } + + ~str_vararg_node() + { + if (final_node_ && final_deletable_) + { + delete final_node_; + final_node_ = 0; + } + + for (std::size_t i = 0; i < arg_list_.size(); ++i) + { + if (arg_list_[i] && delete_branch_[i]) + { + delete arg_list_[i]; + arg_list_[i] = 0; + } + } + } + + inline T value() const + { + if (!arg_list_.empty()) + { + VarArgFunction::process(arg_list_); + } + + final_node_->value(); + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return str_base_ptr_->str(); + } + + const char* base() const + { + return str_base_ptr_->base(); + } + + std::size_t size() const + { + return str_base_ptr_->size(); + } + + range_t& range_ref() + { + return str_range_ptr_->range_ref(); + } + + const range_t& range_ref() const + { + return str_range_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringvararg; + } + + private: + + expression_ptr final_node_; + bool final_deletable_; + bool initialised_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + std::vector arg_list_; + std::vector delete_branch_; + }; #endif template @@ -15078,6 +15215,12 @@ namespace exprtk return node && (expression_node::e_strccondition == node->type()); } + template + inline bool is_string_vararg_node(const expression_node* node) + { + return node && (expression_node::e_stringvararg == node->type()); + } + template inline bool is_genricstring_range_node(const expression_node* node) { @@ -15100,7 +15243,8 @@ namespace exprtk case expression_node::e_strconcat : case expression_node::e_strfunction : case expression_node::e_strcondition : - case expression_node::e_strccondition : return true; + case expression_node::e_strccondition : + case expression_node::e_stringvararg : return true; default : return false; } } @@ -21909,7 +22053,8 @@ namespace exprtk typename Allocator2, template class Sequence> inline expression_node_ptr simplify(Sequence& expression_list, - Sequence& side_effect_list) + Sequence& side_effect_list, + const bool specialise_on_final_type = false) { if (expression_list.empty()) return error_node(); @@ -21980,6 +22125,8 @@ namespace exprtk if (1 == expression_list.size()) return expression_list[0]; + else if (specialise_on_final_type && is_generally_string_node(expression_list.back())) + return expression_generator_.vararg_function(details::e_smulti,expression_list); else return expression_generator_.vararg_function(details::e_multi,expression_list); } @@ -22056,7 +22203,7 @@ namespace exprtk break; } - result = simplify(arg_list,side_effect_list); + result = simplify(arg_list,side_effect_list,source.empty()); sdd.delete_ptr = (0 == result); return result; @@ -24536,6 +24683,7 @@ namespace exprtk { return parse_swap_statement(); } + #ifndef exprtk_disable_return_statement else if ( details::imatch(current_token().value,symbol_return) && settings_.control_struct_enabled(current_token().value) @@ -24543,6 +24691,7 @@ namespace exprtk { return parse_return_statement(); } + #endif else if (symtab_store_.valid() || !sem_.empty()) { return parse_symtab_symbol(); @@ -26345,22 +26494,30 @@ namespace exprtk else if (all_nodes_variables(arg_list)) return varnode_optimise_varargfunc(operation,arg_list); - switch (operation) + if (details::e_smulti == operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arg_list); \ + return node_allocator_-> + allocate > >(arg_list); + } + else + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) - #undef case_stmt - default : return error_node(); + case_stmt(details::e_sum, details::vararg_add_op ) + case_stmt(details::e_prod, details::vararg_mul_op ) + case_stmt(details::e_avg, details::vararg_avg_op ) + case_stmt(details::e_min, details::vararg_min_op ) + case_stmt(details::e_max, details::vararg_max_op ) + case_stmt(details::e_mand, details::vararg_mand_op ) + case_stmt(details::e_mor, details::vararg_mor_op ) + case_stmt(details::e_multi,details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } } } @@ -32935,14 +33092,16 @@ namespace exprtk details::is_string_concat_node (branch[0]) || details::is_string_function_node (branch[0]) || details::is_string_condition_node (branch[0]) || - details::is_string_ccondition_node (branch[0]) ; + details::is_string_ccondition_node (branch[0]) || + details::is_string_vararg_node (branch[0]) ; const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || details::is_genricstring_range_node(branch[1]) || details::is_string_concat_node (branch[1]) || details::is_string_function_node (branch[1]) || details::is_string_condition_node (branch[1]) || - details::is_string_ccondition_node (branch[1]) ; + details::is_string_ccondition_node (branch[1]) || + details::is_string_vararg_node (branch[1]) ; if (details::e_add == opr) { diff --git a/exprtk_test.cpp b/exprtk_test.cpp index ab3c06c..1fc884d 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -4382,6 +4382,15 @@ inline bool run_test10() "0 == (for (var i := 0; i < 10; i += 1) { ~{continue; break[7]; i += i} })", "1 == (for (var i := 0; i < 10; i += 1) { ~{break[i += 1]; continue; i += i} })", + "var s := 'abc'; s == ~{'abc' } ", + "var s := 'abc'; s == ~{s } ", + "var s := 'abc'; s == ~{'ab' + 'c'} ", + "var s := 'abc'; ~{'abc' } == s ", + "var s := 'abc'; ~{s } == s ", + "var s := 'abc'; ~{'ab' + 'c'} == s ", + "var s := 'abc'; ~{1 + 2; 'abc' + s; s} == s ", + "var s := 'abc'; ~{1 + 2; var x := 'ab'; x + 'c'} == s ", + "var x[10^6] := null; var y[10^7] := null; 0 * (min(x) + min(y)) + x[] + y[] == 10^7 + 10^6" };