note description: "Evaluator to evaluate expressions in the context of collected state expressions" author: "" date: "$Date$" revision: "$Revision$" class CI_EXPRESSION_EVALUATOR inherit AST_ITERATOR redefine process_un_old_as, process_void_as, process_integer_as, process_bool_as, process_bin_and_as, process_bin_and_then_as, process_bin_or_as, process_bin_or_else_as, process_bin_implies_as, process_bin_xor_as, process_bin_eq_as, process_bin_ge_as, process_bin_gt_as, process_bin_le_as, process_bin_lt_as, process_bin_ne_as, process_bin_minus_as, process_bin_plus_as, process_access_feat_as, process_nested_as, process_un_not_as, process_bin_tilde_as, process_bin_not_tilde_as, process_tuple_as, process_un_free_as, process_bin_free_as, process_expr_call_as end EPA_SHARED_EQUALITY_TESTERS EPA_UTILITY SHARED_TEXT_ITEMS ETR_PARSING_HELPER select error_handler end CI_SEQUENCE_OPERATOR_NAMES feature{NONE} -- Access for implementation -- old_state: detachable EPA_STATE -- -- State where 'old' expressions are evaluated. -- -- Evaluation of 'old' fails if `old_state' is Void. -- -- When `is_evaluating_pre_expressions' is True, `old_state' is set to Void; -- -- When it is False, `old_state' is equal to `prestate'. -- -- -- -- See `working_state'. -- do -- if is_evaluating_pre_expressions then -- Result := Void -- else -- Result := prestate -- end -- end -- working_state: EPA_STATE -- -- State where non-old expressions are evaluated. -- -- When `is_evaluating_pre_expressions' is True, `working_state' is equal to `prestate'; -- -- When it is False, `working_state' is equal to `poststate'. -- -- -- -- See `old_state'. -- do -- if is_evaluating_pre_expressions then -- Result := prestate -- else -- Result := poststate -- end -- end feature -- Access evaluation result missing_expressions: DS_HASH_SET [EPA_EXPRESSION] -- Set of expressions that were needed to by the last -- `evaluate' but are missing in `transtion_context'. -- Note: The test case in `transition_context' needs to be executed -- again to get the values of these missing expressions last_value: EPA_EXPRESSION_VALUE -- Value of the last evaluated expression by `evaluate' feature -- Access initial evaluation context context_class: CLASS_C -- Context class for expression evaluation prestate: EPA_STATE -- Values in pre-state poststate: EPA_STATE -- Values in post-state extra_pre_state_values: detachable EPA_STATE -- Extra pre-state values extra_post_state_values: detachable EPA_STATE -- Extra post-state values feature -- Access derived evaluation context state_values (a_old_state: BOOLEAN): EPA_STATE -- Return `old_state_values' if `a_old_state'; -- Return `working_state_values' otherwise. do if a_old_state then Result := old_state_values else Result := working_state_values end end extra_state_values (a_old_state: BOOLEAN): detachable EPA_STATE -- Return `extra_old_state_values' if `a_old_state'; -- Return `extra_working_state_values' otherwise. do if a_old_state then Result := extra_old_state_values else Result := extra_working_state_values end end feature{NONE} -- Derived evaluation context implementation old_state_values: EPA_STATE -- State values for evaluating 'old' expressions. -- Evaluation of an 'old' expression fails if both `old_state_values' and `old_extra_state_values' are Void. -- Return Void if `is_evaluating_pre_expressions'; -- Return `prestate' otherwise. -- -- See `working_state_values'. do if is_evaluating_pre_expressions then Result := Void else Result := prestate end end working_state_values: EPA_STATE -- State values for evaluating non-old expressions. -- Return `prestate' if `is_evaluating_pre_expressions'; -- Return `poststate' otherwise. -- -- See `old_state_values'. do if is_evaluating_pre_expressions then Result := prestate else Result := poststate end end extra_old_state_values: EPA_STATE -- Extra state values for evaluating 'old' expressions. -- Evaluation of an 'old' expression fails if both `old_state_values' and `old_extra_state_values' are Void. -- Return Void if `is_evaluating_pre_expressions'; -- Return `extra_pre_state_values' otherwise. -- -- See `extra_working_state_values'. do if is_evaluating_pre_expressions then Result := Void else Result := extra_pre_state_values end end extra_working_state_values: EPA_STATE -- Extra state values for evaluating non-old expressions. -- Return `extra_pre_state_values' if `is_evaluating_pre_expressions'; -- Return `extra_post_state_values' otherwise. -- -- See `extra_old_state_values'. do if is_evaluating_pre_expressions then Result := extra_pre_state_values else Result := extra_post_state_values end end feature -- Status report is_evaluating_pre_expressions: BOOLEAN assign set_evaluating_pre_expressions -- Is the evaluator for evaluating pre-expressions? -- If True, `pre_state' is the context, and 'old' expressions will trigger error; -- Otherwise, `post_state' is the context and 'old' expressions are allowed. is_ternary_logic_enabled: BOOLEAN -- Is ternary logic enabled? -- So nonsensical values can be used in boolean algebra? -- Default: False has_error: BOOLEAN -- Was an error during last expression evaluation? error_reason: detachable STRING -- Reason for the last error feature -- Basic operations evaluate (a_expr: AST_EIFFEL) -- Evaluate `a_expr' in the current evaluation context, and make result available in `last_value'. -- Store missing expressions (if any) in `missing_expressions'. -- Old expressions will be evaluated in `old_state_values' and `extra_old_state_values'; -- Non-old expressions will be evaluated in `working_state_values' and `extra_working_state_values'. -- For example: in "old o.has (v) implies o.has (v)", sub-expression -- "old o.has (v)" will be evaluated in `*old_state_values' state, and sub-expression -- "o.has (v)" will be evaluated in `*working_state_values' state. require a_expr_attached: a_expr /= Void do initialize_data_structures a_expr.process (Current) end evaluate_string (a_string: STRING) -- Evaluate `a_string' in `transition_context'. -- See comment of `evaluate' for details. local l_parser: like etr_expr_parser do l_parser := etr_expr_parser setup_formal_parameters (l_parser, context_class) l_parser.parse_from_utf8_string (once "check " + a_string, context_class) check l_parser.expression_node /= Void end evaluate (l_parser.expression_node) end feature -- Setting set_context (a_prestate: like prestate; a_poststate: like poststate; a_context_class: like context_class) -- Setup context. do prestate := a_prestate poststate := a_poststate context_class := a_context_class end set_evaluating_pre_expressions (a_flag: BOOLEAN) -- Set `is_evaluating_pre_expressions' with `a_flag'. do is_evaluating_pre_expressions := a_flag end set_extra_pre_state_values (a_values: like extra_pre_state_values) -- Set `extra_pre_state_values' with `a_values' do extra_pre_state_values := a_values end set_extra_post_state_values (a_values: like extra_post_state_values) -- Set `extra_post_state_values' with `a_values' do extra_post_state_values := a_values end set_is_ternary_logic_enabled (b: BOOLEAN) -- Set `is_ternary_logic_enabled' with `b'. do is_ternary_logic_enabled := b ensure is_ternary_logic_enabled_set: is_ternary_logic_enabled = b end wipe_out_error -- Wipe all error do has_error := False error_reason := "" end feature{NONE} -- Implementation initialize_data_structures -- Initialize data structures. do last_value := Void create missing_expressions.make (5) missing_expressions.set_equality_tester (expression_equality_tester) wipe_out_error end set_has_error (b: BOOLEAN; a_reason: STRING) -- Set `has_error' with `b'. do has_error := b error_reason := a_reason.twin ensure has_error_set: has_error = b end sequence_value (a_value: EPA_EXPRESSION_VALUE): detachable ANY -- Sequence value out of `a_value', if not possible, return the original `a_value' do if attached {EPA_ANY_VALUE} a_value as l_value then if attached {CI_SEQUENCE [EPA_EXPRESSION_VALUE]} a_value.item as l_sequence then Result := l_sequence.content elseif attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_value.item as l_sequence then Result := l_sequence end end if Result = Void then Result := a_value end end equation_by_expression_ast (a_expr_as: AST_EIFFEL; a_old_state: BOOLEAN): detachable EPA_EQUATION -- Equation whose expression is equal to `a_expr_as' -- use old state values if `a_old_state' is True, otherwise, -- use working state values. -- Void if no such equation is found. do Result := equation_by_expression (text_from_ast (a_expr_as), a_old_state) end equation_by_expression (a_expr: STRING; a_old_state: BOOLEAN): detachable EPA_EQUATION -- Equation whose expression is equal to `a_expr' -- use old state values if `a_old_state' is True, otherwise, -- use working state values. -- Void if no such equation is found. do if attached state_values (a_old_state) as lt_state_values then Result := lt_state_values.item_with_expression_text (a_expr) if Result = Void and then attached extra_state_values (a_old_state) as lt_extra_state_values then Result := lt_extra_state_values.item_with_expression_text (a_expr) end end -- Result := state_values (a_old_state).item_with_expression_text (a_expr) -- if Result = Void then -- if attached {EPA_STATE} extra_state_values (a_pre_state) as l_state then -- Result := l_state.item_with_expression_text (a_expr) ---- if Result /= Void and then attached {EPA_ANY_VALUE} Result.value as l_any then ---- if attached {CI_SEQUENCE [EPA_EXPRESSION_VALUE]} l_any.item as l_sequence then ---- if log_manager /= Void then ---- log_manager.put_line_at_info_level ("%T" + a_expr + " == " + l_sequence.out + "%N") ---- end ---- elseif attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} l_any.item as l_sequence then ---- if log_manager /= Void then ---- log_manager.put_line_at_info_level ("%T" + a_expr + " == " + l_sequence.out + "%N") ---- end ---- end ---- end -- end -- end end evalute_unary_sequence_operator (a_sequence: MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]; a_operator_name: STRING) -- Evaluate `a_sequence' on operator `a_operator_name', -- Make result available in `last_value'. require a_operator_name_valid: sequence_un_operators.has (a_operator_name) do if a_operator_name ~ sequence_is_empty_un_operator then create {EPA_BOOLEAN_VALUE} last_value.make (a_sequence.is_empty) elseif a_operator_name ~ sequence_count_un_operator then create {EPA_INTEGER_VALUE} last_value.make (a_sequence.count) end end evalute_binary_sequence_operator (a_left, a_right: ANY; a_operator_name: STRING) -- Evaluate `a_sequence' on operator `a_operator_name', -- Make result available in `last_value'. require a_operator_name_valid: sequence_bin_operators.has (a_operator_name) local l_sequence: CI_SEQUENCE [EPA_EXPRESSION_VALUE] do if a_operator_name ~ sequence_is_equal_bin_operator then if attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_left as l_left and then attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_right as l_right then create {EPA_BOOLEAN_VALUE} last_value.make (l_left |=| l_right) else set_has_error (True, msg_type_error_sequence_expected) end elseif a_operator_name ~ sequence_is_prefix_of_bin_operator then if attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_left as l_left and then attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_right as l_right then create {EPA_BOOLEAN_VALUE} last_value.make (l_left.is_prefix_of (l_right)) else set_has_error (True, msg_type_error_sequence_expected) end elseif a_operator_name ~ sequence_is_suffix_of_bin_operator then if attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_left as l_left and then attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_right as l_right then create {EPA_BOOLEAN_VALUE} last_value.make (l_left.is_suffix_of (l_right)) else set_has_error (True, msg_type_error_sequence_expected) end elseif a_operator_name ~ sequence_concatenation_bin_operator then if attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_left as l_left and then attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_right as l_right then create {EPA_ANY_VALUE} last_value.make (l_left |+| l_right) else set_has_error (True, msg_type_error_sequence_expected) end elseif a_operator_name ~ sequence_head_bin_operator then if attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_left as l_left and then attached {EPA_INTEGER_VALUE} a_right as l_right then create {EPA_ANY_VALUE} last_value.make (l_left.front (l_right.item - l_left.lower_bound + 1)) else set_has_error (True, msg_type_error_sequence_expected) end elseif a_operator_name ~ sequence_tail_bin_operator then if attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} a_left as l_left and then attached {EPA_INTEGER_VALUE} a_right as l_right then create {EPA_ANY_VALUE} last_value.make (l_left.tail (l_right.item - l_left.lower_bound + 1)) else set_has_error (True, msg_type_error_sequence_expected) end else set_has_error (True, msg_free_binary_operator_not_supported (a_operator_name)) end end feature{NONE} -- Implementation process_access_feat_as (l_as: ACCESS_FEAT_AS) do process_expression (l_as) end process_expression (a_ast: AST_EIFFEL) -- Process `a_ast'. local l_equation: detachable EPA_EQUATION do if not has_error then l_equation := equation_by_expression_ast (a_ast, False) if l_equation /= Void then last_value := l_equation.value else set_has_error (True, msg_missing_expression (a_ast, False)) end end end process_expr_call_as (l_as: EXPR_CALL_AS) do process_expression (l_as) end process_nested_as (l_as: NESTED_AS) do process_expression (l_as) end process_un_old_as (l_as: UN_OLD_AS) local l_expr_text: STRING l_equation: detachable EPA_EQUATION do if not has_error then if attached {PARAN_AS} l_as.expr as l_paran then l_equation := equation_by_expression_ast (l_paran.expr, True) else l_equation := equation_by_expression_ast (l_as.expr, True) end if l_equation /= Void then last_value := l_equation.value else set_has_error (True, msg_missing_expression (l_as.expr, True)) end end end process_void_as (l_as: VOID_AS) do if not has_error then create {EPA_VOID_VALUE} last_value.make end end process_bool_as (l_as: BOOL_AS) do if not has_error then create {EPA_BOOLEAN_VALUE} last_value.make (l_as.value) end end process_integer_as (l_as: INTEGER_AS) do if not has_error then create {EPA_INTEGER_VALUE} last_value.make (l_as.integer_32_value) end end process_binary_boolean_operator_as (a_left: EXPR_AS; a_right: EXPR_AS; a_operator_name: STRING) -- Process binary boolean operator. local l_left_value: like last_value l_right_value: like last_value l_value: BOOLEAN do if not has_error then -- Process left. process_boolean_expression (a_left) if not has_error then l_left_value := last_value end -- Process right. if not has_error then process_boolean_expression (a_right) if not has_error then l_right_value := last_value end end if not has_error then if l_left_value.is_boolean and then l_right_value.is_boolean then -- Evaluate expression if a_operator_name ~ ti_and_keyword then l_value := l_left_value.as_boolean.item and l_right_value.as_boolean.item elseif a_operator_name ~ ti_or_keyword then l_value := l_left_value.as_boolean.item or l_right_value.as_boolean.item elseif a_operator_name ~ ti_implies_keyword then l_value := l_left_value.as_boolean.item implies l_right_value.as_boolean.item elseif a_operator_name ~ ti_xor_keyword then l_value := l_left_value.as_boolean.item xor l_right_value.as_boolean.item end create {EPA_BOOLEAN_VALUE} last_value.make (l_value) elseif is_ternary_logic_enabled then if l_left_value.is_nonsensical and then l_right_value.is_nonsensical then create {EPA_NONSENSICAL_VALUE} last_value elseif l_left_value.is_nonsensical and then l_right_value.is_boolean then if a_operator_name ~ ti_and_keyword then create {EPA_NONSENSICAL_VALUE} last_value elseif a_operator_name ~ ti_or_keyword or a_operator_name ~ ti_implies_keyword then if l_right_value.as_boolean.is_true then create {EPA_BOOLEAN_VALUE} last_value.make (True) else create {EPA_NONSENSICAL_VALUE} last_value end elseif a_operator_name ~ ti_xor_keyword then create {EPA_NONSENSICAL_VALUE} last_value end elseif l_left_value.is_boolean and then l_right_value.is_nonsensical then if a_operator_name ~ ti_and_keyword then create {EPA_NONSENSICAL_VALUE} last_value elseif a_operator_name ~ ti_or_keyword then if l_left_value.as_boolean.is_true then create {EPA_BOOLEAN_VALUE} last_value.make (True) else create {EPA_NONSENSICAL_VALUE} last_value end elseif a_operator_name ~ ti_implies_keyword then if l_left_value.as_boolean.is_false then create {EPA_BOOLEAN_VALUE} last_value.make (True) else create {EPA_NONSENSICAL_VALUE} last_value end elseif a_operator_name ~ ti_xor_keyword then create {EPA_NONSENSICAL_VALUE} last_value end else set_has_error (True, msg_type_error_boolean_value_expected) end end end end end process_boolean_expression (a_expr: EXPR_AS) -- Process `a_expr' as if it is a boolean expression local l_value: like last_value do if not has_error then a_expr.process (Current) if not has_error then l_value := last_value if l_value.is_boolean or else (l_value.is_nonsensical and then is_ternary_logic_enabled) then else set_has_error (True, msg_type_error (a_expr, {EPA_EXPRESSION_VALUE}.boolean_type_name, last_value.type_name)) end end end end process_integer_expression (a_expr: EXPR_AS) -- Process `a_expr' as if it is an integer expression do if not has_error then a_expr.process (Current) if not has_error then if not last_value.is_integer then set_has_error (True, msg_type_error (a_expr, {EPA_EXPRESSION_VALUE}.integer_type_name, last_value.type_name)) end end end end process_bin_and_as (l_as: BIN_AND_AS) do process_binary_boolean_operator_as (l_as.left, l_as.right, ti_and_keyword) end process_bin_and_then_as (l_as: BIN_AND_THEN_AS) do process_binary_boolean_operator_as (l_as.left, l_as.right, ti_and_keyword) end process_bin_implies_as (l_as: BIN_IMPLIES_AS) do process_binary_boolean_operator_as (l_as.left, l_as.right, ti_implies_keyword) end process_bin_or_as (l_as: BIN_OR_AS) do process_binary_boolean_operator_as (l_as.left, l_as.right, ti_or_keyword) end process_bin_or_else_as (l_as: BIN_OR_ELSE_AS) do process_binary_boolean_operator_as (l_as.left, l_as.right, ti_or_keyword) end process_bin_xor_as (l_as: BIN_XOR_AS) do process_binary_boolean_operator_as (l_as.left, l_as.right, ti_xor_keyword) end process_binary_integer_operator_as (a_left: EXPR_AS; a_right: EXPR_AS; a_operator_name: STRING) -- Process binary integer operator. local l_left_value: detachable EPA_INTEGER_VALUE l_right_value: detachable EPA_INTEGER_VALUE l_value: INTEGER do if not has_error then -- Process left. process_integer_expression (a_left) if not has_error then l_left_value := last_value.as_integer end -- Process right. if not has_error then process_integer_expression (a_right) if not has_error then l_right_value := last_value.as_integer end end if not has_error then -- Evaluate expression if a_operator_name ~ "+" then l_value := l_left_value.item + l_right_value.item elseif a_operator_name ~ "-" then l_value := l_left_value.item - l_right_value.item end create {EPA_INTEGER_VALUE} last_value.make (l_value) end end end process_bin_minus_as (l_as: BIN_MINUS_AS) do process_binary_integer_operator_as (l_as.left, l_as.right, once "-") end process_bin_plus_as (l_as: BIN_PLUS_AS) do process_binary_integer_operator_as (l_as.left, l_as.right, once "+") end process_binary_integer_relation_operator_as (a_left: EXPR_AS; a_right: EXPR_AS; a_operator_name: STRING) -- Process binary integer relation_operator. local l_left_value: detachable EPA_INTEGER_VALUE l_right_value: detachable EPA_INTEGER_VALUE l_value: BOOLEAN do if not has_error then -- Process left. process_integer_expression (a_left) if not has_error then l_left_value := last_value.as_integer end -- Process right. if not has_error then process_integer_expression (a_right) if not has_error then l_right_value := last_value.as_integer end end if not has_error then -- Evaluate expression if a_operator_name ~ ">" then l_value := l_left_value.item > l_right_value.item elseif a_operator_name ~ "<" then l_value := l_left_value.item < l_right_value.item elseif a_operator_name ~ ">=" then l_value := l_left_value.item >= l_right_value.item elseif a_operator_name ~ "<=" then l_value := l_left_value.item <= l_right_value.item end create {EPA_BOOLEAN_VALUE} last_value.make (l_value) end end end process_bin_ge_as (l_as: BIN_GE_AS) do process_binary_integer_relation_operator_as (l_as.left, l_as.right, once ">=") end process_bin_gt_as (l_as: BIN_GT_AS) do process_binary_integer_relation_operator_as (l_as.left, l_as.right, once ">") end process_bin_le_as (l_as: BIN_LE_AS) do process_binary_integer_relation_operator_as (l_as.left, l_as.right, once "<=") end process_bin_lt_as (l_as: BIN_LT_AS) do process_binary_integer_relation_operator_as (l_as.left, l_as.right, once "<") end process_binary_equality_relation_operator_as (a_left: EXPR_AS; a_right: EXPR_AS; a_operator_name: STRING) -- Process binary equality related operator (= or /=). local l_left_value: detachable EPA_EXPRESSION_VALUE l_right_value: detachable EPA_EXPRESSION_VALUE l_value: BOOLEAN do if not has_error then -- Process left. a_left.process (Current) if not has_error then l_left_value := last_value end -- Process right. if not has_error then a_right.process (Current) if not has_error then l_right_value := last_value end end if not has_error then -- Evaluate expression if a_operator_name ~ "=" then l_value := expression_value_equality_tester.test (l_left_value, l_right_value) elseif a_operator_name ~ "/=" then l_value := not expression_value_equality_tester.test (l_left_value, l_right_value) end create {EPA_BOOLEAN_VALUE} last_value.make (l_value) end end end process_bin_eq_as (l_as: BIN_EQ_AS) local l_equation: detachable EPA_EQUATION do if not has_error then l_equation := equation_by_expression_ast (l_as, False) if l_equation /= Void then last_value := l_equation.value else process_binary_equality_relation_operator_as (l_as.left, l_as.right, once "=") end end end process_bin_ne_as (l_as: BIN_NE_AS) local l_equation: detachable EPA_EQUATION do if not has_error then l_equation := equation_by_expression_ast (l_as, False) if l_equation /= Void then last_value := l_equation.value else process_binary_equality_relation_operator_as (l_as.left, l_as.right, once "/=") end end end process_un_not_as (l_as: UN_NOT_AS) local l_value: like last_value do process_unary_as (l_as) if not has_error then process_boolean_expression (l_as.expr) l_value := last_value if not has_error then if l_value.is_boolean then create {EPA_BOOLEAN_VALUE} last_value.make (not last_value.as_boolean.item) elseif l_value.is_nonsensical and then is_ternary_logic_enabled then create {EPA_NONSENSICAL_VALUE} last_value else set_has_error (True, msg_type_error_boolean_value_expected) end end end end process_bin_tilde_as (l_as: BIN_TILDE_AS) do if not has_error then process_expression (l_as) end end process_bin_not_tilde_as (l_as: BIN_NOT_TILDE_AS) do if not has_error then process_expression (l_as) end end process_tuple_as (l_as: TUPLE_AS) do process_expression (l_as) end process_un_free_as (l_as: UN_FREE_AS) local l_operator: STRING do if not has_error then l_operator := l_as.operator_name process_unary_as (l_as) if not has_error and then sequence_un_operators.has (l_operator) then if attached {MML_FINITE_SEQUENCE [EPA_EXPRESSION_VALUE]} sequence_value (last_value) as l_sequence then evalute_unary_sequence_operator (l_sequence, l_operator) else set_has_error (True, msg_sequence_value_expected (l_operator, last_value)) end else set_has_error (True, msg_free_unary_operator_not_supported (l_operator)) end end end process_bin_free_as (l_as: BIN_FREE_AS) local l_left, l_right: like sequence_value l_operator: STRING do if not has_error then l_operator := l_as.op_name.name if sequence_bin_operators.has (l_operator) then l_as.left.process (Current) if not has_error then l_left := sequence_value (last_value) if l_left /= Void then l_as.right.process (Current) if not has_error then l_right := sequence_value (last_value) if l_right /= Void then evalute_binary_sequence_operator (l_left, l_right, l_operator) else set_has_error (True, msg_sequence_value_expected (l_operator, last_value)) end end else set_has_error (True, msg_sequence_value_expected (l_operator, last_value)) end end else set_has_error (True, msg_free_binary_operator_not_supported (l_operator)) end end end feature -- Error messages msg_missing_expression (a_expr_as: AST_EIFFEL; a_old_state: BOOLEAN): STRING -- Message reporting that expressions `a_expr_as' is mising in state values. do create Result.make (64) Result.append (once "Expression missing: %"") Result.append (text_from_ast (a_expr_as)) Result.append (once "%" is missing in ") Result.append (state_phase_name (a_old_state)) end msg_type_error (a_expr_as: EXPR_AS; a_expected_type: STRING; a_actual_type: STRING): STRING -- Message reporting a type error do create Result.make (64) Result.append (once "Type error: type of expression %"") Result.append (text_from_ast (a_expr_as)) Result.append (once "should be ") Result.append (a_expected_type) Result.append (once ", but it is ") Result.append (a_actual_type) end msg_sequence_value_expected (a_operator: STRING; a_value: detachable EPA_EXPRESSION_VALUE): STRING -- Message reporting that a required value of type sequence is missing local l_value: STRING do if a_value = Void then l_value := "Void" else l_value := a_value.out end create Result.make (64) Result.append ("For sequence operator %"" + a_operator + "%", a value of type sequence is expected, but got " + l_value) end msg_free_unary_operator_not_supported (a_operator: STRING): STRING -- Message reporting that free unary operator `a_operator' is not supported. do create Result.make (64) Result.append ("Free unary operator %"") Result.append (a_operator) Result.append ("%" is not supported.") end msg_free_binary_operator_not_supported (a_operator: STRING): STRING -- Message reporting that free binary operator `a_operator' is not supported. do create Result.make (64) Result.append ("Free binary operator %"") Result.append (a_operator) Result.append ("%" is not supported.") end msg_type_error_sequence_expected: STRING = "A sequence value is expected." msg_type_error_boolean_value_expected: STRING = "A boolean value is expected." state_phase_name (a_old_state: BOOLEAN): STRING -- State phase name do create Result.make (14) if a_old_state then Result.append (once "old-state") else Result.append (once "working_state") end end end