#include "Node.h"

#include <ctype.h>

#include <stdio.h>

extern oop s_v_;

TranslationUnit::TranslationUnit(void) : Environment(0)
{
  mOutputStream= (new String)->writeStream();
  mSelectors= new Dictionary();
}

oop TranslationUnit::outputStream(void)
{
  return mOutputStream;
}

oop TranslationUnit::declare(oop name, oop classNode)
{
  shouldNotImplement(0);
}

oop TranslationUnit::declareClass(oop classNode)
{
  oop prev= atOrNil(classNode->name());
  if (prev)
    {
      if (prev->isClassNode() && (*classNode == prev))
	return prev;
      error("declaration of class\n\t%s\nconflicts with previous declaration\n\t%s",
	    classNode->printCString(),
	    prev->printCString());
    }
  return Environment::declare(classNode->name(), classNode);
}

oop TranslationUnit::declareSelector(oop name)
{
  oop mangled= mSelectors->atOrNil(name);
  if (!mangled)
    {
      mangled= mangleSelector(name);
      mSelectors->atPut(name, mangled);
    }
  return mangled;
}

oop TranslationUnit::declareGlobal(oop name)
{
  return Environment::declare(name, new GlobalVariable(name, mangleVariable(name)));
}

oop TranslationUnit::lookup(oop name)
{
  return Environment::lookup(name);
}

oop TranslationUnit::lookupClass(oop name)
{
  return Environment::lookup(name);
}

oop TranslationUnit::lookupSelector(oop name)
{
  return mSelectors->at(name);
}

oop TranslationUnit::mangleSelector(oop selector)
{
  oop in= selector->readStream();
  oop out= (new String)->writeStream();
  out->format("s_");
  while (!in->atEnd())
    {
      oop c= in->next();
      int v= c->asciiValue();
      switch (v)
	{
	case ':':
	  out->format("_");
	  break;

	default:
	  if (isalnum(v))
	    out->nextPut(c);
	  else
	    out->format("_%02x", v);
	  break;
	}
    }
  return out->contents();
}

oop TranslationUnit::mangleVariable(oop name)
{
  return *s_v_ + name;
}

static int nameOrder(oop x, oop y)	{ return *x->value()->name() <= y->value()->name(); }
static int valueOrder(oop x, oop y)	{ return *x->value() <= y->value(); }

oop TranslationUnit::genDefinitions(void)
{
  iterate(asSortedCollection(nameOrder), current)
    mOutputStream->format("static oop %s= 0;\n", (*current)->value()->mangledName()->cString());
  iterate(mSelectors->asSortedCollection(valueOrder), current)
    mOutputStream->format("static sel_t %s= 0;\n", (*current)->value()->cString());
  mOutputStream->format("\n");
  return this;
}

oop TranslationUnit::genInitialisations(void)
{
  iterate(mSelectors->asSortedCollection(valueOrder), current)
    mOutputStream->format("  %s= _selector(\"%s\");\n",
			  (*current)->value()->cString(),
			  (*current)->key()->cString());
  return this;
}
