#include "Node.h"
#include "options.h"
#include "idst-config.h"

#include <stdio.h>

#define _do_symbols()					\
  _do("*",			_2a)			\
  _do("+",			_2b)			\
  _do("-",			_2d)			\
  _do("//",			_2f_2f)			\
  _do("<",			_3c)			\
  _do("<=",			_3c_3d)			\
  _do("=",			_3d)			\
  _do("==",			_3d_3d)			\
  _do(">",			_3e)			\
  _do(">=",			_3e_3d)			\
  _do("\\\\",			_5c_5c)			\
  _do("~=",			_7e_3d)			\
  _do("~~",			_7e_7e)			\
  _do("_debugName",		_5fdebugName)		\
  _do("_size:value:",		_5fsize_value_)		\
  _do("_sizeof",		_5fsizeof)		\
  _do("_value:",		_5fvalue_)		\
  _do("bitAnd:",		bitAnd_)		\
  _do("bitOr:",			bitOr_)			\
  _do("bitXor:",		bitXor_)		\
  _do("and:",			and_)			\
  _do("false",			false)			\
  _do("ifFalse:",		ifFalse_)		\
  _do("ifFalse:ifTrue:",	ifFalse_ifTrue_)	\
  _do("ifTrue:",		ifTrue_)		\
  _do("ifTrue:ifFalse:",	ifTrue_ifFalse_)	\
  _do("is",			is)			\
  _do("nil",			nil)			\
  _do("or:",			or_)			\
  _do("self",			self)			\
  _do("((struct t_BlockClosure *)_self)->receiver", _self_2d_3e) \
  _do("super",			super)			\
  _do("t_",			t_)			\
  _do("true",			true)			\
  _do("v_",			v_)			\
  _do("value",			value)			\
  _do("whileFalse",		whileFalse)		\
  _do("whileFalse:",		whileFalse_)		\
  _do("whileTrue",		whileTrue)		\
  _do("whileTrue:",		whileTrue_)		\
  _do("ImmutableArray",		ImmutableArray)		\
  _do("ImmutableByteArray",	ImmutableByteArray)	\
  _do("Character",		Character)		\
  _do("SmallInteger",		SmallInteger)		\
  _do("ImmutableString",	ImmutableString)	\
  _do("Symbol",			Symbol)			\
  _do("UndefinedObject",	UndefinedObject)	\
  _do("WordArray",		WordArray)

#define _do(string, mangled) oop s_##mangled= 0;
 _do_symbols();
#undef _do

ProgramNode::ProgramNode(void)
{
}

oop ProgramNode::compile(void)
{
  oop unit= new TranslationUnit();
  oop stream= unit->outputStream();

# define _do(string, mangled) s_##mangled= new String(string);
  _do_symbols();
# undef _do

  unit->declareGlobal(s_nil);
  unit->declareGlobal(s_true);
  unit->declareGlobal(s_false);

  if (opt_d) print();

  iterate(this, iter)
    {
      if (opt_v) fprintf(stderr, "encode: %s\n", iter.element()->printCString());
      iter.element()->encodeIn(unit);
    }

  if (opt_d) print();

  stream->format("#include \"idst.h\"\n\n");

  iterate(this, iter)
    {
      if (opt_v) fprintf(stderr, "declare: %s\n", iter.element()->printCString());
      iter.element()->genDeclarationIn(unit);
    }

  unit->genDefinitions();

  iterate(this, iter)
    {
      if (opt_v) fprintf(stderr, "implement: %s\n", iter.element()->printCString());
      iter.element()->genImplementationIn(unit);
    }

  stream->format("int main(int argc, char **argv)\n"
		 "{\n"
		 "  _idst_initialise(argc, argv);\n"
		 "  oop self= 0;\n"
		 "  (void)self;\n");

  unit->genInitialisations();

  iterate(this, iter)
    {
      if (opt_v) fprintf(stderr, "initialise: %s\n", iter.element()->printCString());
      iter.element()->genInitialisationIn(unit);
    }

  stream->format("  return 0;\n"
		 "}\n");

  FILE *out= stdout;

  if (opt_o && !(out= fopen(opt_o, "w")))
    {
      perror(opt_o);
      exit(1);
    }
  fprintf(out, "%s", stream->contents()->cString());
  if (opt_o)
    fclose(out);

  //print();

  return this;
}
