/*
 * Copyright (c) 1995, 1996, 1998, 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 *
 * This file is part of Flick, the Flexible IDL Compiler Kit.
 *
 * Flick 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.
 *
 * Flick 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 Flick; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
 */

#include <assert.h>
#include <mom/compiler.h>
#include <mom/c/libcast.h>

#define CHECK_OPT_STRING(str) assert(str != 0);
#define CHECK_STRING(str) assert(str != 0); assert(strlen(str) > 0);

void cast_check_scoped_name(cast_scoped_name *name)
{
	int i;
	
	for (i = 0; i < (signed int)name->cast_scoped_name_len; i++) {
		assert(name->cast_scoped_name_val[i].name);
		cast_check_template_arg_array(&name->cast_scoped_name_val[i].
					      args);
	}
}

void cast_check_opt_scoped_name(cast_scoped_name *name)
{
	if (name->cast_scoped_name_len) {
		cast_check_scoped_name(name);
	}
}

void cast_check_primitive_type(cast_primitive_kind kind, cast_primitive_modifier mod)
{
	if (mod & CAST_MOD_SIGNED) assert(!(mod & CAST_MOD_UNSIGNED));
	if (mod & CAST_MOD_SHORT) assert(!(mod & CAST_MOD_LONG));
	if (mod & CAST_MOD_LONG_LONG) assert(!(mod & CAST_MOD_LONG));
	switch (kind)
	{
		case CAST_PRIM_BOOL:
			assert(!mod);
			break;
		case CAST_PRIM_CHAR:
			assert(!(mod & ~(CAST_MOD_SIGNED | CAST_MOD_UNSIGNED)));
			break;
		case CAST_PRIM_INT:
			break;
		case CAST_PRIM_FLOAT:
			assert(!mod);
			break;
		case CAST_PRIM_DOUBLE:
			assert(!(mod & ~(CAST_MOD_LONG | CAST_MOD_LONG_LONG)));
			break;
		default:
			panic("cast_check_lit_prim: unknown cast_primitive_kind %d", kind);
	}
}

void cast_check_enum(cast_enum_type *et)
{
	unsigned int i;
	
	cast_check_opt_scoped_name(&et->name);
	assert(et->slots.slots_val);
	
	for(i = 0; i < et->slots.slots_len; i++) {
		CHECK_STRING(et->slots.slots_val[i].name);
		cast_check_expr(et->slots.slots_val[i].val);
	}
}

void cast_check_aggregate_type(cast_aggregate_type *atype)
{
	unsigned int i;
	
	cast_check_scoped_name(&atype->name);
	
	cast_check(&atype->scope);
	
	for (i = 0; i < atype->parents.parents_len; i++ ) {
		cast_check_scoped_name(&atype->parents.parents_val[i].name);
	}
}

void cast_check_template_param(cast_template_param *param)
{
	int i;
	
	CHECK_STRING(param->name);
	if (param->default_value)
		cast_check_template_arg(param->default_value);
	switch(param->u.kind) {
	case CAST_TEMP_PARAM_TYPE:
		cast_check_type(param->u.cast_template_param_u_u.type_param);
		break;
	case CAST_TEMP_PARAM_CLASS:
		break;
	case CAST_TEMP_PARAM_TYPENAME:
		break;
	case CAST_TEMP_PARAM_TEMPLATE:
		for (i = 0;
		     i < (signed int)param->u.cast_template_param_u_u.
			 params.params_len;
		     i++) {
			cast_check_template_param(
				param->u.cast_template_param_u_u.
				params.params_val[i]);
		}
		break;
	default:
		panic("cast_check_template_param param kind %d is unknown",
		      param->u.kind);
	}
}

void cast_check_template_arg(cast_template_arg arg)
{
	assert(arg);
	switch(arg->kind) {
	case CAST_TEMP_ARG_NAME:
		cast_check_scoped_name(&arg->cast_template_arg_u_u.name);
		break;
	case CAST_TEMP_ARG_TYPE:
		cast_check_type(arg->cast_template_arg_u_u.type);
		break;
	case CAST_TEMP_ARG_EXPR:
		cast_check_expr(arg->cast_template_arg_u_u.expr);
		break;
	}
}

void cast_check_template_arg_array(cast_template_arg_array *array)
{
	int i;

	for (i = 0; i < (signed int)array->cast_template_arg_array_len; i++) {
		cast_check_template_arg(array->cast_template_arg_array_val[i]);
	}
}

void cast_check_type_array(cast_type_array *array)
{
	int i;

	for (i = 0; i < (signed int)array->cast_type_array_len; i++) {
		cast_check_type(array->cast_type_array_val[i]);
	}
}

