/* Oort * Copyright 2007, Soren Sandmann Pedersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ast.h" #include /* Check switch statements */ gboolean switch_check (ast_t *ast) { int n_cases; ast_case_t **cases; ast_type_spec_t *bool; int i, j; if (!ast_is (ast, AST_STATEMENT, AST_SWITCH_STATEMENT)) { GList *list; for (list = ast->common.children->head; list; list = list->next) { if (!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. * * We could do it in O(n log n) by sorting, but the problem is, how do * you assign a total order to the values while making sure things * like "2.0" and "2" compare equal? It is just much simpler and more * robust to rely on the EQUAL operator, which is what the interpreter * is using anyway. * * With 200000 cases in a single switch, this function completely * dominates the profile, so maybe do something about it some day. */ bool = ast_type_spec_new (AST_BOOL_TYPE); for (i = 0; i < n_cases; ++i) { for (j = i + 1; j < n_cases; ++j) { const ast_case_t *case_a = cases[i]; const ast_case_t *case_b = cases[j]; if (case_a->common.type == AST_DEFAULT_CASE && case_b->common.type == AST_DEFAULT_CASE) { return report_error ("duplicate default case\n"); } else if (case_a->common.type == AST_EXPRESSION_CASE && case_b->common.type == AST_EXPRESSION_CASE) { const ast_type_spec_t *type_a; const ast_type_spec_t *type_b; const value_t *value_a; const value_t *value_b; value_t result; type_a = case_a->expression.expr->common.type_spec; value_a = &case_a->expression.expr->common.constant_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, type_b, value_b, bool, &result); if (result.bool_val == TRUE) return report_error ("duplicate case value\n"); } } } return TRUE; }