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

/*
 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 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 code for parsing module syntax: */

#ifndef FILE_DEFS_H
#include "file_defs.h"
#endif

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

#ifndef KEYWORD_DEFS_H
#include "keyword_defs.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_EXPORTS_H
#include "msg_exports.h"
#endif

#ifndef OBJECT_EXPORTS_H
#include "object_exports.h"
#endif

#ifndef PARSER_DEFS_H
#include "parser_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 TOKEN_DEFS_H
#include "token_defs.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 UNIX_UNISTD_H
#include "unix_unistd.h"
#endif

#ifndef VAR_DEFS_H
#include "var_defs.h"
#endif

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

LOCAL Import	import_parse(Parser);

/*
 * module_parse(parser)
 *	This routine will parse and return a module object from "parser".
 */
Module
module_parse(
	Parser			parser)
{
	Vec(Str)		comments;
	Heap			heap;
	Import			import;
	Vec(Import)		imports;
	Module			module;
	Routine			routine;
	Vec(Routine)		routines;
	Token			token;
	Type_def		type_def;
	Type_def_table		type_def_table;
	Type_defs		type_defs;

	heap = parser->heap;
	comments = vec_create(Str, heap);
	type_defs = vec_create(Type_def, heap);
	routines = vec_create(Statement, heap);
	type_def_table = parser->type_tables->type_def_table;

	module = heap_allocate(heap, Module);
	module->comment = (Str)0;
	module->comments = comments;
	module->consts = vec_create(Var, heap);
	module->exports = vec_create(Export, heap);
	module->identify = (Str)0;
	module->import_type_defs = vec_create(Type_def, heap);
	imports = vec_create(Import, heap);
	module->imports = imports;
	module->name = (Str)0;
	module->object_table = parser->object_table;
	module->routines = routines;
	module->type_defs = type_defs;
	module->version = (Str)0;

	/* Before anything else get the native language: */
	token = parser_token_peek(parser);
	switch (token->type) {
	    case Token_type_symbol:
		module->language = token->value.symbol;
		(void)parser_token_read(parser);
		if (strcmp(module->language, "english") != 0) {
			msg_out(parser->msg, parser->file->position,
				"Only english is currently supported");
		}
		(void)parser_eol_read(parser);
		break;
	    default:
		msg_out(parser->msg, parser->file->position,
			     "No language found");
		module->language = "english";
	}

	/* XXX: This code does not enforce the declaration order! */
	while (parser_loop_next(parser)) {
		switch (parser_keyword_parse(parser, 1, 1)) {
		    case Key_define:
			type_def = type_def_parse(module->routines,
						  module, parser);
			if (type_def != (Type_def)0) {
				vec_append(Type_def, type_defs, type_def);
				if (type_def_table_insert(type_def_table,
							  type_def)) {
					msg_out(parser->msg, type_def->position,
					    "Type %s is already defined!",
					    type_def->name);
				}
			}
			break;
		    case Key_eol:
			vec_append(Str, comments, parser_eol_read(parser));
			break;
		    case Key_identify:
			module->identify =
				parser_untranslated_string_read(parser);
			break;
		    case Key_import:
			PARSER_LOOP(parser) {
				import = import_parse(parser);
				if (import != (Import)0) {
					vec_append(Import, imports, import);
				}
			}
			break;
		    case Key_module:
			token = parser_symbol_parse(parser);
			module->name = token->value.symbol;
			module->position = token->position;
			module->comment = parser_eol_read(parser);
			module->comments = comments;
			comments = vec_create(Str, heap);
			break;
		    case Key_none:
			msg_out(parser->msg, parser->file->position,
				"Unrecognized declaration keyword");
			(void)parser_eol_read(parser);
			break;
		    case Key_object:
		      {
			Token		object_name;
			Type_ref	object_type_ref;
			Token		token;

			/* Get the object name: */
			object_name = parser_symbol_parse(parser);
			token = parser_token_peek(parser);
			if (token->type != Token_type_at) {
				msg_out(parser->msg, token->position,
					"No `@' after object name!");
				(void)parser_eol_read(parser);
				break;
			}
			(void)parser_token_read(parser);
			object_type_ref = type_ref_parse(parser);

			type_def = type_def_table_lookup(type_def_table,
						object_type_ref->name);
			if (type_def == (Type_def)0) {
				msg_out(parser->msg, token->position,
					"Type `%s' is undefined!",
					object_name->value.symbol);
			} else {
				object_create(parser->object_table,
					      object_name->value.symbol,
					      object_type_ref,
					      type_def,
					      object_name->position);
			}
			(void)parser_eol_read(parser);
			break;
		      }
		    case Key_procedure:
			routine = routine_parse(parser, 1, module);
			if (routine != (Routine)0) {
				routine->comments = comments;
				vec_append(Routine, routines, routine);
			}
			comments = vec_create(Str, heap);
			break;
		    case Key_iterator:
			routine = routine_parse(parser, 0, module);
			if (routine != (Routine)0) {
				routine->comments = comments;
				vec_append(Routine, routines, routine);
			}
			comments = vec_create(Str, heap);
			break;
		    case Key_version:
			module->version =
				parser_untranslated_string_read(parser);
			break;
		    default:
			msg_out(parser->msg, parser->file->position,
				     "Missing declaration keyword");
			break;
		}
	}
	return module;
}

Import
import_parse(
	Parser		parser)
{
	Import		import;
	Token		token;

	import = heap_allocate(parser->heap, Import);
	import->comment = (Str)0;
	import->name = (Str)0;
	import->position = -1;
	token = parser_token_peek(parser);
	if (token->type != Token_type_symbol) {
		msg_out(parser->msg, parser->file->position,
			"Bad import declaration");
		return (Import)0;
	} else {
		import->name = token->value.symbol;
		import->comment = parser_eol_read(parser);
		import->position = token->position;
	}
	return import;
}

