/* %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 debugging code that prints a call node out: */

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

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

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

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

#ifndef OUT_EXPORTS_H
#include "out_exports.h"
#endif

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

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

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

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

#ifndef UNIX_STDIO_H
#include "unix_stdio.h"
#endif

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

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

/*
 * call_list_print(calls, out_file, with_types, indent, type_refs)
 *	This routien will print each call in "calls" to "out_file",
 */
void
call_list_print(
	Vec(Call)	calls,
	Stdio		out_file,
	int		with_types,
	int		indent,
	Vec(Type_ref)	type_refs)
{
	Call		call;
	int		temp;

	VEC_LOOP(Call, calls, call) {
		temp = indent;
		while (temp > 1) {
			(void)fputc('\t', out_file);
			temp -= 2;
		}
		if (temp == 1) {
			(void)fputs("    ", out_file);
		}
		call_print(call, out_file, with_types, type_refs);
		(void)fputc('\n', out_file);
	}
}

/*
 * call_print(call, out_file, with_types, type_refs)
 *	This routine will print "call" to "out_file".  If "with_types" is 1,
 *	type information will be printed as well.
 */
void
call_print(
	Call		call,
	Stdio		out_file,
	int		with_types,
	Vec(Type_ref)	type_refs)
{
	if (with_types) {
		Type_ref	call_type_ref;
		Type_refs	call_type_refs;
		int		first;
		extern Type_tables type_tables_global;

		first = 1;
		out(out_file, "{");
		call_type_refs = call->type_refs;
		TYPE_REFS_LOOP(call_type_refs, call_type_ref) {
			vec_append(Type_ref, type_refs, call_type_ref);
			if (first) {
				first = 0;
			} else {
				out(out_file, ", ");
			}
			out(out_file, "%r", call_type_ref);
		}
		out(out_file, "|");
	}
	switch (call->type) {
	    case Call_type_and_if:
	      {
		Call_binary	call_binary;

		call_binary = call->value.binary;
		out(out_file, "(");
		call_print(call_binary->left,
			   out_file, with_types, type_refs);
		out(out_file, "&&");
		call_print(call_binary->right,
			   out_file, with_types, type_refs);
		out(out_file, ")");
		break;
	      }
	    case Call_type_assign:
	      {
		Call_assign	call_assign;

		call_assign = call->value.assign;
		call_print(call_assign->left,
			   out_file, with_types, type_refs);
		out(out_file, " := ");
		call_print(call_assign->right,
			   out_file, with_types, type_refs);
		break;
	      }
	    case Call_type_cast:
	      {
		Call_cast	call_cast;

		call_cast = call->value.cast;
		out(out_file, "((%r)(", call_cast->type_ref);
		call_print(call_cast->call, out_file, with_types, type_refs);
		out(out_file, ")");
		break;
	      }
	    case Call_type_error:
	      {
		out(out_file, "(Error:'%s')", call->value.error);
		break;
	      }
	    case Call_type_if:
	      {
		Call_if		call_if;

		call_if = call->value.xif;
		out(out_file, "(");
		call_print(call_if->condition,
			   out_file, with_types, type_refs);
		out(out_file, "?");
		call_print(call_if->true, out_file, with_types, type_refs);
		out(out_file, ":");
		call_print(call_if->false, out_file, with_types, type_refs);
		out(out_file, ")");
		break;
	      }
	    case Call_type_integer:
	      {
		int		integer;

		integer = call->value.integer;
		out(out_file, "%d", integer);
		break;
	      }
	    case Call_type_invoke:
	      {
		Call		actual;
		Vec(Call)	actuals;
		Call_invoke	call_invoke;
		int		first;

		call_invoke = call->value.invoke;
		call_print(call_invoke->call, out_file, with_types, type_refs);
		out(out_file, "(");
		actuals = call_invoke->actuals;
		first = 1;
		VEC_LOOP(Call, actuals, actual) {
			if (first) {
				first = 0;
			} else {
				out(out_file, ", ");
			}
			call_print(actual, out_file, with_types, type_refs);
		}
		out(out_file, ")");
		break;
	      }
	    case Call_type_multi:
	      {
		Call_multi	call_multi;
		int		first;
		Call		var;
		Vec(Call)	vars;

		call_multi = call->value.multi;
		first = 1;
		vars = call_multi->vars;
		VEC_LOOP(Call, vars, var) {
			if (first) {
				first = 0;
			} else {
				out(out_file, ", ");
			}
			call_print(var, out_file, with_types, type_refs);
		}
		out(out_file, " := ");
		call_print(call_multi->invoke,
			   out_file, with_types, type_refs);
		break;
	      }
	    case Call_type_not:
	      {
		Call		not;

		not = call->value.not;
		out(out_file, "(!");
		call_print(not, out_file, with_types, type_refs);
		out(out_file, ")");
		break;
	      }
	    case Call_type_object:
	      {
		Object_ref	object_ref;

		object_ref = call->value.object;
		out(out_file, "%r@%s",
		    object_ref->type_ref, object_ref->name);
		break;
	      }
	    case Call_type_or_if:
	      {
		Call_binary	call_binary;

		call_binary = call->value.binary;
		out(out_file, "(");
		call_print(call_binary->left, out_file, with_types, type_refs);
		out(out_file, "||");
		call_print(call_binary->right,
			   out_file, with_types, type_refs);
		out(out_file, ")");
		break;
	      }
	    case Call_type_routine:
	      {
		Call_routine	call_routine;
		Routine_ref	routine_ref;

		call_routine = call->value.routine;
		routine_ref = call_routine->routine_ref;
		if (strcmp(routine_ref->type_ref->name, "global__") != 0) {
			type_ref_print(routine_ref->type_ref, out_file);
			out(out_file, "@");
		}
		out(out_file, "%s", routine_ref->name);
		break;
	      }
	    case Call_type_string:
	      {
		out(out_file, "%\"", call->value.string);
		break;
	      }
	    case Call_type_temp:
	      {
		Call_temp	call_temp;

		call_temp = call->value.temp;
		out(out_file, "_temp_%d", call_temp->number);
		break;
	      }
	    case Call_type_text:
	      {
		out(out_file, "%'", call->value.text);
		break;
	      }
	    case Call_type_var:
	      {
		Call_var	call_var;

		call_var = call->value.var;
		out(out_file, "%s", call_var->name);
		break;
	      }
	    default:
		assert_fail(); /* Unknown call type */
	}
	if (with_types) {
		out(out_file, "}");
	}
}

#ifndef lint
/*
 * call_show(call)
 *	This routine will print out the contents of "call" to standard out.
 */
void
call_show(
	Call		call)
{
	Heap		heap;
	Vec(Type_ref)	type_refs;

	heap = heap_standard_create();
	type_refs = vec_create(Type_ref, heap);
	call_print(call, stdout, 0, type_refs);
	(void)printf("\n");
}
#endif /* lint */