void cast_check_expr_array(cast_expr_array *array)
{
	int i;

	for (i = 0; i < (signed int)array->cast_expr_array_len; i++) {
		cast_check_expr(array->cast_expr_array_val[i]);
	}
}

void cast_check_init_array(cast_init_array *array)
{
	int i;

	for (i = 0; i < (signed int)array->cast_init_array_len; i++) {
		cast_check_init(array->cast_init_array_val[i]);
	}
}

void cast_check_func_type(cast_func_type *ftype)
{
	int i;

	for (i = 0; i < (signed int)ftype->params.params_len; i++)
	{
		assert(ftype->params.params_val);
		CHECK_STRING(ftype->params.params_val[i].name);
		cast_check_type(ftype->params.params_val[i].type);
		if (ftype->params.params_val[i].default_value)
			cast_check_init(ftype->params.params_val[i].
					default_value);
	}

	cast_check_type(ftype->return_type);
	cast_check_type_array(&ftype->exception_types);
	cast_check_expr_array(&ftype->initializers);
}

void cast_check_type(cast_type type)
{
	assert(type);
	switch (type->kind)
	{
		case CAST_TYPE_NAME:
		case CAST_TYPE_STRUCT_NAME:
		case CAST_TYPE_UNION_NAME:
		case CAST_TYPE_ENUM_NAME:
		case CAST_TYPE_CLASS_NAME:
		case CAST_TYPE_TYPENAME:
			assert(type->cast_type_u_u.name.cast_scoped_name_val != 0);
			break;
		case CAST_TYPE_PRIMITIVE:
			cast_check_primitive_type(type->cast_type_u_u.primitive_type.kind,
						  type->cast_type_u_u.primitive_type.mod);
			break;
		case CAST_TYPE_AGGREGATE:
			cast_check_aggregate_type(&type->cast_type_u_u.agg_type);
			break;
		case CAST_TYPE_POINTER:
			cast_check_type(type->cast_type_u_u.pointer_type.target);
			break;
		case CAST_TYPE_REFERENCE:
			cast_check_type(type->cast_type_u_u.reference_type.target);
			break;
		case CAST_TYPE_ARRAY:
			cast_check_expr(type->cast_type_u_u.array_type.length);
			cast_check_type(type->cast_type_u_u.array_type.element_type);
			break;
		case CAST_TYPE_FUNCTION:
			cast_check_func_type(&type->cast_type_u_u.func_type);
			break;
		case CAST_TYPE_VOID:
			break;
		case CAST_TYPE_QUALIFIED:
			cast_check_type(type->cast_type_u_u.qualified.actual);
			break;
		case CAST_TYPE_ENUM:
			cast_check_enum(&type->cast_type_u_u.enum_type);
			break;
		case CAST_TYPE_NULL:
			break;
		case CAST_TYPE_TEMPLATE: {
			struct cast_template_type *td;
			struct cast_template_param *tp;
			int i;
			
			td = &type->cast_type_u_u.template_type;
			cast_check_type(td->def);
			for (i = 0;
			     i < (signed int)td->params.params_len;
			     i++) {
				tp = &td->params.params_val[i];
				cast_check_template_param(tp);
			}
			break;
		}
		default:
			panic("cast_check_type: unknown cast_type_kind %d", type->kind);
	}
}

