/****************************************************************************
	Kalkulon - A programmable calculator for programmers

	This file is part of the Kalkulon core.
	
	If you find this source code useful, your are encouraged to use it in your own projects.
	Please give me credit!

	COPYRIGHT by Juergen Holetzeck 2003 - 2008
	e-mail:		contact@kalkulon.de
	homepage:	www.kalkulon.de
****************************************************************************/


// Token.cpp: implementation of the Token class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include <sstream>

#include "DataObject.h"
#include "Token.h"
#include "serialize.h"

using namespace Kalkulon;

////////////////////////////////////////////////////////////////////////////// 
// conversations for tokens
Token::operator std::string()
{
	std::ostringstream os;
	os << *this;
	return os.str();
}


////////////////////////////////////////////////////////////////////////////// 
// output stream operator
std::ostream& operator<< (std::ostream& out, Token& t )
{
	switch(t.tid)
	{
		case Token::DATAOBJECT:
			out << t.data;
			break;
		case Token::FUNC:
		case Token::UNKNOWN:
		case Token::CAST_U08:
		case Token::CAST_U16:
		case Token::CAST_U32:
		case Token::CAST_S08:
		case Token::CAST_S16:
		case Token::CAST_S32:
		case Token::CAST_STRING:
			out << t.token_str;
			break;
		case Token::WHILE:
		case Token::DO:
		case Token::IF:
		case Token::FOR:
			#if _DEBUG
			out << t.token_str << '_' << t.uid;
			#else
			out << t.token_str;
			#endif
			break;
		case Token::NAME:
			out << ((t.token_flags&Token::FLAG_GLOBALSCOPE)? "::" : "") << t.token_str << ((t.token_flags&Token::FLAG_INDEXED)? "[]" : "");
			break;
		case Token::LSNAME:
			out << ((t.token_flags&Token::FLAG_GLOBALSCOPE)? "::" : "") << t.token_str << ((t.token_flags&Token::FLAG_INDEXED)? "[]" : "");
			switch(t.sid)
			{
				case Token::UNKNOWN:
					break;
				case Token::LSHIFT:
					out << "<<";
					break;
				case Token::RSHIFT:
					out << ">>";
					break;
				default:
					out << static_cast<char>(t.sid);
					break;
			}
			out << '=';
			break;
		case Token::LSFUNC:
			#if _DEBUG
			out << t.token_str << '@' << t.token_int << '=' << t.uid;
			#else
			out << t.token_str << "=";
			#endif
			break;
		case Token::INC:
			out << "++";
			break;
		case Token::DEC:
			out << "--";
			break;
		case Token::PREINC:
			out << "++" << ((t.token_flags&Token::FLAG_GLOBALSCOPE)? "::" : "") << t.token_str << ((t.token_flags&Token::FLAG_INDEXED)? "[]" : "");
			break;
		case Token::PREDEC:
			out << "--" << ((t.token_flags&Token::FLAG_GLOBALSCOPE)? "::" : "") << t.token_str << ((t.token_flags&Token::FLAG_INDEXED)? "[]" : "");
			break;
		case Token::POSTINC:
			out << ((t.token_flags&Token::FLAG_GLOBALSCOPE)? "::" : "") << t.token_str << ((t.token_flags&Token::FLAG_INDEXED)? "[]" : "") << "++";
			break;
		case Token::POSTDEC:
			out << ((t.token_flags&Token::FLAG_GLOBALSCOPE)? "::" : "") << t.token_str << ((t.token_flags&Token::FLAG_INDEXED)? "[]" : "") << "--";
			break;
		case Token::LSHIFT:
			out << "<<";
			break;
		case Token::RSHIFT:
			out << ">>";
			break;
		case Token::POW:
			out << "**";
			break;
		case Token::EQUAL:
			out << "==";
			break;
		case Token::NOT_EQUAL:
			out << "!=";
			break;
		case Token::GREATER_EQUAL:
			out << ">=";
			break;
		case Token::LESSER_EQUAL:
			out << "<=";
			break;
		case Token::LOGICAL_AND:
			out << "AND";
			break;
		case Token::LOGICAL_OR:
			out << "OR";
			break;
		case Token::NEG:
			out << "NEG";
			break;
		case Token::DELIM:
			#if _DEBUG
			out << ";" << t.uid;
			#else
			out << ";";
			#endif
			break;
		case Token::END:
			out << "END";
			break;
		case Token::BLOCKEND:
			out << "END_" << t.uid;
			break;
		case Token::LISTEND:
			out << "LIST@" << t.token_int;
			break;
		case Token::INDEXEND:
			out << "INDEX@" << t.token_int;
			break;
		default:
			out << static_cast<char>(t.tid);
			break;
	}
  return out;
}

bool Token::operator!=(const Token& rhs) const
{
  if(this->tid != rhs.tid) return true;
  if(this->sid != rhs.sid) return true;
  if(this->uid != rhs.uid) return true;
  if(this->token_int != rhs.token_int) return true;
  if(this->token_flags != rhs.token_flags) return true;
  if(this->token_str != rhs.token_str) return true;
  if((DATAOBJECT == tid) && (this->data != rhs.data)) return true;
  return false;
}

bool Token::operator==(const Token& rhs) const
{
  return !(rhs != *this);
}

void Token::serialize(std::ostream& os) const
{
  serialize::put(os, (int) tid);
  serialize::put(os, (int) sid);
  serialize::put(os, (int) pos);
  serialize::put(os, (int) uid);
  serialize::put(os, (int) token_int);
  serialize::put(os, (int) token_flags);
  serialize::put(os, token_str);
  if(Token::DATAOBJECT == tid)
    data.serialize(os);
}

Token Token::deserialize(std::istream& is)
{
  Token tok;
  tok.tid = (TokenId) serialize::getInt(is);
  tok.sid = (TokenId) serialize::getInt(is);
  tok.pos = serialize::getInt(is);
  tok.uid = serialize::getInt(is);
  tok.token_int = serialize::getInt(is);
  tok.token_flags = (TokenFlags) serialize::getInt(is);
  tok.token_str = serialize::getString(is);

  if(Token::DATAOBJECT == tok.tid)
    tok.data = DataObject::deserialize(is);

  return tok;
}

