/* %Z%%M% %I% %E% */

/*
 * Copyright (c) 1992, 1993, 1995, 2000 by Wayne C. Gramlich.
 * All rights reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * for any purpose is hereby granted without fee provided that the above
 * copyright notice and this permission are retained.  The author makes
 * no representations about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 */

/*
 * This file contains code for converting between expression tree format
 * to call tree format:
 */

#ifndef CALL_DEFS_H
#include "call_defs.h"
#endif

#ifndef FLAGS_DEFS_H
#include "flags_defs.h"
#endif

#ifndef GENERATE_DEFS_H
#include "generate_defs.h"
#endif

#ifndef HEAP_EXPORTS_H
#include "heap_exports.h"
#endif

#ifndef LINT_H
#include "lint.h"
#endif

#ifndef NEED_EXPORTS_H
#include "need_exports.h"
#endif

#ifndef ROUTINE_DEFS_H
#include "routine_defs.h"
#endif

#ifndef STR_EXPORTS_H
#include "str_exports.h"
#endif

#ifndef STRVEC_EXPORTS_H
#include "strvec_exports.h"
#endif

#ifndef TABLE_EXPORTS_H
#include "table_exports.h"
#endif

#ifndef TYPE_DEFS_H
#include "type_defs.h"
#endif

#ifndef VECTOR_DEFS_H
#include "vector_defs.h"
#endif

#ifndef UNIX_ASSERT_H
#include "unix_assert.h"
#endif

#ifndef UNIX_CTYPE_H
#include "unix_ctype.h"
#endif

#ifndef UNIX_UNISTD_H
#include "unix_unistd.h"
#endif

#ifdef OLD

LOCAL void	generate_def_new_convert(Type_def, Routine, Convert);
LOCAL void	type_def_access_convert(Type_def, Convert);
LOCAL void	type_def_address_get_convert(Type_def, Routine, Convert);
LOCAL void	type_def_copy_convert(Type_def, Routine, Convert);
LOCAL void	type_def_equal_convert(Type_def, Routine, Convert);
LOCAL void	type_def_erase_convert(Type_def, Routine, Convert);
LOCAL void	type_def_hash_convert(Type_def, Routine, Convert);
LOCAL void	type_def_input_convert(Type_def, Routine, Convert);
LOCAL void	type_def_output_convert(Type_def, Routine, Convert);
LOCAL void	type_def_print_convert(Type_def, Routine, Convert);
LOCAL void	type_def_struct_convert(Type_def, Routine, Convert);

/*
 * type_def_access_convert(routine, convert)
 */
LOCAL void
type_def_access_convert(
	Type_def	type_def,
	Convert		convert)
{
	Need_table	need_table;
	Str		type_name;

	assert_fail();
	if (type_ref_is_paramterized(type_def->type_ref)) {
		return;
	}
	type_name = type_def->name;
	need_table = convert->routine->need_table;
	switch (type_def->kind) {
	    case Type_kind_record:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Str		name;
		Str		var_name;

		fields = type_def->value.record->fields;
		VEC_LOOP(Type_field, fields, field) {
			/* Generate the get routine: */
			field_name = field->name;
			field_type = field->type_ref->name;
		}
		break;
	      }
	    case Type_kind_variant:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Type_field	tag_field;
		Str		tag_field_name;
		Str		tag_field_type;
		Type_variant	variant;

		variant = type_def->value.variant;

		/* Generate tag field access routine: */
		tag_field = variant->tag_field;
		tag_field_name = tag_field->name;
		tag_field_type = tag_field->type_ref->name;

		fields = variant->fields;
		VEC_LOOP(Type_field, fields, field) {
			/* Generate the set routine: */
			field_name = field->name;
			field_type = field->type_ref->name;
		}
		break;
	      }
	}
}

/*
 * type_def_copy_convert(routine, convert)
 */
