/* assembler.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2009 */

/*

Copyright (c) 2005-2009 Made to Order Software Corp.

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

#include	"assembler.h"


namespace sswf
{
namespace asas
{


//**********************************************************************
//***  PUBLIC ASSEMBLER  ***********************************************
//**********************************************************************
Assembler::Assembler(void)
{
	f_error_stream = &f_default_error_stream;
	f_options = 0;
}

Assembler::~Assembler()
{
}

int Assembler::AssembleClasses(as::NodePtr& program, TagBase& parent, bool& has_actions)
{
	IntAssembler	int_asm(*f_error_stream, *f_options);

	return int_asm.AssembleClasses(program, parent, has_actions);
}


int Assembler::Assemble(as::NodePtr& program, TagBase& tag, Vectors *actions)
{
	IntAssembler	int_asm(*f_error_stream, *f_options);

	return int_asm.Assemble(program, tag, actions);
}


void Assembler::SetErrorStream(as::ErrorStream& error_stream)
{
	f_error_stream = &error_stream;
}



void Assembler::SetOptions(as::Options& options)
{
	f_options = &options;
}




//**********************************************************************
//***  PRIVATE ASSEMBLER  **********************************************
//**********************************************************************
IntAssembler::IntAssembler(as::ErrorStream& error_stream, as::Options& options)
{
	f_error_stream = &error_stream;
	f_options = &options;
	f_parent = 0;
	f_tag = 0;
	f_actions = 0;
	f_try_info = 0;

	//f_registers -- auto-init

	f_label = 0;		// for unique labels
}


IntAssembler::~IntAssembler()
{
}


int IntAssembler::AssembleClasses(as::NodePtr& program, TagBase& parent, bool& has_actions)
{
	f_parent = &parent;
	f_tag = 0;
	f_actions = 0;

//fprintf(stderr, "o AssembleClasses() called\n");
//program.Display(stderr);

	int level = 0;
	has_actions = ListClass(program, level);

	f_parent = 0;
	f_tag = 0;
	f_actions = 0;

	return f_error_stream->ErrCount();
}


bool IntAssembler::ListClass(as::NodePtr& list, int level)
{
	bool has_actions = false;
	int max = list.GetChildCount();
	for(int idx = 0; idx < max; ++idx) {
		as::NodePtr& child = list.GetChild(idx);
		as::Data& data = child.GetData();
		switch(data.f_type) {
		case as::NODE_CLASS:
		case as::NODE_INTERFACE:
			Class(child);
			ListClass(child, level + 1);
			// here ListClass() can't return true so we ignore
			// the result since <whatever> || false is <whatever>
			break;

		case as::NODE_DIRECTIVE_LIST:
			// directive (blocks) don't add a level here
			has_actions = has_actions || ListClass(child, level);
			break;

		case as::NODE_PACKAGE:
			if((data.f_int.Get() & as::NODE_PACKAGE_FLAG_REFERENCED) != 0) {
				has_actions = has_actions || level == 0;
				ListClass(child, level + 1);
			}
			break;

		default:
			has_actions = has_actions || level == 0;
			ListClass(child, level + 1);
			// here ListClass() can't return true so we ignore
			// the result since <whatever> || false is <whatever>
			break;

		}
	}

	return has_actions;
}


void IntAssembler::FunctionClass(DefineClass& define, as::NodePtr& function)
{
	unsigned long attrs = function.GetAttrs();
	if((attrs & (as::NODE_ATTR_FALSE | as::NODE_ATTR_CONSTRUCTOR)) != 0) {
		return;
	}
	if((attrs & (as::NODE_ATTR_UNUSED | as::NODE_ATTR_DYNAMIC)) == as::NODE_ATTR_UNUSED) {
		return;
	}

	define.InsertProp(function);

	as::Data data = function.GetData();

	//	push <prototype register>
	//	push <function name>
	//	push <function>
	//	set member
	if(!define.f_first) {
		f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);
	}
	define.f_first = false;

	ActionPushData *pd = new ActionPushData(f_tag);
	char *str = data.f_str.GetUTF8();
	pd->AddString(str);
	delete [] str;
	f_actions->Insert(-1, pd);

	// second the function
	Function(function, false);

	Action *a = new Action(f_tag, Action::ACTION_SET_MEMBER);
	f_actions->Insert(-1, a);
}


void IntAssembler::VarClass(DefineClass& define, as::NodePtr& var)
{
	ActionPushData	*pd;
	int		idx, j, max, cnt;
	bool		has_set;
	char		*str;

	max = var.GetChildCount();
	for(idx = 0; idx < max; ++idx) {
		as::NodePtr& variable = var.GetChild(idx);
		as::Data& data = variable.GetData();

		define.InsertProp(variable);

		//	push <prototype register>
		//	push <variable name>
		//	push <value> | undefined
		//	set member
		if(!define.f_first) {
			f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);
		}
		define.f_first = false;

		pd = new ActionPushData(f_tag);
		str = data.f_str.GetUTF8();
		pd->AddString(str);
		delete [] str;
		f_actions->Insert(-1, pd);

		// second the content -- note that if there
		// isn't a NODE_SET, then we push undefined.
		has_set = false;
		cnt = variable.GetChildCount();
		for(j = 0; j < cnt; ++j) {
			as::NodePtr& set = variable.GetChild(j);
			as::Data& data = set.GetData();
			if(data.f_type == as::NODE_SET) {
				as::NodePtr& expr = set.GetChild(0);
				Expression(expr);
				has_set = true;
				break;
			}
		}
		if(!has_set) {
			pd = new ActionPushData(f_tag);
			pd->AddUndefined();
			f_actions->Insert(-1, pd);
		}

		Action *a = new Action(f_tag, Action::ACTION_SET_MEMBER);
		f_actions->Insert(-1, a);
	}
}




void IntAssembler::StackClass(DefineClass& define, as::NodePtr& list)
{
	int			idx, max;

	max = list.GetChildCount();
	for(idx = 0; idx < max; ++idx) {
		as::NodePtr& child = list.GetChild(idx);
		as::Data& data = child.GetData();
		switch(data.f_type) {
		case as::NODE_EXTENDS:
		case as::NODE_IMPLEMENTS:
			// we just skip those here...
			break;

		case as::NODE_DIRECTIVE_LIST:
			StackClass(define, child);
			break;

		case as::NODE_FUNCTION:
			FunctionClass(define, child);
			break;

		case as::NODE_VAR:
		case as::NODE_ENUM:
			VarClass(define, child);
			break;

		case as::NODE_CLASS:
		case as::NODE_INTERFACE:
			// sub-classes are managed from outside this loop
			break;

		default:
fprintf(stderr, "INTERNAL ERROR: IntAssembler::StackClass found an unsupported node; type is: %d.\n", data.f_type);
			break;

		}
	}
}



int IntAssembler::UserConstructorClass(as::NodePtr& class_node, const char *class_name, int& count, bool& extends)
{
	unsigned long	attrs;
	int		idx, max, members;
	bool		found;

	members = 0;
	max = class_node.GetChildCount();
	for(idx = 0; idx < max; ++idx) {
		as::NodePtr& child = class_node.GetChild(idx);
		as::Data& data = child.GetData();
		switch(data.f_type) {
		case as::NODE_EXTENDS:
			extends = true;
			break;

		case as::NODE_DIRECTIVE_LIST:
			members += UserConstructorClass(child, class_name, count, extends);
			break;

		case as::NODE_FUNCTION:
			attrs = child.GetAttrs();
			// default constructor?
			found = data.f_str == class_name;
			if(found) {
				child.SetAttrs(attrs | as::NODE_ATTR_CONSTRUCTOR);
			}
			if(!found) {
				// user marked constructor?
				// [not too sure we can support those here?!]
				found = (attrs & as::NODE_ATTR_CONSTRUCTOR) != 0;
			}
			if(found) {
				count++;
				// TODO: user extra constructors...
				// we can't create more than one function
				// for the constructor as far as I know
				// so at this time this looping is wrong
				// and thus we avoid creating more than
				// one function
				if(count == 1) {
					Function(child, false);
				}
			}
			else if((attrs & (as::NODE_ATTR_UNUSED | as::NODE_ATTR_DYNAMIC)) != as::NODE_ATTR_UNUSED) {
				members++;
			}
			break;

		case as::NODE_IMPLEMENTS:
		case as::NODE_CLASS:
		case as::NODE_INTERFACE:
			// these aren't considered members here
			break;

		case as::NODE_VAR:
		case as::NODE_ENUM:
			members += child.GetChildCount();
			break;

		default:
			members++;
			break;

		}
	}

	return members;
}


int IntAssembler::ConstructorClass(as::NodePtr& class_node, const char *class_name)
{
	ActionPushData	*pd;
	Action		*a;
	int		count, members;
	bool		extends;

	count = 0;
	extends = false;
	members = UserConstructorClass(class_node, class_name, count, extends);

	// class needs a default constructor?
	if(count == 0) {
		ActionFunction *func;
		if(extends) {
			func = new ActionFunction(f_tag, Action::ACTION_DECLARE_FUNCTION2);
			func->SetRegistersCount(2);
			func->AddParameter("/this");
			func->AddParameter("/arguments");
			func->AddParameter("super");

			pd = new ActionPushData(f_tag);
			pd->AddInteger(0);
			pd->AddRegister(1);
			pd->AddUndefined();
			func->AddAction(pd);

			a = new Action(f_tag, Action::ACTION_CALL_METHOD);
			func->AddAction(a);

			// NOTE: I would put a RETURN rather than a POP here...
			a = new Action(f_tag, Action::ACTION_POP);
			func->AddAction(a);
		}
		else {
			func = new ActionFunction(f_tag);
		}
		f_actions->Insert(-1, func);
	}

	return members;
}


void IntAssembler::ExtendsClass(as::NodePtr& class_node, const char *class_name)
{
	ActionPushData	*pd;
	Action		*a;
	int		idx, max, j, cnt, count;

	max = class_node.GetChildCount();
	for(idx = 0; idx < max; ++idx) {
		as::NodePtr& extends = class_node.GetChild(idx);
		as::Data& extends_data = extends.GetData();
		if(extends_data.f_type == as::NODE_EXTENDS) {
			//	push "_global"
			//	get variable
			// repeat for each name (parent most first) {
			//	push <class name>
			//	get member
			// }
			//	push <extends expression>
			//	get variable
			//	extends
			pd = new ActionPushData(f_tag);
			pd->AddString("_global");
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);

			// TODO: fix the name! we need to loop on all the
			//	 parent classes to be correct.
			pd = new ActionPushData(f_tag);
			pd->AddString(class_name);
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_GET_MEMBER);
			f_actions->Insert(-1, a);

			Expression(extends.GetChild(0));
			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);

			a = new Action(f_tag, Action::ACTION_EXTENDS);
			f_actions->Insert(-1, a);
			break;
		}
	}

	count = 0;
	for(idx = 0; idx < max; ++idx) {
		as::NodePtr& implements = class_node.GetChild(idx);
		as::Data& implements_data = implements.GetData();
		if(implements_data.f_type == as::NODE_IMPLEMENTS) {
			as::NodePtr& list = implements.GetChild(0);
			as::Data& data = list.GetData();
			if(data.f_type == as::NODE_LIST) {
				cnt = list.GetChildCount();
				for(j = 0; j < cnt; ++j) {
					Expression(list.GetChild(j));
					a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
					f_actions->Insert(-1, a);
				}
				count += cnt;
			}
			else {
				Expression(implements.GetChild(0));
				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
				f_actions->Insert(-1, a);
				count++;
			}
		}
	}

	if(count > 0) {
		// [in the previous for() loop]
		// repeat <count> {
		//	push <implement name>
		// }
		//	push <count>
		//	push "_global"
		//	get variable
		//	push <class name>
		//	get member
		//	implements
		//
		pd = new ActionPushData(f_tag);
		pd->AddInteger(count);
		pd->AddString("_global");
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);

		// TODO: fix the name!
		pd = new ActionPushData(f_tag);
		pd->AddString(class_name);
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_GET_MEMBER);
		f_actions->Insert(-1, a);

		a = new Action(f_tag, Action::ACTION_IMPLEMENTS);
		f_actions->Insert(-1, a);
	}
}


IntAssembler::DefineClass::DefineClass(as::NodePtr& class_node, int prototype, int max)
	: f_class_node(class_node)
{
	f_first = true;
	f_prototype = prototype;
	f_count = 0;
	f_max = max;
	f_prop_flags = new PropFlags[max];
}


IntAssembler::DefineClass::~DefineClass()
{
	delete [] f_prop_flags;
}


void IntAssembler::DefineClass::InsertProp(as::NodePtr& prop)
{
	int		i, j, p, r, flags;

	AS_ASSERT(f_count < f_max);

	// first, we do a SetProp() so we can get the flags
	flags = f_prop_flags[f_count].SetProp(prop);

	// then we quick sort (binary)
	p = 0;
	if(f_count < 4) {
		// slow sort when not enough entries to quick sort
		for(p = 0; p < f_count; ++p) {
			if(flags > f_prop_flags[p].f_flags) {
				break;
			}
		}
	}
	else {
		i = 0;
		j = f_count;
		while(i < j) {
			p = i + (j - i) / 2;
			r = flags - f_prop_flags[p].f_flags;
			if(r == 0) {
				break;
			}
			if(r > 0) {
				p++;
				i = p;
			}
			else {
				j = p;
			}
		}
	}
	if(p != f_count) {
		for(i = f_count; i > p; --i) {
			f_prop_flags[i] = f_prop_flags[i - 1];
		}
		f_prop_flags[p].SetProp(prop);
	}
	f_count++;
}


IntAssembler::PropFlags::PropFlags(void)
{
	f_flags = 0;
	//f_prop -- auto-init
}


int IntAssembler::PropFlags::SetProp(as::NodePtr& prop)
{
	f_prop = prop;
	f_flags = 0;		// because of our copies, when we enter here flags != 0
	as::Data& data = prop.GetData();
	int flags = data.f_int.Get();
	switch(data.f_type) {
	case as::NODE_VARIABLE:
		if((flags & as::NODE_VAR_FLAG_CONST) == 0) {
			f_flags |= ActionFunction::PROP_FLAG_CAN_OVERWRITE;
		}
		break;

	default:
		break;

	}

	unsigned long attrs = prop.GetAttrs();
	if((attrs & as::NODE_ATTR_ENUMERABLE) == 0) {
		f_flags |= ActionFunction::PROP_FLAG_IS_HIDDEN;
	}
	if((attrs & as::NODE_ATTR_DYNAMIC) != 0) {
		f_flags |= ActionFunction::PROP_FLAG_CAN_DELETE;
	}

	return f_flags;
}



void IntAssembler::FlagsClass(DefineClass& define)
{
	ActionPushData	*pd;
	Action		*a;
	int		i, max, count, flags;
	char		*str;

	max = define.f_count;
	if(max == 0) {
		return;
	}

	flags = define.f_prop_flags[0].f_flags;
	for(i = 1; i < max; ++i) {
		if(define.f_prop_flags[i].f_flags != flags) {
			break;
		}
	}

	if(i == max) {
		// all members have the same flags!
		//	push <flags>
		//	push null
		//	push prototype register
		//	push 3
		//	push "ASSetPropFlags"
		//	call function
		//	[pop] -- done outside
		pd = new ActionPushData(f_tag);
		pd->AddInteger(flags);
		pd->AddNull();
		f_actions->Insert(-1, pd);

		f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);

		pd = new ActionPushData(f_tag);
		pd->AddInteger(3);
		pd->AddString("ASSetPropFlags");
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
		f_actions->Insert(-1, a);
	}
	else {
		//	push <flags>
		// repeat {
		//	push <members sharing flags>
		// }
		//	push <count>
		//	declare array
		//	push prototype register
		//	push 3
		//	push "ASSetPropFlags"
		//	call function
		//	[pop] -- done outside
		i = 0;
		while(i < max) {
			flags = define.f_prop_flags[i].f_flags;

			pd = new ActionPushData(f_tag);
			pd->AddInteger(flags);
			f_actions->Insert(-1, pd);

			as::Data& data = define.f_prop_flags[i].f_prop.GetData();

			pd = new ActionPushData(f_tag);
			str = data.f_str.GetUTF8();
			pd->AddString(str);
			delete [] str;
			f_actions->Insert(-1, pd);

			count = 1;
			i++;
			while(i < max && flags == define.f_prop_flags[i].f_flags) {
				as::Data& data = define.f_prop_flags[i].f_prop.GetData();

				pd = new ActionPushData(f_tag);
				str = data.f_str.GetUTF8();
				pd->AddString(str);
				delete [] str;
				f_actions->Insert(-1, pd);

				i++;
				count++;
			}

			pd = new ActionPushData(f_tag);
			pd->AddInteger(count);
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
			f_actions->Insert(-1, a);

			f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);

			pd = new ActionPushData(f_tag);
			pd->AddInteger(3);
			pd->AddString("ASSetPropFlags");
			f_actions->Insert(-1, pd);

			a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
			f_actions->Insert(-1, a);

			if(i < max) {
				a = new Action(f_tag, Action::ACTION_POP);
				f_actions->Insert(-1, a);
			}
		}
	}
}



void IntAssembler::Class(as::NodePtr& class_node)
{
	// TODO: we may want to rename classes too!

	ActionPushData	*pd;
	ActionBranch	*branch;
	ActionLabel	*label;
	Action		*a;
	TagSprite	*sprite;
	TagDoAction	*do_action;
	as::String	l1;
	char		*class_name, *str1;
	int		constructor, prototype, members;

	// A class (object model) is created by creating
	// a sprite and assigning code to it using a
	// DoInitAction.
	sprite = new TagSprite(f_parent);
	do_action = new TagDoAction(f_parent);
	do_action->SetSprite(sprite->Identification());

	f_tag = do_action;
	f_actions = &do_action->Actions();

	Label(l1);
	str1 = l1.GetUTF8();

	as::Data& data = class_node.GetData();
	class_name = data.f_str.GetUTF8();

	//	push _global
	//	get variable
	//	push <class name>
	//	get member
	//	logical not
	//	logical not
	//	if true, goto done
	pd = new ActionPushData(f_tag);
	pd->AddString("_global");
	f_actions->Insert(-1, pd);
	a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
	f_actions->Insert(-1, a);

	pd = new ActionPushData(f_tag);
	char *str = data.f_str.GetUTF8();
	pd->AddString(str);
	delete [] str;
	f_actions->Insert(-1, pd);
	a = new Action(f_tag, Action::ACTION_GET_MEMBER);
	f_actions->Insert(-1, a);

	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
	f_actions->Insert(-1, a);
	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
	f_actions->Insert(-1, a);

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	branch->SetLabel(str1);
	f_actions->Insert(-1, branch);

	//	push "_global"
	//	get variable
	//	push <class name>
	//	<push constructor function>
	//	store reg A	(constructor)
	//	set member
	pd = new ActionPushData(f_tag);
	pd->AddString("_global");
	f_actions->Insert(-1, pd);
	a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
	f_actions->Insert(-1, a);

	pd = new ActionPushData(f_tag);
	pd->AddString(class_name);
	f_actions->Insert(-1, pd);

	// as we insert the constructor(s) we count the number of members
	members = ConstructorClass(class_node, class_name);

	constructor = f_registers.StoreRegister(f_tag, f_actions, false);
	a = new Action(f_tag, Action::ACTION_SET_MEMBER);
	f_actions->Insert(-1, a);

	// Flash first 'extends' and then adds extra members
	// (this call also adds the 'implements')
	ExtendsClass(class_node, class_name);

	//	load reg A
	//	push "prototype"
	//	get member
	//	store reg B	(prototype)
	//	pop
	f_registers.LoadRegister(constructor, false, f_tag, f_actions);
	pd = new ActionPushData(f_tag);
	pd->AddString("prototype");
	f_actions->Insert(-1, pd);
	a = new Action(f_tag, Action::ACTION_GET_MEMBER);
	f_actions->Insert(-1, a);
	prototype = f_registers.StoreRegister(f_tag, f_actions, false);

	// Add all the members and save some info about them
	DefineClass define(class_node, prototype, members);
	StackClass(define, class_node);

	// Now we have a list of members and their flags in define
	FlagsClass(define);

	label = new ActionLabel(f_tag);
	label->SetLabel(str1);
	f_actions->Insert(-1, label);

	// Flash adds the pop after the label, I'd put it before...
	a = new Action(f_tag, Action::ACTION_POP);
	f_actions->Insert(-1, a);

	delete [] class_name;

	f_tag = 0;
	f_actions = 0;
	f_registers.FreeRegister(prototype);
	f_registers.FreeRegister(constructor);
}




int IntAssembler::Assemble(as::NodePtr& program, TagBase& tag, Vectors *actions)
{
	f_tag = &tag;
	f_actions = actions;

//fprintf(stderr, "o Assemble() called\n");
//program.Display(stderr);

	// Now save everything other than classes
	DirectiveList(program, false);

	return f_error_stream->ErrCount();
}



void IntAssembler::DirectiveList(as::NodePtr& list, bool clear)
{
	int max = list.GetChildCount();
	int idx = 0;
	List(list, idx, max);
	if(clear) {
		ClearVariables(list);
	}
}


void IntAssembler::List(as::NodePtr& list, int& from, int to, list_flags_t flags)
{
	//
	// 1. 	we look for declarations (only functions at this time)
	//	we assemble them first
	//
	// 2.	we assemble the rest (i.e. we start over and skip all
	//	the functions)
	//
	// NOTE: Classes and interfaces are not assembled here since these
	//	 are taken cared of in AssembleClasses() instead.
	//

	if((flags & LIST_FLAG_DECLARATIONS) != 0) {
		for(int idx = from; idx < to; ++idx) {
			as::NodePtr& child = list.GetChild(idx);
			as::Data& data = child.GetData();
			switch(data.f_type) {
			case as::NODE_FUNCTION:
				Directive(list, idx, child);
				break;

			default:
				break;

			}
		}
	}

	if((flags & LIST_FLAG_STATEMENTS) != 0) {
		while(from < to) {
			as::NodePtr& child = list.GetChild(from);
			as::Data& data = child.GetData();
			switch(data.f_type) {
			case as::NODE_FUNCTION:
				break;

			default:
				Directive(list, from, child);
				break;

			}
			++from;
		}
		// come back on the last item we worked on
		--from;
	}
}


void IntAssembler::Directive(as::NodePtr& list, int& index, as::NodePtr& child)
{
	as::Data& data = child.GetData();
	switch(data.f_type) {
	case as::NODE_PACKAGE:
		// we do nothing here about packages, that's the IMPORT
		// which forces an assembly of packages
		break;

	case as::NODE_PROGRAM:
	case as::NODE_ROOT:
		DirectiveList(child, false);
		break;

	case as::NODE_DIRECTIVE_LIST:
		DirectiveList(child);
		break;

	case as::NODE_LABEL:
		UserLabel(child);
		break;

	case as::NODE_IF:
		If(child);
		break;

	case as::NODE_FOR:
		For(child);
		break;

	case as::NODE_SWITCH:
		Switch(child);
		break;

	case as::NODE_WHILE:
	case as::NODE_DO:
		While(child);
		break;

	case as::NODE_GOTO:
	case as::NODE_BREAK:
	case as::NODE_CONTINUE:
		Goto(child);
		break;

	case as::NODE_WITH:
		With(child);
		break;

	case as::NODE_THROW:
		Throw(child);
		break;

	case as::NODE_TRY:
		TryCatchFinally(list, index, child);
		break;

	case as::NODE_VAR:
		Var(child);
		break;

	case as::NODE_ASSIGNMENT:
	case as::NODE_ASSIGNMENT_ADD:
	case as::NODE_ASSIGNMENT_BITWISE_AND:
	case as::NODE_ASSIGNMENT_BITWISE_OR:
	case as::NODE_ASSIGNMENT_BITWISE_XOR:
	case as::NODE_ASSIGNMENT_DIVIDE:
	case as::NODE_ASSIGNMENT_LOGICAL_AND:
	case as::NODE_ASSIGNMENT_LOGICAL_OR:
	case as::NODE_ASSIGNMENT_LOGICAL_XOR:
	case as::NODE_ASSIGNMENT_MAXIMUM:
	case as::NODE_ASSIGNMENT_MINIMUM:
	case as::NODE_ASSIGNMENT_MODULO:
	case as::NODE_ASSIGNMENT_MULTIPLY:
	case as::NODE_ASSIGNMENT_POWER:
	case as::NODE_ASSIGNMENT_ROTATE_LEFT:
	case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
	case as::NODE_ASSIGNMENT_SHIFT_LEFT:
	case as::NODE_ASSIGNMENT_SHIFT_RIGHT:
	case as::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
	case as::NODE_ASSIGNMENT_SUBTRACT:
	case as::NODE_CALL:
	case as::NODE_DECREMENT:
	case as::NODE_DELETE:
	case as::NODE_IDENTIFIER:
	case as::NODE_INCREMENT:
	case as::NODE_NEW:
	case as::NODE_POST_DECREMENT:
	case as::NODE_POST_INCREMENT:
		VoidExpression(child);
		break;

	case as::NODE_FUNCTION:
		Function(child, true);
		break;

	case as::NODE_CLASS:
	case as::NODE_INTERFACE:
		// ignored here. is assembled by AssembleClasses() instead.
		break;

	case as::NODE_RETURN:
		Return(child);
		break;

	case as::NODE_ENUM:
		// enums are like lists of variables
		Var(child);
		break;

	case as::NODE_CATCH:		// assembled in TryCatchFinally()
	case as::NODE_FINALLY:		// assembled in TryCatchFinally()
	case as::NODE_CASE:
	case as::NODE_DEFAULT:
		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, child, "token '%s' (catch, finally, case or default) found in IntAssembler::Directive().", data.GetTypeName());
		break;

	default:
		// at this time, do nothing with any other node
		f_error_stream->ErrMsg(as::AS_ERR_NOT_SUPPORTED, child, "token '%s' not handled yet in IntAssembler::Directive().", data.GetTypeName());
		break;

	}
}


void IntAssembler::ClearVariables(as::NodePtr& frame)
{
	// clear all the variables of this list
	// (the order should not matter until we implement
	// a working callback feature on the destructions
	// of objects -- unless that already works in
	// Flash?)
	int max = frame.GetVariableCount();
	for(int idx = 0; idx < max; ++idx) {
		as::NodePtr& variable = frame.GetVariable(idx);

		as::Data& data = variable.GetData();
		int flags = data.f_int.Get();
		if((flags & as::NODE_VAR_FLAG_INUSE) == 0) {
			continue;
		}

		unsigned long attrs = variable.GetAttrs();
		if((attrs & (as::NODE_ATTR_INTRINSIC | as::NODE_ATTR_DYNAMIC)) == 0) {
			ActionPushData *pd = new ActionPushData(f_tag);
			pd->AddUndefined();
			f_actions->Insert(-1, pd);

			as::NodePtr name;
			Assignment(name, variable, false);
		}
	}
}


void IntAssembler::UserLabel(as::NodePtr& user_label)
{
	ActionLabel	*label;
	char		*str;

	as::Data& data = user_label.GetData();

	str = data.f_str.GetUTF8();

	label = new ActionLabel(f_tag);
	label->SetLabel(str);
	f_actions->Insert(-1, label);

	delete [] str;
}


void IntAssembler::If(as::NodePtr& if_node)
{
	ActionLabel	*label;
	ActionBranch	*branch;
	Action		*a;
	as::String	l1, l2;
	char		*str1, *str2;
	bool		add_not;
	int		max;

	// NOTE: the optimizer already optimize 'if' nodes
	// to what they need to be when the condition is
	// already known to be true or false; so we don't
	// have to test that here.
	max = if_node.GetChildCount();
	add_not = true;
	as::NodePtr& condition = if_node.GetChild(0);
	as::Data& data = condition.GetData();
	if(max == 2 && data.f_type == as::NODE_LOGICAL_NOT) {
		// avoid a double not if(!!a) [that's because
		// we only have one conditional branch in Flash!]
		Expression(condition.GetChild(0));
		add_not = false;
	}
	else {
		Expression(condition);
	}

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	Label(l1);
	str1 = l1.GetUTF8();
	branch->SetLabel(str1);

	if(max == 2) {
		if(add_not) {
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
		}

		f_actions->Insert(-1, branch);

		DirectiveList(if_node.GetChild(1));

		label = new ActionLabel(f_tag);
		label->SetLabel(str1);
		f_actions->Insert(-1, label);
	}
	else {
		f_actions->Insert(-1, branch);

		// note that the branch is inverted!
		// so we include the else part first
		DirectiveList(if_node.GetChild(2));

		branch = new ActionBranch(f_tag);
		Label(l2);
		str2 = l2.GetUTF8();
		branch->SetLabel(str2);
		f_actions->Insert(-1, branch);

		label = new ActionLabel(f_tag);
		label->SetLabel(str1);
		f_actions->Insert(-1, label);

		DirectiveList(if_node.GetChild(1));

		label = new ActionLabel(f_tag);
		label->SetLabel(str2);
		f_actions->Insert(-1, label);

		delete [] str2;
	}

	delete [] str1;
}



void IntAssembler::EmptyEnumeration(void)
{
	ActionPushData	*pd;
	ActionBranch	*branch;
	ActionLabel	*label;
	Action		*a;
	as::String	l;
	char		*str;

	// label l
	// push null
	// strictly equal
	// logical not
	// if true, goto l

	Label(l);
	str = l.GetUTF8();

	label = new ActionLabel(f_tag);
	label->SetLabel(str);
	f_actions->Insert(-1, label);

	pd = new ActionPushData(f_tag);
	pd->AddNull();
	f_actions->Insert(-1, pd);

	a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
	f_actions->Insert(-1, a);

	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
	f_actions->Insert(-1, a);

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	branch->SetLabel(str);
	f_actions->Insert(-1, branch);

	delete [] str;
}


void IntAssembler::For(as::NodePtr& for_node)
{
	ActionPushData	*pd;
	ActionBranch	*branch;
	ActionLabel	*label;
	Action		*a;
	as::String	l1, l2;
	char		*str1, *str2, *str3;
	int		reg, max;

	// NOTE: The for node will have one entry per expression
	//	 in the for parenthesis plus the list of directives.
	//	 This means the for is a C/C++ like for when there
	//	 are 4 entries and it is a for each when there are
	//	 3 entries

	LoopData *wd = GetLoopData(for_node);
	Label(wd->f_continue);
	str3 = wd->f_continue.GetUTF8();

	max = for_node.GetChildCount();

	Label(l1);
	str1 = l1.GetUTF8();
	Label(l2);
	str2 = l2.GetUTF8();

	if(max == 3) {
		// TODO: this version is not exception safe?!
		//	 the stack will be a big mess in case of an exception
		//	 (or will the system exception handling take care of
		//	 the stack for us?!)
		//
		// for(var name in object) ...
		//	(if var used init variable[s])
		//	push object name
		//	enumerate object
		//	label repeat
		//	store reg
		//	push null
		//	strictly equal
		//	if true -> done
		//	load reg
		//	push variable name
		//	set variable
		//	*directive list*
		//	goto repeat
		//		(if there is a break)
		//		label break
		//		empty stack (see EmptyEnumeration();)
		//	label done

		// Init
		as::NodePtr& variable = for_node.GetChild(0);
		as::NodePtr& object = for_node.GetChild(1);
		as::NodePtr& list = for_node.GetChild(2);
		as::Data& for_data = for_node.GetData();
		bool for_each = (for_data.f_int.Get() & as::NODE_FOR_FLAG_FOREACH) != 0;

		as::Data& variable_data = variable.GetData();

		if(variable_data.f_type == as::NODE_VAR) {
			// init here
			Var(variable);
		}

		// Generate Code
		Expression(object);

		a = new Action(f_tag, Action::ACTION_ENUMERATE_OBJECT);
		f_actions->Insert(-1, a);

		label = new ActionLabel(f_tag);
		label->SetLabel(str1);
		f_actions->Insert(-1, label);

		label = new ActionLabel(f_tag);
		label->SetLabel(str3);
		f_actions->Insert(-1, label);

		reg = f_registers.StoreRegister(f_tag, f_actions, false);

		pd = new ActionPushData(f_tag);
		pd->AddNull();
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
		f_actions->Insert(-1, a);

		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
		branch->SetLabel(str2);
		f_actions->Insert(-1, branch);

		if(for_each) {
			Expression(object);
		}
		f_registers.LoadRegister(reg, false, f_tag, f_actions);
		if(for_each) {
			// TODO: What happens if the member is a method?
			//	 Do we get a valid reference?!
			a = new Action(f_tag, Action::ACTION_GET_MEMBER);
			f_actions->Insert(-1, a);
		}

		if(variable_data.f_type == as::NODE_VAR) {
			as::NodePtr& instance = variable.GetChild(variable.GetChildCount() - 1);
			Assignment(variable, instance, false);
		}
		else {
			as::NodePtr instance;
			Assignment(variable, instance, false);
		}

		DirectiveList(list);

		branch = new ActionBranch(f_tag);
		branch->SetLabel(str1);
		f_actions->Insert(-1, branch);

		if(!wd->f_break.IsEmpty()) {
			// found a 'break' statement add its label
			// and the emptying of the stack
			label = new ActionLabel(f_tag);
			delete [] str1;
			str1 = wd->f_break.GetUTF8();
			label->SetLabel(str1);
			f_actions->Insert(-1, label);

			EmptyEnumeration();
		}

		label = new ActionLabel(f_tag);
		label->SetLabel(str2);
		f_actions->Insert(-1, label);

		f_registers.FreeRegister(reg);
	}
	else {
		AS_ASSERT(max == 4);
		// for(init; condition; next) ...
		//
		//	*void expression init*
		//	goto l2
		//	label l1
		//	*list*
		//	label l3 (continue)
		//	*void expression next*
		//	label l2
		//	*expression condition*
		//	if true, goto l1
		//
		// If the condition is empty, then it is a loop forever
		// type of loop and thus we don't need label l2 and the
		// if true becomes a branch as follow:
		//
		//	*void expression init*
		//	label l1
		//	*list*
		//	*void expression next*
		//	branch l1
		//
		// Note: The initialization expression may also be a
		//	 list of variables or be empty.
		//
		//	 The next expression can be empty in which case
		//	 we simply don't insert anything for it. In effect,
		//	 a for(;;) becomes the simplified loop:
		//
		//	 label l1
		//	 *list*
		//	 branch l1
		//

		// Init
		as::NodePtr& init = for_node.GetChild(0);
		as::NodePtr& cond = for_node.GetChild(1);
		as::NodePtr& next = for_node.GetChild(2);
		as::NodePtr& list = for_node.GetChild(3);

		as::Data& init_data = init.GetData();
		as::Data& cond_data = cond.GetData();
		as::Data& next_data = next.GetData();

		if(init_data.f_type != as::NODE_EMPTY) {
			if(init_data.f_type == as::NODE_VAR) {
				Var(init);
			}
			else {
				VoidExpression(init);
			}
		}

		if(cond_data.f_type != as::NODE_EMPTY) {
			branch = new ActionBranch(f_tag);
			branch->SetLabel(str2);
			f_actions->Insert(-1, branch);
		}

		label = new ActionLabel(f_tag);
		label->SetLabel(str1);
		f_actions->Insert(-1, label);

		DirectiveList(list);

		label = new ActionLabel(f_tag);
		label->SetLabel(str3);
		f_actions->Insert(-1, label);

		if(next_data.f_type != as::NODE_EMPTY) {
			VoidExpression(next);
		}

		if(cond_data.f_type != as::NODE_EMPTY) {
			label = new ActionLabel(f_tag);
			label->SetLabel(str2);
			f_actions->Insert(-1, label);

			Expression(cond);

			branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
			branch->SetLabel(str1);
			f_actions->Insert(-1, branch);
		}
		else {
			branch = new ActionBranch(f_tag);
			branch->SetLabel(str1);
			f_actions->Insert(-1, branch);
		}

		if(!wd->f_break.IsEmpty()) {
			// found a 'break' statement add its label
			label = new ActionLabel(f_tag);
			str1 = wd->f_break.GetUTF8();
			label->SetLabel(str1);
			delete [] str1;
			f_actions->Insert(-1, label);
		}
	}

	delete [] str1;
	delete [] str2;
	delete [] str3;
}



void IntAssembler::Switch(as::NodePtr& switch_node)
{
	ActionBranch	*branch;
	ActionLabel	*label;
	switch_info_t	info;
	int		idx, max;
	char		*str1, *str2;

// TODO: Gee's!! Did I write that?! Simplify the branches?
//
//	 I really need to fix all of these branches which are
//	 not too sensical; though out future lower level optimizer
//	 will take care of that, it is often a good idea to do
//	 clean up in the generator first!
//

	// switch(expr) with(operator) { case ...: ... }
	//	push expr
	//	store reg
	// for each case
	//	push case expr
	//	load reg
	//	[compare with specified operator]
	//	logical not
	//	branch if true next case
	//	[statements]
	//	branch to next case statements [unless continue or break]
	//	label next case
	// repeat case statements
	//
	// case of default is like case without test
	//

	info.f_attrs = switch_node.GetAttrs();

	Expression(switch_node.GetChild(0));
	info.f_reg = f_registers.StoreRegister(f_tag, f_actions, true);

	info.f_loop_data = GetLoopData(switch_node);

	Label(info.f_loop_data->f_break);
	str2 = info.f_loop_data->f_break.GetUTF8();

	bool no_autobreak = false;
	as::NodePtr& list = switch_node.GetChild(1);
	max = list.GetChildCount();

	idx = 0;
	List(list, idx, max, LIST_FLAG_DECLARATIONS);

	for(idx = 0; idx < max; ++idx) {
		as::NodePtr& child = list.GetChild(idx);
		as::Data& data = child.GetData();
fprintf(stderr, "Case Child type %d\n", data.f_type);
		switch(data.f_type) {
		case as::NODE_CASE:
			Case(switch_node, child, info, no_autobreak);
			no_autobreak = true;
			break;

		case as::NODE_DEFAULT:
			Default(info);
			no_autobreak = true;
			break;

		default:
			// a [regular] statement
			List(list, idx, idx + 1, LIST_FLAG_STATEMENTS);
			no_autobreak = false;
			break;

		}
	}

	if(!info.f_default_label.IsEmpty()) {
		branch = new ActionBranch(f_tag);
		branch->SetLabel(str2);
		f_actions->Insert(-1, branch);
	}

	// the last case/default label will jump here if
	// none were true; and then we can jump to the
	// default label if there is one
	label = new ActionLabel(f_tag);
	str1 = info.f_loop_data->f_continue.GetUTF8();
	label->SetLabel(str1);
	delete [] str1;
	f_actions->Insert(-1, label);

	if(!info.f_default_label.IsEmpty()) {
		branch = new ActionBranch(f_tag);
		str1 = info.f_default_label.GetUTF8();
		branch->SetLabel(str1);
		delete [] str1;
		f_actions->Insert(-1, branch);
	}

	label = new ActionLabel(f_tag);
	label->SetLabel(str2);
	f_actions->Insert(-1, label);

	delete [] str2;
}


void IntAssembler::Case(as::NodePtr& switch_node, as::NodePtr& case_node, switch_info_t& info, bool no_autobreak)
{
	ActionBranch	*branch;
	ActionLabel	*label;
	Action		*a;
	as::String	skip_test;
	int		op;
	char		*str1, *str2;

	str2 = 0;
	if(!info.f_loop_data->f_continue.IsEmpty()) {
//fprintf(stderr, "Flags (1) %d, (2) %d\n", info.f_attrs & as::NODE_ATTR_AUTOBREAK, no_autobreak);
		if((info.f_attrs & as::NODE_ATTR_AUTOBREAK) != 0 && !no_autobreak) {
			branch = new ActionBranch(f_tag);
			str1 = info.f_loop_data->f_break.GetUTF8();
			branch->SetLabel(str1);
			delete [] str1;
			f_actions->Insert(-1, branch);
		}
		else if((info.f_attrs & as::NODE_ATTR_FOREACH) == 0) {
			Label(skip_test);
			str2 = skip_test.GetUTF8();

			branch = new ActionBranch(f_tag);
			branch->SetLabel(str2);
			f_actions->Insert(-1, branch);
		}

		// save our label
		label = new ActionLabel(f_tag);
		str1 = info.f_loop_data->f_continue.GetUTF8();
		label->SetLabel(str1);
		delete [] str1;
		f_actions->Insert(-1, label);
	}

	// define the next case label right now
	Label(info.f_loop_data->f_continue);
	str1 = info.f_loop_data->f_continue.GetUTF8();

	int max = case_node.GetChildCount();
	if(max == 2) {
		// a range! we assume the operator is proper
		//	load reg
		//	push lower bound
		//	less_than
		//	branch_if_true skip_case
		//	load reg
		//	push higher bound
		//	greater_than
		//	branch_if_true skip_case

		f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
		Expression(case_node.GetChild(0));
		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
		f_actions->Insert(-1, a);

		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
		branch->SetLabel(str1);
		f_actions->Insert(-1, branch);

		f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
		Expression(case_node.GetChild(1));
		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
		f_actions->Insert(-1, a);
	}
	else {
		// a single expression, we need to use the user specified
		// operator to compare the two expressions
		f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
		Expression(case_node.GetChild(0));

		as::Data& switch_data = switch_node.GetData();
		op = switch_data.f_int.Get() & as::NODE_MASK;
		switch(op) {
		case as::NODE_UNKNOWN:	// default
		case as::NODE_DEFAULT:	// user defining the default...
		case as::NODE_STRICTLY_EQUAL:
			a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_STRICTLY_NOT_EQUAL:
			a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_EQUAL:
			a = new Action(f_tag, Action::ACTION_EQUAL);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_NOT_EQUAL:
			a = new Action(f_tag, Action::ACTION_EQUAL);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_INSTANCEOF:
		case as::NODE_IS:
			a = new Action(f_tag, Action::ACTION_INSTANCE_OF);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_GREATER:
			a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_GREATER_EQUAL:
			a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_LESS:
			a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_LESS_EQUAL:
			a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_AS:
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_CAST_OBJECT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_IN:
			f_error_stream->ErrMsg(as::AS_ERR_INVALID_EXPRESSION, switch_node, "the 'in' operator when used in a 'switch' statement expects cases to only use ranges.");
			break;

		case as::NODE_MATCH:
		default:
			f_error_stream->ErrMsg(as::AS_ERR_NOT_SUPPORTED, switch_node, "operator (%d) not yet implemented in IntAssembler::Case().", op);
			break;

		}
	}

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	branch->SetLabel(str1);
	f_actions->Insert(-1, branch);

	delete [] str1;

	if(str2 != 0) {
		label = new ActionLabel(f_tag);
		label->SetLabel(str2);
		f_actions->Insert(-1, label);

		delete [] str2;
	}
}


void IntAssembler::Default(switch_info_t& info)
{
	ActionBranch	*branch;
	ActionLabel	*label;
	as::String	skip_test;
	char		*str1, *str2;

	str2 = 0;
	if(!info.f_loop_data->f_continue.IsEmpty()) {
		if((info.f_attrs & as::NODE_ATTR_AUTOBREAK) != 0) {
			branch = new ActionBranch(f_tag);
			str1 = info.f_loop_data->f_break.GetUTF8();
			branch->SetLabel(str1);
			delete [] str1;
			f_actions->Insert(-1, branch);
		}
		/*
		else if((info.f_attrs & as::NODE_ATTR_FOREACH) == 0) {
			Label(skip_test);
			str2 = skip_test.GetUTF8();

			branch = new ActionBranch(f_tag);
			branch->SetLabel(str2);
			f_actions->Insert(-1, branch);
		}
		*/

		Label(skip_test);
		str2 = skip_test.GetUTF8();

		branch = new ActionBranch(f_tag);
		branch->SetLabel(str2);
		f_actions->Insert(-1, branch);

		// save our label
		label = new ActionLabel(f_tag);
		str1 = info.f_loop_data->f_continue.GetUTF8();
		label->SetLabel(str1);
		delete [] str1;
		f_actions->Insert(-1, label);
	}

	// define the next case label right now
	Label(info.f_loop_data->f_continue);
	str1 = info.f_loop_data->f_continue.GetUTF8();

	branch = new ActionBranch(f_tag);
	branch->SetLabel(str1);
	f_actions->Insert(-1, branch);

	delete [] str1;

	// create a label for the default statements
	Label(info.f_default_label);

	label = new ActionLabel(f_tag);
	str1 = info.f_default_label.GetUTF8();
	label->SetLabel(str1);
	delete [] str1;
	f_actions->Insert(-1, label);

	if(str2 != 0) {
		label = new ActionLabel(f_tag);
		label->SetLabel(str2);
		f_actions->Insert(-1, label);

		delete [] str2;
	}
}



