#include "Node.h"

extern oop s__5fvalue_;
extern oop s_ImmutableString;

//  oop mValue;

StringNode::StringNode(oop value)
{
  mValue= value;
}

oop StringNode::unescape(oop string)
{
  char *in=        string->cString();
  oop   unescaped= new String(in);
  char *out=       unescaped->cString();
  int   c;

  while ((c= *in++))
    switch (c)
      {
      case '\\':
	switch (c= *in++)
	  {
	  case '\0':	string->error("EOF in character/string literal");  break;
	  case  'a': 	c= 0x07;  break;
	  case  'b': 	c= 0x08;  break;
	  case  'e': 	c= 0x1b;  break;
	  case  'f': 	c= 0x0c;  break;
	  case  'n': 	c= 0x0a;  break;
	  case  'r': 	c= 0x0d;  break;
	  case  't': 	c= 0x09;  break;
	  case  'v': 	c= 0x0b;  break;
	  case '\\': 	c= '\\';  break;
	  default:
	    if (('0' <= c) && (c <= '7'))
	      {
		int i, octal= 0;
		for (i= 0;  i < 3;  ++i)
		  {
		    if (('0' <= c) && (c <= '7'))
		      octal= octal * 8 + (c - '0');
		    else if ('\0' == c)
		      string->error("too few digits in octal escape");
		    else
		      string->error("illegal character '%c' in octal escape", c);
		    c= *in++;
		  }
		--in;	// gobbled one too many
		c= octal;
	      }
	  }
	// fall through...

      default:
	*out++= c;
	break;
      }
    
  *out= '\0';
  unescaped->size(out - unescaped->cString());
  return unescaped;
}

oop StringNode::fromString(oop string)
{
  return new StringNode(unescape(string));
}

oop StringNode::encode(oop compiler)
{
  LiteralNode::encode(compiler);
  compiler->translationUnit()->lookupClass(s_ImmutableString);
  compiler->translationUnit()->declareSelector(s__5fvalue_);
  return this;
}

oop StringNode::genInitialisation(oop unit)
{
  oop stream= unit->outputStream();
  unit->outputStream()->format("  l_%d= _bind(v_ImmutableString, s__5fvalue_)(v_ImmutableString, (oop)\"", mTag);
  for (char *ptr= mValue->cString();  *ptr;  ++ptr)
    switch (*ptr)
      {
      case '"':  stream->format("\\\""); continue;	
      default:
	if ((*ptr < 32) || (*ptr == '\\') || (*ptr > 126))
	  stream->format("\\%03o", *ptr);
	else
	  stream->format("%c", *ptr);
      }
  stream->format("\");\n");
  return this;
}

oop StringNode::printOn(oop stream)
{
  stream->format("StringNode(%s)", mValue->cString());
  return this;
}