void
type_def_copy_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Str		type_name;

	assert_fail();
	switch (type_def->kind) {
	    case Type_kind_enumeration:
		break;
	    case Type_kind_record:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;

#ifdef BROKEN
		fields = type_def->value.record->fields;
		size = vec_size(Type_field, fields);
		for (index = 0; index < size; index++) {
			field = vec_fetch(Type_field, fields, index);
			if (!type_ref_is_parameterized(field->type_ref)) {
				continue;
			}
			type_proto = type_proto_create(Type_proto_procedure,
				type_refs_empty,
				parameter->type_refs,
				type_refs_empty,
				type_refs_empty,
				type_signals_empty_create(type_tables),
				type_needs_empty_create(type_tables),
				0,
				type_tables);
			need_table_routine_insert(need_table, "erase",
						  parameter, type_proto,
						  parameters);
		}
#endif /* BROKEN */
		break;
	      }
	    case Type_kind_variant:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Type_field	tag_field;
		Str		tag_field_type;
		Type_variant	variant;

		/* Output the local variables: */
		variant = type_def->value.variant;
		tag_field = variant->tag_field;
		tag_field_type = tag_field->type_ref->name;

		fields = variant->fields;
		VEC_LOOP(Type_field, fields, field) {
			field_name = field->name;
			field_type = field->type_ref->name;
		}

		/* Output the return statement: */
		break;
	      }
	}
}

/*
 * type_def_equal_convert(routine, convert)
 */
void
type_def_equal_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Str		type_name;

	assert_fail();
	type_name = type_def->name;
	switch (type_def->kind) {
	    case Type_kind_enumeration:
		break;
	    case Type_kind_record:
	      {
		Type_field	field;
		Str		field_name;
		Type_fields	fields;
		int		index;
		Str		name;
		int		size;

		fields = type_def->value.record->fields;
		size = vec_size(Type_field, fields);
		for (index = 0; index < size; index++) {
			field = vec_fetch(Type_field, fields, index);
			field_name = field->name;

			name = field->type_ref->name;
		}
		break;
	      }
	    case Type_kind_variant:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Type_field	tag_field;
		Str		tag_field_type;
		Type_variant	variant;

		/* Output the local variable: */
		variant = type_def->value.variant;
		tag_field = variant->tag_field;
		tag_field_type = tag_field->type_ref->name;

		/* Output the switch statement: */
		fields = variant->fields;
		VEC_LOOP(Type_field, fields, field) {
			field_name = field->name;
			field_type = field->type_ref->name;
		}
		break;
	      }
	    default:
		assert_fail();
	}
}

/*
 * type_def_erase_convert(Routine, convert)
 */
void
type_def_erase_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Need_table	need_table;
	Type_tables	type_tables;
	Type_refs	type_refs_empty;

	need_table = routine->need_table;
	type_tables = convert->type_tables;
	type_refs_empty = convert->type_refs_empty;

	switch (type_def->kind) {
	    case Type_kind_enumeration:
		break;
	    case Type_kind_record:
	      {
		Type_field	field;
		Type_fields	fields;
		Type_ref	type_ref;

		fields = type_def->value.record->fields;
		VEC_LOOP(Type_field, fields, field) {
			type_ref = field->type_ref;
			if (!type_refs_is_parameterized(type_ref)) {
				assert_fail();
				need_table_object_insert(need_table, "??",
							 type_ref, type_ref,
							 0);
			}
		}
		break;
	      }
	    default:
		assert_fail();
	}
}

/*
 * type_def_hash_convert(Routine, convert)
 *	This routine will generate the hash routine for "type_def"
 *	using "gen".
 */
void
type_def_hash_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Str		type_name;

	assert_fail();
	type_name = type_def->name;
	switch (type_def->kind) {
	    case Type_kind_enumeration:
		break;
	    case Type_kind_record:
	      {
		Type_field	field;
		Str		field_name;
		Type_fields	fields;
		int		index;
		Str		name;
		int		size;

		fields = type_def->value.record->fields;
		size = vec_size(Type_field, fields);
		for (index = 0; index < size; index++) {
			field = vec_fetch(Type_field, fields, index);
			field_name = field->name;
			name = field->type_ref->name;
		}
		break;
	      }
	    case Type_kind_variant:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Type_field	tag_field;
		Str		tag_field_type;
		Type_variant	variant;

		/* Output the local variable: */
		variant = type_def->value.variant;
		tag_field = variant->tag_field;
		tag_field_type = tag_field->type_ref->name;

		/* Output the switch statement: */
		fields = variant->fields;
		VEC_LOOP(Type_field, fields, field) {
			field_name = field->name;
			field_type = field->type_ref->name;
		}
		break;
	      }
	    default:
		assert_fail();
	}
}

/*
 * type_def_initial_object_convert(Routine, convert)
 *	This routine will generate the initial object(s) for "type_def"
 *	using "gen".
 */
void
type_def_initial_object_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
	
