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

/*
 * Copyright (c) 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 will parse a routine_info signature string: */

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

#ifndef ROUTINE_INFO_DEFS_H
#include "routine_info_defs.h"
#endif

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

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

#ifndef UNIX_STDLIB_H
#include "unix_stdlib.h"
#endif

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

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

static Str	symbol_get(Str, Heap);
static Str	type_ref_get(Str, Heap);

/*
 * routine__info__parse(info, heap)
 *	This routine will parse and return a routine__info__type object
 *	allocated from "heap" using "info".
 */
routine__info__type
routine__info__parse(
	Str		info,
	Heap		heap)
{
	Vec(Str)	argument_names;
	Vec(Str)	argument_type_refs;
	int		index;
	int		line_number;
	Vec(int)	line_numbers;
	Str		name;
	Vec(Str)	return_type_refs;
	routine__info__type routine_info;
	Str		routine_name;
	Str		type_name;
	Str		type_ref;
	Vec(Str)	variable_names;
	Vec(Str)	variable_type_refs;
	Vec(Str)	yield_type_refs;

	routine_name = symbol_get(info, heap);
	info += strlen(routine_name);
	if (info[0] == '@') {
		info++;
		type_name = symbol_get(info, heap);
		info += strlen(type_name);
	} else {
		type_name = "global__";
	}

	/* Set up all of the fields; */
	argument_names = vec_create(Str, heap);
	argument_type_refs = vec_create(Str, heap);
	line_numbers  = vec_create(int, heap);
	return_type_refs = vec_create(Str, heap);
	variable_names = vec_create(Str, heap);
	variable_type_refs = vec_create(Str, heap);
	yield_type_refs = vec_create(Str, heap);

	/* Extract the rest of the information: */
	do {
		switch (info[0]) {
		    case '(':	/* Arguments */
			info++;
			while (info[0] != ')') {
				name = symbol_get(info, heap);
				vec_append(Str, argument_names, name);
				info += strlen(name) + 1;
				type_ref = type_ref_get(info, heap);
				info += strlen(type_ref);
				vec_append(Str, argument_type_refs, type_ref);
				if (info[0] == ',') {
					info++;
				}
			}
			info++;
			break;
		    case '=':	/* Returns */
			index = 0;
			info++;
			info++;
			do {
				info++;
				index++;
				type_ref = type_ref_get(info, heap);
				vec_append(Str, return_type_refs, type_ref);
				info += strlen(type_ref);
				name = strprintf(heap,
					        "return__value__%d", index);
			} while (info[0] == ',');
			info++;
			break;
		    case '-':	/* Yields */
			info++;
			index = 0;
			do {
				info++;
				index++;
				type_ref = type_ref_get(info, heap);
				vec_append(Str, yield_type_refs, type_ref);
				info += strlen(type_ref);
				name = strprintf(heap,
					        "yield__value__%d", index);
			} while (info[0] == ',');
			break;
		    case '{':	/* Variables: */
			info++;
			while (info[0] != '}') {
				name = symbol_get(info, heap);
				vec_append(Str, variable_names, name);
				info += strlen(name) + 1;
				type_ref = type_ref_get(info, heap);
				info += strlen(type_ref);
				vec_append(Str, variable_type_refs, type_ref);
				if (info[0] == ',') {
					info++;
				}
			}
			info++;
			break;
		    case '[':
			info++;
			do {
				line_number = atoi(info);
				vec_append(int, line_numbers, line_number);
				while (isdigit(info[0])) {
					info++;
				}
			} while (*info++ != ']');
			break;
		    case '\0':	/* All done: */
			break;
		    default:
			assert_fail();
		}
	} while (info[0] != '\0');

	routine_info = heap_allocate(heap, routine__info__type);
	routine_info->argument_names = argument_names;
	routine_info->argument_type_refs = argument_type_refs;
	routine_info->breakpoints = (char *)0;
	routine_info->instantiations = (instantiation___object *)0;
	routine_info->line_numbers = line_numbers;
	routine_info->name = routine_name;
	routine_info->return_type_refs = return_type_refs;
	routine_info->type_name = type_name;
	routine_info->variable_names = variable_names;
	routine_info->variable_type_refs = variable_type_refs;
	routine_info->yield_type_refs = yield_type_refs;

	return routine_info;
}

/*
 * symbol_get(info, heap)
 *	This routine will return the symbol at the front of "info" allocated
 *	from "heap".
 */

static Str
symbol_get(
	Str		info,
	Heap		heap)
{
	char		chr;
	Str		pointer;
	Str		result;
	int		size;

	pointer = info;
	do {
		chr = *pointer++;
	} while (isalpha(chr) || (chr == '_') || isdigit(chr));
	size = pointer - info;
	result = (Str)heap_alloc(heap, size);
	size--;
	(void)strncpy(result, info, size);
	result[size] = '\0';
	return result;
}

/*
 * routine__info__type_ref_get(info, heap)
 *	This routine will get the next type reference from "info" using
 *	"heap".
 */
static Str
type_ref_get(
	Str		info,
	Heap		heap)
{
	int		bracket_count;
	char		chr;
	Str		pointer;
	Str		result;
	int		size;

	bracket_count = 0;
	pointer = info;
	do {
		chr = *pointer++;
		if (chr == '[') {
			bracket_count++;
			do {
				chr = *pointer++;
				switch (chr) {
				    case '[':
					bracket_count++;
					break;
				    case ']':
					bracket_count--;
					break;
				}
			} while (bracket_count != 0);
			chr = *pointer++;
		}
	} while (isalpha(chr) || (chr == '_') || isdigit(chr));
	size = pointer - info;
	result = (Str)heap_alloc(heap, size);
	size--;
	(void)strncpy(result, info, size);
	result[size] ='\0';
	return result;
}

