/*
 *  misc1.c
 *
 *  Created September 15, 1990 by Raymie Stata
 */

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "type.h"
#include "misc1.h"
#include "setexpr.h"
#include "list.h"
#include "bucket.h"
#include "symmap.h"

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

/* begin rep */
struct procstruct {
  int tcode;
  Type args, returns;
  Setexpr raises;
};

struct declstruct {
  int sym;
  Type type;
};

struct varstruct {
  /* Represent an ID '.' ID syntactic element. */
  int module, sym;
};

struct mthdstruct {
  int msgname;
  Var proc;
};
/* end rep */


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


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


/* Exported routines. */
EXPORT void misc1_init()
{
  int s1 = sizeof(struct procstruct), s2 = sizeof(struct declstruct);
  int s3 = sizeof(struct varstruct);
  int ms1 = (s1 > s2 ? s1 : s2);
  mnodes = bk_create( ms1 > s3 ? ms1 : s3 );
}


EXPORT Decl decl_create(sym, type)
  int sym;
  Type type;
{
  Decl decl = (Decl) bk_alloc(mnodes);
  assert(decl);
  decl->sym = sym; decl->type = type;
  return(decl);
}


EXPORT char *decl_unparse(decl)
  Decl decl;
{
  char *field = sm_pname(decl->sym);
  char *type = t_unparse(decl->type);
  char *ret = malloc(strlen(field) + strlen(type) + strlen(": ") + 1);
  assert(ret);
  sprintf(ret, "%s: %s", field, type);
  free(type);
  return(ret);
}


EXPORT Var var_create(module, sym)
  int module, sym;
{
  Var v = (Var) bk_alloc(mnodes);
  assert(v);
  v->module = module; v->sym = sym;
  return(v);
}


EXPORT int var_eq(v1, v2)
  Var v1, v2;
{ return( sm_eq(v1->module, v2->module) && sm_eq(v1->sym, v2->sym) ); }


EXPORT char *var_unparse(var)
  Var var;
{
  char *module = sm_pname(var->module);
  char *symbol = sm_pname(var->sym);
  char *ret = malloc(strlen(symbol) + strlen(module) + strlen(".") + 1);
  assert(ret);
  sprintf(ret, "%s.%s", module, symbol);
  return(ret);
}


EXPORT Method mthd_create(msgname, proc)
  int msgname;
  Var proc;
{
  Method m = (Method) bk_alloc(mnodes);
  assert(m);
  m->msgname = msgname; m->proc = proc;
  return(m);
}


EXPORT int mthd_eq(m1, m2)
  Method m1, m2;
{ return( sm_eq(m1->msgname, m2->msgname) && var_eq(m1->proc, m2->proc) ); }


EXPORT char *mthd_unparse(mthd)
  Method mthd;
{
  char *msgname = sm_pname(mthd->msgname);
  char *proc = var_unparse(mthd->proc);
  char *ret = malloc(strlen(msgname) + strlen(proc) + strlen(" := ") + 1);
  sprintf(ret, "%s := %s", msgname, proc);
  free(proc);
  return(ret);
}


EXPORT Proctype proc_create(tcode, args, returns, raises)
  int tcode;
  Type args, returns;
  Setexpr raises;
{
  Proctype p = (Proctype) bk_alloc(mnodes);
  assert(p);
  p->tcode = tcode;
  p->args = args; p->returns = returns;
  p->raises = raises;
  return(p);
}


EXPORT char *proc_unparse(proc)
  Proctype proc;
{
  char *header, *ret;
  int has_returns = (! t_eq(tc_none, proc->returns));
  int has_raises = (! setex_empty(proc->raises));
  char *args = t_unparse(proc->args);
  char *returns = t_unparse(proc->returns);
  char *raises = setex_unparse(proc->raises, sm_unparse);

  switch(proc->tcode) {
  case T_FUNC:  header = ""; break;
  case T_PROC:  header = "PROC "; break;
  case T_APROC: header = "APROC "; break;
  default: assert(0);
  }

  ret = malloc(strlen(header) + strlen(args) + strlen(returns)
	        + strlen(raises) + strlen("( -> RAISES )") + 1);
  assert(ret);

  if (has_returns && has_raises)
    sprintf(ret, "(%s%s -> %s RAISES %s)", header, args, returns, raises);
  else if (has_returns && ! has_raises)
    sprintf(ret, "(%s%s -> %s)", header, args, returns);
  else if (! has_returns && has_raises)
    sprintf(ret, "(%s%s RAISES %s)", header, args, raises);
  else sprintf(ret, "(%s%s)", header, args);

  free(args); free(returns); free(raises);
  return(ret);
}