{
	Str		type_name;

	assert_fail();
	type_name = type_def->name;
	switch (type_def->kind) {
	    case Type_kind_enumeration:
	      {
		int		index;
		Type_item	item;
		Str		item_name;
		Vec(Type_item)	items;
		int		size;

		items = type_def->value.enumeration->items;
		size = vec_size(Type_item, items);
		for (index = 0; index < size; index++) {
			item = vec_fetch(Type_item, items, index);
			item_name = item->name;
		}
		break;
	      }
	    case Type_kind_record:
		break;
	    case Type_kind_variant:
		break;
	}
}

/*
 * type_def_input_convert(Routine, convert)
 *	This routine will generate the input routine for "type_def"
 *	using "gen".
 */
void
type_def_input_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Str		type_name;

	assert_fail();
	type_name = type_def->name;
	switch (type_def->kind) {
	    case Type_kind_enumeration:
		break;
	    case Type_kind_record:
	      {
		Type_field	field;
		Type_fields	fields;

		fields = type_def->value.record->fields;
		VEC_LOOP(Type_field, fields, field) {
		}
		break;
	      }
	    case Type_kind_variant:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Type_field	tag_field;
		Str		tag_field_type;
		Type_variant	variant;

		/* Output the local variables: */
		variant = type_def->value.variant;
		tag_field = variant->tag_field;
		tag_field_type = tag_field->type_ref->name;


		/* Output the switch statement: */
		fields = variant->fields;
		VEC_LOOP(Type_field, fields, field) {
			field_name = field->name;
			field_type = field->type_ref->name;
		}
		break;
	      }
	    default:
		assert_fail();
	}
}

/*
 * type_def_needs_parameter_block(type_def)
 *	This routine will return a 1 if any field in "type_def" is
 *	parameterized; otherwise, 0 is returned.
 */
LOCAL int
type_def_needs_parameter_block(
	Type_def	type_def)
{
	assert_fail();
	if (!type_ref_is_parameterized(type_def->type_ref)) {
		return 0;
	}
	switch (type_def->kind) {
	    case Type_kind_record:
	      {
		Type_field	field;
		Type_fields	fields;

		fields = type_def->value.record->fields;
		VEC_LOOP(Type_field, fields, field) {
			if (type_refs_is_parameter(field->type_ref)) {
				return 1;
			}
		}
		break;
	      }
	    default:
		assert_fail();
	}
	return 0;
}
#endif /* OLD */

/*
 * generate_allocate_convert(type_def, routine, convert)
 */
LOCAL void
generate_allocate_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Type_ref	type_ref;
	Type_proto	type_proto;
	Type_refs	type_refs_empty;
	Type_tables	type_tables;
	
	type_tables = convert->type_tables;
	type_refs_empty = type_refs_empty_create(type_tables);
	type_ref = type_def->type_ref;
	type_proto = type_proto_create(Type_proto_procedure,
				       type_ref->parameters,
				       type_ref->type_refs,
				       type_refs_empty,
				       type_refs_empty,
				       type_signals_empty_create(type_tables),
				       type_needs_empty_create(type_tables),
				       0,
				       type_tables);
	if (type_ref_is_parameterized(type_ref)) {
		need_table_routine_insert(routine->need_table,
					  "erase", type_ref, type_proto);
	}
}


/*
 * generate_new_convert(type_def, routine, convert)
 */
LOCAL void
generate_new_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Type_ref	type_ref;
	Type_proto	type_proto;
	Type_refs	type_refs_empty;
	Type_tables	type_tables;
	
	type_tables = convert->type_tables;
	type_refs_empty = type_refs_empty_create(type_tables);
	type_ref = type_def->type_ref;
	type_proto = type_proto_create(Type_proto_procedure,
				       type_ref->parameters,
				       type_ref->type_refs,
				       type_refs_empty,
				       type_refs_empty,
				       type_signals_empty_create(type_tables),
				       type_needs_empty_create(type_tables),
				       0,
				       type_tables);
	if (type_ref_is_parameterized(type_ref)) {
		need_table_routine_insert(routine->need_table,
					  "erase", type_ref, type_proto);
	}
}


#ifdef OLD

/*
 * type_def_output_convert(Routine, convert)
 *	This routine will generate the output routine for "type_def"
 *	using "gen".
 */
void
type_def_output_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Str		type_name;

	assert_fail();
	type_name = type_def->name;
	switch (type_def->kind) {
	    case Type_kind_enumeration:
		break;
	    case Type_kind_record:
	      {
		Type_field	field;
		Type_fields	fields;

		fields = type_def->value.record->fields;
		VEC_LOOP(Type_field, fields, field) {
		}
		break;
	      }
	    case Type_kind_variant:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Type_field	tag_field;
		Str		tag_field_type;
		Type_variant	variant;

		/* Output the local variable: */
		variant = type_def->value.variant;
		tag_field = variant->tag_field;
		tag_field_type = tag_field->type_ref->name;

		/* Output the switch statement: */
		fields = variant->fields;
		VEC_LOOP(Type_field, fields, field) {
			field_name = field->name;
			field_type = field->type_ref->name;
		}
		break;
	      }
	    default:
		assert_fail();
	}
}

