/*
 *  type.c
 *
 *  Created September 15, 1990 by Raymie Stata
 *   based on original by R. Finn (9 jan 90)
 */

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "type.h"
#include "misc1.h"
#include "setexpr.h"
#include "symmap.h"
#include "list.h"
#include "bucket.h"

#define LOCAL static
#define IMPORT extern
#define EXPORT /* */

/* begin rep */
struct typestruct {
  int tcode;
  Setexpr methodset;
  union {
    char *universal;  /* Hack to avoid type casts... */
    Type subtype;     /* SEQ[type], SET[type] */
    List sublist;     /* UNION[typeList], RECORD[fieldList], etc. */
    Proctype proc;    /* 3 procedural types. */
    Var var;          /* A ID . ID equate */ 
  } tu;
};
/* end rep */

/* Imported variables. */
IMPORT Symmap symmap;
IMPORT char *malloc();


/* Exported variables */
EXPORT Type tc_any, tc_bool, tc_char, tc_int, tc_null, tc_none, tc_string;

/* Symbol numbers for reserved identifiers. */
EXPORT int rid_any, rid_bool, rid_char, rid_int, rid_null, rid_string;
EXPORT int rid_true, rid_false, rid_nil;



/* Local variables. */
LOCAL Bucket tnodes = NULL;


/* Exported routines. */
EXPORT void ty_init()
{
  /* Find largest structure that we use for argument to bucket abstrac. */
  tnodes = bk_create(sizeof(struct typestruct));

  tc_any  = t_create(T_ANY, NULL);
  tc_bool = t_create(T_BOOL, NULL);
  tc_char = t_create(T_CHAR, NULL);
  tc_int  = t_create(T_INT, NULL);
  tc_null = t_create(T_NULL, NULL);
  tc_none = t_create(T_NONE, NULL);
  tc_string = t_create(T_STRING, NULL);
}


EXPORT Type t_create(code, subinfo)
  int code;
  char *subinfo;
{
  Type ty = (Type) bk_alloc(tnodes);
  assert(ty);
  ty->tcode = code;
  ty->tu.universal = subinfo;
  ty->methodset = NULL;
  return(ty);
}


EXPORT Type t_setmethods(t, mset)
  Type t;
  Setexpr mset;
{
  t->methodset = mset;
  return(t);
}


EXPORT int t_eq(t1, t2)
  Type t1, t2;
{
  if (t1->tcode != t2->tcode) return(0);

  switch(t1->tcode) {
  case T_ANY: case T_BOOL: case T_CHAR: case T_INT:
  case T_NULL: case T_STRING: case T_NONE:
    return(1);
  default: return(0);
  }
}

EXPORT char *t_unparse(ty)
  Type ty;
{
  static char form_buf[15];
  char *form, *internal, *methods, *result;
  char *(*unparse)();
  int result_length, r = 0;

  switch(ty->tcode) {
  case T_ANY:    form = "ANY"; break;
  case T_BOOL:   form = "BOOL"; break;
  case T_CHAR:   form = "CHAR"; break;
  case T_ENUM:   form = "ENUM[%s]";   r = 2; unparse = sm_unparse; break;
  case T_INT:    form = "INT"; break;
  case T_NULL:   form = "NULL"; break;
  case T_STRING: form = "STRING"; break;

  case T_RECORD: form = "RECORD[%s]"; r = 2; unparse = decl_unparse; break;
  case T_TUPLE:  form = "(%s)";       r = 2; unparse = t_unparse; break;
  case T_SET:    form = "SET[%s]";    r = 1; unparse = t_unparse; break;
  case T_SEQ:    form = "SEQ[%s]";    r = 1; unparse = t_unparse; break;
  case T_UNION:  form = "UNION[%s]";  r = 2; unparse = t_unparse; break;

  case T_FUNC: case T_PROC: case T_APROC:
                 form = "%s";         r = 1; unparse = proc_unparse; break;
  case T_EQU:    form = "EQU[%s]";    r = 1; unparse = var_unparse; break;
  case T_NONE:   form = "()"; break;
  default:       form = "UNKNOWN"; break;
  };

  if (r == 1) internal = unparse(ty->tu.subtype);
    else if (r == 2) internal = lst_unparse(ty->tu.sublist, unparse);
    else internal = "";    

  result_length = strlen(form) + strlen(internal) + 1;

  if (ty->methodset) {
    methods = setex_unparse(ty->methodset, mthd_unparse);
    result_length += strlen(methods) + strlen("() WITH ");
    sprintf(form_buf, "(%s WITH %%s)", form);
    form = form_buf;
  } else methods = NULL;

  assert( result = malloc( result_length ) );
  if (r) { sprintf(result, form, internal, methods); free(internal); }
    else sprintf(result, form, methods);
  if (methods) free(methods);

  return(result);
}
