/* %Z%%M% %I% %E% */ /* * Copyright (c) 1990-2006 by Wayne C. Gramlich. * All rights reserved. */ /* * This file contains code for converting from expression tress to call trees: */ #ifndef CALL_DEFS_H #include "call_defs.h" #endif #ifndef ERROR_EXPORTS_H #include "error_exports.h" #endif #ifndef EXP_DEFS_H #include "exp_defs.h" #endif #ifndef HEAP_EXPORTS_H #include "heap_exports.h" #endif #ifndef LIBC_EXPORTS_H #include "libc_exports.h" #endif #ifndef LINT_H #include "lint.h" #endif #ifndef MSG_EXPORTS_H #include "msg_exports.h" #endif #ifndef OBJECT_EXPORTS_H #include "object_exports.h" #endif #ifndef ROUTINE_DEFS_H #include "routine_defs.h" #endif #ifndef STATEMENT_DEFS_H #include "statement_defs.h" #endif #ifndef TABLE_EXPORTS_H #include "table_exports.h" #endif #ifndef TYPE_DEFS_H #include "type_defs.h" #endif #ifndef UNIX_ASSERT_H #include "unix_assert.h" #endif #ifndef VAR_DEFS_H #include "var_defs.h" #endif #ifndef VECTOR_DEFS_H #include "vector_defs.h" #endif LOCAL void statement_exp_convert(Statement, Exp, Convert); LOCAL void statement_convert(Statement, Convert); LOCAL void statement_logical_convert(Statement, Convert); /* * statement_convert(statement, convert) * This routine will type check "statement" using "covnert". */ LOCAL void statement_convert( Statement statement, Convert convert) { switch (statement->kind) { case Statement_kind_assert: statement_logical_convert(statement, convert); break; case Statement_kind_break: break; case Statement_kind_continue: break; case Statement_kind_eval: statement->calls = call_assign_convert(convert, statement->value.exp); break; case Statement_kind_extract: { Exp exp; Statement_extract extract; Object_table object_table; Statement_tag tag; Str tag_name; Vec(Str) tag_names; Vec(Statement_tag) tags; Type_def type_def; Type_ref type_ref; Type_refs type_refs; Type_variant type_variant; Var var; statement->calls = vec_create(Call, convert->heap); extract = statement->value.extract; exp = extract->exp; exp->call = call_exp_convert(convert, exp, convert->type_refs_empty, statement->calls); /* Make sure that the type definition exists and is correct: */ type_refs = exp->type_refs; assert(type_refs != (Type_refs)0); assert(type_refs_size(type_refs) == 1); type_ref = type_refs_fetch(type_refs, 0); type_def = type_def_table_lookup(convert->type_def_table, type_ref->name); if (type_def == (Type_def)0) { msg_out(convert->msg, statement->position, "Type `%s' is not defined!", type_ref->name); } else { type_def_structure_needed(type_def); if (type_def->kind != Type_kind_variant) { msg_out(convert->msg, statement->position, "extract statement needs a variant type; " "type `%s' is not a variant type!", type_ref->name); } /* Verify that tag type is an enumeration type: */ type_variant = type_def->value.variant; type_ref = type_variant->tag_field->type_ref; type_def = type_def_table_lookup(convert->type_def_table, type_ref->name); if (type_def == (Type_def)0) { msg_out(convert->msg, statement->position, "Type `%s' is not defined!", type_ref->name); } else { type_def_structure_needed(type_def); if (type_def->kind != Type_kind_enumeration) { msg_out(convert->msg, statement->position, "extract statement needs an " "enumeration type; type `%s' " "is not a enumeration type!", type_ref->name); } } } object_table = convert->object_table; tags = extract->tags; VEC_LOOP(Statement_tag, tags, tag) { if (tag->var_type_ref != (Type_ref)0) { var = table_lookup(Str, Var, convert->var_table, tag->var_name); if (var == (Var)0) { var = heap_allocate(convert->heap, Var); var->comment = (Str)0; var->name = tag->var_name; var->position = tag->position; var->type_ref = tag->var_type_ref; (void)table_insert(Str, Var, convert->var_table, var->name, var); vec_append(Var, convert->routine->vars, var); } else { if (!type_ref_equal(var->type_ref, tag->var_type_ref)) { msg_out(convert->msg, tag->position, "%s is of type %r not %r", var->name, var->type_ref, tag->var_type_ref); } } } tag_names = tag->tag_names; VEC_LOOP(Str, tag_names, tag_name) { (void)object_ref_lookup(object_table, tag_name, type_def->type_ref); } statement_list_convert(tag->statements, convert); } break; } case Statement_kind_if: { Call call; Vec(Call) calls; Statement_cond cond; Vec(Statement_cond) conds; conds = statement->value.xif; VEC_LOOP(Statement_cond, conds, cond) { if (cond->exp != (Exp)0) { calls = vec_create(Call, convert->heap); call = call_exp_convert(convert, cond->exp, convert->type_refs_logical, calls); cond->exp->call = call; cond->calls = calls; } statement_list_convert(cond->statements, convert); } break; } case Statement_kind_loop: statement_list_convert(statement->value.loop->statements, convert); break; case Statement_kind_initialize: { Vec(Call) calls; Type_ref exp_type_ref; Heap heap; Statement_initialize initialize; Str name; Var var; Type_ref type_ref; Type_refs type_refs; initialize = statement->value.initialize; heap = convert->heap; name = initialize->var_name; type_ref = initialize->var_type_ref; var = table_lookup(Str, Var, convert->var_table, name); if (var == (Var)0) { if (type_ref == (Type_ref)0) { msg_out(convert->msg, statement->position, "%s is an undefined variable", name); } else { var = heap_allocate(heap, Var); var->comment = (Str)0; var->name = name; var->position = statement->position; var->type_ref = type_ref; assert(table_insert(Str, Var, convert->var_table, name, var) == 0); vec_append(Var, convert->routine->vars, var); } } else if ((type_ref != (Type_ref)0) && (!type_ref_equal(type_ref, var->type_ref))) { msg_out(convert->msg, statement->position, "Variable %s has type of %r, not %r", name, var->type_ref, type_ref); } type_ref = var->type_ref; calls = vec_create(Call, heap); if (initialize->exp != (Exp)0) { initialize->exp->call = call_exp_convert(convert, initialize->exp, convert->type_refs_empty, calls); type_refs = initialize->exp->call->type_refs; if (type_refs_size(type_refs) == 1) { exp_type_ref = type_refs_fetch(type_refs, 0); if (!type_ref_equal(type_ref, exp_type_ref)) { msg_out(convert->msg, statement->position, "%s has type of %r, not %r", name, exp_type_ref, type_ref); } } else { msg_out(convert->msg, statement->position, "Expression should return " "only one value"); } } statement_list_convert(initialize->statements, convert); statement->calls = calls; break; } case Statement_kind_none: break; case Statement_kind_return: { Vec(Call) calls; Exp exp; Type_ref exp_type_ref; Type_refs exp_type_refs; Vec(Exp) exps; Heap heap; int index; Type_refs return_type_refs; Type_refs returns; int size; Type_ref type_ref; Type_tables type_tables; Type_refs type_refs; heap = convert->heap; type_tables = convert->type_tables; calls = vec_create(Call, heap); exps = statement->value.exps; returns = convert->routine->returns; size = vec_size(Exp, exps); if (size != type_refs_size(returns)) { msg_out(convert->msg, statement->position, "Routine is supposed to return %d values, not %d", type_refs_size(returns), size); break; } return_type_refs = type_refs_empty_create(type_tables); for (index = 0; index < size; index++) { exp = vec_fetch(Exp, exps, index); type_ref = type_refs_fetch(returns, index); return_type_refs = type_refs_append(return_type_refs, type_ref, type_tables); type_refs = type_ref->type_refs; exp->call = call_exp_convert(convert, exp, type_refs, calls); exp_type_refs = exp->type_refs; if (type_refs_size(exp_type_refs) == 0) { msg_out(convert->msg, statement->position, "return statement returning expression" " with no value instead type %s", type_ref->name); } else { exp_type_ref = type_refs_fetch(exp_type_refs, 0); if (!type_ref_equal(type_ref, exp_type_ref)) { msg_out(convert->msg, statement->position, "return statement returning type %s" " instead of type %s", exp_type_ref->name, type_ref->name); } } } if (type_refs_size(return_type_refs) > 1) { type_refs_multiple_needed(return_type_refs, convert->type_tables); } statement->calls = calls; break; } case Statement_kind_switch: { Statement_case xcase; Vec(Statement_case) cases; Vec(Call) calls; Exp exp; Vec(Exp) exps; Heap heap; Statement_switch xswitch; Type_def type_def; Type_ref type_ref; Type_refs type_refs; heap = convert->heap; xswitch = statement->value.xswitch; exp = xswitch->exp; statement_exp_convert(statement, exp, convert); /* Make sure that the type definition exists and is correct: */ type_refs = exp->type_refs; assert(type_refs != (Type_refs)0); if (type_refs_size(type_refs) != 1) { msg_out(convert->msg, statement->position, "Switch expression returns %d types", type_refs_size(type_refs)); break; } type_ref = type_refs_fetch(type_refs, 0); type_def = type_def_table_lookup(convert->type_def_table, type_ref->name); if (type_def == (Type_def)0) { msg_out(convert->msg, statement->position, "Type `%s' is not defined!", type_ref->name); break; } else { type_def_structure_needed(type_def); } if (type_def->kind != Type_kind_enumeration) { msg_out(convert->msg, statement->position, "Switch statement needs a enumeration type; " "type `%s' is not a enumeration type!", type_ref->name); } calls = vec_create(Call, heap); cases = xswitch->cases; VEC_LOOP(Statement_case, cases, xcase) { exps = xcase->exps; VEC_LOOP(Exp, exps, exp) { exp->call = call_exp_constant(convert, exp, type_refs, calls); } statement_list_convert(xcase->statements, convert); } assert(vec_empty(Call, calls)); statement->calls = calls; break; } case Statement_kind_until: case Statement_kind_while: statement_logical_convert(statement, convert); break; case Statement_kind_yield: { Vec(Call) calls; Exp exp; Vec(Exp) exps; Heap heap; int index; int size; Type_ref type_ref; Type_refs type_refs; Type_refs yields; heap = convert->heap; calls = vec_create(Call, heap); exps = statement->value.exps; yields = convert->routine->yields; size = vec_size(Exp, exps); assert(size == type_refs_size(yields)); for (index = 0; index < size; index++) { exp = vec_fetch(Exp, exps, index); type_ref = type_refs_fetch(yields, index); type_refs = type_ref->type_refs; exp->call = call_exp_convert(convert, exp, type_refs, calls); } statement->calls = calls; break; } default: error_abort("Bad statement"); } } /* * statement_exp_convert(statement, exp, convert) * This routine will extract the call tree from "exp" and store it in * "exp"->call. Any preceeding call operations are stored in * "statement"->calls. */ void statement_exp_convert( Statement statement, Exp exp, Convert convert) { Call call; Vec(Call) calls; calls = vec_create(Call, convert->heap); call = call_exp_convert(convert, exp, convert->type_refs_empty, calls); exp->call = call; statement->calls = calls; } /* * statement_list_convert(statements, convert) * This routine will convert all of the expressions in "statements" * into call trees. */ void statement_list_convert( Vec(Statement) statements, Convert convert) { Statement statement; VEC_LOOP(Statement, statements, statement) { statement_convert(statement, convert); } } /* * statement_logical_convert(statement) * This routine will convert the expression assoicated with "statement" * into an call tree of type logical. */ LOCAL void statement_logical_convert( Statement statement, Convert convert) { Call call; Vec(Call) calls; Exp exp; exp = statement->value.exp; calls = vec_create(Call, convert->heap); call = call_exp_convert(convert, exp, convert->type_refs_logical, calls); exp->call = call; statement->calls = calls; }