/*
 * type_def_print_convert(Routine, convert)
 *	This routine will generate the print routine for "type_def"
 *	using "gen".
 */
void
type_def_print_convert(
	Type_def	type_def,
	Routine		routine,
	Convert		convert)
{
	Str		type_name;

	assert_fail();
	type_name = type_def->name;
	switch (type_def->kind) {
	    case Type_kind_enumeration:
	      {
		Type_item		item;
		Vec(Type_item)		items;

		items = type_def->value.enumeration->items;
		VEC_LOOP(Type_item, items, item){ 
		}
		break;
	      }
	    case Type_kind_record:
	      {
		Type_field	field;
		Type_fields	fields;
		int		index;
		int		size;

		fields = type_def->value.record->fields;
		VEC_LOOP(Type_field, fields, field) {
		}
		size = vec_size(Type_field, fields);
		for (index = 0; index < size; index++) {
			field = vec_fetch(Type_field, fields, index);
		}
		break;
	      }
	    case Type_kind_variant:
	      {
		Type_field	field;
		Str		field_name;
		Str		field_type;
		Type_fields	fields;
		Type_field	tag_field;
		Str		tag_field_type;
		Type_variant	variant;

		/* Output the local variable: */
		variant = type_def->value.variant;
		tag_field = variant->tag_field;
		tag_field_type = tag_field->type_ref->name;

		fields = variant->fields;
		VEC_LOOP(Type_field, fields, field) {
		}

		/* We should be more careful to get a stable tag and value! */

		/* Output the switch statement: */
		VEC_LOOP(Type_field, fields, field) {
			field_name = field->name;
			field_type = field->type_ref->name;
		}
		break;
	      }
	    default:
		assert_fail();
	}
}
#endif /* OLD */

/*
 * generate_routines_convert(type_def, convert)
 *	This routien will generate all of the access routines for "type_def"
 *	using "gen".
 */
void
generate_routines_convert(
	Type_def	type_def,
	Convert		convert)
{
	Generate	generate;
	Vec(Generate)	generates;
	Routine		routine;
	Routine_entry	routine_entry;

	generates = type_def->generates;
	VEC_LOOP(Generate, generates, generate) {
		routine_entry = routine_entry_lookup(convert->routine_table,
					generate_unparse(generate->kind),
					type_def->type_ref->name, -1);
		if ((routine_entry != (Routine_entry)0) &&
		    (routine_entry->routine != (Routine)0)) {
			generate->routine = routine_entry->routine;
		}
	}
	switch (type_def->kind) {
	    case Type_kind_enumeration:
		VEC_LOOP(Generate, generates, generate) {
			routine = generate->routine;
			switch (generate->kind) {
			    case Generate_allocate:
				break;
			    case Generate_copy:
				break;
			    case Generate_equal:
				break;
			    case Generate_hash:
				break;
			    case Generate_identical:
				break;
			    case Generate_input:
				break;
			    case Generate_integer_convert:
				break;
			    case Generate_new:
				break;
			    case Generate_output:
				break;
			    case Generate_print:
				break;
			    case Generate_save:
				break;
			    case Generate_unsigned_convert:
				break;
			    default:
				assert_fail();
			}
		}
		break;
	    case Type_kind_record:
	    case Type_kind_variant:
		VEC_LOOP(Generate, generates, generate) {
			routine = generate->routine;
			switch (generate->kind) {
			    case Generate_address_get:
				break;
			    case Generate_allocate:
				generate_allocate_convert(type_def,
							  routine, convert);
				break;
			    case Generate_copy:
				break;
			    case Generate_erase:
				break;
			    case Generate_equal:
				break;
			    case Generate_hash:
				break;
			    case Generate_identical:
				break;
			    case Generate_input:
				break;
			    case Generate_new:
				generate_new_convert(type_def,
						     routine, convert);
				break;
			    case Generate_output:
				break;
			    case Generate_print:
				break;
			    case Generate_save:
				break;
			    default:
				assert_fail();
			}
		}
		break;
	    case Type_kind_external:
		break;
	    default:
		assert_fail();
	}
}