IntAssembler::LoopData *IntAssembler::GetLoopData(as::NodePtr& while_node)
{
	LoopData	**p;

	as::Data& data = while_node.GetData();
	if(data.f_user_data.Size() == 0) {
		data.f_user_data.New((sizeof(LoopData *) + sizeof(int) - 1) / sizeof(int));
		p = reinterpret_cast<LoopData **>(data.f_user_data.Buffer());
		p[0] = new LoopData;
	}
	else {
		p = reinterpret_cast<LoopData **>(data.f_user_data.Buffer());
	}

	return p[0];
}



void IntAssembler::While(as::NodePtr& while_node)
{
	ActionLabel	*label;
	ActionBranch	*branch;
	as::String	l1, l2;
	char		*str1, *str2;
	int		order;

	Label(l1);
	str1 = l1.GetUTF8();

	as::Data& data = while_node.GetData();
	if(data.f_type == as::NODE_WHILE) {
		branch = new ActionBranch(f_tag);
		branch->SetLabel(str1);
		f_actions->Insert(-1, branch);
		order = 1;
	}
	else {
		order = 0;
	}

	Label(l2);
	str2 = l2.GetUTF8();
	label = new ActionLabel(f_tag);
	label->SetLabel(str2);
	f_actions->Insert(-1, label);

	// save the continue label by default; if
	// we need a break label, it will be created
	// by the assembler if it finds a break node
	LoopData *wd = GetLoopData(while_node);
	wd->f_continue = l1;

	DirectiveList(while_node.GetChild(order));

	label = new ActionLabel(f_tag);
	label->SetLabel(str1);
	f_actions->Insert(-1, label);

	Expression(while_node.GetChild(order ^ 1));

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	branch->SetLabel(str2);
	f_actions->Insert(-1, branch);

	delete [] str1;
	delete [] str2;

	if(!wd->f_break.IsEmpty()) {
		// found a 'break' statement add its label
		label = new ActionLabel(f_tag);
		str1 = wd->f_break.GetUTF8();
		label->SetLabel(str1);
		delete [] str1;
		f_actions->Insert(-1, label);
	}
}