void cast_check_expr(cast_expr expr)
{
	assert(expr);
	switch (expr->kind)
	{
		case CAST_EXPR_CONST_NAME:
		case CAST_EXPR_NAME:
			cast_check_scoped_name(&expr->cast_expr_u_u.name);
			break;
		case CAST_EXPR_LIT_PRIM:
			cast_check_primitive_type(expr->cast_expr_u_u.lit_prim.u.kind,
						  expr->cast_expr_u_u.lit_prim.mod);
			break;
		case CAST_EXPR_LIT_STRING:
			CHECK_OPT_STRING(expr->cast_expr_u_u.lit_string);
			break;
		case CAST_EXPR_CALL:
		{
			cast_expr_call *c = &expr->cast_expr_u_u.call;

			cast_check_expr(c->func);
			cast_check_expr_array(&c->params);
			break;
		}
		case CAST_EXPR_SEL:
			cast_check_expr(expr->cast_expr_u_u.sel.var);
			cast_check_scoped_name(&expr->cast_expr_u_u.
					       sel.member);
			break;
		case CAST_EXPR_UNARY:
			assert(expr->cast_expr_u_u.unary.op);
			cast_check_expr(expr->cast_expr_u_u.unary.expr);
			break;
		case CAST_EXPR_CONST_CAST:
		case CAST_EXPR_DYNAMIC_CAST:
		case CAST_EXPR_REINTERPRET_CAST:
		case CAST_EXPR_STATIC_CAST:
		case CAST_EXPR_CAST:
			cast_check_expr(expr->cast_expr_u_u.cast.expr);
			cast_check_type(expr->cast_expr_u_u.cast.type);
			break;
		case CAST_EXPR_SIZEOF_EXPR:
			cast_check_expr(expr->cast_expr_u_u.sizeof_expr);
			break;
		case CAST_EXPR_SIZEOF_TYPE:
			cast_check_type(expr->cast_expr_u_u.sizeof_type);
			break;
		case CAST_EXPR_BINARY:
		case CAST_EXPR_OP_ASSIGN:
			assert(expr->cast_expr_u_u.binary.op);
			cast_check_expr(expr->cast_expr_u_u.binary.expr[0]);
			cast_check_expr(expr->cast_expr_u_u.binary.expr[1]);
			break;
		case CAST_EXPR_COND:
			cast_check_expr(expr->cast_expr_u_u.cond.test);
			cast_check_expr(expr->cast_expr_u_u.cond.true_expr);
			cast_check_expr(expr->cast_expr_u_u.cond.false_expr);
			break;
		case CAST_EXPR_OP_NEW:
			if (expr->cast_expr_u_u.op_new.placement)
				cast_check_expr(expr->cast_expr_u_u.
						op_new.placement);
			cast_check_type(expr->cast_expr_u_u.op_new.type);
			if (expr->cast_expr_u_u.op_new.init)
				cast_check_init(expr->cast_expr_u_u.
						op_new.init);
			break;
		case CAST_EXPR_OP_DELETE:
			cast_check_expr(expr->cast_expr_u_u.op_delete.expr);
			break;
		case CAST_EXPR_TYPEID_EXPR:
			cast_check_expr(expr->cast_expr_u_u.typeid_expr);
			break;
		case CAST_EXPR_TYPEID_TYPE:
			cast_check_type(expr->cast_expr_u_u.typeid_type);
			break;
		case CAST_EXPR_TYPE:
			cast_check_type(expr->cast_expr_u_u.type_expr);
			break;
		default:
			panic("cast_check_expr: unknown cast_expr_kind %d", expr->kind);
	}
}

void cast_check_block(cast_block *block)
{
	int i;

	cast_check(&block->scope);

	for (i = 0; i < (signed int)block->stmts.stmts_len; i++)
	{
		assert(block->stmts.stmts_val);
		cast_check_stmt(block->stmts.stmts_val[i]);
	}
}

void cast_check_stmt(cast_stmt stmt)
{
	assert(stmt);
	switch (stmt->kind)
	{
		case CAST_STMT_EXPR:
			cast_check_expr(stmt->cast_stmt_u_u.expr);
			break;
		case CAST_STMT_BLOCK:
			cast_check_block(&stmt->cast_stmt_u_u.block);
			break;
		case CAST_STMT_IF:
			cast_check_expr(stmt->cast_stmt_u_u.s_if.test);
			cast_check_stmt(stmt->cast_stmt_u_u.s_if.true_stmt);
			cast_check_stmt(stmt->cast_stmt_u_u.s_if.false_stmt);
			break;
		case CAST_STMT_WHILE:
			cast_check_expr(stmt->cast_stmt_u_u.s_while.test);
			cast_check_stmt(stmt->cast_stmt_u_u.s_while.stmt);
			break;
		case CAST_STMT_DO_WHILE:
			cast_check_expr(stmt->cast_stmt_u_u.s_do_while.test);
			cast_check_stmt(stmt->cast_stmt_u_u.s_do_while.stmt);
			break;
		case CAST_STMT_FOR:
			if (stmt->cast_stmt_u_u.s_for.init)
				cast_check_expr(stmt->cast_stmt_u_u.s_for.init);
			if (stmt->cast_stmt_u_u.s_for.test)
				cast_check_expr(stmt->cast_stmt_u_u.s_for.test);
			if (stmt->cast_stmt_u_u.s_for.iter)
				cast_check_expr(stmt->cast_stmt_u_u.s_for.iter);
			cast_check_stmt(stmt->cast_stmt_u_u.s_for.stmt);
			break;
		case CAST_STMT_SWITCH:
			cast_check_expr(stmt->cast_stmt_u_u.s_switch.test);
			cast_check_stmt(stmt->cast_stmt_u_u.s_switch.stmt);
			break;
		case CAST_STMT_BREAK:
			break;
		case CAST_STMT_CONTINUE:
			break;
		case CAST_STMT_GOTO:
			CHECK_STRING(stmt->cast_stmt_u_u.goto_label);
			break;
		case CAST_STMT_LABEL:
			CHECK_STRING(stmt->cast_stmt_u_u.s_label.label);
			cast_check_stmt(stmt->cast_stmt_u_u.s_label.stmt);
			break;
		case CAST_STMT_CASE:
			cast_check_expr(stmt->cast_stmt_u_u.s_case.label);
			cast_check_stmt(stmt->cast_stmt_u_u.s_case.stmt);
			break;
		case CAST_STMT_DEFAULT:
			cast_check_stmt(stmt->cast_stmt_u_u.default_stmt);
			break;
		case CAST_STMT_RETURN:
			cast_check_expr(stmt->cast_stmt_u_u.return_expr);
			break;
		case CAST_STMT_NULL:
		case CAST_STMT_EMPTY:
			break;
		case CAST_STMT_TRY: {
			struct cast_try *ct;
			int i;

			ct = &stmt->cast_stmt_u_u.try_block;
			cast_check_stmt(ct->block);
			for (i = 0;
			     i < (signed int)ct->handlers.handlers_len;
			     i++) {
				CHECK_STRING(ct->handlers.handlers_val[i].
					     name);
				cast_check_type(ct->handlers.handlers_val[i].
						type);
				cast_check_stmt(ct->handlers.handlers_val[i].
						block);
			}
			break;
		}
		case CAST_STMT_THROW: {
			if (stmt->cast_stmt_u_u.throw_expr)
				cast_check_expr(stmt->cast_stmt_u_u.
						throw_expr);
			break;
		}
		case CAST_STMT_DECL: {
			cast_check(&stmt->cast_stmt_u_u.decl);
			break;
		}
		default:
			panic("cast_check_stmt: unknown cast_stmt_kind %d", stmt->kind);
	}
}

