/*****
 NAME
 	ctoken.m - header file for CToken class
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/ctoken.h>
#include <coconut/cerror.h>
#include <coconut/ptext.h>

@implementation CToken

+ (id <PToken>) newToken
{
	id <PToken>	token ;
	token = [[CToken alloc] init] ;
	g_assert(token != nil) ;
	return token ;
}

- init
{
	token_type = unknown_token ;
	return [super init] ;
}

- (void) dealloc
{
	[super dealloc] ;
}

- (token_t) type
{
	return token_type ;
}

- (error_code_t) errorCode
{
	return token_value.error_code ;
}

- (id <PConstStr>) string
{
	return token_value.string_obj ;
}

- (int) rwordId
{
	return token_value.rword.rword_id ;
}

- (id <PConstStr>) rwordStr
{
	return token_value.rword.rword_str ;
}

- (id <PNumber>) number
{
	return token_value.number_obj ;
}

- (id <PConstStr>) ident
{
	return token_value.ident_obj ;
}

- setErrorCode: (error_code_t) code 
{
	token_type = error_token ;
	token_value.error_code = code ;
	return nil ;
}

- setNumber: (id <PNumber>) num
{
	token_type = number_token ;
	token_value.number_obj = num ;
	[num retain] ;
	return nil ;
}

- setString: (id <PConstStr>) str
{
	token_type = string_token ;
	token_value.string_obj = str ;
	[str retain] ;
	return nil ;
}

- setIdent: (id <PConstStr>) str
{
	token_type = ident_token ;
	token_value.ident_obj = str ;
	[str retain] ;
	return nil ;
}

- setRWord: (int) rid str: (id <PConstStr>) str
{
	token_type = rword_token ;
	token_value.rword.rword_id = rid ;
	token_value.rword.rword_str = str ;
	[str retain] ;
	return nil ;
}

#define	INT(V)		((int) V)

- (int) compare: (id <PToken>) src
{
	int	delta ;

	delta = INT(token_type) - INT([src type]) ;
	if(delta != 0)
		return delta ;
	switch(token_type){
	  case unknown_token:
	  	delta = 0 ;
	  break ;
	  case error_token:
	  	delta = INT(token_value.error_code) - INT([src errorCode]) ;
	  break ;
	  case rword_token:
	  	delta = token_value.rword.rword_id - [src rwordId] ;
	  break ;
	  case ident_token:
	  	delta = [token_value.ident_obj compare: [src ident]] ;
	  break ;
	  case number_token:
	  	delta = [token_value.number_obj compare: [src number]] ;
	  break ;
	  case string_token:
	  	delta = [token_value.string_obj compare: [src string]] ;
	  break ;
	  default:
	  	g_warning("ctoken.m, compare: can not happen") ;
		delta = 0 ;
	  break ;
	}
	return delta ;
}

- (u_int) hashkey
{
	u_int	key ;

	switch(token_type){
	  case unknown_token:
	  	key = 0 ;
	  break ;
	  case error_token:
	  	key = INT(token_value.error_code) + 32 ;
	  break ;
	  case rword_token:
	  	key = INT(token_value.rword.rword_id) + 64 ;
	  break ;
	  case ident_token:
	  	key = [token_value.ident_obj hashkey] + 96 ;
	  break ;
	  case number_token:
	  	key = [token_value.number_obj hashkey] + 128 ;
	  break ;
	  case string_token:
	  	key = [token_value.string_obj hashkey] + 160 ;
	  break ;
	  default:
	  	g_warning("ctoken.m, hashkey: can not happen") ;
		key = 0 ;
	  break ;
	}
	return INT(token_type) << 8 | key ;
}

#define	STREAM	((id <PIndentStream>) stream)
- print: (id) stream
{
	[STREAM putFormat: "(token (type %x) ", (int) token_type] ;
	switch(token_type){
	  case unknown_token:
	  	[STREAM putPtr: "(unknown)"] ;
	  break ;
	  case error_token:
	  	[STREAM putFormat: "(error %x)", INT(token_value.error_code)] ;
	  break ;
	  case rword_token:
	  	[STREAM putFormat: "(rword %x)", 
	  	  INT(token_value.rword.rword_id)] ;
	  break ;
	  case ident_token:
	  	[STREAM putFormat: "(ident %s)", [token_value.ident_obj ptr]] ;
	  break ;
	  case number_token:
	  	[STREAM putPtr: "(number "] ;
	  	[token_value.number_obj print: STREAM] ;
		[STREAM putPtr: ")"] ;
	  break ;
	  case string_token:
	  	[STREAM putPtr: "(string \""] ;
	  	[token_value.string_obj print: STREAM] ;
		[STREAM putPtr: "\")"] ;
	  break ;
	  default:
	  	g_warning("ctoken.m, print: can not happen") ;
	  break ;
	}
	[STREAM putChar: ')'] ;
	return nil ;
}

@end