//
// The GOTO, BREAK and CONTINUE statements all work the same way.
//
// The GOTO has two parts: going out of the current frames and then
// in a new set of frames. The BREAK and CONTINUE only go out of
// the current frame by default. Whenever, the BREAK and CONTINUE
// have a label, they may get out of more than one frame.
//
// What is complicated in the implementation of this instruction
// is the exiting and entering of frames which are blocks which
// can't be broken up. There is currently the following blocks we
// have to deal with:
//
// 	. WITH		to exit a WITH, you need to goto at the
// 			end of the with first; then, once exited,
// 			you need to test a variable to know what
// 			you have to do; this means up to one test
//			per GOTO, BREAK and CONTINUE within a WITH
//			to exit it.
//
//	. TRY		the TRY block is similar to the WITH except
//			that the finally part will always be executed;
//			so the TRY block itself stops at the point
//			where the GOTO, BREAK or CONTINUE is found and
//			then the process goes in the FINALLY; once the
//			FINALLY is over, it tests a variable to know
//			where the GOTO, BREAK or CONTINUE needs to go
//
//	. CATCH		the CATCH is the same as the TRY, it will have
//			to execute the instructions in the FINALLY
//			before to go on; there can't be a GOTO, BREAK
//			or CONTINUE already in action when the CATCH
//			is being executed
//
//	. FINALLY	the FINALLY is like the WITH block; it just
//			needs to be exited and once exited, the code
//			after will determine the destination; however,
//			there is a run-time error to check: if the
//			user already was in a GOTO, BREAK or CONTINUE
//			from the corresponding TRY or CATCH, then the
//			process needs to generate an error because it
//			can't continue at two places (note that this
//			error may be caught by the compiler if the
//			compiler can see that it will obviously not
//			work, the run time error will be a throw)
//
void IntAssembler::Goto(as::NodePtr& goto_node)
{
// first we need to get out of the current frame(s) up to the
// top frame which also includes the destination frame; if that
// works (it always should) then we can enter the destination
// frame (only GOTOs enter other frames)
	if(ExitFrame(goto_node)) {
		EnterFrame(goto_node);
	}
}


bool IntAssembler::ExitFrame(as::NodePtr& goto_node)
{
	ActionBranch	*branch;
	char		*str;
	bool		end;

	as::Data& goto_data = goto_node.GetData();

	as::NodePtr parent = goto_node;
	as::NodePtr& exit = goto_node.GetLink(as::NodePtr::LINK_GOTO_EXIT);
	for(;;) {
		parent = parent.GetParent();
		if(!parent.HasNode()) {
			// this should not happen
			return false;
		}

		// are we on that last frame?
		end = exit.SameAs(parent);

		as::Data& data = parent.GetData();
		switch(data.f_type) {
		case as::NODE_WHILE:
		case as::NODE_FOR:
		case as::NODE_DO:
		case as::NODE_SWITCH:
			if(end) {
				LoopData *wd = GetLoopData(parent);
				switch(goto_data.f_type) {
				case as::NODE_CONTINUE:
					// continue MUST already be defined
					branch = new ActionBranch(f_tag);
					str = wd->f_continue.GetUTF8();
					branch->SetLabel(str);
					delete [] str;
					f_actions->Insert(-1, branch);
					break;

				case as::NODE_BREAK:
					// the break may not already be
					// defined; do it if necessary
					if(wd->f_break.IsEmpty()) {
						Label(wd->f_break);
					}
					branch = new ActionBranch(f_tag);
					str = wd->f_break.GetUTF8();
					branch->SetLabel(str);
					delete [] str;
					f_actions->Insert(-1, branch);
					break;

				default:
					// in case of a goto, we don't
					// have to do anything here
					break;

				}
			}
			else if(data.f_type == as::NODE_FOR) {
				if(parent.GetChildCount() == 3) {
					// ha! this is an enumeration
					// we need to remove the data
					// from the stack
					EmptyEnumeration();
				}
			}
			// else do nothing; the do/while loops don't
			// save anything which would need to be released
			// when a goto goes through
			break;

		case as::NODE_DIRECTIVE_LIST:
			if(!end) {
				ClearVariables(parent);
			}
			break;

		case as::NODE_WITH:
		case as::NODE_TRY:
		case as::NODE_CATCH:
		case as::NODE_FINALLY:
fprintf(stderr, "INTERNAL ERROR: going through a WITH, TRY, CATCH & FINALLY not supported yet with GOTO, BREAK and CONTINUE.\n");
			AS_ASSERT(0);
			break;

		default:
			break;

		}

		if(end) {
			return true;
		}
	}
	/*NOTREACHED*/
	AS_ASSERT(0);
	return false;
}

void IntAssembler::EnterFrame(as::NodePtr& goto_node)
{
	ActionBranch	*branch;
	char		*str;
	bool		end;

	as::Data& goto_data = goto_node.GetData();
	if(goto_data.f_type != as::NODE_GOTO) {
		return;
	}

	str = goto_data.f_str.GetUTF8();

	as::NodePtr& exit = goto_node.GetLink(as::NodePtr::LINK_GOTO_EXIT);
	as::NodePtr parent = goto_node.GetLink(as::NodePtr::LINK_GOTO_ENTER);
	for(;;) {
		parent = parent.GetParent();
		if(!parent.HasNode()) {
			// this should not happen
			break;
		}

		// are we on that last frame?
		end = exit.SameAs(parent);

		as::Data& data = parent.GetData();
		switch(data.f_type) {
		case as::NODE_WITH:
		case as::NODE_TRY:
		case as::NODE_CATCH:
		case as::NODE_FINALLY:
fprintf(stderr, "INTERNAL ERROR: WITH, TRY, CATCH & FINALLY not supported yet with GOTO, BREAK and CONTINUE.\n");
			AS_ASSERT(0);
			break;

		default:
			break;

		}

		if(end) {
			branch = new ActionBranch(f_tag);
			branch->SetLabel(str);
			f_actions->Insert(-1, branch);
			break;
		}
	}

	delete [] str;
}



void IntAssembler::With(as::NodePtr& with)
{
	Expression(with.GetChild(0));

	ActionWith *w = new ActionWith(f_tag);
	f_actions->Insert(-1, w);

	Vectors *current = f_actions;
	f_actions = w->SubList();

	DirectiveList(with.GetChild(1));

	f_actions = current;
}


void IntAssembler::Throw(as::NodePtr& throw_node)
{
	Expression(throw_node.GetChild(0));

	Action *a = new Action(f_tag, Action::ACTION_THROW);
	f_actions->Insert(-1, a);
}


void IntAssembler::TryCatchFinally(as::NodePtr& list, int& index, as::NodePtr& try_node)
{
	try_info_t	info, *save_try_info;
	int		max;
	bool		is_last;

	save_try_info = f_try_info;
	f_try_info = &info;

	Try(info, try_node);

	max = list.GetChildCount();
	while(index + 1 < max) {
		as::NodePtr& next = list.GetChild(index + 1);
		as::Data& data = next.GetData();
		switch(data.f_type) {
		case as::NODE_CATCH:
			if(index + 2 < max) {
				as::NodePtr& after = list.GetChild(index + 2);
				as::Data& data = after.GetData();
				is_last = data.f_type != as::NODE_CATCH;
			}
			else {
				is_last = true;
			}
			Catch(info, next, is_last);
			break;

		case as::NODE_FINALLY:
			Finally(info, next);
			break;

		default:
			goto exit;

		}
		++index;
	}
exit:
	// release this register for others
	f_registers.FreeRegister(info.f_reg);

	// restore the previous try info
	f_try_info = save_try_info;
}


void IntAssembler::Try(try_info_t& info, as::NodePtr& try_node)
{
	info.f_try = new ActionTry(f_tag);
	f_actions->Insert(-1, info.f_try);

	Vectors *save_actions = f_actions;
	f_actions = info.f_try->SubListTry();
	DirectiveList(try_node.GetChild(0));
	f_actions = save_actions;
}


void IntAssembler::Catch(try_info_t& info, as::NodePtr& catch_node, bool is_last)
{
	ActionBranch	*branch;
	ActionPushData	*pd;
	ActionLabel	*label;
	Action		*a;
	as::String	l;
	char		*str, buf[256];

	Vectors *save_actions = f_actions;
	f_actions = info.f_try->SubListCatch();

	if(info.f_reg < 0 && info.f_regname.GetLength() == 0) {
		Label(info.f_end);
		info.f_str = info.f_end.GetUTF8();
		// avoid using reg 0 for the catch
		info.f_reg = f_registers.AllocRegister(1);
		if(info.f_reg < 0) {
			snprintf(buf, sizeof(buf), "__c%d", f_label);
			f_label++;
			info.f_regname = buf;
			info.f_try->SetIdentifier(buf);
			info.f_regname_str = info.f_regname.GetUTF8();
		}
		else {
			info.f_try->SetIdentifier(info.f_reg);
		}
	}

	// NOTE: - Should we clear the f_catch_reg if we
	//	   enter a catch(...)?
	//	 - It most certainly won't matter since it
	//	   shouldn't be referenced in the block of
	//	   directives.

	str = 0;
	as::Data& data = catch_node.GetData();
	if((data.f_int.Get() & as::NODE_CATCH_FLAG_TYPED) != 0) {
		//	push catch reg
		//	push expression type
		//	instance of
		//	logical not
		//	branch if true, goto skip
		//	<catch instructions>
		//	branch, goto end
		// skip:
		if(info.f_reg >= 0) {
			f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
		}
		else {
			pd = new ActionPushData(f_tag);
			pd->AddString(info.f_regname_str);
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);
		}
		as::NodePtr& parameters = catch_node.GetChild(0);
		as::NodePtr& param = parameters.GetChild(0);
		as::NodePtr& type = param.GetChild(0);
		as::Data& type_data = type.GetData();
		if(type_data.f_type == as::NODE_IDENTIFIER) {
			// Here we compare names without taking the case
			// in account since Flash returns type names in
			// lowercase.
			if(type_data.f_str == "Integer"
			|| type_data.f_str == "Double"
			|| type_data.f_str == "Number") {
				if(info.f_has_number) {
					f_error_stream->ErrMsg(as::AS_ERR_INCOMPATIBLE, catch_node, "Flash cannot distinguish between Integer and Double. You need to use Number and find a different way to know what raised the exception.");
				}
				else {
					if(type_data.f_str == "Number") {
fprintf(stderr, "WARNING: the type for a catch() in Flash cannot be Integer or Double, it needs to be Number. And you cannot have Number twice.\n");
					}
					pd = new ActionPushData(f_tag);
					pd->AddString("Number");
					f_actions->Insert(-1, pd);
					info.f_has_number = true;
				}
			}
			else {
				pd = new ActionPushData(f_tag);
				str = type_data.f_str.GetUTF8();
				pd->AddString(str);
				delete [] str;
				f_actions->Insert(-1, pd);
			}
		}
		else {
			Expression(type);
		}
		// Flash is using CAST, I'm not too sure whether a
		// cast or instanceof is better here... but the cast
		// just doesn't work properly
#if 0
// a la Flash which doesn't work:
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_CAST);
		f_actions->Insert(-1, a);
		pd = new ActionPushData(f_tag);
		pd->AddNull(str);
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_EQUAL_TYPED);
		f_actions->Insert(-1, a);
#else
		a = new Action(f_tag, Action::ACTION_INSTANCE_OF);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
#endif
		Label(l);
		str = l.GetUTF8();
		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
		branch->SetLabel(str);
		f_actions->Insert(-1, branch);
	}

	DirectiveList(catch_node.GetChild(1));

	branch = new ActionBranch(f_tag);
	branch->SetLabel(info.f_str);
	f_actions->Insert(-1, branch);

	if(str != 0) {
		label = new ActionLabel(f_tag);
		label->SetLabel(str);
		f_actions->Insert(-1, label);

		delete [] str;

		// in this case we have to raise the exception again
		// (last catch is typed too and we didn't match any
		// type yet!)
		if(is_last) {
			if(info.f_reg >= 0) {
				f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
			}
			else {
				pd = new ActionPushData(f_tag);
				pd->AddString(info.f_regname_str);
				f_actions->Insert(-1, pd);
				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
				f_actions->Insert(-1, a);
			}
			a = new Action(f_tag, Action::ACTION_THROW);
			f_actions->Insert(-1, a);
		}
	}

	if(is_last) {
		label = new ActionLabel(f_tag);
		label->SetLabel(info.f_str);
		f_actions->Insert(-1, label);
	}

	f_actions = save_actions;
}


void IntAssembler::Finally(try_info_t& info, as::NodePtr& finally_node)
{
	Vectors *save_actions = f_actions;
	f_actions = info.f_try->SubListFinally();
	DirectiveList(finally_node.GetChild(0));
	f_actions = save_actions;
}