void cast_check_init(cast_init init)
{
	assert(init);
	switch (init->kind)
	{
		case CAST_INIT_EXPR:
		{
			cast_check_expr(init->cast_init_u_u.expr);
			break;
		}
		case CAST_INIT_AGGREGATE:
		{
			cast_check_init_array(&init->cast_init_u_u.subs);
			break;
		}
		case CAST_INIT_CONSTRUCT:
		{
			cast_check_expr_array(&init->cast_init_u_u.exprs);
			break;
		}
		default:
			panic("cast_check_init: unknown cast_init_kind %d", init->kind);
	}
}

void cast_check_def(cast_def *def)
{
	assert(def);
	cast_check_opt_scoped_name(&def->name);
	switch (def->u.kind)
	{
		case CAST_TYPEDEF:
			cast_check_type(def->u.cast_def_u_u.typedef_type);
			break;
		case CAST_TYPE:
			cast_check_type(def->u.cast_def_u_u.type);
			break;
		case CAST_FUNC_DECL:
			cast_check_func_type(&def->u.cast_def_u_u.func_type);
			break;
		case CAST_FUNC_DEF:
			cast_check_func_type(&def->u.cast_def_u_u.func_def.type);
			cast_check_block(&def->u.cast_def_u_u.func_def.block);
			break;
		case CAST_VAR_DECL:
			cast_check_type(def->u.cast_def_u_u.var_type);
			break;
		case CAST_VAR_DEF:
			cast_check_type(def->u.cast_def_u_u.var_def.type);
			if (def->u.cast_def_u_u.var_def.init)
				cast_check_init(def->u.cast_def_u_u.var_def.init);
			break;
		case CAST_DEFINE:
			cast_check_expr(def->u.cast_def_u_u.define_as);
			break;
		case CAST_INCLUDE:
			CHECK_STRING(def->u.cast_def_u_u.include.filename);
			break;
		case CAST_DIRECT_CODE:
			CHECK_STRING(def->u.cast_def_u_u.direct.code_string);
			break;
		case CAST_NAMESPACE:
			cast_check_scoped_name(&def->name);
			cast_check(def->u.cast_def_u_u.new_namespace);
			break;
		case CAST_LINKAGE:
			cast_check_scoped_name(&def->name);
			cast_check(def->u.cast_def_u_u.linkage);
			break;
		case CAST_USING:
			switch(def->u.cast_def_u_u.using_scope) {
			case CAST_USING_NAME:
			case CAST_USING_TYPENAME:
			case CAST_USING_NAMESPACE:
				break;
			default:
				panic("cast_check_def: unknown "
				      "cast_using_kind %d",
				      def->u.cast_def_u_u.using_scope);
			}
			break;
		case CAST_FRIEND:
			cast_check_type(def->u.cast_def_u_u.friend_decl);
			break;
		default:
			panic("cast_check_def: unknown cast_def_kind %d", def->u.kind);
	}
}

void cast_check(cast_scope *scope)
{
	int i;

	for (i = 0; i < (signed int)scope->cast_scope_len; i++)
	{
		assert(scope->cast_scope_val);
		cast_check_def(&scope->cast_scope_val[i]);
	}
}



syntax highlighted by Code2HTML, v. 0.9.1