diff options
author | Søren Sandmann Pedersen <ssp@l3000.localdomain> | 2011-03-23 09:39:11 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@l3000.localdomain> | 2011-03-23 09:39:38 -0400 |
commit | 7a5f615e0c8e191b2ed1e0de40c11b9486848c69 (patch) | |
tree | 0f3000cb7181e7a225307d13038a4ab330de8bd1 /switch.c | |
parent | 6adbade35aa76b19074f16e5d30c177e68385f0f (diff) |
Move constant-expression marking to a separate phase.
Diffstat (limited to 'switch.c')
-rw-r--r-- | switch.c | 170 |
1 files changed, 25 insertions, 145 deletions
@@ -22,140 +22,7 @@ /* Check switch statements */ static gboolean -constant_expression (ast_expression_t *expr, - value_t *value) -{ - value_t left; - value_t right; - value_t result; - - g_assert (((ast_t *)expr)->common.type == AST_EXPRESSION); - - switch (expr->common.type) - { - case AST_INT_LITERAL_EXPRESSION: - value->int32_val = expr->int_literal.value; - break; - - case AST_BOOL_LITERAL_EXPRESSION: - value->bool_val = expr->bool_literal.value; - break; - - case AST_STRING_LITERAL_EXPRESSION: - value->pointer_val = expr->string_literal.value; - break; - - case AST_NULL_EXPRESSION: - value->pointer_val = NULL; - break; - - case AST_IDENTIFIER_EXPRESSION: - /* FIXME: maybe check if it's a constant, particularly - * when we add enums - */ - return FALSE; - break; - - case AST_LAMBDA_EXPRESSION: - case AST_CALL_EXPRESSION: - case AST_STATEMENT_EXPRESSION: - case AST_NEW_EXPRESSION: - case AST_DOT_EXPRESSION: - case AST_THIS_EXPRESSION: - case AST_VOID_EXPRESSION: - case AST_INDEX_EXPRESSION: - return FALSE; - break; - - case AST_DEFINITION_EXPRESSION: - /* FIXME: It might actually be useful to allow this */ - return FALSE; - break; - - case AST_BLOCK_EXPRESSION: - if (!constant_expression (expr->block.body, value)) - return FALSE; - break; - - case AST_UNARY_EXPRESSION: - if (!constant_expression (expr->unary.expr, &result)) - return FALSE; - - evaluate_unary_operator (expr->unary.operator, - expr->unary.expr->common.type_spec, &result, - expr->common.type_spec, value); - break; - - case AST_BINARY_EXPRESSION: - if (!constant_expression (expr->binary.left, &left)) - return FALSE; - - if (!constant_expression (expr->binary.right, &right)) - return FALSE; - - evaluate_binary_operator (expr->binary.operator, - expr->binary.left->common.type_spec, &left, - expr->binary.right->common.type_spec, &right, - expr->common.type_spec, value); - break; - - case AST_TERNARY_EXPRESSION: - if (!constant_expression (expr->ternary.cond, &result)) - return FALSE; - - /* FIXME: we could require only the taken branch to be constant */ - - if (!constant_expression (expr->ternary.then_expr, &left)) - return FALSE; - - if (!constant_expression (expr->ternary.else_expr, &right)) - return FALSE; - - if (result.bool_val) - *value = left; - else - *value = right; - break; - } - - return TRUE; -} - -static gboolean -check_constant_case_expressions (ast_t *ast) -{ - GList *list; - - for (list = ast->common.children->head; list; list = list->next) - { - if (!check_constant_case_expressions (list->data)) - return FALSE; - } - - if (ast_is (ast, AST_CASE, AST_EXPRESSION_CASE)) - { - value_t value; - - if (!constant_expression (ast->case_.expression.expression, &value)) - { - return report_error ( - "Expression in case clause must be constant\n"); - } - -#if 0 - g_print ("constant expression evaluates to "); - print_value ( - &value, ast->case_.expression.expression->common.type_spec); -#endif - - ast->case_.expression.value = value; - } - - return TRUE; -} - -static gboolean -check_unique_cases (ast_t *ast) +real_switch_check (ast_t *ast) { int n_cases; ast_case_t **cases; @@ -168,13 +35,31 @@ check_unique_cases (ast_t *ast) for (list = ast->common.children->head; list; list = list->next) { - if (!check_unique_cases (list->data)) + if (!real_switch_check (list->data)) return FALSE; } return TRUE; } + n_cases = array_length ((gpointer *)ast->statement.switch_.cases); + cases = ast->statement.switch_.cases; + + /* Check that all case expressions are constant */ + for (i = 0; i < n_cases; ++i) + { + const ast_case_t *case_ = cases[i]; + + if (case_->common.type == AST_EXPRESSION_CASE) + { + if (!case_->expression.expr->common.constant) + { + return report_error ( + "Expression in case clause must be constant\n"); + } + } + } + /* This algorithm is O(n^2) in the number of cases, but it's noise * on the profile even with thousands of cases. * @@ -184,8 +69,6 @@ check_unique_cases (ast_t *ast) * robust to rely on the EQUAL operator, which is what the interpreter * is using anyway. */ - n_cases = array_length ((gpointer *)ast->statement.switch_.cases); - cases = ast->statement.switch_.cases; bool = ast_type_spec_new (AST_BOOL_TYPE); for (i = 0; i < n_cases; ++i) @@ -209,11 +92,11 @@ check_unique_cases (ast_t *ast) const value_t *value_b; value_t result; - type_a = case_a->expression.expression->common.type_spec; - value_a = &case_a->expression.value; + type_a = case_a->expression.expr->common.type_spec; + value_a = &case_a->expression.expr->common.constant_value; - type_b = case_b->expression.expression->common.type_spec; - value_b = &case_b->expression.value; + type_b = case_b->expression.expr->common.type_spec; + value_b = &case_b->expression.expr->common.constant_value; evaluate_binary_operator (AST_EQUAL, type_a, value_a, @@ -232,10 +115,7 @@ check_unique_cases (ast_t *ast) gboolean switch_check (ast_program_t *program) { - if (!check_constant_case_expressions ((ast_t *)program)) - return FALSE; - - if (!check_unique_cases ((ast_t *)program)) + if (!real_switch_check ((ast_t *)program)) return FALSE; return TRUE; |