void IntAssembler::Function(as::NodePtr& function, bool use_name)
{
	// a function marked unused & dynamic is compiled with
	// as a throw new Error("Cannot call an unused function");
	// a function only marked unused is ignored
	unsigned long attrs = function.GetAttrs();
	if((attrs & (as::NODE_ATTR_UNUSED | as::NODE_ATTR_DYNAMIC)) == as::NODE_ATTR_UNUSED) {
		return;
	}

	ActionFunction *func = new ActionFunction(f_tag, Action::ACTION_DECLARE_FUNCTION2);
	f_actions->Insert(-1, func);

	// Optimizations:
	//
	// whenever a function has just one parameter we just create
	// a function with one parameter in a register;
	//
	// if the function has any parameter defined as OUT, then we
	// create a one parameter function which needs to be an array
	// this is required to get the value back out (Flash is always
	// passing parameters by value [or copy], but the content of
	// an array is read/write)
	//
	// the user can also use the special attribute 'array'; this
	// will force the use of an array for all the parameters
	// even if it isn't required. This can save some space for
	// functions using many parameters since the order in which
	// parameters are stack is easier to handle.

	as::Data& data = function.GetData();
	if(use_name) {
		// don't rename global functions
		bool rename = true;
		as::NodePtr& parent = function.GetParent();
		as::Data& parent_data = parent.GetData();
		if(parent_data.f_type == as::NODE_DIRECTIVE_LIST) {
			as::NodePtr& program = parent.GetParent();
			as::Data& program_data = program.GetData();
			if(program_data.f_type == as::NODE_PROGRAM) {
				rename = false;
			}
		}

		char *name;
		if(rename) {
			FunctionData **fd;
			AS_ASSERT(data.f_user_data.Size() == 0);

			data.f_user_data.New((sizeof(FunctionData *) + sizeof(int) - 1) / sizeof(int));
			fd = reinterpret_cast<FunctionData **>(data.f_user_data.Buffer());
			fd[0] = new VariableData;
			fd[0]->GenerateName("__f");
			name = fd[0]->f_name.GetUTF8();
		}
		else {
			name = data.f_str.GetUTF8();
		}
		func->SetName(name);
		delete [] name;
	}

	// search for the parameters and directive list
	as::NodePtr parameters, list;
	int idx, max = function.GetChildCount();
	for(idx = 0; idx < max; ++idx) {
		as::NodePtr& child = function.GetChild(idx);
		as::Data& data = child.GetData();
		switch(data.f_type) {
		case as::NODE_PARAMETERS:
			parameters = child;
			break;

		case as::NODE_DIRECTIVE_LIST:
			list = child;
			break;

		default:
			// skip the type
			break;

		}
	}

	f_registers.Push(254);

	FuncParam **p = 0;
	max = parameters.GetChildCount();
	if(max > 0) {
		unsigned long flags = data.f_int.Get();
		if((attrs & as::NODE_ATTR_ARRAY) != 0
		|| (flags & as::NODE_FUNCTION_FLAG_OUT) != 0) {
			// we want to use register 10 for the array parameter
			int r = f_registers.AllocRegister(10);
			func->AddParameter(0, r);

			for(int idx = 0; idx < max; ++idx) {
				as::NodePtr& param = parameters.GetChild(idx);
				as::Data& param_data = param.GetData();

				param_data.f_user_data.New((sizeof(FuncParam *) + sizeof(int) - 1) / sizeof(int));
				p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
				p[0] = new FuncParam;
				p[0]->f_mode = FuncParam::MODE_ARRAY;
				p[0]->f_reg = r;
				p[0]->f_index = max - idx - 1;
			}
		}
		else {
			// make it a standard (which means we need to
			// use many registers for calls...); standard
			// calls a more compatible!
			for(int idx = 0; idx < max; ++idx) {
				as::NodePtr& param = parameters.GetChild(idx);
				as::Data& param_data = param.GetData();

				param_data.f_user_data.New((sizeof(FuncParam *) + sizeof(int) - 1) / sizeof(int));
				p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
				p[0] = new FuncParam;

				int r = f_registers.AllocRegister(10);
				if(r == -1) {
					p[0]->f_mode = FuncParam::MODE_VARIABLE;

					// over 244 parameters?!
					// Flash will probably break on that one!
					char *name = data.f_str.GetUTF8();
					func->AddParameter(name);
					delete [] name;
				}
				else {
					p[0]->f_mode = FuncParam::MODE_REGISTER;
					p[0]->f_reg = r;

					// should we have the name too?
					// TODO: add an option to request
					//	 for names to be kept
					//if(option[name])
					if(0) {
						as::NodePtr& param = parameters.GetChild(idx);
						as::Data& data = param.GetData();
						char *name = data.f_str.GetUTF8();
						func->AddParameter(name, r);
						delete [] name;
					}
					else {
						func->AddParameter(0, r);
					}
				}
			}
		}
	}

	// TODO: we need to test the version and create the
	//	 function itself after if we want to avoid
	//	 version 7 always...
	Vectors *current = f_actions;
	f_actions = func->SubList();

	if((attrs & as::NODE_ATTR_UNUSED) != 0) {
		ActionPushData *pd = new ActionPushData(f_tag);
		pd->AddString("A function marked 'unused' cannot be called.");
		pd->AddInteger(1);
		pd->AddString("Error");
		f_actions->Insert(-1, pd);

		Action *a = new Action(f_tag, Action::ACTION_NEW);
		f_actions->Insert(-1, a);

		a = new Action(f_tag, Action::ACTION_THROW);
		f_actions->Insert(-1, a);
	}
	else {
		DirectiveList(list, false);
	}

	f_actions = current;

	f_registers.Pop();

	for(int idx = 0; idx < max; ++idx) {
		as::NodePtr& param = parameters.GetChild(idx);
		as::Data& param_data = param.GetData();

		p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
		// registers don't need to be freed since there
		// were restored by the Pop().
		delete p[0];
		param_data.f_user_data.New(0);
	}
}





void IntAssembler::Return(as::NodePtr& return_node)
{
	int max = return_node.GetChildCount();

	if(max == 1) {
		Expression(return_node.GetChild(0));
	}
	else {
		// A function not returning anything generates
		// "undefined" by default.
		ActionPushData *pd = new ActionPushData(f_tag);
		pd->AddUndefined();
		f_actions->Insert(-1, pd);
		// TODO: it could be that we don't actually need
		// to add this undefined ourselves (tbd)
	}

	Action *a = new Action(f_tag, Action::ACTION_RETURN);
	f_actions->Insert(-1, a);
}


void IntAssembler::Var(as::NodePtr& var)
{
	int max = var.GetChildCount();
	for(int idx = 0; idx < max; ++idx) {
		as::NodePtr& child = var.GetChild(idx);
		as::Data& data = child.GetData();
		if(data.f_type != as::NODE_VARIABLE) {
			continue;
		}
		int flags = data.f_int.Get();
		if((flags & as::NODE_VAR_FLAG_INUSE) == 0) {
			// this is either an attribute variable
			// or a totally unreferenced variable
			continue;
		}
		// a variable is transformed as:
		//	push expression
		//	push name
		//	set [local] variable action
		bool has_expr = false;
		int jmax = child.GetChildCount();
		for(int j = 0; j < jmax; ++j) {
			as::NodePtr& node = child.GetChild(j);
			as::Data& data = node.GetData();
			if(data.f_type == as::NODE_SET) {
				as::NodePtr& expr = node.GetChild(0);
				if((flags & as::NODE_VAR_FLAG_ENUM) != 0
				&& ExpressionIsConstant(expr)) {
					// TODO:
					// unless there is a bug, all
					// variables should use this
					// condition...
					break;
				}
				has_expr = true;
				Expression(expr);
				break;
			}
		}
		// we skip variable definitions
		if(!has_expr) {
			continue;
		}

		// we don't have any specific name here
		as::NodePtr name;
		Assignment(name, child, false);
	}
}


void IntAssembler::Label(as::String& label)
{
	char		buf[256];

	snprintf(buf, sizeof(buf), "l%d", f_label);
	label = buf;
	f_label++;
}


void IntAssembler::ExpressionIdentifierParam(as::NodePtr& instance, as::Data& inst_data)
{
	// first check whether this param is a catch(); if it is
	// then we use the f_catch_reg
	if((inst_data.f_int.Get() & as::NODE_PARAMETERS_FLAG_CATCH) != 0) {
		if(f_try_info == 0) {
			f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, instance, "reached a NODE_PARAM of a 'catch' without a try info structure available.");
			return;
		}
		if(f_try_info->f_reg >= 0) {
			f_registers.LoadRegister(f_try_info->f_reg, false, f_tag, f_actions);
		}
		else {
			ActionPushData *pd = new ActionPushData(f_tag);
			pd->AddString(f_try_info->f_regname_str);
			f_actions->Insert(-1, pd);
			Action *a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);
		}
		return;
	}

	// ha! this is a NODE_SET within a function list of
	// parameters; the content of that variable may be
	// in a register and for sure it isn't defined under
	// the same name!
	if(inst_data.f_user_data.Size() == 0) {
		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, instance, "reached a NODE_PARAM without a user data buffer set.");
		return;
	}

	FuncParam **p;
	p = reinterpret_cast<FuncParam **>(inst_data.f_user_data.Buffer());

	switch(p[0]->f_mode) {
	case FuncParam::MODE_REGISTER:
		f_registers.LoadRegister(p[0]->f_reg, false, f_tag, f_actions);
		break;

	case FuncParam::MODE_CONSTANT:
		Expression(p[0]->f_constant);
		break;

	case FuncParam::MODE_ARRAY:
	{
		f_registers.LoadRegister(p[0]->f_reg, false, f_tag, f_actions);
		ActionPushData *pd = new ActionPushData(f_tag);
		pd->AddInteger(p[0]->f_index);
		f_actions->Insert(-1, pd);
		Action *a = new Action(f_tag, Action::ACTION_GET_MEMBER);
		f_actions->Insert(-1, a);
	}
		break;

	case FuncParam::MODE_VARIABLE:
		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, instance, "IntAssembler::ExpressionIdentifierParam() MODE_VARIABLE not written yet.");
		break;

	default:
		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, instance, "found a NODE_PARAM with an unknown FuncParam::mode_t value (%d).", p[0]->f_mode);
		break;

	}
}



void IntAssembler::ExpressionIdentifierType(as::NodePtr& id)
{
	// in case of a type, we don't get any content,
	// just the name of the type unless we are on
	// the left side of a MEMBER ('a' in 'a.b')
	as::Data& data = id.GetData();

	char *str = data.f_str.GetUTF8();

	ActionPushData *pd = new ActionPushData(f_tag);
	pd->AddString(str);
	f_actions->Insert(-1, pd);

	delete [] str;

	if(data.f_type != as::NODE_FUNCTION) {
		// check the parent
		as::NodePtr& parent = id.GetParent();
		as::Data& data = parent.GetData();
		if(data.f_type == as::NODE_MEMBER) {
			Action *a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);
		}
	}
}



void IntAssembler::ExpressionIdentifierVariable(as::NodePtr& variable, as::Data& inst_data, bool with_object)
{
	ActionPushData		*pd;
	Action			*a;
	char			*str;
	VariableData		**vd;

	unsigned long attrs = variable.GetAttrs();

	if(!with_object && (inst_data.f_int.Get() & as::NODE_VAR_FLAG_MEMBER) != 0) {
		if((attrs & as::NODE_ATTR_STATIC) != 0) {
			//	push <class name>
			//	get variable
			//	push <static member name>
			//	get member
			as::NodePtr class_node = variable;
			as::Data *class_data = 0;
			for(;;) {
				class_node = class_node.GetParent();
				if(!class_node.HasNode()) {
					break;
				}
				class_data = &class_node.GetData();
				if(class_data->f_type == as::NODE_CLASS
				|| class_data->f_type == as::NODE_INTERFACE) {
					break;
				}
			}
			if(class_node.HasNode()) {
				pd = new ActionPushData(f_tag);
				str = class_data->f_str.GetUTF8();
				pd->AddString(str);
				delete [] str;
				f_actions->Insert(-1, pd);
				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
				f_actions->Insert(-1, a);
			}
			pd = new ActionPushData(f_tag);
			str = inst_data.f_str.GetUTF8();
			pd->AddString(str);
			delete [] str;
			f_actions->Insert(-1, pd);
			if(class_node.HasNode()) {
				a = new Action(f_tag, Action::ACTION_GET_MEMBER);
			}
			else {
				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			}
			f_actions->Insert(-1, a);
			return;
		}
		// a member needs to be transformed to this.<name> whenever
		// this wasn't specified by the user...
		pd = new ActionPushData(f_tag);
		pd->AddString("this");
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);

		pd = new ActionPushData(f_tag);
		str = inst_data.f_str.GetUTF8();
		pd->AddString(str);
		delete [] str;
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_GET_MEMBER);
		f_actions->Insert(-1, a);
		return;
	}

	vd = 0;

	if(inst_data.f_user_data.Size() == 0) {
		if(!with_object && (inst_data.f_int.Get() & as::NODE_VAR_FLAG_MEMBER) == 0) {
			if((attrs & (as::NODE_ATTR_INTRINSIC | as::NODE_ATTR_DYNAMIC)) == 0) {
				// if we don't have any "variable data" structure
				// then we have a problem since we are supposed to
				// have written something in this variable already
//fprintf(stderr, "WARNING: pushing 'undefined' since variable '%S' wasn't set yet.\n", inst_data.f_str.GetLength(), inst_data.f_str.Get());
				pd = new ActionPushData(f_tag);
				pd->AddUndefined();
				f_actions->Insert(-1, pd);
				return;
			}
		}
	}
	else {
		vd = reinterpret_cast<VariableData **>(inst_data.f_user_data.Buffer());
	}

	if(vd && vd[0]->f_mode == VariableData::MODE_REGISTER) {
		pd = new ActionPushData(f_tag);
		pd->AddRegister(vd[0]->f_reg);
		f_actions->Insert(-1, pd);
	}
	else {
		pd = new ActionPushData(f_tag);
		if(vd) {
			str = vd[0]->f_name.GetUTF8();
		}
		else {
			str = inst_data.f_str.GetUTF8();
		}
		pd->AddString(str);
		delete [] str;
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);
	}
}


void IntAssembler::ExpressionIdentifier(as::NodePtr& id)
{
	as::Data& data = id.GetData();
	bool with_object = (data.f_int.Get() & as::NODE_IDENTIFIER_FLAG_WITH) != 0;

	as::NodePtr& instance = id.GetLink(as::NodePtr::LINK_INSTANCE);

	if(!instance.HasNode()) {
		as::Data& data = id.GetData();
		f_error_stream->ErrStrMsg(as::AS_ERR_INTERNAL_ERROR, id, "found identifier '%S' without an instance.", &data.f_str);
		return;
	}

	as::Data& inst_data = instance.GetData();

	switch(inst_data.f_type) {
	case as::NODE_PARAM:
		ExpressionIdentifierParam(instance, inst_data);
		break;

	case as::NODE_CLASS:
	case as::NODE_INTERFACE:
	case as::NODE_FUNCTION:
		ExpressionIdentifierType(id);
		break;

	case as::NODE_VARIABLE:
		ExpressionIdentifierVariable(instance, inst_data, with_object);
		break;

	default:
		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, id, "unknown instance data type in IntAssembler::ExpressionIdentifier().");
		break;

	}
}



void IntAssembler::ExprIn(as::NodePtr& expr)
{
	ActionPushData		*pd;
	ActionBranch		*branch;
	ActionLabel		*label;
	Action			*a;
	char			*str1, *str2, *str3, *str4;
	as::String		l1, l2, l3, l4;

	int cnt = expr.GetChildCount();
	if(cnt == 3) {
		// expr in expr .. expr
		//
		// test to perform:
		// expr[0] >= expr[1] && expr[0] <= expr[2]
		//
		//	expr[0]
		//	dup
		//	expr[1]
		//	less_than
		//	branch_if_true branch_false
		//	expr[2]
		//	swap
		//	greater_than
		//	goto branch_done
		// branch_false:
		//	pop
		//	push false
		// branch_done:
		//
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_DUPLICATE);
		f_actions->Insert(-1, a);
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
		f_actions->Insert(-1, a);
		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
		Label(l1);
		str1 = l1.GetUTF8();
		branch->SetLabel(str1);
		f_actions->Insert(-1, branch);
		Expression(expr.GetChild(2));
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		branch = new ActionBranch(f_tag);
		str2 = l2.GetUTF8();
		branch->SetLabel(str2);
		f_actions->Insert(-1, branch);
		label = new ActionLabel(f_tag);
		label->SetLabel(str1);
		f_actions->Insert(-1, label);
		a = new Action(f_tag, Action::ACTION_POP);
		f_actions->Insert(-1, a);
		pd = new ActionPushData(f_tag);
		pd->AddBoolean(false);
		f_actions->Insert(-1, pd);
		label = new ActionLabel(f_tag);
		label->SetLabel(str2);
		f_actions->Insert(-1, label);
		delete [] str1;
		delete [] str2;
		return;
	}

	AS_ASSERT(cnt == 2);

	// expr in expr
	//	evaluate expr[0]
	//	store reg_find
	//	pop
	//	evaluate expr[1]
	//	enumerate object
	// repeat:
	//	store reg_name
	//	push null
	//	equal
	//	branch if true, goto return_false
	//	load reg_find
	//	load reg_name
	//	strictly equal
	//	logical not
	//	branch if true, goto repeat
	// empty:
	//	push null
	//	equal
	//	logical not
	//	branch if true, goto empty
	//	push true
	//	goto done
	// return_false:
	//	push false
	// done:

	Label(l1);
	Label(l2);
	Label(l3);
	Label(l4);

	str1 = l1.GetUTF8();
	str2 = l2.GetUTF8();
	str3 = l3.GetUTF8();
	str4 = l4.GetUTF8();

	// evaluate the string (member name)
	Expression(expr.GetChild(0));
	int reg_find = f_registers.StoreRegister(f_tag, f_actions, true);

	// evaluate the object
	Expression(expr.GetChild(1));
	a = new Action(f_tag, Action::ACTION_ENUMERATE_OBJECT);
	f_actions->Insert(-1, a);

	label = new ActionLabel(f_tag);
	label->SetLabel(str1);
	f_actions->Insert(-1, label);

	int reg_name = f_registers.StoreRegister(f_tag, f_actions, false);

	pd = new ActionPushData(f_tag);
	pd->AddNull();
	f_actions->Insert(-1, pd);

	a = new Action(f_tag, Action::ACTION_EQUAL);
	f_actions->Insert(-1, a);

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	branch->SetLabel(str3);
	f_actions->Insert(-1, branch);

	f_registers.LoadRegister(reg_find, true, f_tag, f_actions);
	f_registers.LoadRegister(reg_name, true, f_tag, f_actions);

	a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
	f_actions->Insert(-1, a);

	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
	f_actions->Insert(-1, a);

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	branch->SetLabel(str1);
	f_actions->Insert(-1, branch);

	label = new ActionLabel(f_tag);
	label->SetLabel(str2);
	f_actions->Insert(-1, label);

	pd = new ActionPushData(f_tag);
	pd->AddNull();
	f_actions->Insert(-1, pd);

	a = new Action(f_tag, Action::ACTION_EQUAL);
	f_actions->Insert(-1, a);

	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
	f_actions->Insert(-1, a);

	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	branch->SetLabel(str2);
	f_actions->Insert(-1, branch);

	pd = new ActionPushData(f_tag);
	pd->AddBoolean(true);
	f_actions->Insert(-1, pd);

	branch = new ActionBranch(f_tag);
	branch->SetLabel(str4);
	f_actions->Insert(-1, branch);

	label = new ActionLabel(f_tag);
	label->SetLabel(str3);
	f_actions->Insert(-1, label);

	pd = new ActionPushData(f_tag);
	pd->AddBoolean(false);
	f_actions->Insert(-1, pd);

	label = new ActionLabel(f_tag);
	label->SetLabel(str4);
	f_actions->Insert(-1, label);

	delete [] str1;
	delete [] str2;
	delete [] str3;
	delete [] str4;
}



bool IntAssembler::ExpressionIsConstant(as::NodePtr& expr, int inclusive)
{
	as::Data& data = expr.GetData();
	switch(data.f_type) {
	case as::NODE_FLOAT64:
		return (inclusive & INCLUSIVE_FLOAT) != 0;

	case as::NODE_INT64:
		return (inclusive & INCLUSIVE_INTEGER) != 0;

	case as::NODE_STRING:
		return (inclusive & INCLUSIVE_STRING) != 0;

	case as::NODE_TRUE:
	case as::NODE_FALSE:
		return (inclusive & INCLUSIVE_BOOLEAN) != 0;

	case as::NODE_UNDEFINED:
		return (inclusive & INCLUSIVE_UNDEFINED) != 0;

	case as::NODE_NULL:
		return (inclusive & INCLUSIVE_NULL) != 0;

	default:
		return false;

	}
}


