/*****
 NAME
 	clangsystem.m - source code for CLangSystem class
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/clangsystem.h>
#include <coconut/clangscope.h>
#include <coconut/ctoken.h>
#include <coconut/cidhash.h>
#include <coconut/ctree.h>
#include <coconut/cconststr.h>
#include <coconut/creal.h>
#include <coconut/cint.h>
#include <coconut/fobject.h>
#include <coconut/ptext.h>

static id <PLangSystem>		s_lang_system = nil ;

/* functions for token or reserved word table */
static guint hash_token(gconstpointer s) ;
static guint hash_rword(gconstpointer s) ;

@implementation CLangSystem

+ (id <PLangSystem>) langSystem
{
	return s_lang_system ;
}

- init
{
	g_assert(s_lang_system == nil) ;
	s_lang_system = self ;
	token_table = [[CIdHash alloc] initIdHash: &hash_token 
	  equalKeyFunc: &equal_object_func removeKeyFunc: &remove_nothing_func];
	rword_table = [[CIdHash alloc] initIdHash: &hash_rword 
	  equalKeyFunc: &equal_object_func removeKeyFunc: &remove_nothing_func];
	scope_tree = [[CTree alloc] init] ;
	g_assert(token_table && rword_table && scope_tree);

	/* add root scope */
	[scope_tree appendChild: [[CLangScope alloc] init]] ;

	return [super init] ;
}

- (void) dealloc
{
	[token_table release] ;
	[rword_table release] ;
	[scope_tree release] ;
	[super dealloc] ;
}

- (id <PToken>) errorToken
{
	static id <PToken> errorToken = nil ;
	if(errorToken == nil){
		errorToken = [CToken newToken] ;
		g_assert(errorToken != nil) ;
		[errorToken setErrorCode: illegal_format_err] ;
	} else {
		[errorToken retain] ;
	}
	return errorToken ;
}

- (id <PToken>) doubleToken: (double) dvalue
{
	id <PToken>	token ;
	id <PToken>	newtoken ;
	id <PNumber> 	number ;

	token = [[CToken alloc] init] ;
	number = [CReal newReal: dvalue] ;
	[token setNumber: number] ;
	if((newtoken = (id <PToken>) [token_table search: token]) == nil){
		[token_table add: token object: token] ;
		newtoken = token ;
	}
	[token release] ;
	[number release] ;
	return newtoken ;
}

- (id <PToken>) intToken: (int) ivalue
{
	id <PToken>	token ;
	id <PToken>	newtoken ;
	id <PNumber> 	number ;

	token = [[CToken alloc] init] ;
	number = [CInt newInt: ivalue format: dec_format] ;
	[token setNumber: number] ;
	if((newtoken = (id <PToken>) [token_table search: token]) == nil){
		[token retain] ;
		[token_table add: token object: token] ;
		newtoken = token ;
	}
	[token release] ;
	[number release] ;
	return newtoken ;
}

- (id <PToken>) strToken: (const utf8_char *) str
{
	id <PToken>	token ;
	id <PToken>	newtoken ;
	id <PConstStr>	cons ;

	token = [[CToken alloc] init] ;
	cons = [CConstStr newConstStr: str] ;
	[token setString: cons] ;
	if((newtoken = (id <PToken>) [token_table search: token]) == nil){
		[token_table add: token object: token] ;
		newtoken = token ;
	}
	[token release] ;
	[cons release] ;
	return newtoken ;
}

- (id <PToken>) identToken: (const utf8_char *) str
{
	id <PToken>	token ;
	id <PToken>	newtoken ;
	id <PConstStr>	cons ;

	token = [[CToken alloc] init] ;
	cons = [CConstStr newConstStr: str] ;
	[token setIdent: cons] ;
	if((newtoken = (id <PToken>) [token_table search: token]) == nil){
		[token_table add: token object: token] ;
		newtoken = token ;
	} 
	[token release] ;
	[cons release] ;
	return newtoken ;
}

- (id <PToken>) addReservedWord: (int) rid name: (const utf8_char *) name
{
	id <PToken>	token ;
	id <PToken>	newtoken ;
	id <PConstStr>	cons ;

	cons = [CConstStr newConstStr: name] ;
	if((newtoken = (id <PToken>) [rword_table search: cons]) == nil){
		token = [[CToken alloc] init] ;
		[token setRWord: rid str: cons] ;
		[rword_table add: cons object: token] ;
		[token release] ;
		newtoken = token ;
	}
	[cons release] ;
	return newtoken ;
}

- (id <PToken>) searchReservedWord: (const char *) text
{
	id <PConstStr>	cons ;
	id <PToken>	token ;
	cons = [CConstStr newConstStr: text] ;
	token = (id <PToken>) [rword_table search: cons] ;
	[cons release] ;
	return token ;
}

- (id <PLangScope>) currentScope
{
	id scope ;
	scope =  [scope_tree currentNode] ;
	return (id <PLangScope>) scope ;
}

- append
{
	id <PLangScope>		scope ;

	scope = [[CLangScope alloc] init] ;
	g_assert(scope != NULL) ;
	[scope_tree appendSibling: scope] ;
	return nil ;
}

- push
{
	id <PLangScope>	scope ;
	scope = [[CLangScope alloc] init] ;
	g_assert(scope != NULL) ;
	[scope_tree appendChild: scope] ;
	return nil ;
}

- pop
{
	[scope_tree removeCurrentNode] ;
	return nil ;
}

#define	STREAM	((id <PIndentStream>) stream)
- print: (id) stream
{
	id result ;
	[STREAM putPtr: "(rword_table\n"] ;
	  [STREAM incLevel] ;
	  result = [rword_table foreach: @selector(print:) with: STREAM 
	    with: NULL] ;
	  g_assert(result == nil) ;
	  [STREAM decLevel] ;
	[STREAM putPtr: ")\n"] ;
	[STREAM putPtr: "(token_table\n"] ;
	  [STREAM incLevel] ;
	  result = [token_table foreach: @selector(print:) with: STREAM 
	    with: NULL] ;
	  g_assert(result == nil) ;
	  [STREAM decLevel] ;
	[STREAM putPtr: ")\n"] ;
	return result ;
}

@end

static guint hash_token(gconstpointer s)
{
	id <PToken>	token = (id <PToken>) s ;
	return [token hashkey] ;
}

static guint hash_rword(gconstpointer s)
{
	id <PConstStr>	str = (id <PConstStr>) s ;
	return [str hashkey] ;
}

