/*
 *  setexpr.h
 *
 *  Created September 16, 1990 by Raymie Stata
 *  (c) 1990 Raymie Stata, All Rights Reserved
 */

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

#include "setexpr.h"
#include "list.h"
#include "symmap.h"

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

/* begin rep */
/*   REP for sets and setexpr's are lists.  For sets, the car is
 * the equality function for elements in the set and cdr points
 * to a list of UNIQUE elements.  For set expr's, the car is
 * a set of symbols that haven't been unioned in yet, and the
 * cdr is the list of elements that have been unioned in.  Note that
 * this rep for setexpr's relies set's being lists, since strictly
 * speaking the only thing that can be a cdr is a list.
 */
/* end rep */


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

LOCAL nullfn() {return(0);}

/* Exported routines. */
EXPORT Setexpr setex_create(eq)
  int (*eq)();
{
  Set ref_part = set_create(sm_eq); /* Empty set of symbols. */
  Set item_part = set_create(eq);   /* Empty set of items. */
  return( lst_cons(ref_part, item_part) );
}


EXPORT Setexpr setex_ref(eq, sym)
  int (*eq)();
  int sym;
{
  Set ref_part = set_singleton(sm_eq, sym);
  Set item_part = set_create(eq);   /* Empty set of items. */
  return(lst_cons(ref_part, item_part));
}


EXPORT Setexpr setex_itemlist(eq, item_list)
  int (*eq)();
  List item_list;
{
  Set ref_part = set_create(sm_eq); /* Empty set of symbols. */
  Set item_part = set_multiton(eq, item_list);
  return( lst_cons(ref_part, item_part) );
}


EXPORT Setexpr setex_uniond(se1, se2)
  Setexpr se1, se2;
{
  Set ref_part = set_uniond(lst_car(se1), lst_car(se2));
  Set item_part = set_uniond(lst_cdr(se1), lst_cdr(se2));
  lst_free_node(se1); lst_free_node(se2);
  return( lst_cons(ref_part, item_part) );
}


EXPORT int setex_empty(se)
  Setexpr se;
{
  return(set_empty(lst_car(se)) && set_empty(lst_cdr(se)));
}

EXPORT char *setex_unparse(se, unparse)
  Setexpr se;
  char *(*unparse)();
{
  char *ret;

  /* If exit no ref's, then just print the item set.  Other wise,
   * print [ {ref-set}, {item-set} ]
   */
  if (set_empty(lst_car(se))) ret = set_unparse(lst_cdr(se), unparse);
  else {
    char *refs, *items;
    refs = set_unparse(lst_car(se), sm_unparse);
    items = set_unparse(lst_cdr(se), unparse);
    ret = malloc(strlen(refs) + strlen(items) + strlen("[, ]") + 1);
    assert( ret );
    sprintf(ret, "[%s,  %s]", refs, items);
    free(refs); free(items);
  }
  return(ret);
}


EXPORT Set set_create(eq)
  int (*eq)();
{  return( lst_cons(eq, NULL) ); }


EXPORT Set set_singleton(eq, item)
  int (*eq)();
  char *item;
{
  List item_list = lst_cons(item, NULL);
  return( lst_cons(eq, item_list) );
}


EXPORT Set set_multiton(eq, itemList)
  int (*eq)();
  List itemList;
{ return( lst_cons(eq, itemList) ); }


EXPORT Set set_uniond(s1, s2)
  Set s1, s2;
{
  List p, list2, result;
  int (*eq)();

  eq = (int (*)()) lst_car(s1);
  assert((char *)eq == lst_car(s2)); /* Make sure element types are same. */
  result = list2 = lst_cdr(s2);

  for(p = lst_cdr(s1); p; p = lst_cdr(p)) {
    char *item1 = lst_car(p);
    if (! lst_member(list2, item1, eq)) result = lst_cons(item1, result);
  }

  lst_free_node(s2);
  lst_free_list(s1);

  return( lst_cons(eq, result) );
}


EXPORT int set_empty(set)
  Set set;
{ return(lst_cdr(set) == NULL); }


EXPORT char *set_unparse(set, unparse)
  Set set;
  char *(*unparse)();
{
  char *ret;
  if (set_empty(set)) {
    ret = malloc(strlen("{}") + 1);
    assert(ret);
    ret = strcpy(ret, "{}");
  } else {
    char *elements_unparsed = lst_unparse(lst_cdr(set), unparse);
    ret = malloc(strlen(elements_unparsed) + 5);
    assert( ret );
    sprintf(ret, "{ %s }", elements_unparsed);
    free(elements_unparsed);
  }
  return(ret);
}