const IntAssembler::special_function_t *IntAssembler::IsSpecial(as::NodePtr& function, as::Data& data)
{
	static const special_function_t special_functions[] = {
		{
			"Native", "duplicateMovieClip",
			Action::ACTION_DUPLICATE_SPRITE,
			special_function_t::STACK_ORDER_REVERSED,
			false
		},
		{
			"Native", "fscommand",
			Action::ACTION_URL2,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "fscommand2",
			Action::ACTION_FSCOMMAND2,
			special_function_t::STACK_ORDER_PERFECT_COUNT,
			false
		},
		{
			"Native", "getProperty",
			Action::ACTION_GET_PROPERTY,
			special_function_t::STACK_ORDER_REVERSED,
			true
		},
		{
			"Native", "getTimer",
			Action::ACTION_GET_TIMER,
			special_function_t::STACK_ORDER_SPECIAL, // we actually ignore this one
			true
		},
		{
			"Native", "getURL",
			Action::ACTION_URL2,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "gotoAndPlay",
			Action::ACTION_GOTO_FRAME,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "gotoAndStop",
			Action::ACTION_GOTO_FRAME,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "loadMovie",
			Action::ACTION_URL2,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "loadMovieNum",
			Action::ACTION_URL2,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "loadVariables",
			Action::ACTION_URL2,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "loadVariablesNum",
			Action::ACTION_URL2,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "nextFrame",
			Action::ACTION_NEXT_FRAME,
			special_function_t::STACK_ORDER_PERFECT,
			false
		},
		{
			"Native", "play",
			Action::ACTION_PLAY,
			special_function_t::STACK_ORDER_PERFECT,
			false
		},
		{
			"Native", "prevFrame",
			Action::ACTION_PREVIOUS_FRAME,
			special_function_t::STACK_ORDER_PERFECT,
			false
		},
		{
			"Native", "removeMovieClip",
			Action::ACTION_REMOVE_SPRITE,
			special_function_t::STACK_ORDER_PERFECT,
			false
		},
		{
			"Native", "setProperty",
			Action::ACTION_SET_PROPERTY,
			special_function_t::STACK_ORDER_REVERSED,
			false
		},
		{
			"Native", "startDrag",
			Action::ACTION_START_DRAG,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "stop",
			Action::ACTION_STOP,
			special_function_t::STACK_ORDER_PERFECT,
			false
		},
		{
			"Native", "stopAllSounds",
			Action::ACTION_STOP_SOUND,
			special_function_t::STACK_ORDER_PERFECT,
			false
		},
		{
			"Native", "stopDrag",
			Action::ACTION_STOP_DRAG,
			special_function_t::STACK_ORDER_PERFECT,
			false
		},
		{
			"Native", "targetpath",
			Action::ACTION_GET_TARGET,
			special_function_t::STACK_ORDER_PERFECT,
			true
		},
		{
			"Native", "unloadMovie",
			Action::ACTION_URL,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		{
			"Native", "unloadMovieNum",
			Action::ACTION_URL,
			special_function_t::STACK_ORDER_SPECIAL,
			false
		},
		/* special functions still to be implemented
		function fscommand(func : String, params : String) : Void; -> getURL('FSCommand:' + func, params);
		function getURL(url : String, target : String) : Void;
		function getTimer(Void) : Integer;
		function nextScene(Void) : Void;
		function nextScene(Void) : Void;
		function on(event : mouse_event, ...) : Void;
		function onClipEvent(event : movie_event) : Void;
		function onUpdate(Void) : Void;
		function prevScene(Void) : Void;
		function print(target : Object, bounds : String) : Void;
		function printAsBitmap(target : Object, bounds : String) : Void;
		function printAsBitmapNum(level : Integer, bounds : String) : Void;
		function printNum(level : Integer, bounds : String) : Void;
		function unloadMovie(target : MovieClip) : Void;
		function unloadMovie(target : String) : Void;
		function unloadMovieNum(level : Integer) : Void;
		function updateAfterEvent(Void) : Void;
		*/
	};

	long length = data.f_str.GetLength();
	if(length <= 0) {
		// this should not happen...
		return 0;
	}

	int i = 0;
	int j = sizeof(special_functions) / sizeof(special_function_t);
	int r, p;

#if defined(_DEBUG) || defined(DEBUG)
	for(p = 1; p < j; ++p) {
		if(strcmp(special_functions[p - 1].f_function_name,
			special_functions[p].f_function_name) >= 0) {
fprintf(stderr, "INTERNAL ERROR: special functions are not listed in order (necessary for our binary search).\n");
			AS_ASSERT(0);
		}
	}
#endif

	r = -1;	// avoid warnings
	while(i < j) {
		p = (j - i) / 2 + i;
		r = data.f_str.Compare(special_functions[p].f_function_name);
		if(r == 0) {

//fprintf(stderr, "+++ Found '%s'\n", special_functions[p].f_function_name);

			break;
		}
		if(r > 0) {
			i = p + 1;
		}
		else {
			j = p;
		}
	}
	if(r != 0) {
		// not found, this isn't an error
		return 0;
	}

	const special_function_t *special = special_functions + p;

	as::NodePtr parent = function.GetParent();
	while(parent.HasNode()) {
		as::Data& data = parent.GetData();
		if(data.f_type == as::NODE_PACKAGE) {
			if(data.f_str == special->f_package_name) {
				return special;
			}
			// we cannot have more than one package
			// at this time (i.e. depth 1)
			break;
		}
		parent = parent.GetParent();
	}

	return 0;
}


void IntAssembler::Member(as::NodePtr& member, Action::action_t action)
{
	ActionPushData	*pd;
	Action		*a;
	char		*str;

	as::NodePtr& left = member.GetChild(0);
#if 0
	as::Data& left_data = left.GetData();
	switch(left_data.f_type) {
	case as::NODE_THIS:
		pd = new ActionPushData(f_tag);
		pd->AddString("this");
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_SUPER:
		pd = new ActionPushData(f_tag);
		pd->AddString("super");
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);
		break;

	default:
		Expression(left);
		break;

	}
#endif
	Expression(left);

	// TODO: special case?! I'd like to make sure that this is
	//	 really correct at some point... we may have to do
	//	 that sort of special handling with other types too
	as::NodePtr& left_type = left.GetLink(as::NodePtr::LINK_TYPE);
	if(left_type.HasNode()) {
		as::Data& left_type_data = left_type.GetData();
		if(left_type_data.f_str == "String") {
			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);
		}
	}

	if(action == Action::ACTION_SET_MEMBER) {
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
	}

	as::NodePtr& right = member.GetChild(1);
	as::Data& right_data = right.GetData();
	switch(right_data.f_type) {
	case as::NODE_IDENTIFIER:
		// This is the direct and exact name of the
		// variable member to access right now
		pd = new ActionPushData(f_tag);
		str = right_data.f_str.GetUTF8();
		pd->AddString(str);
		delete [] str;
		f_actions->Insert(-1, pd);
		break;

#if 0
	case as::NODE_CALL:
		// this should be caught in the compiler!
		if(action == Action::ACTION_SET_MEMBER) {
fprintf(stderr, "ERROR: can't set a member call?!\n");
			f_errcnt++;
			return;
		}
		Call(right, Action::ACTION_CALL_METHOD);
		return;
#endif

	case as::NODE_MEMBER:
		Member(right, Action::ACTION_UNKNOWN);
		return;

	default:
		Expression(right);
		break;

	}

	if(action == Action::ACTION_SET_MEMBER) {
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
	}

	a = new Action(f_tag, action);
	f_actions->Insert(-1, a);
}


void IntAssembler::Array(as::NodePtr& array, Action::action_t action)
{
	ActionPushData		*pd;
	Action			*a;

	as::NodePtr& obj = array.GetChild(0);

	int max = array.GetChildCount();
	if(max == 1) {
		// ha! special case of an empty array
		if(obj.HasSideEffects()) {
			// Compile because it could have side
			// effects which the user may expect.
			VoidExpression(obj);
		}
		// Create an empty array
		//	push 0
		//	declare array
		pd = new ActionPushData(f_tag);
		pd->AddInteger(0);
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
		f_actions->Insert(-1, a);
		return;
	}

	// get the array reference
	Expression(obj);

	if(action == Action::ACTION_SET_MEMBER) {
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
	}

	as::NodePtr& index = array.GetChild(1);
	as::Data& data = index.GetData();
	switch(data.f_type) {
	case as::NODE_LIST:
		// special case that generates an array from the
		// items specified in the list
		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, array, "array list not implemented yet in IntAssembler::Array().");
		return;

	case as::NODE_ARRAY:
		Array(index, Action::ACTION_GET_MEMBER);
		break;

	case as::NODE_MEMBER:
		Member(index, Action::ACTION_GET_MEMBER);
		break;

	default:
		Expression(index);
		break;

	}

	if(action == Action::ACTION_SET_MEMBER) {
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
	}

	a = new Action(f_tag, action);
	f_actions->Insert(-1, a);
}


void IntAssembler::Call(as::NodePtr& call)
{
	ActionPushData	*pd;
	Action		*a;

	as::NodePtr& name = call.GetChild(0);
	as::Data& name_data = name.GetData();

	// get the name to see whether this is a special Flash
	// function (i.e. a function which really returns Void
	// and/or a function which has a special set of parameters)
	as::NodePtr& function = call.GetLink(as::NodePtr::LINK_INSTANCE);
	unsigned long attrs = 0;
	unsigned long flags = 0;
	const special_function_t *special = 0;
	if(function.HasNode()) {
		as::Data& data = function.GetData();
		attrs = function.GetAttrs();
		flags = data.f_int.Get();

		// only intrinsic functions can be converted in
		// a specialised byte code
		if((attrs & as::NODE_ATTR_INTRINSIC) != 0
		&& name_data.f_type == as::NODE_IDENTIFIER) {
			special = IsSpecial(function, data);
		}
	}

	// find the list of parameters
	as::NodePtr list;
	int max = call.GetChildCount();
	// note: call.GetChild(0) is the name of the function to call
	for(int idx = 1; idx < max; ++idx) {
		as::NodePtr& child = call.GetChild(idx);
		as::Data& data = child.GetData();
		if(data.f_type == as::NODE_LIST) {
			list = child;
			break;
		}
	}

	if(!list.HasNode()) {
		return;
	}

	if(name_data.f_type == as::NODE_IDENTIFIER
	&& name_data.f_str == "trace") {
		if(f_options != 0
		&& !f_options->GetOption(as::AS_OPTION_TRACE)) {
			// no trace, just put undefined (which the next
			// optimizer should be taking out for us...)
			pd = new ActionPushData(f_tag);
			pd->AddUndefined();
			f_actions->Insert(-1, pd);
			return;
		}
		if(f_options != 0
		&& f_options->GetOption(as::AS_OPTION_TRACE_TO_OBJECT)) {
			//	push __LINE__
			//	push __FILENAME__
			//	push "<package>::<class>::<function>"
			//	push <expr> (user funcion parameter)
			int max = list.GetChildCount();
			if(max > 1) {
				int idx = max;
				while(idx > 1) {
					// TODO: this is backward... (i.e.
					//	 right to left stacking!)
					//	 but debug stuff shouldn't
					//	 have any side effects?!
					--idx;
					Expression(list.GetChild(idx));
				}
			}
			pd = new ActionPushData(f_tag);
			pd->AddInteger(call.GetLine());
			const as::String& filename = call.GetFilename();
			char *str = filename.GetUTF8();
			pd->AddString(str);
			delete [] str;
			// we need the name of the function + class
			as::String qualified_func;
			as::NodePtr parent = call;
			for(;;) {
				parent = parent.GetParent();
				if(!parent.HasNode()) {
					break;
				}
				as::Data& data = parent.GetData();
				if(data.f_type == as::NODE_PROGRAM
				|| data.f_type == as::NODE_ROOT) {
					break;
				}
				if(data.f_type == as::NODE_FUNCTION
				|| data.f_type == as::NODE_CLASS
				|| data.f_type == as::NODE_INTERFACE
				|| data.f_type == as::NODE_PACKAGE) {
					if(qualified_func.IsEmpty()) {
						qualified_func = data.f_str;
					}
					else {
						// TODO: create the + operator
						//	 on String.
						as::String p = data.f_str;
						p += ".";
						p += qualified_func;
						qualified_func = p;
					}
					if(data.f_type == as::NODE_PACKAGE) {
						// we don't really care if we
						// are yet in another package
						// at this time...
						break;
					}
				}
			}
			str = qualified_func.GetUTF8();
			pd->AddString(str);
			delete [] str;
			f_actions->Insert(-1, pd);
			if(max >= 1) {
				Expression(list.GetChild(0));
			}
			else /*if(max == 0)*/ {
				// put a default
				pd = new ActionPushData(f_tag);
				pd->AddString("trace()");
				f_actions->Insert(-1, pd);
				max = 1;
			}
			pd = new ActionPushData(f_tag);
			pd->AddInteger(max + 3);
			pd->AddString("Trace");
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);
			pd = new ActionPushData(f_tag);
			pd->AddString("Message");
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_CALL_METHOD);
			f_actions->Insert(-1, a);
			return;
		}
		// user wants the regular trace()...
	}

	// get the parameters
	as::NodePtr parameters;
	int max_func = function.GetChildCount();
	for(int idx = 0; idx < max_func; ++idx) {
		as::NodePtr& child = function.GetChild(idx);
		as::Data& data = child.GetData();
		if(data.f_type == as::NODE_PARAMETERS) {
			parameters = child;
			break;
		}
	}

	// if the function requires an array to be called it is much
	// different; we need to: create an array, fill it, call the
	// function, read the 'out' variable if any, delete the array; 
	bool array = (attrs & as::NODE_ATTR_ARRAY) != 0
			|| (flags & as::NODE_FUNCTION_FLAG_OUT) != 0;

	if(array && special != 0) {
		as::Data& data = function.GetData();
		f_error_stream->ErrStrMsg(as::AS_ERR_INVALID_DEFINITION, call, "a Flash internal function ('%S' here) cannot be defined with the array attribute or have 'out' parameters.", &data.f_str);
	}

	if(array && name_data.f_type == as::NODE_SUPER) {
		f_error_stream->ErrMsg(as::AS_ERR_INVALID_ARRAY_FUNCTION, call, "'super' cannot be used with arrays.");
		array = false;
	}

	//
	// okay, this is a standard call, but we need to compute
	// the parameters from left to right which is the opposite
	// of what Flash wants on the stack for user functions;
	// so what we need to do is compute each expression and
	// store them in registers and local variables as required,
	// then push them backward on the stack;
	//
	// this doesn't hold for all the Flash special functions
	// which often are declared the right way (i.e. the stacking
	// and calling order are proper)
	//
	// NOTE: but this is really only necessary if we have calls
	// within that list of parameters; in other words, if we
	// only have direct operators, variables and constants, we
	// can stack that in any order EXCEPT assignments which
	// obviously need to be defined in the right order too;
	// also we are supporting reuse of parameter values in
	// the following parameters... and that could include
	// calls, assignments, etc. and let's not forget the
	// getters and setters!
	//
	//   Example:
	//
	// We're fine with (unless a, b or c is a getter, but that's
	// already viewed as a function at thist time):
	//
	//	call(a, b, c);
	//
	// Here the function b() could change a and/or c thus we need
	// to respect the order:
	//
	//	call(a, b(), c);
	//
	// A function that has parameters that are defined as the
	// result of an expression including previous parameters:
	//
	//	function call(a, b = a * 2);
	//	...
	//	call(55);	becomes		call(55, 110);
	//
	// since this becomes equivalent to:
	//
	// 	temp_a = 55;
	// 	temp_b = temp_a * 2;
	// 	call(temp_a, temp_b);
	//
	// we also need to do that in order.
	//
	// Another one, is when the user specify the name of the
	// parameters he wants to define in a call, this means the
	// order in which the parameters are computed is actually
	// different than the order in which the parameters are to
	// be given to the function.
	//
	//	call(a: x(), c: z(), b: y());
	//
	// here the temporaries are computed in the order the user
	// specified the parameters; it is important since calling
	// y() first could make z() return a different result
	//
	//	temp_a = x();
	//	temp_c = z();
	//	temp_b = y();
	//	call(temp_a, temp_b, temp_c);
	//

	struct reg_t {
				reg_t(void)
				{
					f_defined = false;
					f_referenced = false;
					f_reg = -1;
				}

		bool		f_defined;
		bool		f_referenced;
		int		f_reg;
	};

// Get the array of indexes which converts
// the list index into a parameter index
	as::Data& call_data = call.GetData();
	int size = call_data.f_user_data.Size();
	bool ordered = true;
	special_function_t::setup_t order;
	if(special != 0) {
		order = special->f_stack_order;
	}
	else {
		order = special_function_t::STACK_ORDER_PERFECT;
	}
	int *indexes = 0;
	if(size > 0) {
		indexes = call_data.f_user_data.Buffer();

		if(order == special_function_t::STACK_ORDER_PERFECT
		|| order == special_function_t::STACK_ORDER_PERFECT_COUNT) {
			for(int idx = 0; idx < size; ++idx) {
				if(indexes[idx] != idx) {
					ordered = false;
					break;
				}
			}
		}
		else if(order == special_function_t::STACK_ORDER_REVERSED
			|| order == special_function_t::STACK_ORDER_REVERSED_COUNT) {
			for(int idx = 0; idx < size; ++idx) {
				if(indexes[idx] != size - idx - 1) {
					ordered = false;
					break;
				}
			}
		}
	}
	if(order != special_function_t::STACK_ORDER_PERFECT
	&& order != special_function_t::STACK_ORDER_PERFECT_COUNT
	&& order != special_function_t::STACK_ORDER_REVERSED
	&& order != special_function_t::STACK_ORDER_REVERSED_COUNT) {
		// TODO: handle special cases here?
		ordered = false;
	}

// 1. compute parameters which aren't constants and save them in temporaries
//    [but skip auto definitions]
//
//    NOTE: we define links back to the parameters in case we have some
//    autos which use the previous parameters as variables to be computed.
//
	FuncParam **p = 0;
	as::NodePtr param;
	int pos;
	int count = list.GetChildCount();
	int max_params = parameters.GetChildCount();

//fprintf(stderr, "Size = %d, max = %d\n", size, max_params);
//	AS_ASSERT(size >= max_params);

	reg_t *regs = new reg_t[count];
	for(int idx = 0; idx < count; ++idx) {
		as::NodePtr& expr = list.GetChild(idx);
		as::Data& data = expr.GetData();

		bool put_in_reg = false;
		if(indexes != 0) {
			pos = indexes[idx];
			if(pos >= max_params) {
				pos = max_params - 1;
			}
			param = parameters.GetChild(pos);
			as::Data& param_data = param.GetData();
			if((param_data.f_int.Get() & as::NODE_PARAMETERS_FLAG_PARAMREF) != 0) {
				regs[idx].f_referenced = true;
				put_in_reg = !ExpressionIsConstant(expr, INCLUSIVE_ALL & ~INCLUSIVE_STRING);
			}
			param_data.f_user_data.New((sizeof(FuncParam *) + sizeof(int) - 1) / sizeof(int));
			p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
			p[0] = new FuncParam;
		}
		if(array && p == 0 && ordered) {
			Expression(expr);
		}
		else {
			if(array && ordered) {
				put_in_reg = true;
			}
			else if(!put_in_reg) {
				// this can include an AUTO parameter
				put_in_reg = expr.HasSideEffects();
			}
			else if(data.f_type == as::NODE_AUTO) {
				// this is true in the next loop instead
				put_in_reg = false;
			}

			if(put_in_reg) {
				// if so, then compute it now
				Expression(expr);
				regs[idx].f_defined = true;
				regs[idx].f_reg = f_registers.StoreRegister(f_tag, f_actions, !array || !ordered);
				if(p != 0) {
					p[0]->f_mode = FuncParam::MODE_REGISTER;
					p[0]->f_reg = regs[idx].f_reg;

//fprintf(stderr, "Setting p[0]->f_reg to %d\n", regs[idx].f_reg);

				}
			}
			else if(data.f_type != as::NODE_AUTO) {
				// this includes 'undefined' parameters
				regs[idx].f_defined = true;
				if(p != 0) {
					p[0]->f_mode = FuncParam::MODE_CONSTANT;
					p[0]->f_constant = expr;
				}
			}
		}
	}

// 2. compute automatic parameters which require it (i.e. not just undefined)
	if(!array || !ordered) for(int idx = 0; idx < count; ++idx) {
		as::NodePtr& expr = list.GetChild(idx);
		as::Data& data = expr.GetData();
		if(data.f_type == as::NODE_AUTO
		&& !regs[idx].f_defined) {
			// if we have an auto we've got to have a valid
			// function declaration and thus a list of indexes
			AS_ASSERT(indexes != 0);

			pos = indexes[idx];
			if(pos >= max_params) {
				pos = max_params - 1;
			}
			param = parameters.GetChild(pos);
			as::Data& param_data = param.GetData();
			p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());

			if(regs[idx].f_referenced || expr.HasSideEffects()
			|| !ExpressionIsConstant(expr, INCLUSIVE_ALL & ~INCLUSIVE_STRING)) {
				// if so, then compute it now
				Expression(expr);
				regs[idx].f_defined = true;
				regs[idx].f_reg = f_registers.StoreRegister(f_tag, f_actions, true);
				if(p != 0) {
					p[0]->f_mode = FuncParam::MODE_REGISTER;
					p[0]->f_reg = regs[idx].f_reg;
				}
			}
			else {
				regs[idx].f_defined = true;
				if(p != 0) {
					p[0]->f_mode = FuncParam::MODE_CONSTANT;
					p[0]->f_constant = expr;
				}
			}
		}
	}

