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

/*
 * Copyright (c) 1990, 1991, 1992, 1993, 1995 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 routine for outputing code for modules: */

#ifndef ERROR_EXPORTS_H
#include "error_exports.h"
#endif

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

#ifndef GEN_DEFS_H
#include "gen_defs.h"
#endif

#ifndef GENERATE_EXPORTS_H
#include "generate_exports.h"
#endif

#ifndef LIBC_EXPORTS_H
#include "libc_exports.h"
#endif

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

#ifndef MODULE_DEFS_H
#include "module_defs.h"
#endif

#ifndef MSG_DEFS_H
#include "msg_defs.h"
#endif

#ifndef OBJECT_DEFS_H
#include "object_defs.h"
#endif

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

#ifndef STR_EXPORTS_H
#include "str_exports.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 UNIX_DIRENT_H
#include "unix_dirent.h"
#endif

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

/* Lint is a lot happier if we don't #include "run_time_exports.h"! */
extern char	*run__time__enums;
extern char	*run__time__type_defs;
extern char	*run__time__struct_defs;

LOCAL void	module_linkage_gen(Module, Gen);

/*
 * module_gen(module, gen)
 *	This routine will generate the C code associated with "module"
 *	using "gen" to control the generated code.
 */
void
module_gen(
	Module		module,
	Gen		gen)
{
	Type_defs	import_type_defs;
	Type_defs	type_defs;

	gen_comments(gen, module->comments, 0);
	gen_comment(gen, module->comment, 0);

	if (gen->linkage) {
		gen_out(gen, "%s", run__time__enums);
		gen_out(gen, "%s", run__time__type_defs);
		gen_out(gen, "typedef void *routine__info__type;\n");
		gen_out(gen, "%s", run__time__struct_defs);
	}

	/* Output the typedefs for the imported types: */

	/* Output the type__ref data structure (if necessary): */
	if (gen->need_type_ref) {
		gen_out(gen, "typedef type__ref___struct "
			"*type__ref___type;\n");
		gen_out(gen, "struct type__ref___struct {\n");
		gen_out(gen, "%\tchar *name;\n", 1);
		gen_out(gen, "%\tint size;\n", 1);
		gen_out(gen, "%\ttype__ref___type *parameters;\n", 1);
		gen_out(gen, "};\n");
		gen_out(gen, "\n");
		gen->need_routine_ref = 1;
	}
	if (gen->need_routine_ref) {
		gen_out(gen, "typedef routine__ref___struct "
			"*routine__ref___type;\n");
		gen_out(gen, "struct routine__ref___struct {\n");
		gen_out(gen, "%\tvoid *((*routine)(void));\n", 1);
		gen_out(gen, "%\tvoid *block;\n", 1);
		gen_out(gen, "\n");
	}

	type_defs = module->type_defs;
	import_type_defs = module->import_type_defs;

	type_defs_typedef_gen(type_defs, gen);
	type_defs_typedef_gen(import_type_defs, gen);

	gen_out(gen, "\n");

	/* Output the typedefs for the multiple types: */
	type_refs_multiple_gen(gen->type_tables, gen);
	type_proto_table_gen(gen->type_tables->type_proto_table, gen);

	type_defs_enumeration_gen(type_defs, gen);
	type_defs_enumeration_gen(import_type_defs, gen);

	type_defs_structure_gen(type_defs, gen);
	type_defs_structure_gen(import_type_defs, gen);

	object_table_extern_gen(gen->object_table, gen);

	routine_table_proto_gen(gen->routine_table, gen);

	type_defs_external_gen(type_defs, gen);
	type_defs_external_gen(import_type_defs, gen);

	/* Output the generic debugger type definitions: */
	if (gen->linkage) {
		if (1 || gen->debug) {
			gen_out(gen, "extern void "
				"run__time__assertion_failed(char *, int);\n");
			gen_out(gen, "extern void "
				"run__time__uninitialized__routine(void);\n");
			gen_out(gen,
				"extern void run__time__bad__case(void);\n");
			gen_out(gen,
				"extern void run__time__breakpoint(void);\n");
			gen_out(gen,
				"extern void *run__time__convert__create(int, "
				"int, char *);\n");
			gen_out(gen, "extern void run__time__pop(void);\n");
			gen_out(gen,
			    "void run__time__push(activation___object *);\n");
			gen_out(gen, "\n");
		}
		gen_out(gen, "extern void run__time__signal(char *);\n");
		gen_out(gen,
			"extern void run__time__routine_print(void *, "
			"void *);\n");
		/* gen_out(gen,
		   "extern void *heap_alloc(heap___type, int);\n"); */
		gen_out(gen, "extern module___object %s%s__module__object;\n",
		   gen->flags->package_name, module->name);
		routine_table_signature_gen(gen->routine_table, gen);
	}

	routines_gen(module->routines, gen);

	objects_gen(module->object_table, gen);

	type_defs_routines_gen(type_defs, gen);

	if (gen->linkage) {
		module_linkage_gen(module, gen);
	}
}

