/* Copyright (C) 2001 Michael Leonhard
 * Mike Leonhard
 * mike at tamale dot net
 * http://tamale.net/
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "ascorbic.h"

void Particle_Add( struct Particle *particle, struct Particle *child ) {
	int c;
	
	assert( particle );
	assert( particle->childnum > -1 );
	assert( particle->childspace > -1 );
	assert( particle->childnum <= particle->childspace );
	assert( child );
	assert( child->place > -1 );
	assert( child->place >= particle->place );

	/* need more childspace */
	if( particle->childnum == particle->childspace ) {
		particle->childspace *= 2;
		if( particle->childspace == 0 ) particle->childspace = 1;
		particle->child = (struct Particle **)realloc( particle->child, sizeof( struct Particle * ) * particle->childspace );
		assert( particle->child );
		}
	
	/* add particle */
	particle->child[ particle->childnum ] = child;
	particle->childnum++;
	}

void Particle_AddNew( struct Particle *parent, int type, int place ) {
	struct Particle *particle;
	
	assert( type > -1 );
	assert( place > -1 );
	
	particle = Particle_New( type, place );
	assert( particle );
	
	Particle_Add( parent, particle );
	}

void Particle_Free( struct Particle *particle ) {
	int p;
	
	assert( 0 );
	assert( particle );
	
	/* free children */
	Particle_FreeChildren( particle );
	
	/* free child list */
	if( particle->child ) free( particle->child );
	
	/* free particle */
	free( particle );
	}

void Particle_FreeChildren( struct Particle *particle ) {
	int p;
	
	assert( particle );
	
	/* free child particles */
	for( p = 0; p < particle->childnum; p++ ) Particle_Free( particle->child[p] );
		
	/* reset child list */
	particle->childnum = 0;
	}

struct Particle *Particle_New( int type, int place ) {
	struct Particle *particle;
	int p;
	
	assert( type > -1 );
	assert( place > -1 );
	
	/* allocate */
	particle = (struct Particle *)malloc( sizeof( struct Particle ) );
	assert( particle );
	
	/* set */
	particle->type = type;
	particle->place = place;
	particle->data = NULL;
	particle->child = NULL;
	particle->childnum = 0;
	particle->childspace = 0;
	
	return particle;
	}

void Particle_Print( struct Ascorbic *asc, struct Particle *particle, int depth ) {
	int d, p;
	char *name, milk[32];
	
	assert( particle );
	assert( particle->type > -1 );
	assert( particle->place > -1 );
	
	/* indent */
	for( d = 0; d < depth; d++ ) printf( "   " );

	/* find name */
	switch( particle->type ) {
		case vitaminc: name = "vitaminc"; break;
		case statementblock: name = "statementblock"; break;
		case statement: name = "statement"; break;
		case definition: name = "definition"; break;
		case assign: name = "assign"; break;

		case expression: name = "expression"; break;
		case or: name = "or"; break;
		case xor: name = "xor"; break;
		case lsh: name = "lsh"; break;
		case rsh: name = "rsh"; break;
		case gt: name = "gt"; break;
		case lt: name = "lt"; break;
		case equal: name = "equal"; break;
		case subtract: name = "subtract"; break;
		case add: name = "add"; break;
		case multiply: name = "multiply"; break;
		case divide: name = "divide"; break;
	
		case tokenlist: name = "tokenlist"; break;
		case identifier:
			name = (char *)particle->data;
			break;
		case subkeyword: name = "subkeyword"; break;
		case returnkeyword: name = "returnkeyword"; break;
		case intkeyword: name = "intkeyword"; break;
		case floatkeyword: name = "floatkeyword"; break;
		case stringkeyword: name = "stringkeyword"; break;
		case integer:
			snprintf( milk, 31, "integer %d", (int)particle->data );
			milk[31] = 0;
			name = milk;
			break;
		case floatingpoint:
			snprintf( milk, 31, "floatingpoint %f", *(float *)&particle->data );
			milk[31] = 0;
			name = milk;
			break;
		case string:
			snprintf( milk, 31, "string \"%s\"", (char *)particle->data );
			milk[31] = 0;
			name = milk;
			break;
		case colonsymbol: name = "colonsymbol"; break;
		case assignsymbol: name = "assignsymbol"; break;
		case semicolonsymbol: name = "semicolonsymbol"; break;
		case leftparensymbol: name = "leftparensymbol"; break;
		case rightparensymbol: name = "rightparensymbol"; break;
		case orsymbol: name = "orsymbol"; break;
		case xorsymbol: name = "xorsymbol"; break;
		case lshsymbol: name = "lshsymbol"; break;
		case rshsymbol: name = "rshsymbol"; break;
		case gtsymbol: name = "gtsymbol"; break;
		case ltsymbol: name = "ltsymbol"; break;
		case equalsymbol: name = "equalsymbol"; break;
		case subtractsymbol: name = "subtractsymbol"; break;
		case addsymbol: name = "addsymbol"; break;
		case multiplysymbol: name = "multiplysymbol"; break;
		case dividesymbol: name = "dividesymbol"; break;
		case endline: name = "endline"; break;
		default: 
			printf( "unknown particle type %d\n", particle->type );
			assert( 0 );
		}
	
	printf( " - %s at %d\n", name, particle->place );
	
	/* print each child particle */
	for( p = 0; p < particle->childnum; p++ ) Particle_Print( asc, particle->child[p], depth + 1 );
	}