// 3. put all of that on the stack in the right order
	if(!array || !ordered) {
		int idx, step, end;
		idx = step = end = 0;
		if(order == special_function_t::STACK_ORDER_PERFECT
		|| order == special_function_t::STACK_ORDER_PERFECT_COUNT) {
			idx = count - 1;
			step = -1;
			end = -1;
		}
		else if(order == special_function_t::STACK_ORDER_REVERSED
			|| order == special_function_t::STACK_ORDER_REVERSED_COUNT) {
			idx = 0;
			step = 1;
			end = count;
		}
		else if(order == special_function_t::STACK_ORDER_SPECIAL) {
			switch(special->f_action) {
			case Action::ACTION_START_DRAG:
				idx = count - 1;
				step = -1;
				end = -1;
				if(count <= 2) {
					// rectangle flag (b3)
					pd = new ActionPushData(f_tag);
					pd->AddBoolean(false);
					f_actions->Insert(-1, pd);
				}
				break;

			case Action::ACTION_GOTO_FRAME:
			{
				// TODO: this will need loads of testing
				//	 it feels to me that this is all wrong right
				//	 now... (cool hey? {8-})
				Action::action_t action = Action::ACTION_GOTO_EXPRESSION;
				as::String sprite_name;
				as::String frame_name;
				as::String label_name;
				int cnt = 2;
				long frame_no = -1;
				bool play = special->f_function_name[7] == 'P';

				AS_ASSERT(count == 2);
				AS_ASSERT(regs[0].f_defined);
				AS_ASSERT(regs[1].f_defined);

				if(indexes != 0) {
					pos = indexes[0] == 0 ? 0 : 1;
				}
				else {
					pos = 0;
				}

//fprintf(stderr, "[GotoFrame] Loading %d [%d]\n", pos, idx);

				if(regs[pos].f_reg < 0) {
					// compute the expression on the fly it has no
					// side effect (constant or no call(), assignment, etc.)
					as::NodePtr& expr = list.GetChild(pos);
					as::Data& data = expr.GetData();
					if(data.f_type == as::NODE_UNDEFINED) {
						cnt = 1;
					}
					else if(data.f_type == as::NODE_STRING) {
						sprite_name = data.f_str;
						if(sprite_name.IsEmpty()) {
							f_error_stream->ErrMsg(as::AS_ERR_INVALID_EXPRESSION, expr, "an empty string is an invalid sprite name.");
						}
					}
					else {
						Expression(expr);
					}
				}
				else {
					f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
				}
				pos ^= 1;
				if(regs[pos].f_reg < 0) {
					// compute the expression on the fly it has no
					// side effect (constant or no call(), assignment, etc.)
					as::NodePtr& expr = list.GetChild(pos);
					as::Data& data = expr.GetData();
					if(data.f_type == as::NODE_STRING && cnt == 1) {
						label_name = data.f_str;
						if(label_name.IsEmpty()) {
							f_error_stream->ErrMsg(as::AS_ERR_INVALID_LABEL, expr, "an empty string is an invalid label name.");
						}
						action = Action::ACTION_GOTO_LABEL;
					}
					else if(data.f_type == as::NODE_INT64 && cnt == 1) {
						frame_no = data.f_int.Get();
						action = Action::ACTION_GOTO_FRAME;
					}
					else if(data.f_type == as::NODE_STRING && !sprite_name.IsEmpty()) {
						frame_name = data.f_str;
						if(frame_name.IsEmpty()) {
							f_error_stream->ErrMsg(as::AS_ERR_INVALID_FRAME, expr, "an empty string is an invalid frame name.");
						}
					}
					else if(data.f_type == as::NODE_INT64 && !sprite_name.IsEmpty()) {
						frame_no = data.f_int.Get();
					}
					else {
						if(!sprite_name.IsEmpty()) {
							as::NodePtr& expr = list.GetChild(pos ^ 1);
							Expression(expr);
							sprite_name = "";
						}
						Expression(expr);
					}
				}
				else {
					if(!sprite_name.IsEmpty()) {
						as::NodePtr& expr = list.GetChild(pos ^ 1);
						Expression(expr);
						sprite_name = "";
					}
					f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
				}
				if(sprite_name.IsEmpty() && cnt == 2) {
					// we need to concatenate the names with ':' in between
					pd = new ActionPushData(f_tag);
					pd->AddString(":");
					f_actions->Insert(-1, pd);
					a = new Action(f_tag, Action::ACTION_SWAP);
					f_actions->Insert(-1, a);
					a = new Action(f_tag, Action::ACTION_CONCATENATE);
					f_actions->Insert(-1, a);
					//a = new Action(f_tag, Action::ACTION_SWAP);
					//f_actions->Insert(-1, a);
					a = new Action(f_tag, Action::ACTION_CONCATENATE);
					f_actions->Insert(-1, a);
				}
				else if(action == Action::ACTION_GOTO_EXPRESSION) {
					// we want to create the fullname right now
					// and push it at once on the stack
					sprite_name += ":";
					if(!frame_name.IsEmpty()) {
						sprite_name += frame_name;
					}
					else {
						char buf[16];
						sprintf(buf, "%ld", frame_no);
						sprite_name += buf;
					}
					pd = new ActionPushData(f_tag);
					char *str = sprite_name.GetUTF8();
					pd->AddString(str);
					delete [] str;
					f_actions->Insert(-1, pd);
				}

				ActionGoto *action_goto;
				if(action == Action::ACTION_GOTO_EXPRESSION) {
					action_goto = new ActionGoto(f_tag, action);
					action_goto->SetPlay(play);
				}
				else {
					// we can't have the PLAY/STOP inside the instruction
					// in this case so we apply it first
					a = new Action(f_tag, play ? Action::ACTION_PLAY : Action::ACTION_STOP);
					f_actions->Insert(-1, a);
					action_goto = new ActionGoto(f_tag, action);
					if(action == Action::ACTION_GOTO_FRAME) {
						char buf[16];
						sprintf(buf, "%ld", frame_no);
						action_goto->SetFrameName(buf);
					}
					else {
						char *str = label_name.GetUTF8();
						action_goto->SetFrameName(str);
						delete [] str;
					}
				}
				f_actions->Insert(-1, action_goto);
				// don't add anything on the stack
				idx = 0;
				end = 0;
			}
				break;

			case Action::ACTION_URL:
			{
				AS_ASSERT(count == 1);
				AS_ASSERT(regs[0].f_defined);

				as::String target;
				bool constant_target = false;

				if(regs[0].f_reg < 0) {
					// compute the expression on the fly it has no
					// side effect (constant or no call(), assignment, etc.)
					as::NodePtr& expr = list.GetChild(0);
					as::Data& data = expr.GetData();
					if(data.f_type == as::NODE_STRING) {
						// constant string!
						target = data.f_str;
						constant_target = true;
					}
					else if(data.f_type == as::NODE_INT64) {
						// constant string!
						int target_no = data.f_int.Get();
						char buf[32];
						sprintf(buf, "_level%d", target_no);
						target = buf;
						constant_target = true;
					}
					else {
						pd = new ActionPushData(f_tag);
						pd->AddString("");
						f_actions->Insert(-1, pd);
						Expression(expr);
					}
				}
				else {
					pd = new ActionPushData(f_tag);
					pd->AddString("");
					f_actions->Insert(-1, pd);
					f_registers.LoadRegister(regs[0].f_reg, true, f_tag, f_actions);
				}

				ActionURL *action_url = 0;
				if(constant_target) {
					// we can make use of ACTION_URL instead of ACTION_URL2
					action_url = new ActionURL(f_tag, Action::ACTION_URL);
					char *str = target.GetUTF8();
					action_url->SetURL("", str);
					delete [] str;
				}
				else {
					action_url = new ActionURL(f_tag, Action::ACTION_URL2);
					action_url->SetMethod(ActionURL::URL_METHOD_NOVARIABLES);
				}
				f_actions->Insert(-1, action_url);

				// don't add anything on the stack
				idx = 0;
				end = 0;
			}
				break;

			case Action::ACTION_URL2:
			{
				bool is_fscommand = strcmp(special->f_function_name, "fscommand") == 0;

				AS_ASSERT(count == (is_fscommand ? 2 : 3));
				AS_ASSERT(regs[0].f_defined);
				AS_ASSERT(regs[1].f_defined);
				AS_ASSERT(is_fscommand || regs[2].f_defined);

				as::String url;
				as::String target;
				long url_pos = -1;
				long target_pos = -1;
				ActionURL::url_method_t method = ActionURL::URL_METHOD_NOVARIABLES;
				bool constant_url = false;

				for(idx = 0; idx < count; ++idx) {
					if(indexes != 0) {
						// we need an inverted table; note that allocated
						// on the heap to have an inverted table should
						// not be much faster than this loop since in most
						// cases we'll have just 1 or 2 parameters
						pos = -1;
						for(int j = 0; j < count; ++j) {
							if(indexes[j] == idx) {
								pos = j;
								break;
							}
						}
						AS_ASSERT(pos >= 0);
					}
					else {
						pos = idx;
					}

					switch(idx) {
					case 0:
						if(regs[pos].f_reg < 0) {
							// compute the expression on the fly it has no
							// side effect (constant or no call(), assignment, etc.)
							as::NodePtr& expr = list.GetChild(pos);
							as::Data& data = expr.GetData();
							if(data.f_type == as::NODE_STRING) {
								// constant string!
								url_pos = pos;
								url = is_fscommand ? "FSCommand:" : "";
								url += data.f_str;
								constant_url = true;
							}
							else {
								if(is_fscommand) {
									pd = new ActionPushData(f_tag);
									pd->AddString("FSCommand:");
									f_actions->Insert(-1, pd);
									Expression(expr);
									a = new Action(f_tag, Action::ACTION_CONCATENATE);
									f_actions->Insert(-1, a);
								}
								else {
									Expression(expr);
								}
							}
						}
						else {
							f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
						}
						break;

					case 1:
						if(regs[pos].f_reg < 0) {
							// compute the expression on the fly it has no
							// side effect (constant or no call(), assignment, etc.)
							as::NodePtr& expr = list.GetChild(pos);
							as::Data& data = expr.GetData();
							if(data.f_type == as::NODE_STRING && constant_url) {
								// constant string!
								target_pos = pos;
								target = data.f_str;
							}
							else if(data.f_type == as::NODE_INT64 && constant_url && !is_fscommand) {
								// level defined by number
								// constant string!
								target_pos = pos;
								int target_no = data.f_int.Get();
								char buf[32];
								sprintf(buf, "_level%d", target_no);
								target = buf;
							}
							else {
								if(constant_url) {
									// It is constant, so we don't need to call Expression()
									// Also, the string may have "FSCommand:" pre-pended
									//Expression(list.GetChild(url_pos));
									pd = new ActionPushData(f_tag);
									pd->AddString(url.GetUTF8());
									f_actions->Insert(-1, pd);
									constant_url = false;
								}
								Expression(expr);
							}
						}
						else {
							if(constant_url) {
								Expression(list.GetChild(url_pos));
								constant_url = false;
							}
							f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
						}
						break;

					case 2:
						if(regs[pos].f_reg < 0) {
							// compute the expression on the fly it has no
							// side effect (constant or no call(), assignment, etc.)
							as::NodePtr& expr = list.GetChild(pos);
							as::Data& data = expr.GetData();
							if(data.f_type == as::NODE_UNDEFINED) {
								// user didn't define, use default
								method = ActionURL::URL_METHOD_NOVARIABLES;
							}
							else if(data.f_type == as::NODE_STRING) {
								// constant string!
								int len = data.f_str.GetLength();
								if(len == 0) {
									method = ActionURL::URL_METHOD_NOVARIABLES;
								}
								else {
									const long *str = data.f_str.Get();
									if(len == 3
									&& towupper(str[0]) == 'G'
									&& towupper(str[1]) == 'E'
									&& towupper(str[2]) == 'T') {
										method = ActionURL::URL_METHOD_GET;
									}
									else if(len == 4
									&& towupper(str[0]) == 'P'
									&& towupper(str[1]) == 'O'
									&& towupper(str[2]) == 'S'
									&& towupper(str[3]) == 'T') {
										method = ActionURL::URL_METHOD_POST;
									}
									else {
										f_error_stream->ErrMsg(as::AS_ERR_INVALID_EXPRESSION, expr, "invalid URL method, only an empty string, GET and POST are expected.");
									}
								}
							}
							else {
								method = ActionURL::URL_METHOD_UNDEFINED;
							}
						}
						else {
							method = ActionURL::URL_METHOD_UNDEFINED;
						}
						break;

					}
				}
				ActionURL *action_url = 0;
				if(method == ActionURL::URL_METHOD_UNDEFINED) {
					f_error_stream->ErrMsg(as::AS_ERR_INVALID_EXPRESSION, call, "the loadMovie[Num]() functions require the method parameter to be a constant string (empty, 'GET' or 'POST'). It cannot be dynamic.");
				}
				else if(constant_url && method == ActionURL::URL_METHOD_NOVARIABLES) {
					// we can make use of ACTION_URL instead of ACTION_URL2
					action_url = new ActionURL(f_tag, Action::ACTION_URL);
					char *str1 = url.GetUTF8();
					char *str2 = target.GetUTF8();
					action_url->SetURL(str1, str2);
					delete [] str1;
					delete [] str2;
				}
				else {
					if(constant_url) {
						Expression(list.GetChild(url_pos));
						Expression(list.GetChild(target_pos));
					}
					action_url = new ActionURL(f_tag, Action::ACTION_URL2);
					action_url->SetMethod(method);
				}
				f_actions->Insert(-1, action_url);

				// don't add anything on the stack
				idx = 0;
				end = 0;
			}
				break;

			default:
				// ignore others
				break;

			}
		}
		//int idx = count;
		//while(idx > 0)
		for(; idx != end; idx += step) {
			if(indexes != 0) {
				// we need an inverted table; note that allocated
				// on the heap to have an inverted table should
				// not be much faster than this loop since in most
				// cases we'll have just 1 or 2 parameters
				pos = -1;
				for(int j = 0; j < count; ++j) {
					if(indexes[j] == idx) {
						pos = j;
						break;
					}
				}

#if defined(_DEBUG) || defined(DEBUG)
if(pos == -1) {
	fprintf(stderr, "INTERNAL ERROR: count = %d, idx = %d (end: %d, step: %d), indexes[0] = %d\n", count, idx, end, step, indexes[0]);
}
#endif

				AS_ASSERT(pos >= 0);
			}
			else {
				pos = idx;
			}

//printf("Loading %d [%d]\n", pos, idx);

			AS_ASSERT(regs[pos].f_defined);
			if(regs[pos].f_reg < 0) {
				// compute the expression on the fly it has no
				// side effect (constant or no call(), assignment, etc.)
				as::NodePtr& expr = list.GetChild(pos);
				Expression(expr);
			}
			else {
				f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
			}

			if(special != 0) {
				switch(special->f_action) {
				case Action::ACTION_START_DRAG:
					if(idx == 2) {
						// rectangle flag (b3)
						pd = new ActionPushData(f_tag);
						pd->AddBoolean(true);
						f_actions->Insert(-1, pd);
					}
					break;

				default:
					// ignore others
					break;

				}
			}
		}
	}

	int array_reg = -1;
	if(array) {
		pd = new ActionPushData(f_tag);
		pd->AddInteger(count);
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
		f_actions->Insert(-1, a);

		// for out parameters to be read back we need to
		// save the register # and save a reference to
		// this array
		array_reg = f_registers.StoreRegister(f_tag, f_actions);
	}

	if(special == 0
	|| order == special_function_t::STACK_ORDER_REVERSED_COUNT
	|| order == special_function_t::STACK_ORDER_PERFECT_COUNT) {
// 4. push the number of arguments
		pd = new ActionPushData(f_tag);
		pd->AddInteger(array ? 1 : count);
		f_actions->Insert(-1, pd);
	}

	if(special == 0) {
// 5. push the name of the function
		if(name_data.f_type == as::NODE_SUPER) {
			// the constructor function name is 'undefined'
			pd = new ActionPushData(f_tag);
			pd->AddString("super");
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);
			pd = new ActionPushData(f_tag);
			pd->AddUndefined();
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_CALL_METHOD);
			f_actions->Insert(-1, a);
		}
		else if(name_data.f_type == as::NODE_MEMBER) {
			// when the parent of the CALL is a NEW
			// then we are creating an object
			as::NodePtr& parent = call.GetParent();
			as::Data& parent_data = parent.GetData();
			if(parent_data.f_type == as::NODE_NEW) {
				Member(name, Action::ACTION_NEW_METHOD);
			}
			else {
				Member(name, Action::ACTION_CALL_METHOD);
			}
// 6. call the method [right before exiting Member()]
		}
		else {
			if(name_data.f_type == as::NODE_IDENTIFIER) {
				pd = new ActionPushData(f_tag);
				char *str = 0;
				if(function.HasNode()) {
					as::Data& data = function.GetData();
					if(data.f_user_data.Size() != 0) {
						FunctionData **fd;
						fd = reinterpret_cast<FunctionData **>(data.f_user_data.Buffer());
						str = fd[0]->f_name.GetUTF8();
					}
				}
				if(str == 0) {
					str = name_data.f_str.GetUTF8();
				}
				pd->AddString(str);
				delete [] str;
				f_actions->Insert(-1, pd);
			}
			else {
				Expression(name);
			}

// 6. call the function
			a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
			f_actions->Insert(-1, a);
		}
	}
	else {
// 7. call the special function at once
		// special functions don't require a call, they are
		// "straight forward" functions
		switch(special->f_action) {
		case Action::ACTION_GOTO_FRAME:
		case Action::ACTION_URL:
		case Action::ACTION_URL2:
			// those are done earlier because they can vary
			// depending on the type of the parameters
			break;

		default:
			a = new Action(f_tag, special->f_action);
			f_actions->Insert(-1, a);
			break;

		}

		// TODO:
		// at this time, this is silly, but for us to have
		// a valid stack we need to push undefined in case
		// the special function does not otherwise return data?!
		// [should be optimized by the future DoAction optimizer]
		if(!special->f_returns) {
			pd = new ActionPushData(f_tag);
			pd->AddUndefined();
			f_actions->Insert(-1, pd);
		}
	}

// 8. read the "out" parameters back to our variables
	if((flags & as::NODE_FUNCTION_FLAG_OUT) != 0) {
		AS_ASSERT(indexes != 0);
		AS_ASSERT(array);
		// the parameters don't have to be in order...
		// but we can read the array in any order
		for(int idx = 0; idx < count; ++idx) {
			pos = indexes[idx];
			if(pos >= max_params) {
				// because we can name the "rest"
				// parameter, this needs to continue!
				continue;
			}
			param = parameters.GetChild(pos);
			as::Data& param_data = param.GetData();
			if((param_data.f_int.Get() & as::NODE_PARAMETERS_FLAG_OUT) == 0) {
				// is this one an out?!
				continue;
			}

			as::NodePtr& expr = list.GetChild(idx);
			as::Data& data = expr.GetData();
			// got to be a variable name!
			AS_ASSERT(data.f_type == as::NODE_IDENTIFIER);

			pd = new ActionPushData(f_tag);
			pd->AddRegister(array_reg);
			pd->AddInteger(pos);
			f_actions->Insert(-1, pd);

			a = new Action(f_tag, Action::ACTION_GET_MEMBER);
			f_actions->Insert(-1, a);

			as::NodePtr instance;
			Assignment(expr, instance, false);
		}
	}

// 9. free the register used for the array
	if(array_reg >= 0) {
		// TODO: put nil in the array reference so it gets
		//	 deleted (it probably doesn't matter much
		//	 at this time)
		/*
		pd = new ActionPushData(f_tag);
		pd->AddNull();
		pd->AddRegister();
		f_actions->Insert(-1, pd);
		delete [] name;

		a = new Action(f_tag, Action::ACTION_SET_LOCAL_VARIABLE);
		f_actions->Insert(-1, a);
		*/
		f_registers.FreeRegister(array_reg);
	}

// 10. free all the registers used for the parameters
	if(indexes != 0) {
		for(int pos = 0; pos < max_params; ++pos) {
			param = parameters.GetChild(pos);
			as::Data& param_data = param.GetData();
			p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
			if(p[0]->f_mode == FuncParam::MODE_REGISTER) {
				f_registers.FreeRegister(p[0]->f_reg);
			}
			delete p[0];
			param_data.f_user_data.New(0);
		}
	}

	delete [] regs;
}