/*
 * module_linkage_gen(module, gen)
 *	This routine will emit all of the module linkage information
 *	for "module" to "gen".
 */
LOCAL void
module_linkage_gen(
	Module		module,
	Gen		gen)
{
	int		line_number;
	Str		package_name;
	int		objects_size;
	Routine		routine;
	Vec(Routine)	routines;
	int		routines_size;

	/* Output the vectors for the module___object structure: */
	/*XXX: This code chunk should be migrated to routine.c: */
	package_name = gen->flags->package_name;
	routines = module->routines;
	routines_size = vec_size(Routine, routines);
	gen_out(gen, "static routine___object *module___routines[%d] = {\n",
		routines_size);
	VEC_LOOP(Routine, routines, routine) {
		gen_out(gen, "%\t&%s%s__%s__routine__object,\n", 1,
			package_name,
			routine->type_ref->name,
			routine->name);
	}
	gen_out(gen, "};\n");
	gen_out(gen, "\n");

	objects_size = object_table_module_objects_gen(module->object_table,
						       gen);

	/* Output the module___object structure: */
	if (gen->msg->position_split >= 0) {
		line_number = msg_line_get(gen->msg, gen->msg->position_split);
	} else {
		line_number = -1;
	}
	gen_out(gen, "module___object %s%s__module__object = {\n",
		package_name, module->name);
	gen_out(gen, "%\t%\",\n", 1, package_name);
	gen_out(gen, "%\t%\",\n", 1, module->name);
	gen_out(gen, "%\t%\",\n", 1, gen->flags->in_file->full);
	gen_out(gen, "%\t%\",\n", 1, gen->flags->gen_file->full);
	gen_out(gen, "%\t%d,\n", 1, line_number);
	gen_out(gen, "%\t%d,\n", 1, objects_size);
	if (objects_size == 0) {
		gen_out(gen, "%\t(object___object **)0,\n", 1);
	} else {
		gen_out(gen, "%\tmodule___objects,\n", 1);
	}
	gen_out(gen, "%\t%d,\n", 1, 0);		/* Types count */
	gen_out(gen, "%\t(type___object **)0, \n", 1); /* types */
	gen_out(gen, "%\t%d,\n", 1, routines_size);
	gen_out(gen, "%\tmodule___routines,\n", 1); /* Routines */
	gen_out(gen, "%\t%d,\n", 1,		/* Used routine count */
		routine_table_used_size(gen->routine_table));
	gen_out(gen, "%\t(routine___use **)0,\n", 1);
	gen_out(gen, "%\t%d,\n", 1, 0 /* Object uses count */);
	gen_out(gen, "%\t(object___use **)0,\n", 1);
	gen_out(gen, "%\t%d,\n", 1, 0 /* Initial object uses count */);
	gen_out(gen, "%\t(type___reference **)0,\n", 1);
	gen_out(gen, "%\t(void **)0,\n", 1); /* Addresses */
	gen_out(gen, "};\n");
	gen_out(gen, "\n");

	/* Output the module initialization routine: */
	gen_out(gen, "void %s__module__initialize(void)\n", module->name);
	gen_out(gen, "{\n");
	type_defs_initialization_gen(module->type_defs, gen);
	type_defs_initialization_gen(module->import_type_defs, gen);
	gen_out(gen, "}\n");
	gen_out(gen, "\n");
}