void IntAssembler::Add(as::NodePtr& expr, bool right_to_left)
{
	Action		*a;

	int cnt = expr.GetChildCount();
	if(cnt == 1) {	// Positive
		// do nothing about this one
		// (should we do (expr + 0) instead?
		// or maybe (expr).ToNumber();?)
		Expression(expr.GetChild(0));
		return;
	}

	as::NodePtr& right = expr.GetChild(1);
	as::Data& right_data = right.GetData();
	if(right_data.f_type == as::NODE_INT64) {
		if(right_data.f_int.Get() == 1) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_INCREMENT);
			f_actions->Insert(-1, a);
			return;
		}
		if(right_data.f_int.Get() == -1) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DECREMENT);
			f_actions->Insert(-1, a);
			return;
		}
	}
	else if(right_data.f_type == as::NODE_FLOAT64) {
		if(right_data.f_float.Get() == 1.0) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_INCREMENT);
			f_actions->Insert(-1, a);
			return;
		}
		if(right_data.f_float.Get() == -1.0) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DECREMENT);
			f_actions->Insert(-1, a);
			return;
		}
	}

	as::NodePtr& left = expr.GetChild(0);
	as::Data& left_data = left.GetData();
	if(left_data.f_type == as::NODE_INT64) {
		if(left_data.f_int.Get() == 1) {
			Expression(expr.GetChild(1));
			a = new Action(f_tag, Action::ACTION_INCREMENT);
			f_actions->Insert(-1, a);
			return;
		}
		if(left_data.f_int.Get() == -1) {
			Expression(expr.GetChild(1));
			a = new Action(f_tag, Action::ACTION_DECREMENT);
			f_actions->Insert(-1, a);
			return;
		}
	}
	else if(left_data.f_type == as::NODE_FLOAT64) {
		if(left_data.f_float.Get() == 1.0) {
			Expression(expr.GetChild(1));
			a = new Action(f_tag, Action::ACTION_INCREMENT);
			f_actions->Insert(-1, a);
			return;
		}
		if(left_data.f_float.Get() == -1.0) {
			Expression(expr.GetChild(1));
			a = new Action(f_tag, Action::ACTION_DECREMENT);
			f_actions->Insert(-1, a);
			return;
		}
	}

	if(right_to_left) {
		Expression(expr.GetChild(1));
		Expression(expr.GetChild(0));
	}
	else {
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
	}
	a = new Action(f_tag, Action::ACTION_ADD_TYPED);
	f_actions->Insert(-1, a);
}


void IntAssembler::Subtract(as::NodePtr& expr, bool right_to_left)
{
	ActionPushData	*pd;
	Action		*a;

	int cnt = expr.GetChildCount();
	if(cnt == 1) {
		// there is not NEG in Flash do 0 - expr
		// 0 is pushed as an integer so if expr is
		// an integer, the result is an integer
		pd = new ActionPushData(f_tag);
		pd->AddInteger(0);
		f_actions->Insert(-1, pd);
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_SUBTRACT);
		f_actions->Insert(-1, a);
		return;
	}

	as::NodePtr& right = expr.GetChild(1);
	as::Data& right_data = right.GetData();
	if(right_data.f_type == as::NODE_INT64) {
		if(right_data.f_int.Get() == 1) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DECREMENT);
			f_actions->Insert(-1, a);
			return;
		}
		if(right_data.f_int.Get() == -1) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_INCREMENT);
			f_actions->Insert(-1, a);
			return;
		}
	}
	else if(right_data.f_type == as::NODE_FLOAT64) {
		if(right_data.f_float.Get() == 1.0) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_INCREMENT);
			f_actions->Insert(-1, a);
			return;
		}
		if(right_data.f_float.Get() == -1.0) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DECREMENT);
			f_actions->Insert(-1, a);
			return;
		}
	}

	if(right_to_left) {
		// for assignment we need to first compute the right
		// side and not the left
		Expression(expr.GetChild(1));
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
	}
	else {
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
	}
	a = new Action(f_tag, Action::ACTION_SUBTRACT);
	f_actions->Insert(-1, a);
}


void IntAssembler::Multiply(as::NodePtr& expr)
{
	Action		*a;

	// Here we simplify 2 x X or X x 2 as X + X
	// which is shorter in Flash

	as::NodePtr& child0 = expr.GetChild(0);
	as::Data& data0 = child0.GetData();
	if(data0.f_type == as::NODE_INT64) {
		if(data0.f_int.Get() == 2) {
			// TODO: if expr1 is a string, this is wrong
			Expression(expr.GetChild(1));
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_ADD);
			f_actions->Insert(-1, a);
			return;
		}
	}
	else if(data0.f_type == as::NODE_FLOAT64) {
		if(data0.f_float.Get() == 2.0f) {
			// TODO: if expr1 is a string, this is wrong
			Expression(expr.GetChild(1));
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_ADD);
			f_actions->Insert(-1, a);
			return;
		}
	}

	as::NodePtr& child1 = expr.GetChild(1);
	as::Data& data1 = child1.GetData();
	if(data1.f_type == as::NODE_INT64) {
		if(data1.f_int.Get() == 2) {
			// TODO: if expr1 is a string, this is wrong
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_ADD);
			f_actions->Insert(-1, a);
			return;
		}
	}
	else if(data1.f_type == as::NODE_FLOAT64) {
		if(data1.f_float.Get() == 2.0f) {
			// TODO: if expr1 is a string, this is wrong
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_ADD);
			f_actions->Insert(-1, a);
			return;
		}
	}

	Expression(expr.GetChild(0));
	Expression(expr.GetChild(1));
	a = new Action(f_tag, Action::ACTION_MULTIPLY);
	f_actions->Insert(-1, a);
}


void IntAssembler::Power(as::NodePtr& expr, bool right_to_left)
{
	Action			*a;

	// NOTE: expr ** 0 and expr ** 1 were already optimized
	//	 as was 1 ** expr

	// Simplify 'expr ** 2' into 'expr * expr'
	as::NodePtr& right = expr.GetChild(1);
	as::Data& right_data = right.GetData();
	if(right_data.f_type == as::NODE_INT64) {
		if(right_data.f_int.Get() == 2) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_MULTIPLY);
			f_actions->Insert(-1, a);
			return;
		}
	}
	else if(right_data.f_type == as::NODE_FLOAT64) {
		if(right_data.f_float.Get() == 2.0) {
			Expression(expr.GetChild(0));
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_MULTIPLY);
			f_actions->Insert(-1, a);
			return;
		}
	}

	if(right_to_left) {
		Expression(expr.GetChild(1));
		Expression(expr.GetChild(0));
	}
	else {
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		// TODO: make sure this is the right order for a function
		// NOTE: we could test whether the expressions have side
		//	 effects and put them in the right order at once
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
	}
	ActionPushData *pd = new ActionPushData(f_tag);
	pd->AddInteger(2);
	pd->AddString("Math.pow");
	f_actions->Insert(-1, pd);
	a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
	f_actions->Insert(-1, a);
}


void IntAssembler::VoidExpression(as::NodePtr& expr)
{
	Expression(expr);
	Action *a = new Action(f_tag, Action::ACTION_POP);
	f_actions->Insert(-1, a);
}


void IntAssembler::Assignment(as::NodePtr& name, as::NodePtr instance, bool duplicate)
{
	char		*str;
	Action		*a;
	ActionPushData	*pd;

	if(duplicate) {
		a = new Action(f_tag, Action::ACTION_DUPLICATE);
		f_actions->Insert(-1, a);
	}

	if(!instance.HasNode()) {
		as::Data& name_data = name.GetData();
		switch(name_data.f_type) {
		case as::NODE_MEMBER:
			Member(name, Action::ACTION_SET_MEMBER);
			return;

		case as::NODE_ARRAY:
			Array(name, Action::ACTION_SET_MEMBER);
			return;

		case as::NODE_IDENTIFIER:
			instance = name.GetLink(as::NodePtr::LINK_INSTANCE);
			break;

		default:
			break;

		}
	}

	if(instance.HasNode()) {
		as::Data& inst_data = instance.GetData();

		if(inst_data.f_type == as::NODE_PARAM) {
			// this is not a variable, deal with this
			// as a function parameter with the FuncParam
			FuncParam **p;
			p = reinterpret_cast<FuncParam **>(inst_data.f_user_data.Buffer());

			switch(p[0]->f_mode) {
			case FuncParam::MODE_REGISTER:
				f_registers.Store(p[0]->f_reg, f_tag, f_actions, true);
				break;

			case FuncParam::MODE_CONSTANT:
				f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, name, "IntAssembler::Assignment() cannot assign a constant function parameter.");
				break;

			case FuncParam::MODE_ARRAY:
			{
				f_registers.LoadRegister(p[0]->f_reg, false, f_tag, f_actions);
				ActionPushData *pd = new ActionPushData(f_tag);
				pd->AddInteger(p[0]->f_index);
				f_actions->Insert(-1, pd);
				Action *a = new Action(f_tag, Action::ACTION_SET_MEMBER);
				f_actions->Insert(-1, a);
			}
				break;

			case FuncParam::MODE_VARIABLE:
				f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, name, "IntAssembler::Assignment() MODE_VARIABLE not written yet.");
				break;

			default:
				f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, name, "found a NODE_PARAM with an unknown FuncParam::mode_t value (%d).", p[0]->f_mode);
				break;

			}
			return;
		}

		// special case when we are setting a variable member from
		// a function in a class
		if(inst_data.f_type == as::NODE_VARIABLE
		&& (inst_data.f_int.Get() & as::NODE_VAR_FLAG_MEMBER) != 0) {
			pd = new ActionPushData(f_tag);
			pd->AddString("this");
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);

			pd = new ActionPushData(f_tag);
			str = inst_data.f_str.GetUTF8();
			pd->AddString(str);
			delete [] str;
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);

			a = new Action(f_tag, Action::ACTION_SET_MEMBER);
			f_actions->Insert(-1, a);
			return;
		}

		if((instance.GetAttrs() & as::NODE_ATTR_DYNAMIC) != 0) {
			// dynamic variables need to be accessed
			// by their original name only
			str = inst_data.f_str.GetUTF8();
		}
		else {
			VariableData **vd;
			if(inst_data.f_user_data.Size() == 0) {
				inst_data.f_user_data.New((sizeof(VariableData *) + sizeof(int) - 1) / sizeof(int));
				vd = reinterpret_cast<VariableData **>(inst_data.f_user_data.Buffer());
				vd[0] = new VariableData;
				if((inst_data.f_int.Get() & as::NODE_VAR_FLAG_LOCAL) == 0) {
					// global variables need to be accessed by name
					// (thought we change the name)
					vd[0]->GenerateName("__g");
				}
				else {
					// local variables we allocate a register if possible
					vd[0]->f_reg = f_registers.AllocRegister();
					if(vd[0]->f_reg >= 0) {
						vd[0]->f_mode = VariableData::MODE_REGISTER;
					}
					else {
						vd[0]->GenerateName("__l");
					}
				}
			}
			else {
				vd = reinterpret_cast<VariableData **>(inst_data.f_user_data.Buffer());
			}
			if(vd[0]->f_mode == VariableData::MODE_REGISTER) {
				f_registers.Store(vd[0]->f_reg, f_tag, f_actions, true);
				return;
			}
			str = vd[0]->f_name.GetUTF8();
		}

		pd = new ActionPushData(f_tag);
		pd->AddString(str);
		f_actions->Insert(-1, pd);

		delete [] str;
	}
	else {
		// a dynamically defined variable name
		Expression(name);
	}


	// ECMAScript says that first you need to computer
	// the right handside of an assignment; makes sense
	// to me too, but to set a variable you need that
	// swapped in Flash...
	a = new Action(f_tag, Action::ACTION_SWAP);
	f_actions->Insert(-1, a);

	if(instance.HasNode()) {
		as::Data& inst_data = instance.GetData();
		a = new Action(f_tag,
			(inst_data.f_int.Get() & as::NODE_VAR_FLAG_LOCAL) == 0 ?
				Action::ACTION_SET_VARIABLE
				: Action::ACTION_SET_LOCAL_VARIABLE);
	}
	else {
		a = new Action(f_tag, Action::ACTION_SET_VARIABLE);
	}

	f_actions->Insert(-1, a);
}


void IntAssembler::ExpressionAssignment(as::NodePtr& expr, as::node_t type)
{
	ActionPushData		*pd;
	ActionBranch		*branch;
	ActionLabel		*label;
	Action			*a;
	as::String		l1;
	char			*str1;
	int			reg;

	// note that a = b returns a copy of a; if the
	// expression is to return void, we should avoid
	// the duplicate here... [optimized later?]
	Expression(expr.GetChild(1));

	if(type != as::NODE_ASSIGNMENT) {
		reg = -1;

		switch(type) {
		case as::NODE_ASSIGNMENT_LOGICAL_XOR:
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_MAXIMUM:
		case as::NODE_ASSIGNMENT_MINIMUM:
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_ROTATE_LEFT:
		case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
			pd = new ActionPushData(f_tag);
			pd->AddInteger(31);
			f_actions->Insert(-1, pd);
			a = new Action(f_tag, Action::ACTION_AND);
			f_actions->Insert(-1, a);
			reg = f_registers.StoreRegister(f_tag, f_actions);
			a = new Action(f_tag, Action::ACTION_POP);
			f_actions->Insert(-1, a);
			break;

		default:
			// do nothing for the others
			break;

		}
		Expression(expr.GetChild(0));
		Action *a;
		switch(type) {
		case as::NODE_ASSIGNMENT_BITWISE_AND:
			a = new Action(f_tag, Action::ACTION_AND);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_BITWISE_OR:
			a = new Action(f_tag, Action::ACTION_OR);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_BITWISE_XOR:
			a = new Action(f_tag, Action::ACTION_XOR);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_DIVIDE:
			// TODO: test that expressions don't need to be swapped
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_DIVIDE);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_LOGICAL_AND:
			a = new Action(f_tag, Action::ACTION_LOGICAL_AND);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_LOGICAL_OR:
			a = new Action(f_tag, Action::ACTION_LOGICAL_OR);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_LOGICAL_XOR:
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_MAXIMUM:
		case as::NODE_ASSIGNMENT_MINIMUM:
			//	expr[0]
			//	dup
			//	expr[1]
			//	store_reg
			//	if_greater_than done [MAXIMUM]
			//	if_less_than done [MINIMUM]
			//	pop
			//	load_reg
			// done:
			reg = f_registers.StoreRegister(f_tag, f_actions);
			a = new Action(f_tag, type == as::NODE_ASSIGNMENT_MAXIMUM ?
					Action::ACTION_GREATER_THAN_TYPED
						: Action::ACTION_LESS_THAN_TYPED);
			f_actions->Insert(-1, a);
			branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
			Label(l1);
			str1 = l1.GetUTF8();
			branch->SetLabel(str1);
			f_actions->Insert(-1, branch);
			a = new Action(f_tag, Action::ACTION_POP);
			f_actions->Insert(-1, a);
			f_registers.LoadRegister(reg, true, f_tag, f_actions);
			label = new ActionLabel(f_tag);
			label->SetLabel(str1);
			f_actions->Insert(-1, label);
			delete [] str1;
			break;

		case as::NODE_ASSIGNMENT_MODULO:
			// TODO: test that expressions don't need to be swapped
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_MODULO);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_MULTIPLY:
			a = new Action(f_tag, Action::ACTION_MULTIPLY);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_ROTATE_LEFT:
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			f_registers.LoadRegister(reg, false, f_tag, f_actions);
			a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			pd = new ActionPushData(f_tag);
			pd->AddInteger(32);
			f_actions->Insert(-1, pd);
			f_registers.LoadRegister(reg, true, f_tag, f_actions);
			a = new Action(f_tag, Action::ACTION_SUBTRACT);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_OR);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
			f_registers.LoadRegister(reg, false, f_tag, f_actions);
			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			pd = new ActionPushData(f_tag);
			pd->AddInteger(32);
			f_actions->Insert(-1, pd);
			f_registers.LoadRegister(reg, true, f_tag, f_actions);
			a = new Action(f_tag, Action::ACTION_SUBTRACT);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_OR);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_SHIFT_LEFT:
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_SHIFT_RIGHT:
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT);
			f_actions->Insert(-1, a);
			break;

		case as::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
			a = new Action(f_tag, Action::ACTION_SWAP);
			f_actions->Insert(-1, a);
			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
			f_actions->Insert(-1, a);
			break;

		default:
			f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, expr, "unsupported assignment #%d in IntAssembler::ExpressionAssignment().", type);
			break;

		}
	}

	as::NodePtr instance;
	Assignment(expr.GetChild(0), instance, true);
}


void IntAssembler::ExpressionAssignmentAdd(as::NodePtr& expr)
{
	// first, compute a ** b making sure we first evaluate
	// b and not a 
	Add(expr, true);

	as::NodePtr instance;
	Assignment(expr.GetChild(0), instance, true);
}


void IntAssembler::ExpressionAssignmentSubtract(as::NodePtr& expr)
{
	// first, compute a ** b making sure we first evaluate
	// b and not a 
	Subtract(expr, true);

	as::NodePtr instance;
	Assignment(expr.GetChild(0), instance, true);
}


void IntAssembler::ExpressionAssignmentPower(as::NodePtr& expr)
{
	// first, compute a ** b making sure we first evaluate
	// b and not a 
	Power(expr, true);

	as::NodePtr instance;
	Assignment(expr.GetChild(0), instance, true);
}


void IntAssembler::ExpressionIncrement(as::NodePtr& expr, as::node_t type)
{
	as::NodePtr		instance;

	// ++a becomes a = a + 1
	// however ++expr becomes expr + 1
	as::NodePtr& child = expr.GetChild(0);
	Expression(child);
	Action *a = new Action(f_tag, type == as::NODE_INCREMENT ? Action::ACTION_INCREMENT : Action::ACTION_DECREMENT);
	f_actions->Insert(-1, a);

	as::Data& data = child.GetData();
	switch(data.f_type) {
	case as::NODE_IDENTIFIER:
		Assignment(child, instance, true);
		break;

	case as::NODE_MEMBER:
		Member(child, Action::ACTION_SET_MEMBER);
		break;

	default:
		// there is nothing special to do with the value here
		break;

	}
}


void IntAssembler::ExpressionPostIncrement(as::NodePtr& expr, as::node_t type)
{
	Action		*a;
	as::NodePtr	instance;

	// a++ becomes t = a, a = a + 1, t
	// however expr++ becomes expr
	// note 1: non-intrinsic post in/decrement don't get here
	// note 2: instead of using a temp, we use duplicate
	as::NodePtr& child = expr.GetChild(0);
	as::Data& child_data = child.GetData();
	switch(child_data.f_type) {
	case as::NODE_IDENTIFIER:
		// <expr>
		// dup
		// increment or decrement
		// <set variable>
		ExpressionIdentifier(child);

		a = new Action(f_tag, Action::ACTION_DUPLICATE);
		f_actions->Insert(-1, a);

		a = new Action(f_tag, type == as::NODE_POST_INCREMENT ? Action::ACTION_INCREMENT : Action::ACTION_DECREMENT);
		f_actions->Insert(-1, a);

		Assignment(child, instance, false);
		break;

	case as::NODE_MEMBER:
		Member(child, Action::ACTION_GET_MEMBER);

		a = new Action(f_tag, Action::ACTION_DUPLICATE);
		f_actions->Insert(-1, a);

		a = new Action(f_tag, type == as::NODE_POST_INCREMENT ? Action::ACTION_INCREMENT : Action::ACTION_DECREMENT);
		f_actions->Insert(-1, a);

		Member(child, Action::ACTION_SET_MEMBER);
		break;

	default:
		// it's not necessary to do + 1 on a throw
		// away value! [this may get optimized in
		// the compiler one day; or it may have
		// to become an error...]
		Expression(child);
		break;

	}
}



void IntAssembler::ExpressionConditional(as::NodePtr& expr)
{
	ActionBranch		*branch;
	ActionLabel		*label;
	char			*str1, *str2;
	as::String		l1, l2;

	// note: this is compiled the other way around since we
	// can branch if true and we can avoid a logical not in
	// this way

	Expression(expr.GetChild(0));
	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
	Label(l1);
	str1 = l1.GetUTF8();
	branch->SetLabel(str1);
	f_actions->Insert(-1, branch);
	Expression(expr.GetChild(2));
	branch = new ActionBranch(f_tag);
	Label(l2);
	str2 = l2.GetUTF8();
	branch->SetLabel(str2);
	f_actions->Insert(-1, branch);
	label = new ActionLabel(f_tag);
	label->SetLabel(str1);
	f_actions->Insert(-1, label);
	Expression(expr.GetChild(1));
	label = new ActionLabel(f_tag);
	label->SetLabel(str2);
	f_actions->Insert(-1, label);
	delete [] str1;
	delete [] str2;
}


void IntAssembler::ExpressionNew(as::NodePtr& expr)
{
	ActionPushData		*pd;
	Action			*a;
	char			*str;

	as::Data& data = expr.GetData();
	switch(data.f_type) {
	case as::NODE_IDENTIFIER:
		pd = new ActionPushData(f_tag);
		pd->AddInteger(0);
		f_actions->Insert(-1, pd);

		pd = new ActionPushData(f_tag);
		str = data.f_str.GetUTF8();
		pd->AddString(str);
		delete [] str;
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_MEMBER:
		// special case which has no parameters
		pd = new ActionPushData(f_tag);
		pd->AddInteger(0);
		f_actions->Insert(-1, pd);
		Member(expr, Action::ACTION_NEW_METHOD);
		return;

	case as::NODE_CALL:
		Expression(expr);
		return;

	default:
		pd = new ActionPushData(f_tag);
		pd->AddInteger(0);
		f_actions->Insert(-1, pd);

		Expression(expr);
		break;

	}
	a = new Action(f_tag, Action::ACTION_NEW);
	f_actions->Insert(-1, a);
}


void IntAssembler::ExpressionDelete(as::NodePtr& expr)
{
	ActionPushData		*pd;
	Action			*a;
	char			*str;

	as::Data& data = expr.GetData();
	switch(data.f_type) {
	case as::NODE_IDENTIFIER:
		pd = new ActionPushData(f_tag);
		//pd->AddUndefined();
		pd->AddString("_root");
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);

		pd = new ActionPushData(f_tag);
		str = data.f_str.GetUTF8();
		pd->AddString(str);
		delete [] str;
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_MEMBER:
		Member(expr, Action::ACTION_DELETE);
		return;

	default:
		pd = new ActionPushData(f_tag);
		//pd->AddUndefined();
		pd->AddString("_root");
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);

		Expression(expr);
		break;

	}
	a = new Action(f_tag, Action::ACTION_DELETE);
	f_actions->Insert(-1, a);
}


void IntAssembler::ExpressionVoid(as::NodePtr& expr)
{
	Expression(expr.GetChild(0));

	// replace result value by undefined
	Action *a = new Action(f_tag, Action::ACTION_POP);
	f_actions->Insert(-1, a);
	ActionPushData *pd = new ActionPushData(f_tag);
	pd->AddUndefined();
	f_actions->Insert(-1, pd);
}


void IntAssembler::ExpressionAs(as::NodePtr& expr)
{
	Action		*a;

	Expression(expr.GetChild(0));
	Expression(expr.GetChild(1));
	a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
	f_actions->Insert(-1, a);
	a = new Action(f_tag, Action::ACTION_SWAP);
	f_actions->Insert(-1, a);
	a = new Action(f_tag, Action::ACTION_CAST_OBJECT);
	f_actions->Insert(-1, a);
}


void IntAssembler::ExpressionList(as::NodePtr& expr)
{
	int idx;
	int max = expr.GetChildCount();
	if(max > 0) {
		for(idx = 0; idx < max; ++idx) {
			// discard the result of all the expressions
			VoidExpression(expr.GetChild(idx));
		}
		// except the last one
		Expression(expr.GetChild(idx));
	}
}


void IntAssembler::ExpressionArrayLiteral(as::NodePtr& expr)
{
	ActionPushData		*pd;
	Action			*a;
	int			idx, max;

	// NOTE:
	//	We can use the ACTION_DECLARE_ARRAY only if all our
	//	values are constants, otherwise we can't predict the
	//	result (i.e. whether some function calls could
	//	have side effects). Thus we create an empty array
	//	and start to fill it as required instead.

	max = expr.GetChildCount();
	as::NodePtr list = expr;
	if(max == 1) {
		list = expr.GetChild(0);
		as::Data& data = list.GetData();
		if(data.f_type != as::NODE_LIST) {
			list = expr;
		}
		else {
			max = list.GetChildCount();
		}
	}

	if(!expr.HasSideEffects()) {
		//
		//	push item (backward)
		//	...
		//	push count
		//	declare array
		//
		idx = max;
		while(idx > 0) {
			idx--;
			Expression(list.GetChild(idx));
		}
		pd = new ActionPushData(f_tag);
		pd->AddInteger(max);
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
		f_actions->Insert(-1, a);
	}
	else {
		//
		//	push 0
		//	declare array
		// <this is not a label per say, just what we repeat in our loop>
		// repeat:
		//	duplicate
		//	push index
		//	push value
		//	set member
		//	<if more members, repeat>
		//

		// An empty array
		pd = new ActionPushData(f_tag);
		pd->AddInteger(0);
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
		f_actions->Insert(-1, a);

		for(idx = 0; idx < max; ++idx) {
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);

			pd = new ActionPushData(f_tag);
			pd->AddInteger(idx);
			f_actions->Insert(-1, pd);

			Expression(list.GetChild(idx));

			a = new Action(f_tag, Action::ACTION_SET_MEMBER);
			f_actions->Insert(-1, a);
		}
	}
}


void IntAssembler::ExpressionObjectLiteral(as::NodePtr& expr)
{
	ActionPushData		*pd;
	Action			*a;
	char			*str;
	int			idx, max;

	// IMPORTANT NOTE:
	//	The ACTION_DECLARE_OBJECT has one advantage: we don't
	//	need any specific order to declare the object members.
	//	This means we can do it in the right order without
	//	having to worry about anything.

	// <this is not a label per say, just what we repeat in our loop>
	// repeat:
	//	push name
	//	push value
	//	<if more members, repeat>
	//	push count / 2
	//	declare object
	//
	max = expr.GetChildCount();

	for(idx = 0; idx < max; idx += 2) {
		as::NodePtr& name = expr.GetChild(idx);
		as::Data& name_data = name.GetData();
		switch(name_data.f_type) {
		case as::NODE_TYPE:
			// dynamic name
			Expression(name.GetChild(0));
			break;

		case as::NODE_IDENTIFIER:
		case as::NODE_STRING:
			pd = new ActionPushData(f_tag);
			str = name_data.f_str.GetUTF8();
			pd->AddString(str);
			delete [] str;
			f_actions->Insert(-1, pd);
			break;

		case as::NODE_INT64:
			pd = new ActionPushData(f_tag);
			pd->AddInteger(name_data.f_int.Get());
			f_actions->Insert(-1, pd);
			break;

		case as::NODE_FLOAT64:
			pd = new ActionPushData(f_tag);
			pd->AddDouble(name_data.f_float.Get());
			f_actions->Insert(-1, pd);
			break;

		default:
			// unsupported type for the type of an object name
			AS_ASSERT(0);
			return;

		}

		Expression(expr.GetChild(idx + 1));

		//a = new Action(f_tag, Action::ACTION_SWAP);
		//f_actions->Insert(-1, a);
	}

	pd = new ActionPushData(f_tag);
	pd->AddInteger(max / 2);
	f_actions->Insert(-1, pd);

	a = new Action(f_tag, Action::ACTION_DECLARE_OBJECT);
	f_actions->Insert(-1, a);
}


void IntAssembler::Expression(as::NodePtr& expr)
{
	ActionPushData		*pd;
	ActionBranch		*branch;
	ActionLabel		*label;
	Action			*a;
	char			*str, *str1;
	int			reg;
	as::String		l1, l2;

	as::Data& data = expr.GetData();

	switch(data.f_type) {
	case as::NODE_TRUE:
		pd = new ActionPushData(f_tag);
		pd->AddBoolean(true);
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_FALSE:
		pd = new ActionPushData(f_tag);
		pd->AddBoolean(false);
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_UNDEFINED:
		pd = new ActionPushData(f_tag);
		pd->AddUndefined();
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_NULL:
		pd = new ActionPushData(f_tag);
		pd->AddNull();
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_ARRAY_LITERAL:
		ExpressionArrayLiteral(expr);
		break;

	case as::NODE_OBJECT_LITERAL:
		ExpressionObjectLiteral(expr);
		break;

	case as::NODE_VOID:
		ExpressionVoid(expr);
		break;

	case as::NODE_FUNCTION:
		Function(expr, false);
		break;

	case as::NODE_INT64:
		pd = new ActionPushData(f_tag);
		pd->AddInteger(data.f_int.Get());
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_FLOAT64:
		pd = new ActionPushData(f_tag);
		pd->AddDouble(data.f_float.Get());
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_STRING:
		pd = new ActionPushData(f_tag);
		str = data.f_str.GetUTF8();
		pd->AddString(str);
		delete [] str;
		f_actions->Insert(-1, pd);
		break;

	case as::NODE_IDENTIFIER:
	case as::NODE_VIDENTIFIER:
		ExpressionIdentifier(expr);
		break;

	case as::NODE_THIS:
		pd = new ActionPushData(f_tag);
		pd->AddString("this");
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_SUPER:
		pd = new ActionPushData(f_tag);
		pd->AddString("super");
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_ARRAY:
		Array(expr, Action::ACTION_GET_MEMBER);
		break;

	case as::NODE_MEMBER:
		Member(expr, Action::ACTION_GET_MEMBER);
		break;

	case as::NODE_CALL:
		Call(expr);
		break;

	case as::NODE_ADD:
		Add(expr, false);
		break;

	case as::NODE_SUBTRACT:
		Subtract(expr, false);
		break;

	case as::NODE_BITWISE_NOT:
		// TODO: test validity with floats...
		// in Flash, there isn't a bitwise not, use the XOR
		// instead
		pd = new ActionPushData(f_tag);
		pd->AddInteger(-1);
		f_actions->Insert(-1, pd);
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_XOR);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_DECREMENT:
	case as::NODE_INCREMENT:
		ExpressionIncrement(expr, data.f_type);
		break;

	case as::NODE_POST_DECREMENT:
	case as::NODE_POST_INCREMENT:
		ExpressionPostIncrement(expr, data.f_type);
		break;

	case as::NODE_LOGICAL_NOT:
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_LOGICAL_AND:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_LOGICAL_AND);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_LOGICAL_OR:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_LOGICAL_OR);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_LOGICAL_XOR:
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_INSTANCEOF:
	case as::NODE_IS:		// TODO: this is only slightly different...
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_INSTANCE_OF);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_TYPEOF:
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_TYPE_OF);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_BITWISE_AND:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_AND);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_BITWISE_OR:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_OR);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_BITWISE_XOR:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_XOR);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_CONDITIONAL:
		ExpressionConditional(expr);
		break;

	case as::NODE_DIVIDE:
		// TODO: test that it doesn't need to be swapped
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_DIVIDE);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_EQUAL:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_EQUAL_TYPED);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_GREATER:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_GREATER_EQUAL:
		// a >= b <=> !(a < b)
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_IN:
		// here we need to enumerate and then compare
		// each item one by one...
		// or test if value is in range
		ExprIn(expr);
		break;

	case as::NODE_LESS:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_LESS_EQUAL:
		// a <= b <=> !(a > b)
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_MAXIMUM:
	case as::NODE_MINIMUM:
		//	expr[0]
		//	dup
		//	expr[1]
		//	store_reg
		//	if_greater_than done [MAXIMUM]
		//	if_less_than done [MINIMUM]
		//	pop
		//	load_reg
		// done:
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_DUPLICATE);
		f_actions->Insert(-1, a);
		Expression(expr.GetChild(1));
		reg = f_registers.StoreRegister(f_tag, f_actions);
		a = new Action(f_tag, data.f_type == as::NODE_MAXIMUM ?
				Action::ACTION_GREATER_THAN_TYPED
					: Action::ACTION_LESS_THAN_TYPED);
		f_actions->Insert(-1, a);
		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
		Label(l1);
		str1 = l1.GetUTF8();
		branch->SetLabel(str1);
		f_actions->Insert(-1, branch);
		a = new Action(f_tag, Action::ACTION_POP);
		f_actions->Insert(-1, a);
		f_registers.LoadRegister(reg, true, f_tag, f_actions);
		label = new ActionLabel(f_tag);
		label->SetLabel(str1);
		f_actions->Insert(-1, label);
		delete [] str1;
		break;

	case as::NODE_MODULO:
		// TODO: test that expressions don't need to be swapped
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_MODULO);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_MULTIPLY:
		Multiply(expr);
		break;

	case as::NODE_NOT_EQUAL:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_EQUAL_TYPED);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_POWER:
		Power(expr, false);
		break;

	case as::NODE_ROTATE_LEFT:
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_DUPLICATE);
		f_actions->Insert(-1, a);
		Expression(expr.GetChild(1));
		pd = new ActionPushData(f_tag);
		pd->AddInteger(31);
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_AND);
		f_actions->Insert(-1, a);
		reg = f_registers.StoreRegister(f_tag, f_actions);
		a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
		pd = new ActionPushData(f_tag);
		pd->AddInteger(32);
		f_actions->Insert(-1, pd);
		f_registers.LoadRegister(reg, true, f_tag, f_actions);
		a = new Action(f_tag, Action::ACTION_SUBTRACT);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_OR);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_ROTATE_RIGHT:
		Expression(expr.GetChild(0));
		a = new Action(f_tag, Action::ACTION_DUPLICATE);
		f_actions->Insert(-1, a);
		Expression(expr.GetChild(1));
		pd = new ActionPushData(f_tag);
		pd->AddInteger(31);
		f_actions->Insert(-1, pd);
		a = new Action(f_tag, Action::ACTION_AND);
		f_actions->Insert(-1, a);
		reg = f_registers.StoreRegister(f_tag, f_actions);
		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
		pd = new ActionPushData(f_tag);
		pd->AddInteger(32);
		f_actions->Insert(-1, pd);
		f_registers.LoadRegister(reg, true, f_tag, f_actions);
		a = new Action(f_tag, Action::ACTION_SUBTRACT);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_OR);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_SHIFT_LEFT:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_SHIFT_RIGHT:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_SHIFT_RIGHT_UNSIGNED:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_STRICTLY_EQUAL:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_STRICTLY_NOT_EQUAL:
		Expression(expr.GetChild(0));
		Expression(expr.GetChild(1));
		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
		f_actions->Insert(-1, a);
		break;

	case as::NODE_NEW:
		ExpressionNew(expr.GetChild(0));
		break;

	case as::NODE_DELETE:
		ExpressionDelete(expr.GetChild(0));
		break;

	case as::NODE_ASSIGNMENT:
	case as::NODE_ASSIGNMENT_BITWISE_AND:
	case as::NODE_ASSIGNMENT_BITWISE_OR:
	case as::NODE_ASSIGNMENT_BITWISE_XOR:
	case as::NODE_ASSIGNMENT_DIVIDE:
	case as::NODE_ASSIGNMENT_LOGICAL_AND:
	case as::NODE_ASSIGNMENT_LOGICAL_OR:
	case as::NODE_ASSIGNMENT_LOGICAL_XOR:
	case as::NODE_ASSIGNMENT_MAXIMUM:
	case as::NODE_ASSIGNMENT_MINIMUM:
	case as::NODE_ASSIGNMENT_MODULO:
	case as::NODE_ASSIGNMENT_MULTIPLY:
	case as::NODE_ASSIGNMENT_ROTATE_LEFT:
	case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
	case as::NODE_ASSIGNMENT_SHIFT_LEFT:
	case as::NODE_ASSIGNMENT_SHIFT_RIGHT:
	case as::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
		ExpressionAssignment(expr, data.f_type);
		break;

	case as::NODE_ASSIGNMENT_ADD:
		ExpressionAssignmentAdd(expr);
		break;

	case as::NODE_ASSIGNMENT_SUBTRACT:
		ExpressionAssignmentSubtract(expr);
		break;

	case as::NODE_ASSIGNMENT_POWER:
		ExpressionAssignmentPower(expr);
		break;

	case as::NODE_AUTO:
	{
		// function parameters auto-assignment of undefined entries
		as::NodePtr& auto_expr = expr.GetLink(as::NodePtr::LINK_INSTANCE);
		Expression(auto_expr);
	}
		break;

	case as::NODE_AS:
		ExpressionAs(expr);
		break;

	case as::NODE_LIST:
		ExpressionList(expr);
		break;

	case as::NODE_RANGE:
	case as::NODE_MATCH:
	default:
		f_error_stream->ErrMsg(as::AS_ERR_NOT_SUPPORTED, expr, "expression type (%d) not yet implemented in IntAssembler::Expression().", data.f_type);
		break;

	}
}




//**********************************************************************
//***  REGISTERS STACK  ************************************************
//**********************************************************************
IntAssembler::Registers::Registers(void)
{
	f_previous = 0;

	f_reg = 4;
	f_reg_max = 4;		// in a function it goes to 254 (v7)
	memset(f_regs, 0, sizeof(f_regs));
}

IntAssembler::Registers::Registers(const Registers& src)
{
	f_previous = src.f_previous;

	f_reg = src.f_reg;
	f_reg_max = src.f_reg_max;
	memcpy(f_regs, src.f_regs, sizeof(f_regs));
}

IntAssembler::Registers::~Registers()
{
	if(f_previous) {
		delete f_previous;
	}
}

void IntAssembler::Registers::Push(int max)
{
	f_previous = new Registers(*this);

	f_reg = max;
	f_reg_max = max;
	memset(f_regs, 0, sizeof(f_regs));
}

void IntAssembler::Registers::Pop(void)
{
	Registers *p = f_previous;

	AS_ASSERT(p != 0);

	f_reg = p->f_reg;
	f_reg_max = p->f_reg_max;
	memcpy(f_regs, p->f_regs, sizeof(f_regs));
	f_previous = p->f_previous;

	p->f_previous = 0;
	delete p;
}

int IntAssembler::Registers::AllocRegister(int start)
{
	int		r;

	for(r = start; r < f_reg_max; ++r) {
		if(f_regs[r] == 0) {
			f_regs[r] = 1;
			return r;
		}
	}

	return -1;
}

void IntAssembler::Registers::Store(int r, TagBase *f_tag, Vectors *f_actions, bool pop)
{
	ActionStoreRegister	*store_register;
	Action			*a;

	store_register = new ActionStoreRegister(f_tag);
	store_register->SetRegister(r);
	f_actions->Insert(-1, store_register);

	if(pop) {
		a = new Action(f_tag, Action::ACTION_POP);
		f_actions->Insert(-1, a);
	}
}

int IntAssembler::Registers::StoreRegister(TagBase *f_tag, Vectors *f_actions, bool pop)
{
	ActionPushData	*pd;
	Action		*a;
	char		buf[256];
	int		r;

	r = AllocRegister();

	if(r < 0) {
		// f_reg starts at f_reg_max
		// (i.e. 4 in a global context and 254 in a function)
		r = f_reg;
		f_reg++;

		// the store doesn't eat the input, a set var does
		if(!pop) {
			a = new Action(f_tag, Action::ACTION_DUPLICATE);
			f_actions->Insert(-1, a);
		}

		// no more reg available, use a temporary variable
		snprintf(buf, sizeof(buf), "__t%d", r);
		pd = new ActionPushData(f_tag);
		pd->AddString(buf);
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_SWAP);
		f_actions->Insert(-1, a);
		a = new Action(f_tag, Action::ACTION_SET_LOCAL_VARIABLE);
		f_actions->Insert(-1, a);
	}
	else {
		Store(r, f_tag, f_actions, pop);
	}

	return r;
}

void IntAssembler::Registers::LoadRegister(int r, bool to_free, TagBase *f_tag, Vectors *f_actions)
{
	ActionPushData	*pd;
	Action		*a;
	char		buf[256];

	// the load does the equivalent to a push data from a register
	if(r >= f_reg_max) {
		// if we are releasing the last register allocated
		// we can get it back so as to reuse it!
		if(r == f_reg - 1 && to_free) {
			--f_reg;
		}

		// load the temporary variable
		snprintf(buf, sizeof(buf), "__t%d", r);
		pd = new ActionPushData(f_tag);
		pd->AddString(buf);
		f_actions->Insert(-1, pd);

		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
		f_actions->Insert(-1, a);
	}
	else {
		pd = new ActionPushData(f_tag);
		pd->AddRegister(r);
		f_actions->Insert(-1, pd);

		if(to_free) {
			f_regs[r] = 0;
		}
	}
}

void IntAssembler::Registers::FreeRegister(int r)
{
	// the load does the equivalent to a push data from a register
	if(r >= f_reg_max) {
		// if we are releasing the last register allocated
		// we can get it back so as to reuse it!
		if(r == f_reg - 1) {
			--f_reg;
		}
	}
	else if(r >= 0) {
		f_regs[r] = 0;
	}
}



//**********************************************************************
//***  VARIABLE DATA  **************************************************
//**********************************************************************
int IntAssembler::VariableData::g_unique;

void IntAssembler::VariableData::GenerateName(const char *introducer)
{
	char		buf[256];

	g_unique++;
	snprintf(buf, sizeof(buf) - 1, "%s%d", introducer, g_unique);
	buf[sizeof(buf) - 1] = '\0';

	f_mode = MODE_VARIABLE;
	f_name = buf;
}



};	// namespace asas
};	// namespace sswf
