1 /* assembler.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2009 */
2 
3 /*
4 
5 Copyright (c) 2005-2009 Made to Order Software Corp.
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 #include	"assembler.h"
35 
36 
37 namespace sswf
38 {
39 namespace asas
40 {
41 
42 
43 //**********************************************************************
44 //***  PUBLIC ASSEMBLER  ***********************************************
45 //**********************************************************************
Assembler(void)46 Assembler::Assembler(void)
47 {
48 	f_error_stream = &f_default_error_stream;
49 	f_options = 0;
50 }
51 
~Assembler()52 Assembler::~Assembler()
53 {
54 }
55 
AssembleClasses(as::NodePtr & program,TagBase & parent,bool & has_actions)56 int Assembler::AssembleClasses(as::NodePtr& program, TagBase& parent, bool& has_actions)
57 {
58 	IntAssembler	int_asm(*f_error_stream, *f_options);
59 
60 	return int_asm.AssembleClasses(program, parent, has_actions);
61 }
62 
63 
Assemble(as::NodePtr & program,TagBase & tag,Vectors * actions)64 int Assembler::Assemble(as::NodePtr& program, TagBase& tag, Vectors *actions)
65 {
66 	IntAssembler	int_asm(*f_error_stream, *f_options);
67 
68 	return int_asm.Assemble(program, tag, actions);
69 }
70 
71 
SetErrorStream(as::ErrorStream & error_stream)72 void Assembler::SetErrorStream(as::ErrorStream& error_stream)
73 {
74 	f_error_stream = &error_stream;
75 }
76 
77 
78 
SetOptions(as::Options & options)79 void Assembler::SetOptions(as::Options& options)
80 {
81 	f_options = &options;
82 }
83 
84 
85 
86 
87 //**********************************************************************
88 //***  PRIVATE ASSEMBLER  **********************************************
89 //**********************************************************************
IntAssembler(as::ErrorStream & error_stream,as::Options & options)90 IntAssembler::IntAssembler(as::ErrorStream& error_stream, as::Options& options)
91 {
92 	f_error_stream = &error_stream;
93 	f_options = &options;
94 	f_parent = 0;
95 	f_tag = 0;
96 	f_actions = 0;
97 	f_try_info = 0;
98 
99 	//f_registers -- auto-init
100 
101 	f_label = 0;		// for unique labels
102 }
103 
104 
~IntAssembler()105 IntAssembler::~IntAssembler()
106 {
107 }
108 
109 
AssembleClasses(as::NodePtr & program,TagBase & parent,bool & has_actions)110 int IntAssembler::AssembleClasses(as::NodePtr& program, TagBase& parent, bool& has_actions)
111 {
112 	f_parent = &parent;
113 	f_tag = 0;
114 	f_actions = 0;
115 
116 //fprintf(stderr, "o AssembleClasses() called\n");
117 //program.Display(stderr);
118 
119 	int level = 0;
120 	has_actions = ListClass(program, level);
121 
122 	f_parent = 0;
123 	f_tag = 0;
124 	f_actions = 0;
125 
126 	return f_error_stream->ErrCount();
127 }
128 
129 
ListClass(as::NodePtr & list,int level)130 bool IntAssembler::ListClass(as::NodePtr& list, int level)
131 {
132 	bool has_actions = false;
133 	int max = list.GetChildCount();
134 	for(int idx = 0; idx < max; ++idx) {
135 		as::NodePtr& child = list.GetChild(idx);
136 		as::Data& data = child.GetData();
137 		switch(data.f_type) {
138 		case as::NODE_CLASS:
139 		case as::NODE_INTERFACE:
140 			Class(child);
141 			ListClass(child, level + 1);
142 			// here ListClass() can't return true so we ignore
143 			// the result since <whatever> || false is <whatever>
144 			break;
145 
146 		case as::NODE_DIRECTIVE_LIST:
147 			// directive (blocks) don't add a level here
148 			has_actions = has_actions || ListClass(child, level);
149 			break;
150 
151 		case as::NODE_PACKAGE:
152 			if((data.f_int.Get() & as::NODE_PACKAGE_FLAG_REFERENCED) != 0) {
153 				has_actions = has_actions || level == 0;
154 				ListClass(child, level + 1);
155 			}
156 			break;
157 
158 		default:
159 			has_actions = has_actions || level == 0;
160 			ListClass(child, level + 1);
161 			// here ListClass() can't return true so we ignore
162 			// the result since <whatever> || false is <whatever>
163 			break;
164 
165 		}
166 	}
167 
168 	return has_actions;
169 }
170 
171 
FunctionClass(DefineClass & define,as::NodePtr & function)172 void IntAssembler::FunctionClass(DefineClass& define, as::NodePtr& function)
173 {
174 	unsigned long attrs = function.GetAttrs();
175 	if((attrs & (as::NODE_ATTR_FALSE | as::NODE_ATTR_CONSTRUCTOR)) != 0) {
176 		return;
177 	}
178 	if((attrs & (as::NODE_ATTR_UNUSED | as::NODE_ATTR_DYNAMIC)) == as::NODE_ATTR_UNUSED) {
179 		return;
180 	}
181 
182 	define.InsertProp(function);
183 
184 	as::Data data = function.GetData();
185 
186 	//	push <prototype register>
187 	//	push <function name>
188 	//	push <function>
189 	//	set member
190 	if(!define.f_first) {
191 		f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);
192 	}
193 	define.f_first = false;
194 
195 	ActionPushData *pd = new ActionPushData(f_tag);
196 	char *str = data.f_str.GetUTF8();
197 	pd->AddString(str);
198 	delete [] str;
199 	f_actions->Insert(-1, pd);
200 
201 	// second the function
202 	Function(function, false);
203 
204 	Action *a = new Action(f_tag, Action::ACTION_SET_MEMBER);
205 	f_actions->Insert(-1, a);
206 }
207 
208 
VarClass(DefineClass & define,as::NodePtr & var)209 void IntAssembler::VarClass(DefineClass& define, as::NodePtr& var)
210 {
211 	ActionPushData	*pd;
212 	int		idx, j, max, cnt;
213 	bool		has_set;
214 	char		*str;
215 
216 	max = var.GetChildCount();
217 	for(idx = 0; idx < max; ++idx) {
218 		as::NodePtr& variable = var.GetChild(idx);
219 		as::Data& data = variable.GetData();
220 
221 		define.InsertProp(variable);
222 
223 		//	push <prototype register>
224 		//	push <variable name>
225 		//	push <value> | undefined
226 		//	set member
227 		if(!define.f_first) {
228 			f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);
229 		}
230 		define.f_first = false;
231 
232 		pd = new ActionPushData(f_tag);
233 		str = data.f_str.GetUTF8();
234 		pd->AddString(str);
235 		delete [] str;
236 		f_actions->Insert(-1, pd);
237 
238 		// second the content -- note that if there
239 		// isn't a NODE_SET, then we push undefined.
240 		has_set = false;
241 		cnt = variable.GetChildCount();
242 		for(j = 0; j < cnt; ++j) {
243 			as::NodePtr& set = variable.GetChild(j);
244 			as::Data& data = set.GetData();
245 			if(data.f_type == as::NODE_SET) {
246 				as::NodePtr& expr = set.GetChild(0);
247 				Expression(expr);
248 				has_set = true;
249 				break;
250 			}
251 		}
252 		if(!has_set) {
253 			pd = new ActionPushData(f_tag);
254 			pd->AddUndefined();
255 			f_actions->Insert(-1, pd);
256 		}
257 
258 		Action *a = new Action(f_tag, Action::ACTION_SET_MEMBER);
259 		f_actions->Insert(-1, a);
260 	}
261 }
262 
263 
264 
265 
StackClass(DefineClass & define,as::NodePtr & list)266 void IntAssembler::StackClass(DefineClass& define, as::NodePtr& list)
267 {
268 	int			idx, max;
269 
270 	max = list.GetChildCount();
271 	for(idx = 0; idx < max; ++idx) {
272 		as::NodePtr& child = list.GetChild(idx);
273 		as::Data& data = child.GetData();
274 		switch(data.f_type) {
275 		case as::NODE_EXTENDS:
276 		case as::NODE_IMPLEMENTS:
277 			// we just skip those here...
278 			break;
279 
280 		case as::NODE_DIRECTIVE_LIST:
281 			StackClass(define, child);
282 			break;
283 
284 		case as::NODE_FUNCTION:
285 			FunctionClass(define, child);
286 			break;
287 
288 		case as::NODE_VAR:
289 		case as::NODE_ENUM:
290 			VarClass(define, child);
291 			break;
292 
293 		case as::NODE_CLASS:
294 		case as::NODE_INTERFACE:
295 			// sub-classes are managed from outside this loop
296 			break;
297 
298 		default:
299 fprintf(stderr, "INTERNAL ERROR: IntAssembler::StackClass found an unsupported node; type is: %d.\n", data.f_type);
300 			break;
301 
302 		}
303 	}
304 }
305 
306 
307 
UserConstructorClass(as::NodePtr & class_node,const char * class_name,int & count,bool & extends)308 int IntAssembler::UserConstructorClass(as::NodePtr& class_node, const char *class_name, int& count, bool& extends)
309 {
310 	unsigned long	attrs;
311 	int		idx, max, members;
312 	bool		found;
313 
314 	members = 0;
315 	max = class_node.GetChildCount();
316 	for(idx = 0; idx < max; ++idx) {
317 		as::NodePtr& child = class_node.GetChild(idx);
318 		as::Data& data = child.GetData();
319 		switch(data.f_type) {
320 		case as::NODE_EXTENDS:
321 			extends = true;
322 			break;
323 
324 		case as::NODE_DIRECTIVE_LIST:
325 			members += UserConstructorClass(child, class_name, count, extends);
326 			break;
327 
328 		case as::NODE_FUNCTION:
329 			attrs = child.GetAttrs();
330 			// default constructor?
331 			found = data.f_str == class_name;
332 			if(found) {
333 				child.SetAttrs(attrs | as::NODE_ATTR_CONSTRUCTOR);
334 			}
335 			if(!found) {
336 				// user marked constructor?
337 				// [not too sure we can support those here?!]
338 				found = (attrs & as::NODE_ATTR_CONSTRUCTOR) != 0;
339 			}
340 			if(found) {
341 				count++;
342 				// TODO: user extra constructors...
343 				// we can't create more than one function
344 				// for the constructor as far as I know
345 				// so at this time this looping is wrong
346 				// and thus we avoid creating more than
347 				// one function
348 				if(count == 1) {
349 					Function(child, false);
350 				}
351 			}
352 			else if((attrs & (as::NODE_ATTR_UNUSED | as::NODE_ATTR_DYNAMIC)) != as::NODE_ATTR_UNUSED) {
353 				members++;
354 			}
355 			break;
356 
357 		case as::NODE_IMPLEMENTS:
358 		case as::NODE_CLASS:
359 		case as::NODE_INTERFACE:
360 			// these aren't considered members here
361 			break;
362 
363 		case as::NODE_VAR:
364 		case as::NODE_ENUM:
365 			members += child.GetChildCount();
366 			break;
367 
368 		default:
369 			members++;
370 			break;
371 
372 		}
373 	}
374 
375 	return members;
376 }
377 
378 
ConstructorClass(as::NodePtr & class_node,const char * class_name)379 int IntAssembler::ConstructorClass(as::NodePtr& class_node, const char *class_name)
380 {
381 	ActionPushData	*pd;
382 	Action		*a;
383 	int		count, members;
384 	bool		extends;
385 
386 	count = 0;
387 	extends = false;
388 	members = UserConstructorClass(class_node, class_name, count, extends);
389 
390 	// class needs a default constructor?
391 	if(count == 0) {
392 		ActionFunction *func;
393 		if(extends) {
394 			func = new ActionFunction(f_tag, Action::ACTION_DECLARE_FUNCTION2);
395 			func->SetRegistersCount(2);
396 			func->AddParameter("/this");
397 			func->AddParameter("/arguments");
398 			func->AddParameter("super");
399 
400 			pd = new ActionPushData(f_tag);
401 			pd->AddInteger(0);
402 			pd->AddRegister(1);
403 			pd->AddUndefined();
404 			func->AddAction(pd);
405 
406 			a = new Action(f_tag, Action::ACTION_CALL_METHOD);
407 			func->AddAction(a);
408 
409 			// NOTE: I would put a RETURN rather than a POP here...
410 			a = new Action(f_tag, Action::ACTION_POP);
411 			func->AddAction(a);
412 		}
413 		else {
414 			func = new ActionFunction(f_tag);
415 		}
416 		f_actions->Insert(-1, func);
417 	}
418 
419 	return members;
420 }
421 
422 
ExtendsClass(as::NodePtr & class_node,const char * class_name)423 void IntAssembler::ExtendsClass(as::NodePtr& class_node, const char *class_name)
424 {
425 	ActionPushData	*pd;
426 	Action		*a;
427 	int		idx, max, j, cnt, count;
428 
429 	max = class_node.GetChildCount();
430 	for(idx = 0; idx < max; ++idx) {
431 		as::NodePtr& extends = class_node.GetChild(idx);
432 		as::Data& extends_data = extends.GetData();
433 		if(extends_data.f_type == as::NODE_EXTENDS) {
434 			//	push "_global"
435 			//	get variable
436 			// repeat for each name (parent most first) {
437 			//	push <class name>
438 			//	get member
439 			// }
440 			//	push <extends expression>
441 			//	get variable
442 			//	extends
443 			pd = new ActionPushData(f_tag);
444 			pd->AddString("_global");
445 			f_actions->Insert(-1, pd);
446 			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
447 			f_actions->Insert(-1, a);
448 
449 			// TODO: fix the name! we need to loop on all the
450 			//	 parent classes to be correct.
451 			pd = new ActionPushData(f_tag);
452 			pd->AddString(class_name);
453 			f_actions->Insert(-1, pd);
454 			a = new Action(f_tag, Action::ACTION_GET_MEMBER);
455 			f_actions->Insert(-1, a);
456 
457 			Expression(extends.GetChild(0));
458 			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
459 			f_actions->Insert(-1, a);
460 
461 			a = new Action(f_tag, Action::ACTION_EXTENDS);
462 			f_actions->Insert(-1, a);
463 			break;
464 		}
465 	}
466 
467 	count = 0;
468 	for(idx = 0; idx < max; ++idx) {
469 		as::NodePtr& implements = class_node.GetChild(idx);
470 		as::Data& implements_data = implements.GetData();
471 		if(implements_data.f_type == as::NODE_IMPLEMENTS) {
472 			as::NodePtr& list = implements.GetChild(0);
473 			as::Data& data = list.GetData();
474 			if(data.f_type == as::NODE_LIST) {
475 				cnt = list.GetChildCount();
476 				for(j = 0; j < cnt; ++j) {
477 					Expression(list.GetChild(j));
478 					a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
479 					f_actions->Insert(-1, a);
480 				}
481 				count += cnt;
482 			}
483 			else {
484 				Expression(implements.GetChild(0));
485 				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
486 				f_actions->Insert(-1, a);
487 				count++;
488 			}
489 		}
490 	}
491 
492 	if(count > 0) {
493 		// [in the previous for() loop]
494 		// repeat <count> {
495 		//	push <implement name>
496 		// }
497 		//	push <count>
498 		//	push "_global"
499 		//	get variable
500 		//	push <class name>
501 		//	get member
502 		//	implements
503 		//
504 		pd = new ActionPushData(f_tag);
505 		pd->AddInteger(count);
506 		pd->AddString("_global");
507 		f_actions->Insert(-1, pd);
508 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
509 		f_actions->Insert(-1, a);
510 
511 		// TODO: fix the name!
512 		pd = new ActionPushData(f_tag);
513 		pd->AddString(class_name);
514 		f_actions->Insert(-1, pd);
515 		a = new Action(f_tag, Action::ACTION_GET_MEMBER);
516 		f_actions->Insert(-1, a);
517 
518 		a = new Action(f_tag, Action::ACTION_IMPLEMENTS);
519 		f_actions->Insert(-1, a);
520 	}
521 }
522 
523 
DefineClass(as::NodePtr & class_node,int prototype,int max)524 IntAssembler::DefineClass::DefineClass(as::NodePtr& class_node, int prototype, int max)
525 	: f_class_node(class_node)
526 {
527 	f_first = true;
528 	f_prototype = prototype;
529 	f_count = 0;
530 	f_max = max;
531 	f_prop_flags = new PropFlags[max];
532 }
533 
534 
~DefineClass()535 IntAssembler::DefineClass::~DefineClass()
536 {
537 	delete [] f_prop_flags;
538 }
539 
540 
InsertProp(as::NodePtr & prop)541 void IntAssembler::DefineClass::InsertProp(as::NodePtr& prop)
542 {
543 	int		i, j, p, r, flags;
544 
545 	AS_ASSERT(f_count < f_max);
546 
547 	// first, we do a SetProp() so we can get the flags
548 	flags = f_prop_flags[f_count].SetProp(prop);
549 
550 	// then we quick sort (binary)
551 	p = 0;
552 	if(f_count < 4) {
553 		// slow sort when not enough entries to quick sort
554 		for(p = 0; p < f_count; ++p) {
555 			if(flags > f_prop_flags[p].f_flags) {
556 				break;
557 			}
558 		}
559 	}
560 	else {
561 		i = 0;
562 		j = f_count;
563 		while(i < j) {
564 			p = i + (j - i) / 2;
565 			r = flags - f_prop_flags[p].f_flags;
566 			if(r == 0) {
567 				break;
568 			}
569 			if(r > 0) {
570 				p++;
571 				i = p;
572 			}
573 			else {
574 				j = p;
575 			}
576 		}
577 	}
578 	if(p != f_count) {
579 		for(i = f_count; i > p; --i) {
580 			f_prop_flags[i] = f_prop_flags[i - 1];
581 		}
582 		f_prop_flags[p].SetProp(prop);
583 	}
584 	f_count++;
585 }
586 
587 
PropFlags(void)588 IntAssembler::PropFlags::PropFlags(void)
589 {
590 	f_flags = 0;
591 	//f_prop -- auto-init
592 }
593 
594 
SetProp(as::NodePtr & prop)595 int IntAssembler::PropFlags::SetProp(as::NodePtr& prop)
596 {
597 	f_prop = prop;
598 	f_flags = 0;		// because of our copies, when we enter here flags != 0
599 	as::Data& data = prop.GetData();
600 	int flags = data.f_int.Get();
601 	switch(data.f_type) {
602 	case as::NODE_VARIABLE:
603 		if((flags & as::NODE_VAR_FLAG_CONST) == 0) {
604 			f_flags |= ActionFunction::PROP_FLAG_CAN_OVERWRITE;
605 		}
606 		break;
607 
608 	default:
609 		break;
610 
611 	}
612 
613 	unsigned long attrs = prop.GetAttrs();
614 	if((attrs & as::NODE_ATTR_ENUMERABLE) == 0) {
615 		f_flags |= ActionFunction::PROP_FLAG_IS_HIDDEN;
616 	}
617 	if((attrs & as::NODE_ATTR_DYNAMIC) != 0) {
618 		f_flags |= ActionFunction::PROP_FLAG_CAN_DELETE;
619 	}
620 
621 	return f_flags;
622 }
623 
624 
625 
FlagsClass(DefineClass & define)626 void IntAssembler::FlagsClass(DefineClass& define)
627 {
628 	ActionPushData	*pd;
629 	Action		*a;
630 	int		i, max, count, flags;
631 	char		*str;
632 
633 	max = define.f_count;
634 	if(max == 0) {
635 		return;
636 	}
637 
638 	flags = define.f_prop_flags[0].f_flags;
639 	for(i = 1; i < max; ++i) {
640 		if(define.f_prop_flags[i].f_flags != flags) {
641 			break;
642 		}
643 	}
644 
645 	if(i == max) {
646 		// all members have the same flags!
647 		//	push <flags>
648 		//	push null
649 		//	push prototype register
650 		//	push 3
651 		//	push "ASSetPropFlags"
652 		//	call function
653 		//	[pop] -- done outside
654 		pd = new ActionPushData(f_tag);
655 		pd->AddInteger(flags);
656 		pd->AddNull();
657 		f_actions->Insert(-1, pd);
658 
659 		f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);
660 
661 		pd = new ActionPushData(f_tag);
662 		pd->AddInteger(3);
663 		pd->AddString("ASSetPropFlags");
664 		f_actions->Insert(-1, pd);
665 
666 		a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
667 		f_actions->Insert(-1, a);
668 	}
669 	else {
670 		//	push <flags>
671 		// repeat {
672 		//	push <members sharing flags>
673 		// }
674 		//	push <count>
675 		//	declare array
676 		//	push prototype register
677 		//	push 3
678 		//	push "ASSetPropFlags"
679 		//	call function
680 		//	[pop] -- done outside
681 		i = 0;
682 		while(i < max) {
683 			flags = define.f_prop_flags[i].f_flags;
684 
685 			pd = new ActionPushData(f_tag);
686 			pd->AddInteger(flags);
687 			f_actions->Insert(-1, pd);
688 
689 			as::Data& data = define.f_prop_flags[i].f_prop.GetData();
690 
691 			pd = new ActionPushData(f_tag);
692 			str = data.f_str.GetUTF8();
693 			pd->AddString(str);
694 			delete [] str;
695 			f_actions->Insert(-1, pd);
696 
697 			count = 1;
698 			i++;
699 			while(i < max && flags == define.f_prop_flags[i].f_flags) {
700 				as::Data& data = define.f_prop_flags[i].f_prop.GetData();
701 
702 				pd = new ActionPushData(f_tag);
703 				str = data.f_str.GetUTF8();
704 				pd->AddString(str);
705 				delete [] str;
706 				f_actions->Insert(-1, pd);
707 
708 				i++;
709 				count++;
710 			}
711 
712 			pd = new ActionPushData(f_tag);
713 			pd->AddInteger(count);
714 			f_actions->Insert(-1, pd);
715 			a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
716 			f_actions->Insert(-1, a);
717 
718 			f_registers.LoadRegister(define.f_prototype, false, f_tag, f_actions);
719 
720 			pd = new ActionPushData(f_tag);
721 			pd->AddInteger(3);
722 			pd->AddString("ASSetPropFlags");
723 			f_actions->Insert(-1, pd);
724 
725 			a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
726 			f_actions->Insert(-1, a);
727 
728 			if(i < max) {
729 				a = new Action(f_tag, Action::ACTION_POP);
730 				f_actions->Insert(-1, a);
731 			}
732 		}
733 	}
734 }
735 
736 
737 
Class(as::NodePtr & class_node)738 void IntAssembler::Class(as::NodePtr& class_node)
739 {
740 	// TODO: we may want to rename classes too!
741 
742 	ActionPushData	*pd;
743 	ActionBranch	*branch;
744 	ActionLabel	*label;
745 	Action		*a;
746 	TagSprite	*sprite;
747 	TagDoAction	*do_action;
748 	as::String	l1;
749 	char		*class_name, *str1;
750 	int		constructor, prototype, members;
751 
752 	// A class (object model) is created by creating
753 	// a sprite and assigning code to it using a
754 	// DoInitAction.
755 	sprite = new TagSprite(f_parent);
756 	do_action = new TagDoAction(f_parent);
757 	do_action->SetSprite(sprite->Identification());
758 
759 	f_tag = do_action;
760 	f_actions = &do_action->Actions();
761 
762 	Label(l1);
763 	str1 = l1.GetUTF8();
764 
765 	as::Data& data = class_node.GetData();
766 	class_name = data.f_str.GetUTF8();
767 
768 	//	push _global
769 	//	get variable
770 	//	push <class name>
771 	//	get member
772 	//	logical not
773 	//	logical not
774 	//	if true, goto done
775 	pd = new ActionPushData(f_tag);
776 	pd->AddString("_global");
777 	f_actions->Insert(-1, pd);
778 	a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
779 	f_actions->Insert(-1, a);
780 
781 	pd = new ActionPushData(f_tag);
782 	char *str = data.f_str.GetUTF8();
783 	pd->AddString(str);
784 	delete [] str;
785 	f_actions->Insert(-1, pd);
786 	a = new Action(f_tag, Action::ACTION_GET_MEMBER);
787 	f_actions->Insert(-1, a);
788 
789 	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
790 	f_actions->Insert(-1, a);
791 	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
792 	f_actions->Insert(-1, a);
793 
794 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
795 	branch->SetLabel(str1);
796 	f_actions->Insert(-1, branch);
797 
798 	//	push "_global"
799 	//	get variable
800 	//	push <class name>
801 	//	<push constructor function>
802 	//	store reg A	(constructor)
803 	//	set member
804 	pd = new ActionPushData(f_tag);
805 	pd->AddString("_global");
806 	f_actions->Insert(-1, pd);
807 	a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
808 	f_actions->Insert(-1, a);
809 
810 	pd = new ActionPushData(f_tag);
811 	pd->AddString(class_name);
812 	f_actions->Insert(-1, pd);
813 
814 	// as we insert the constructor(s) we count the number of members
815 	members = ConstructorClass(class_node, class_name);
816 
817 	constructor = f_registers.StoreRegister(f_tag, f_actions, false);
818 	a = new Action(f_tag, Action::ACTION_SET_MEMBER);
819 	f_actions->Insert(-1, a);
820 
821 	// Flash first 'extends' and then adds extra members
822 	// (this call also adds the 'implements')
823 	ExtendsClass(class_node, class_name);
824 
825 	//	load reg A
826 	//	push "prototype"
827 	//	get member
828 	//	store reg B	(prototype)
829 	//	pop
830 	f_registers.LoadRegister(constructor, false, f_tag, f_actions);
831 	pd = new ActionPushData(f_tag);
832 	pd->AddString("prototype");
833 	f_actions->Insert(-1, pd);
834 	a = new Action(f_tag, Action::ACTION_GET_MEMBER);
835 	f_actions->Insert(-1, a);
836 	prototype = f_registers.StoreRegister(f_tag, f_actions, false);
837 
838 	// Add all the members and save some info about them
839 	DefineClass define(class_node, prototype, members);
840 	StackClass(define, class_node);
841 
842 	// Now we have a list of members and their flags in define
843 	FlagsClass(define);
844 
845 	label = new ActionLabel(f_tag);
846 	label->SetLabel(str1);
847 	f_actions->Insert(-1, label);
848 
849 	// Flash adds the pop after the label, I'd put it before...
850 	a = new Action(f_tag, Action::ACTION_POP);
851 	f_actions->Insert(-1, a);
852 
853 	delete [] class_name;
854 
855 	f_tag = 0;
856 	f_actions = 0;
857 	f_registers.FreeRegister(prototype);
858 	f_registers.FreeRegister(constructor);
859 }
860 
861 
862 
863 
Assemble(as::NodePtr & program,TagBase & tag,Vectors * actions)864 int IntAssembler::Assemble(as::NodePtr& program, TagBase& tag, Vectors *actions)
865 {
866 	f_tag = &tag;
867 	f_actions = actions;
868 
869 //fprintf(stderr, "o Assemble() called\n");
870 //program.Display(stderr);
871 
872 	// Now save everything other than classes
873 	DirectiveList(program, false);
874 
875 	return f_error_stream->ErrCount();
876 }
877 
878 
879 
DirectiveList(as::NodePtr & list,bool clear)880 void IntAssembler::DirectiveList(as::NodePtr& list, bool clear)
881 {
882 	int max = list.GetChildCount();
883 	int idx = 0;
884 	List(list, idx, max);
885 	if(clear) {
886 		ClearVariables(list);
887 	}
888 }
889 
890 
List(as::NodePtr & list,int & from,int to,list_flags_t flags)891 void IntAssembler::List(as::NodePtr& list, int& from, int to, list_flags_t flags)
892 {
893 	//
894 	// 1. 	we look for declarations (only functions at this time)
895 	//	we assemble them first
896 	//
897 	// 2.	we assemble the rest (i.e. we start over and skip all
898 	//	the functions)
899 	//
900 	// NOTE: Classes and interfaces are not assembled here since these
901 	//	 are taken cared of in AssembleClasses() instead.
902 	//
903 
904 	if((flags & LIST_FLAG_DECLARATIONS) != 0) {
905 		for(int idx = from; idx < to; ++idx) {
906 			as::NodePtr& child = list.GetChild(idx);
907 			as::Data& data = child.GetData();
908 			switch(data.f_type) {
909 			case as::NODE_FUNCTION:
910 				Directive(list, idx, child);
911 				break;
912 
913 			default:
914 				break;
915 
916 			}
917 		}
918 	}
919 
920 	if((flags & LIST_FLAG_STATEMENTS) != 0) {
921 		while(from < to) {
922 			as::NodePtr& child = list.GetChild(from);
923 			as::Data& data = child.GetData();
924 			switch(data.f_type) {
925 			case as::NODE_FUNCTION:
926 				break;
927 
928 			default:
929 				Directive(list, from, child);
930 				break;
931 
932 			}
933 			++from;
934 		}
935 		// come back on the last item we worked on
936 		--from;
937 	}
938 }
939 
940 
Directive(as::NodePtr & list,int & index,as::NodePtr & child)941 void IntAssembler::Directive(as::NodePtr& list, int& index, as::NodePtr& child)
942 {
943 	as::Data& data = child.GetData();
944 	switch(data.f_type) {
945 	case as::NODE_PACKAGE:
946 		// we do nothing here about packages, that's the IMPORT
947 		// which forces an assembly of packages
948 		break;
949 
950 	case as::NODE_PROGRAM:
951 	case as::NODE_ROOT:
952 		DirectiveList(child, false);
953 		break;
954 
955 	case as::NODE_DIRECTIVE_LIST:
956 		DirectiveList(child);
957 		break;
958 
959 	case as::NODE_LABEL:
960 		UserLabel(child);
961 		break;
962 
963 	case as::NODE_IF:
964 		If(child);
965 		break;
966 
967 	case as::NODE_FOR:
968 		For(child);
969 		break;
970 
971 	case as::NODE_SWITCH:
972 		Switch(child);
973 		break;
974 
975 	case as::NODE_WHILE:
976 	case as::NODE_DO:
977 		While(child);
978 		break;
979 
980 	case as::NODE_GOTO:
981 	case as::NODE_BREAK:
982 	case as::NODE_CONTINUE:
983 		Goto(child);
984 		break;
985 
986 	case as::NODE_WITH:
987 		With(child);
988 		break;
989 
990 	case as::NODE_THROW:
991 		Throw(child);
992 		break;
993 
994 	case as::NODE_TRY:
995 		TryCatchFinally(list, index, child);
996 		break;
997 
998 	case as::NODE_VAR:
999 		Var(child);
1000 		break;
1001 
1002 	case as::NODE_ASSIGNMENT:
1003 	case as::NODE_ASSIGNMENT_ADD:
1004 	case as::NODE_ASSIGNMENT_BITWISE_AND:
1005 	case as::NODE_ASSIGNMENT_BITWISE_OR:
1006 	case as::NODE_ASSIGNMENT_BITWISE_XOR:
1007 	case as::NODE_ASSIGNMENT_DIVIDE:
1008 	case as::NODE_ASSIGNMENT_LOGICAL_AND:
1009 	case as::NODE_ASSIGNMENT_LOGICAL_OR:
1010 	case as::NODE_ASSIGNMENT_LOGICAL_XOR:
1011 	case as::NODE_ASSIGNMENT_MAXIMUM:
1012 	case as::NODE_ASSIGNMENT_MINIMUM:
1013 	case as::NODE_ASSIGNMENT_MODULO:
1014 	case as::NODE_ASSIGNMENT_MULTIPLY:
1015 	case as::NODE_ASSIGNMENT_POWER:
1016 	case as::NODE_ASSIGNMENT_ROTATE_LEFT:
1017 	case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
1018 	case as::NODE_ASSIGNMENT_SHIFT_LEFT:
1019 	case as::NODE_ASSIGNMENT_SHIFT_RIGHT:
1020 	case as::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
1021 	case as::NODE_ASSIGNMENT_SUBTRACT:
1022 	case as::NODE_CALL:
1023 	case as::NODE_DECREMENT:
1024 	case as::NODE_DELETE:
1025 	case as::NODE_IDENTIFIER:
1026 	case as::NODE_INCREMENT:
1027 	case as::NODE_NEW:
1028 	case as::NODE_POST_DECREMENT:
1029 	case as::NODE_POST_INCREMENT:
1030 		VoidExpression(child);
1031 		break;
1032 
1033 	case as::NODE_FUNCTION:
1034 		Function(child, true);
1035 		break;
1036 
1037 	case as::NODE_CLASS:
1038 	case as::NODE_INTERFACE:
1039 		// ignored here. is assembled by AssembleClasses() instead.
1040 		break;
1041 
1042 	case as::NODE_RETURN:
1043 		Return(child);
1044 		break;
1045 
1046 	case as::NODE_ENUM:
1047 		// enums are like lists of variables
1048 		Var(child);
1049 		break;
1050 
1051 	case as::NODE_CATCH:		// assembled in TryCatchFinally()
1052 	case as::NODE_FINALLY:		// assembled in TryCatchFinally()
1053 	case as::NODE_CASE:
1054 	case as::NODE_DEFAULT:
1055 		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, child, "token '%s' (catch, finally, case or default) found in IntAssembler::Directive().", data.GetTypeName());
1056 		break;
1057 
1058 	default:
1059 		// at this time, do nothing with any other node
1060 		f_error_stream->ErrMsg(as::AS_ERR_NOT_SUPPORTED, child, "token '%s' not handled yet in IntAssembler::Directive().", data.GetTypeName());
1061 		break;
1062 
1063 	}
1064 }
1065 
1066 
ClearVariables(as::NodePtr & frame)1067 void IntAssembler::ClearVariables(as::NodePtr& frame)
1068 {
1069 	// clear all the variables of this list
1070 	// (the order should not matter until we implement
1071 	// a working callback feature on the destructions
1072 	// of objects -- unless that already works in
1073 	// Flash?)
1074 	int max = frame.GetVariableCount();
1075 	for(int idx = 0; idx < max; ++idx) {
1076 		as::NodePtr& variable = frame.GetVariable(idx);
1077 
1078 		as::Data& data = variable.GetData();
1079 		int flags = data.f_int.Get();
1080 		if((flags & as::NODE_VAR_FLAG_INUSE) == 0) {
1081 			continue;
1082 		}
1083 
1084 		unsigned long attrs = variable.GetAttrs();
1085 		if((attrs & (as::NODE_ATTR_INTRINSIC | as::NODE_ATTR_DYNAMIC)) == 0) {
1086 			ActionPushData *pd = new ActionPushData(f_tag);
1087 			pd->AddUndefined();
1088 			f_actions->Insert(-1, pd);
1089 
1090 			as::NodePtr name;
1091 			Assignment(name, variable, false);
1092 		}
1093 	}
1094 }
1095 
1096 
UserLabel(as::NodePtr & user_label)1097 void IntAssembler::UserLabel(as::NodePtr& user_label)
1098 {
1099 	ActionLabel	*label;
1100 	char		*str;
1101 
1102 	as::Data& data = user_label.GetData();
1103 
1104 	str = data.f_str.GetUTF8();
1105 
1106 	label = new ActionLabel(f_tag);
1107 	label->SetLabel(str);
1108 	f_actions->Insert(-1, label);
1109 
1110 	delete [] str;
1111 }
1112 
1113 
If(as::NodePtr & if_node)1114 void IntAssembler::If(as::NodePtr& if_node)
1115 {
1116 	ActionLabel	*label;
1117 	ActionBranch	*branch;
1118 	Action		*a;
1119 	as::String	l1, l2;
1120 	char		*str1, *str2;
1121 	bool		add_not;
1122 	int		max;
1123 
1124 	// NOTE: the optimizer already optimize 'if' nodes
1125 	// to what they need to be when the condition is
1126 	// already known to be true or false; so we don't
1127 	// have to test that here.
1128 	max = if_node.GetChildCount();
1129 	add_not = true;
1130 	as::NodePtr& condition = if_node.GetChild(0);
1131 	as::Data& data = condition.GetData();
1132 	if(max == 2 && data.f_type == as::NODE_LOGICAL_NOT) {
1133 		// avoid a double not if(!!a) [that's because
1134 		// we only have one conditional branch in Flash!]
1135 		Expression(condition.GetChild(0));
1136 		add_not = false;
1137 	}
1138 	else {
1139 		Expression(condition);
1140 	}
1141 
1142 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
1143 	Label(l1);
1144 	str1 = l1.GetUTF8();
1145 	branch->SetLabel(str1);
1146 
1147 	if(max == 2) {
1148 		if(add_not) {
1149 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
1150 			f_actions->Insert(-1, a);
1151 		}
1152 
1153 		f_actions->Insert(-1, branch);
1154 
1155 		DirectiveList(if_node.GetChild(1));
1156 
1157 		label = new ActionLabel(f_tag);
1158 		label->SetLabel(str1);
1159 		f_actions->Insert(-1, label);
1160 	}
1161 	else {
1162 		f_actions->Insert(-1, branch);
1163 
1164 		// note that the branch is inverted!
1165 		// so we include the else part first
1166 		DirectiveList(if_node.GetChild(2));
1167 
1168 		branch = new ActionBranch(f_tag);
1169 		Label(l2);
1170 		str2 = l2.GetUTF8();
1171 		branch->SetLabel(str2);
1172 		f_actions->Insert(-1, branch);
1173 
1174 		label = new ActionLabel(f_tag);
1175 		label->SetLabel(str1);
1176 		f_actions->Insert(-1, label);
1177 
1178 		DirectiveList(if_node.GetChild(1));
1179 
1180 		label = new ActionLabel(f_tag);
1181 		label->SetLabel(str2);
1182 		f_actions->Insert(-1, label);
1183 
1184 		delete [] str2;
1185 	}
1186 
1187 	delete [] str1;
1188 }
1189 
1190 
1191 
EmptyEnumeration(void)1192 void IntAssembler::EmptyEnumeration(void)
1193 {
1194 	ActionPushData	*pd;
1195 	ActionBranch	*branch;
1196 	ActionLabel	*label;
1197 	Action		*a;
1198 	as::String	l;
1199 	char		*str;
1200 
1201 	// label l
1202 	// push null
1203 	// strictly equal
1204 	// logical not
1205 	// if true, goto l
1206 
1207 	Label(l);
1208 	str = l.GetUTF8();
1209 
1210 	label = new ActionLabel(f_tag);
1211 	label->SetLabel(str);
1212 	f_actions->Insert(-1, label);
1213 
1214 	pd = new ActionPushData(f_tag);
1215 	pd->AddNull();
1216 	f_actions->Insert(-1, pd);
1217 
1218 	a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
1219 	f_actions->Insert(-1, a);
1220 
1221 	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
1222 	f_actions->Insert(-1, a);
1223 
1224 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
1225 	branch->SetLabel(str);
1226 	f_actions->Insert(-1, branch);
1227 
1228 	delete [] str;
1229 }
1230 
1231 
For(as::NodePtr & for_node)1232 void IntAssembler::For(as::NodePtr& for_node)
1233 {
1234 	ActionPushData	*pd;
1235 	ActionBranch	*branch;
1236 	ActionLabel	*label;
1237 	Action		*a;
1238 	as::String	l1, l2;
1239 	char		*str1, *str2, *str3;
1240 	int		reg, max;
1241 
1242 	// NOTE: The for node will have one entry per expression
1243 	//	 in the for parenthesis plus the list of directives.
1244 	//	 This means the for is a C/C++ like for when there
1245 	//	 are 4 entries and it is a for each when there are
1246 	//	 3 entries
1247 
1248 	LoopData *wd = GetLoopData(for_node);
1249 	Label(wd->f_continue);
1250 	str3 = wd->f_continue.GetUTF8();
1251 
1252 	max = for_node.GetChildCount();
1253 
1254 	Label(l1);
1255 	str1 = l1.GetUTF8();
1256 	Label(l2);
1257 	str2 = l2.GetUTF8();
1258 
1259 	if(max == 3) {
1260 		// TODO: this version is not exception safe?!
1261 		//	 the stack will be a big mess in case of an exception
1262 		//	 (or will the system exception handling take care of
1263 		//	 the stack for us?!)
1264 		//
1265 		// for(var name in object) ...
1266 		//	(if var used init variable[s])
1267 		//	push object name
1268 		//	enumerate object
1269 		//	label repeat
1270 		//	store reg
1271 		//	push null
1272 		//	strictly equal
1273 		//	if true -> done
1274 		//	load reg
1275 		//	push variable name
1276 		//	set variable
1277 		//	*directive list*
1278 		//	goto repeat
1279 		//		(if there is a break)
1280 		//		label break
1281 		//		empty stack (see EmptyEnumeration();)
1282 		//	label done
1283 
1284 		// Init
1285 		as::NodePtr& variable = for_node.GetChild(0);
1286 		as::NodePtr& object = for_node.GetChild(1);
1287 		as::NodePtr& list = for_node.GetChild(2);
1288 		as::Data& for_data = for_node.GetData();
1289 		bool for_each = (for_data.f_int.Get() & as::NODE_FOR_FLAG_FOREACH) != 0;
1290 
1291 		as::Data& variable_data = variable.GetData();
1292 
1293 		if(variable_data.f_type == as::NODE_VAR) {
1294 			// init here
1295 			Var(variable);
1296 		}
1297 
1298 		// Generate Code
1299 		Expression(object);
1300 
1301 		a = new Action(f_tag, Action::ACTION_ENUMERATE_OBJECT);
1302 		f_actions->Insert(-1, a);
1303 
1304 		label = new ActionLabel(f_tag);
1305 		label->SetLabel(str1);
1306 		f_actions->Insert(-1, label);
1307 
1308 		label = new ActionLabel(f_tag);
1309 		label->SetLabel(str3);
1310 		f_actions->Insert(-1, label);
1311 
1312 		reg = f_registers.StoreRegister(f_tag, f_actions, false);
1313 
1314 		pd = new ActionPushData(f_tag);
1315 		pd->AddNull();
1316 		f_actions->Insert(-1, pd);
1317 
1318 		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
1319 		f_actions->Insert(-1, a);
1320 
1321 		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
1322 		branch->SetLabel(str2);
1323 		f_actions->Insert(-1, branch);
1324 
1325 		if(for_each) {
1326 			Expression(object);
1327 		}
1328 		f_registers.LoadRegister(reg, false, f_tag, f_actions);
1329 		if(for_each) {
1330 			// TODO: What happens if the member is a method?
1331 			//	 Do we get a valid reference?!
1332 			a = new Action(f_tag, Action::ACTION_GET_MEMBER);
1333 			f_actions->Insert(-1, a);
1334 		}
1335 
1336 		if(variable_data.f_type == as::NODE_VAR) {
1337 			as::NodePtr& instance = variable.GetChild(variable.GetChildCount() - 1);
1338 			Assignment(variable, instance, false);
1339 		}
1340 		else {
1341 			as::NodePtr instance;
1342 			Assignment(variable, instance, false);
1343 		}
1344 
1345 		DirectiveList(list);
1346 
1347 		branch = new ActionBranch(f_tag);
1348 		branch->SetLabel(str1);
1349 		f_actions->Insert(-1, branch);
1350 
1351 		if(!wd->f_break.IsEmpty()) {
1352 			// found a 'break' statement add its label
1353 			// and the emptying of the stack
1354 			label = new ActionLabel(f_tag);
1355 			delete [] str1;
1356 			str1 = wd->f_break.GetUTF8();
1357 			label->SetLabel(str1);
1358 			f_actions->Insert(-1, label);
1359 
1360 			EmptyEnumeration();
1361 		}
1362 
1363 		label = new ActionLabel(f_tag);
1364 		label->SetLabel(str2);
1365 		f_actions->Insert(-1, label);
1366 
1367 		f_registers.FreeRegister(reg);
1368 	}
1369 	else {
1370 		AS_ASSERT(max == 4);
1371 		// for(init; condition; next) ...
1372 		//
1373 		//	*void expression init*
1374 		//	goto l2
1375 		//	label l1
1376 		//	*list*
1377 		//	label l3 (continue)
1378 		//	*void expression next*
1379 		//	label l2
1380 		//	*expression condition*
1381 		//	if true, goto l1
1382 		//
1383 		// If the condition is empty, then it is a loop forever
1384 		// type of loop and thus we don't need label l2 and the
1385 		// if true becomes a branch as follow:
1386 		//
1387 		//	*void expression init*
1388 		//	label l1
1389 		//	*list*
1390 		//	*void expression next*
1391 		//	branch l1
1392 		//
1393 		// Note: The initialization expression may also be a
1394 		//	 list of variables or be empty.
1395 		//
1396 		//	 The next expression can be empty in which case
1397 		//	 we simply don't insert anything for it. In effect,
1398 		//	 a for(;;) becomes the simplified loop:
1399 		//
1400 		//	 label l1
1401 		//	 *list*
1402 		//	 branch l1
1403 		//
1404 
1405 		// Init
1406 		as::NodePtr& init = for_node.GetChild(0);
1407 		as::NodePtr& cond = for_node.GetChild(1);
1408 		as::NodePtr& next = for_node.GetChild(2);
1409 		as::NodePtr& list = for_node.GetChild(3);
1410 
1411 		as::Data& init_data = init.GetData();
1412 		as::Data& cond_data = cond.GetData();
1413 		as::Data& next_data = next.GetData();
1414 
1415 		if(init_data.f_type != as::NODE_EMPTY) {
1416 			if(init_data.f_type == as::NODE_VAR) {
1417 				Var(init);
1418 			}
1419 			else {
1420 				VoidExpression(init);
1421 			}
1422 		}
1423 
1424 		if(cond_data.f_type != as::NODE_EMPTY) {
1425 			branch = new ActionBranch(f_tag);
1426 			branch->SetLabel(str2);
1427 			f_actions->Insert(-1, branch);
1428 		}
1429 
1430 		label = new ActionLabel(f_tag);
1431 		label->SetLabel(str1);
1432 		f_actions->Insert(-1, label);
1433 
1434 		DirectiveList(list);
1435 
1436 		label = new ActionLabel(f_tag);
1437 		label->SetLabel(str3);
1438 		f_actions->Insert(-1, label);
1439 
1440 		if(next_data.f_type != as::NODE_EMPTY) {
1441 			VoidExpression(next);
1442 		}
1443 
1444 		if(cond_data.f_type != as::NODE_EMPTY) {
1445 			label = new ActionLabel(f_tag);
1446 			label->SetLabel(str2);
1447 			f_actions->Insert(-1, label);
1448 
1449 			Expression(cond);
1450 
1451 			branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
1452 			branch->SetLabel(str1);
1453 			f_actions->Insert(-1, branch);
1454 		}
1455 		else {
1456 			branch = new ActionBranch(f_tag);
1457 			branch->SetLabel(str1);
1458 			f_actions->Insert(-1, branch);
1459 		}
1460 
1461 		if(!wd->f_break.IsEmpty()) {
1462 			// found a 'break' statement add its label
1463 			label = new ActionLabel(f_tag);
1464 			str1 = wd->f_break.GetUTF8();
1465 			label->SetLabel(str1);
1466 			delete [] str1;
1467 			f_actions->Insert(-1, label);
1468 		}
1469 	}
1470 
1471 	delete [] str1;
1472 	delete [] str2;
1473 	delete [] str3;
1474 }
1475 
1476 
1477 
Switch(as::NodePtr & switch_node)1478 void IntAssembler::Switch(as::NodePtr& switch_node)
1479 {
1480 	ActionBranch	*branch;
1481 	ActionLabel	*label;
1482 	switch_info_t	info;
1483 	int		idx, max;
1484 	char		*str1, *str2;
1485 
1486 // TODO: Gee's!! Did I write that?! Simplify the branches?
1487 //
1488 //	 I really need to fix all of these branches which are
1489 //	 not too sensical; though out future lower level optimizer
1490 //	 will take care of that, it is often a good idea to do
1491 //	 clean up in the generator first!
1492 //
1493 
1494 	// switch(expr) with(operator) { case ...: ... }
1495 	//	push expr
1496 	//	store reg
1497 	// for each case
1498 	//	push case expr
1499 	//	load reg
1500 	//	[compare with specified operator]
1501 	//	logical not
1502 	//	branch if true next case
1503 	//	[statements]
1504 	//	branch to next case statements [unless continue or break]
1505 	//	label next case
1506 	// repeat case statements
1507 	//
1508 	// case of default is like case without test
1509 	//
1510 
1511 	info.f_attrs = switch_node.GetAttrs();
1512 
1513 	Expression(switch_node.GetChild(0));
1514 	info.f_reg = f_registers.StoreRegister(f_tag, f_actions, true);
1515 
1516 	info.f_loop_data = GetLoopData(switch_node);
1517 
1518 	Label(info.f_loop_data->f_break);
1519 	str2 = info.f_loop_data->f_break.GetUTF8();
1520 
1521 	bool no_autobreak = false;
1522 	as::NodePtr& list = switch_node.GetChild(1);
1523 	max = list.GetChildCount();
1524 
1525 	idx = 0;
1526 	List(list, idx, max, LIST_FLAG_DECLARATIONS);
1527 
1528 	for(idx = 0; idx < max; ++idx) {
1529 		as::NodePtr& child = list.GetChild(idx);
1530 		as::Data& data = child.GetData();
1531 fprintf(stderr, "Case Child type %d\n", data.f_type);
1532 		switch(data.f_type) {
1533 		case as::NODE_CASE:
1534 			Case(switch_node, child, info, no_autobreak);
1535 			no_autobreak = true;
1536 			break;
1537 
1538 		case as::NODE_DEFAULT:
1539 			Default(info);
1540 			no_autobreak = true;
1541 			break;
1542 
1543 		default:
1544 			// a [regular] statement
1545 			List(list, idx, idx + 1, LIST_FLAG_STATEMENTS);
1546 			no_autobreak = false;
1547 			break;
1548 
1549 		}
1550 	}
1551 
1552 	if(!info.f_default_label.IsEmpty()) {
1553 		branch = new ActionBranch(f_tag);
1554 		branch->SetLabel(str2);
1555 		f_actions->Insert(-1, branch);
1556 	}
1557 
1558 	// the last case/default label will jump here if
1559 	// none were true; and then we can jump to the
1560 	// default label if there is one
1561 	label = new ActionLabel(f_tag);
1562 	str1 = info.f_loop_data->f_continue.GetUTF8();
1563 	label->SetLabel(str1);
1564 	delete [] str1;
1565 	f_actions->Insert(-1, label);
1566 
1567 	if(!info.f_default_label.IsEmpty()) {
1568 		branch = new ActionBranch(f_tag);
1569 		str1 = info.f_default_label.GetUTF8();
1570 		branch->SetLabel(str1);
1571 		delete [] str1;
1572 		f_actions->Insert(-1, branch);
1573 	}
1574 
1575 	label = new ActionLabel(f_tag);
1576 	label->SetLabel(str2);
1577 	f_actions->Insert(-1, label);
1578 
1579 	delete [] str2;
1580 }
1581 
1582 
Case(as::NodePtr & switch_node,as::NodePtr & case_node,switch_info_t & info,bool no_autobreak)1583 void IntAssembler::Case(as::NodePtr& switch_node, as::NodePtr& case_node, switch_info_t& info, bool no_autobreak)
1584 {
1585 	ActionBranch	*branch;
1586 	ActionLabel	*label;
1587 	Action		*a;
1588 	as::String	skip_test;
1589 	int		op;
1590 	char		*str1, *str2;
1591 
1592 	str2 = 0;
1593 	if(!info.f_loop_data->f_continue.IsEmpty()) {
1594 //fprintf(stderr, "Flags (1) %d, (2) %d\n", info.f_attrs & as::NODE_ATTR_AUTOBREAK, no_autobreak);
1595 		if((info.f_attrs & as::NODE_ATTR_AUTOBREAK) != 0 && !no_autobreak) {
1596 			branch = new ActionBranch(f_tag);
1597 			str1 = info.f_loop_data->f_break.GetUTF8();
1598 			branch->SetLabel(str1);
1599 			delete [] str1;
1600 			f_actions->Insert(-1, branch);
1601 		}
1602 		else if((info.f_attrs & as::NODE_ATTR_FOREACH) == 0) {
1603 			Label(skip_test);
1604 			str2 = skip_test.GetUTF8();
1605 
1606 			branch = new ActionBranch(f_tag);
1607 			branch->SetLabel(str2);
1608 			f_actions->Insert(-1, branch);
1609 		}
1610 
1611 		// save our label
1612 		label = new ActionLabel(f_tag);
1613 		str1 = info.f_loop_data->f_continue.GetUTF8();
1614 		label->SetLabel(str1);
1615 		delete [] str1;
1616 		f_actions->Insert(-1, label);
1617 	}
1618 
1619 	// define the next case label right now
1620 	Label(info.f_loop_data->f_continue);
1621 	str1 = info.f_loop_data->f_continue.GetUTF8();
1622 
1623 	int max = case_node.GetChildCount();
1624 	if(max == 2) {
1625 		// a range! we assume the operator is proper
1626 		//	load reg
1627 		//	push lower bound
1628 		//	less_than
1629 		//	branch_if_true skip_case
1630 		//	load reg
1631 		//	push higher bound
1632 		//	greater_than
1633 		//	branch_if_true skip_case
1634 
1635 		f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
1636 		Expression(case_node.GetChild(0));
1637 		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
1638 		f_actions->Insert(-1, a);
1639 
1640 		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
1641 		branch->SetLabel(str1);
1642 		f_actions->Insert(-1, branch);
1643 
1644 		f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
1645 		Expression(case_node.GetChild(1));
1646 		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
1647 		f_actions->Insert(-1, a);
1648 	}
1649 	else {
1650 		// a single expression, we need to use the user specified
1651 		// operator to compare the two expressions
1652 		f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
1653 		Expression(case_node.GetChild(0));
1654 
1655 		as::Data& switch_data = switch_node.GetData();
1656 		op = switch_data.f_int.Get() & as::NODE_MASK;
1657 		switch(op) {
1658 		case as::NODE_UNKNOWN:	// default
1659 		case as::NODE_DEFAULT:	// user defining the default...
1660 		case as::NODE_STRICTLY_EQUAL:
1661 			a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
1662 			f_actions->Insert(-1, a);
1663 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
1664 			f_actions->Insert(-1, a);
1665 			break;
1666 
1667 		case as::NODE_STRICTLY_NOT_EQUAL:
1668 			a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
1669 			f_actions->Insert(-1, a);
1670 			break;
1671 
1672 		case as::NODE_EQUAL:
1673 			a = new Action(f_tag, Action::ACTION_EQUAL);
1674 			f_actions->Insert(-1, a);
1675 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
1676 			f_actions->Insert(-1, a);
1677 			break;
1678 
1679 		case as::NODE_NOT_EQUAL:
1680 			a = new Action(f_tag, Action::ACTION_EQUAL);
1681 			f_actions->Insert(-1, a);
1682 			break;
1683 
1684 		case as::NODE_INSTANCEOF:
1685 		case as::NODE_IS:
1686 			a = new Action(f_tag, Action::ACTION_INSTANCE_OF);
1687 			f_actions->Insert(-1, a);
1688 			break;
1689 
1690 		case as::NODE_GREATER:
1691 			a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
1692 			f_actions->Insert(-1, a);
1693 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
1694 			f_actions->Insert(-1, a);
1695 			break;
1696 
1697 		case as::NODE_GREATER_EQUAL:
1698 			a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
1699 			f_actions->Insert(-1, a);
1700 			break;
1701 
1702 		case as::NODE_LESS:
1703 			a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
1704 			f_actions->Insert(-1, a);
1705 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
1706 			f_actions->Insert(-1, a);
1707 			break;
1708 
1709 		case as::NODE_LESS_EQUAL:
1710 			a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
1711 			f_actions->Insert(-1, a);
1712 			break;
1713 
1714 		case as::NODE_AS:
1715 			a = new Action(f_tag, Action::ACTION_SWAP);
1716 			f_actions->Insert(-1, a);
1717 			a = new Action(f_tag, Action::ACTION_CAST_OBJECT);
1718 			f_actions->Insert(-1, a);
1719 			break;
1720 
1721 		case as::NODE_IN:
1722 			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.");
1723 			break;
1724 
1725 		case as::NODE_MATCH:
1726 		default:
1727 			f_error_stream->ErrMsg(as::AS_ERR_NOT_SUPPORTED, switch_node, "operator (%d) not yet implemented in IntAssembler::Case().", op);
1728 			break;
1729 
1730 		}
1731 	}
1732 
1733 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
1734 	branch->SetLabel(str1);
1735 	f_actions->Insert(-1, branch);
1736 
1737 	delete [] str1;
1738 
1739 	if(str2 != 0) {
1740 		label = new ActionLabel(f_tag);
1741 		label->SetLabel(str2);
1742 		f_actions->Insert(-1, label);
1743 
1744 		delete [] str2;
1745 	}
1746 }
1747 
1748 
Default(switch_info_t & info)1749 void IntAssembler::Default(switch_info_t& info)
1750 {
1751 	ActionBranch	*branch;
1752 	ActionLabel	*label;
1753 	as::String	skip_test;
1754 	char		*str1, *str2;
1755 
1756 	str2 = 0;
1757 	if(!info.f_loop_data->f_continue.IsEmpty()) {
1758 		if((info.f_attrs & as::NODE_ATTR_AUTOBREAK) != 0) {
1759 			branch = new ActionBranch(f_tag);
1760 			str1 = info.f_loop_data->f_break.GetUTF8();
1761 			branch->SetLabel(str1);
1762 			delete [] str1;
1763 			f_actions->Insert(-1, branch);
1764 		}
1765 		/*
1766 		else if((info.f_attrs & as::NODE_ATTR_FOREACH) == 0) {
1767 			Label(skip_test);
1768 			str2 = skip_test.GetUTF8();
1769 
1770 			branch = new ActionBranch(f_tag);
1771 			branch->SetLabel(str2);
1772 			f_actions->Insert(-1, branch);
1773 		}
1774 		*/
1775 
1776 		Label(skip_test);
1777 		str2 = skip_test.GetUTF8();
1778 
1779 		branch = new ActionBranch(f_tag);
1780 		branch->SetLabel(str2);
1781 		f_actions->Insert(-1, branch);
1782 
1783 		// save our label
1784 		label = new ActionLabel(f_tag);
1785 		str1 = info.f_loop_data->f_continue.GetUTF8();
1786 		label->SetLabel(str1);
1787 		delete [] str1;
1788 		f_actions->Insert(-1, label);
1789 	}
1790 
1791 	// define the next case label right now
1792 	Label(info.f_loop_data->f_continue);
1793 	str1 = info.f_loop_data->f_continue.GetUTF8();
1794 
1795 	branch = new ActionBranch(f_tag);
1796 	branch->SetLabel(str1);
1797 	f_actions->Insert(-1, branch);
1798 
1799 	delete [] str1;
1800 
1801 	// create a label for the default statements
1802 	Label(info.f_default_label);
1803 
1804 	label = new ActionLabel(f_tag);
1805 	str1 = info.f_default_label.GetUTF8();
1806 	label->SetLabel(str1);
1807 	delete [] str1;
1808 	f_actions->Insert(-1, label);
1809 
1810 	if(str2 != 0) {
1811 		label = new ActionLabel(f_tag);
1812 		label->SetLabel(str2);
1813 		f_actions->Insert(-1, label);
1814 
1815 		delete [] str2;
1816 	}
1817 }
1818 
1819 
1820 
GetLoopData(as::NodePtr & while_node)1821 IntAssembler::LoopData *IntAssembler::GetLoopData(as::NodePtr& while_node)
1822 {
1823 	LoopData	**p;
1824 
1825 	as::Data& data = while_node.GetData();
1826 	if(data.f_user_data.Size() == 0) {
1827 		data.f_user_data.New((sizeof(LoopData *) + sizeof(int) - 1) / sizeof(int));
1828 		p = reinterpret_cast<LoopData **>(data.f_user_data.Buffer());
1829 		p[0] = new LoopData;
1830 	}
1831 	else {
1832 		p = reinterpret_cast<LoopData **>(data.f_user_data.Buffer());
1833 	}
1834 
1835 	return p[0];
1836 }
1837 
1838 
1839 
While(as::NodePtr & while_node)1840 void IntAssembler::While(as::NodePtr& while_node)
1841 {
1842 	ActionLabel	*label;
1843 	ActionBranch	*branch;
1844 	as::String	l1, l2;
1845 	char		*str1, *str2;
1846 	int		order;
1847 
1848 	Label(l1);
1849 	str1 = l1.GetUTF8();
1850 
1851 	as::Data& data = while_node.GetData();
1852 	if(data.f_type == as::NODE_WHILE) {
1853 		branch = new ActionBranch(f_tag);
1854 		branch->SetLabel(str1);
1855 		f_actions->Insert(-1, branch);
1856 		order = 1;
1857 	}
1858 	else {
1859 		order = 0;
1860 	}
1861 
1862 	Label(l2);
1863 	str2 = l2.GetUTF8();
1864 	label = new ActionLabel(f_tag);
1865 	label->SetLabel(str2);
1866 	f_actions->Insert(-1, label);
1867 
1868 	// save the continue label by default; if
1869 	// we need a break label, it will be created
1870 	// by the assembler if it finds a break node
1871 	LoopData *wd = GetLoopData(while_node);
1872 	wd->f_continue = l1;
1873 
1874 	DirectiveList(while_node.GetChild(order));
1875 
1876 	label = new ActionLabel(f_tag);
1877 	label->SetLabel(str1);
1878 	f_actions->Insert(-1, label);
1879 
1880 	Expression(while_node.GetChild(order ^ 1));
1881 
1882 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
1883 	branch->SetLabel(str2);
1884 	f_actions->Insert(-1, branch);
1885 
1886 	delete [] str1;
1887 	delete [] str2;
1888 
1889 	if(!wd->f_break.IsEmpty()) {
1890 		// found a 'break' statement add its label
1891 		label = new ActionLabel(f_tag);
1892 		str1 = wd->f_break.GetUTF8();
1893 		label->SetLabel(str1);
1894 		delete [] str1;
1895 		f_actions->Insert(-1, label);
1896 	}
1897 }
1898 
1899 
1900 
1901 
1902 //
1903 // The GOTO, BREAK and CONTINUE statements all work the same way.
1904 //
1905 // The GOTO has two parts: going out of the current frames and then
1906 // in a new set of frames. The BREAK and CONTINUE only go out of
1907 // the current frame by default. Whenever, the BREAK and CONTINUE
1908 // have a label, they may get out of more than one frame.
1909 //
1910 // What is complicated in the implementation of this instruction
1911 // is the exiting and entering of frames which are blocks which
1912 // can't be broken up. There is currently the following blocks we
1913 // have to deal with:
1914 //
1915 // 	. WITH		to exit a WITH, you need to goto at the
1916 // 			end of the with first; then, once exited,
1917 // 			you need to test a variable to know what
1918 // 			you have to do; this means up to one test
1919 //			per GOTO, BREAK and CONTINUE within a WITH
1920 //			to exit it.
1921 //
1922 //	. TRY		the TRY block is similar to the WITH except
1923 //			that the finally part will always be executed;
1924 //			so the TRY block itself stops at the point
1925 //			where the GOTO, BREAK or CONTINUE is found and
1926 //			then the process goes in the FINALLY; once the
1927 //			FINALLY is over, it tests a variable to know
1928 //			where the GOTO, BREAK or CONTINUE needs to go
1929 //
1930 //	. CATCH		the CATCH is the same as the TRY, it will have
1931 //			to execute the instructions in the FINALLY
1932 //			before to go on; there can't be a GOTO, BREAK
1933 //			or CONTINUE already in action when the CATCH
1934 //			is being executed
1935 //
1936 //	. FINALLY	the FINALLY is like the WITH block; it just
1937 //			needs to be exited and once exited, the code
1938 //			after will determine the destination; however,
1939 //			there is a run-time error to check: if the
1940 //			user already was in a GOTO, BREAK or CONTINUE
1941 //			from the corresponding TRY or CATCH, then the
1942 //			process needs to generate an error because it
1943 //			can't continue at two places (note that this
1944 //			error may be caught by the compiler if the
1945 //			compiler can see that it will obviously not
1946 //			work, the run time error will be a throw)
1947 //
Goto(as::NodePtr & goto_node)1948 void IntAssembler::Goto(as::NodePtr& goto_node)
1949 {
1950 // first we need to get out of the current frame(s) up to the
1951 // top frame which also includes the destination frame; if that
1952 // works (it always should) then we can enter the destination
1953 // frame (only GOTOs enter other frames)
1954 	if(ExitFrame(goto_node)) {
1955 		EnterFrame(goto_node);
1956 	}
1957 }
1958 
1959 
ExitFrame(as::NodePtr & goto_node)1960 bool IntAssembler::ExitFrame(as::NodePtr& goto_node)
1961 {
1962 	ActionBranch	*branch;
1963 	char		*str;
1964 	bool		end;
1965 
1966 	as::Data& goto_data = goto_node.GetData();
1967 
1968 	as::NodePtr parent = goto_node;
1969 	as::NodePtr& exit = goto_node.GetLink(as::NodePtr::LINK_GOTO_EXIT);
1970 	for(;;) {
1971 		parent = parent.GetParent();
1972 		if(!parent.HasNode()) {
1973 			// this should not happen
1974 			return false;
1975 		}
1976 
1977 		// are we on that last frame?
1978 		end = exit.SameAs(parent);
1979 
1980 		as::Data& data = parent.GetData();
1981 		switch(data.f_type) {
1982 		case as::NODE_WHILE:
1983 		case as::NODE_FOR:
1984 		case as::NODE_DO:
1985 		case as::NODE_SWITCH:
1986 			if(end) {
1987 				LoopData *wd = GetLoopData(parent);
1988 				switch(goto_data.f_type) {
1989 				case as::NODE_CONTINUE:
1990 					// continue MUST already be defined
1991 					branch = new ActionBranch(f_tag);
1992 					str = wd->f_continue.GetUTF8();
1993 					branch->SetLabel(str);
1994 					delete [] str;
1995 					f_actions->Insert(-1, branch);
1996 					break;
1997 
1998 				case as::NODE_BREAK:
1999 					// the break may not already be
2000 					// defined; do it if necessary
2001 					if(wd->f_break.IsEmpty()) {
2002 						Label(wd->f_break);
2003 					}
2004 					branch = new ActionBranch(f_tag);
2005 					str = wd->f_break.GetUTF8();
2006 					branch->SetLabel(str);
2007 					delete [] str;
2008 					f_actions->Insert(-1, branch);
2009 					break;
2010 
2011 				default:
2012 					// in case of a goto, we don't
2013 					// have to do anything here
2014 					break;
2015 
2016 				}
2017 			}
2018 			else if(data.f_type == as::NODE_FOR) {
2019 				if(parent.GetChildCount() == 3) {
2020 					// ha! this is an enumeration
2021 					// we need to remove the data
2022 					// from the stack
2023 					EmptyEnumeration();
2024 				}
2025 			}
2026 			// else do nothing; the do/while loops don't
2027 			// save anything which would need to be released
2028 			// when a goto goes through
2029 			break;
2030 
2031 		case as::NODE_DIRECTIVE_LIST:
2032 			if(!end) {
2033 				ClearVariables(parent);
2034 			}
2035 			break;
2036 
2037 		case as::NODE_WITH:
2038 		case as::NODE_TRY:
2039 		case as::NODE_CATCH:
2040 		case as::NODE_FINALLY:
2041 fprintf(stderr, "INTERNAL ERROR: going through a WITH, TRY, CATCH & FINALLY not supported yet with GOTO, BREAK and CONTINUE.\n");
2042 			AS_ASSERT(0);
2043 			break;
2044 
2045 		default:
2046 			break;
2047 
2048 		}
2049 
2050 		if(end) {
2051 			return true;
2052 		}
2053 	}
2054 	/*NOTREACHED*/
2055 	AS_ASSERT(0);
2056 	return false;
2057 }
2058 
EnterFrame(as::NodePtr & goto_node)2059 void IntAssembler::EnterFrame(as::NodePtr& goto_node)
2060 {
2061 	ActionBranch	*branch;
2062 	char		*str;
2063 	bool		end;
2064 
2065 	as::Data& goto_data = goto_node.GetData();
2066 	if(goto_data.f_type != as::NODE_GOTO) {
2067 		return;
2068 	}
2069 
2070 	str = goto_data.f_str.GetUTF8();
2071 
2072 	as::NodePtr& exit = goto_node.GetLink(as::NodePtr::LINK_GOTO_EXIT);
2073 	as::NodePtr parent = goto_node.GetLink(as::NodePtr::LINK_GOTO_ENTER);
2074 	for(;;) {
2075 		parent = parent.GetParent();
2076 		if(!parent.HasNode()) {
2077 			// this should not happen
2078 			break;
2079 		}
2080 
2081 		// are we on that last frame?
2082 		end = exit.SameAs(parent);
2083 
2084 		as::Data& data = parent.GetData();
2085 		switch(data.f_type) {
2086 		case as::NODE_WITH:
2087 		case as::NODE_TRY:
2088 		case as::NODE_CATCH:
2089 		case as::NODE_FINALLY:
2090 fprintf(stderr, "INTERNAL ERROR: WITH, TRY, CATCH & FINALLY not supported yet with GOTO, BREAK and CONTINUE.\n");
2091 			AS_ASSERT(0);
2092 			break;
2093 
2094 		default:
2095 			break;
2096 
2097 		}
2098 
2099 		if(end) {
2100 			branch = new ActionBranch(f_tag);
2101 			branch->SetLabel(str);
2102 			f_actions->Insert(-1, branch);
2103 			break;
2104 		}
2105 	}
2106 
2107 	delete [] str;
2108 }
2109 
2110 
2111 
With(as::NodePtr & with)2112 void IntAssembler::With(as::NodePtr& with)
2113 {
2114 	Expression(with.GetChild(0));
2115 
2116 	ActionWith *w = new ActionWith(f_tag);
2117 	f_actions->Insert(-1, w);
2118 
2119 	Vectors *current = f_actions;
2120 	f_actions = w->SubList();
2121 
2122 	DirectiveList(with.GetChild(1));
2123 
2124 	f_actions = current;
2125 }
2126 
2127 
Throw(as::NodePtr & throw_node)2128 void IntAssembler::Throw(as::NodePtr& throw_node)
2129 {
2130 	Expression(throw_node.GetChild(0));
2131 
2132 	Action *a = new Action(f_tag, Action::ACTION_THROW);
2133 	f_actions->Insert(-1, a);
2134 }
2135 
2136 
TryCatchFinally(as::NodePtr & list,int & index,as::NodePtr & try_node)2137 void IntAssembler::TryCatchFinally(as::NodePtr& list, int& index, as::NodePtr& try_node)
2138 {
2139 	try_info_t	info, *save_try_info;
2140 	int		max;
2141 	bool		is_last;
2142 
2143 	save_try_info = f_try_info;
2144 	f_try_info = &info;
2145 
2146 	Try(info, try_node);
2147 
2148 	max = list.GetChildCount();
2149 	while(index + 1 < max) {
2150 		as::NodePtr& next = list.GetChild(index + 1);
2151 		as::Data& data = next.GetData();
2152 		switch(data.f_type) {
2153 		case as::NODE_CATCH:
2154 			if(index + 2 < max) {
2155 				as::NodePtr& after = list.GetChild(index + 2);
2156 				as::Data& data = after.GetData();
2157 				is_last = data.f_type != as::NODE_CATCH;
2158 			}
2159 			else {
2160 				is_last = true;
2161 			}
2162 			Catch(info, next, is_last);
2163 			break;
2164 
2165 		case as::NODE_FINALLY:
2166 			Finally(info, next);
2167 			break;
2168 
2169 		default:
2170 			goto exit;
2171 
2172 		}
2173 		++index;
2174 	}
2175 exit:
2176 	// release this register for others
2177 	f_registers.FreeRegister(info.f_reg);
2178 
2179 	// restore the previous try info
2180 	f_try_info = save_try_info;
2181 }
2182 
2183 
Try(try_info_t & info,as::NodePtr & try_node)2184 void IntAssembler::Try(try_info_t& info, as::NodePtr& try_node)
2185 {
2186 	info.f_try = new ActionTry(f_tag);
2187 	f_actions->Insert(-1, info.f_try);
2188 
2189 	Vectors *save_actions = f_actions;
2190 	f_actions = info.f_try->SubListTry();
2191 	DirectiveList(try_node.GetChild(0));
2192 	f_actions = save_actions;
2193 }
2194 
2195 
Catch(try_info_t & info,as::NodePtr & catch_node,bool is_last)2196 void IntAssembler::Catch(try_info_t& info, as::NodePtr& catch_node, bool is_last)
2197 {
2198 	ActionBranch	*branch;
2199 	ActionPushData	*pd;
2200 	ActionLabel	*label;
2201 	Action		*a;
2202 	as::String	l;
2203 	char		*str, buf[256];
2204 
2205 	Vectors *save_actions = f_actions;
2206 	f_actions = info.f_try->SubListCatch();
2207 
2208 	if(info.f_reg < 0 && info.f_regname.GetLength() == 0) {
2209 		Label(info.f_end);
2210 		info.f_str = info.f_end.GetUTF8();
2211 		// avoid using reg 0 for the catch
2212 		info.f_reg = f_registers.AllocRegister(1);
2213 		if(info.f_reg < 0) {
2214 			snprintf(buf, sizeof(buf), "__c%d", f_label);
2215 			f_label++;
2216 			info.f_regname = buf;
2217 			info.f_try->SetIdentifier(buf);
2218 			info.f_regname_str = info.f_regname.GetUTF8();
2219 		}
2220 		else {
2221 			info.f_try->SetIdentifier(info.f_reg);
2222 		}
2223 	}
2224 
2225 	// NOTE: - Should we clear the f_catch_reg if we
2226 	//	   enter a catch(...)?
2227 	//	 - It most certainly won't matter since it
2228 	//	   shouldn't be referenced in the block of
2229 	//	   directives.
2230 
2231 	str = 0;
2232 	as::Data& data = catch_node.GetData();
2233 	if((data.f_int.Get() & as::NODE_CATCH_FLAG_TYPED) != 0) {
2234 		//	push catch reg
2235 		//	push expression type
2236 		//	instance of
2237 		//	logical not
2238 		//	branch if true, goto skip
2239 		//	<catch instructions>
2240 		//	branch, goto end
2241 		// skip:
2242 		if(info.f_reg >= 0) {
2243 			f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
2244 		}
2245 		else {
2246 			pd = new ActionPushData(f_tag);
2247 			pd->AddString(info.f_regname_str);
2248 			f_actions->Insert(-1, pd);
2249 			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2250 			f_actions->Insert(-1, a);
2251 		}
2252 		as::NodePtr& parameters = catch_node.GetChild(0);
2253 		as::NodePtr& param = parameters.GetChild(0);
2254 		as::NodePtr& type = param.GetChild(0);
2255 		as::Data& type_data = type.GetData();
2256 		if(type_data.f_type == as::NODE_IDENTIFIER) {
2257 			// Here we compare names without taking the case
2258 			// in account since Flash returns type names in
2259 			// lowercase.
2260 			if(type_data.f_str == "Integer"
2261 			|| type_data.f_str == "Double"
2262 			|| type_data.f_str == "Number") {
2263 				if(info.f_has_number) {
2264 					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.");
2265 				}
2266 				else {
2267 					if(type_data.f_str == "Number") {
2268 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");
2269 					}
2270 					pd = new ActionPushData(f_tag);
2271 					pd->AddString("Number");
2272 					f_actions->Insert(-1, pd);
2273 					info.f_has_number = true;
2274 				}
2275 			}
2276 			else {
2277 				pd = new ActionPushData(f_tag);
2278 				str = type_data.f_str.GetUTF8();
2279 				pd->AddString(str);
2280 				delete [] str;
2281 				f_actions->Insert(-1, pd);
2282 			}
2283 		}
2284 		else {
2285 			Expression(type);
2286 		}
2287 		// Flash is using CAST, I'm not too sure whether a
2288 		// cast or instanceof is better here... but the cast
2289 		// just doesn't work properly
2290 #if 0
2291 // a la Flash which doesn't work:
2292 		a = new Action(f_tag, Action::ACTION_SWAP);
2293 		f_actions->Insert(-1, a);
2294 		a = new Action(f_tag, Action::ACTION_CAST);
2295 		f_actions->Insert(-1, a);
2296 		pd = new ActionPushData(f_tag);
2297 		pd->AddNull(str);
2298 		f_actions->Insert(-1, pd);
2299 		a = new Action(f_tag, Action::ACTION_EQUAL_TYPED);
2300 		f_actions->Insert(-1, a);
2301 #else
2302 		a = new Action(f_tag, Action::ACTION_INSTANCE_OF);
2303 		f_actions->Insert(-1, a);
2304 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
2305 		f_actions->Insert(-1, a);
2306 #endif
2307 		Label(l);
2308 		str = l.GetUTF8();
2309 		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
2310 		branch->SetLabel(str);
2311 		f_actions->Insert(-1, branch);
2312 	}
2313 
2314 	DirectiveList(catch_node.GetChild(1));
2315 
2316 	branch = new ActionBranch(f_tag);
2317 	branch->SetLabel(info.f_str);
2318 	f_actions->Insert(-1, branch);
2319 
2320 	if(str != 0) {
2321 		label = new ActionLabel(f_tag);
2322 		label->SetLabel(str);
2323 		f_actions->Insert(-1, label);
2324 
2325 		delete [] str;
2326 
2327 		// in this case we have to raise the exception again
2328 		// (last catch is typed too and we didn't match any
2329 		// type yet!)
2330 		if(is_last) {
2331 			if(info.f_reg >= 0) {
2332 				f_registers.LoadRegister(info.f_reg, false, f_tag, f_actions);
2333 			}
2334 			else {
2335 				pd = new ActionPushData(f_tag);
2336 				pd->AddString(info.f_regname_str);
2337 				f_actions->Insert(-1, pd);
2338 				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2339 				f_actions->Insert(-1, a);
2340 			}
2341 			a = new Action(f_tag, Action::ACTION_THROW);
2342 			f_actions->Insert(-1, a);
2343 		}
2344 	}
2345 
2346 	if(is_last) {
2347 		label = new ActionLabel(f_tag);
2348 		label->SetLabel(info.f_str);
2349 		f_actions->Insert(-1, label);
2350 	}
2351 
2352 	f_actions = save_actions;
2353 }
2354 
2355 
Finally(try_info_t & info,as::NodePtr & finally_node)2356 void IntAssembler::Finally(try_info_t& info, as::NodePtr& finally_node)
2357 {
2358 	Vectors *save_actions = f_actions;
2359 	f_actions = info.f_try->SubListFinally();
2360 	DirectiveList(finally_node.GetChild(0));
2361 	f_actions = save_actions;
2362 }
2363 
2364 
Function(as::NodePtr & function,bool use_name)2365 void IntAssembler::Function(as::NodePtr& function, bool use_name)
2366 {
2367 	// a function marked unused & dynamic is compiled with
2368 	// as a throw new Error("Cannot call an unused function");
2369 	// a function only marked unused is ignored
2370 	unsigned long attrs = function.GetAttrs();
2371 	if((attrs & (as::NODE_ATTR_UNUSED | as::NODE_ATTR_DYNAMIC)) == as::NODE_ATTR_UNUSED) {
2372 		return;
2373 	}
2374 
2375 	ActionFunction *func = new ActionFunction(f_tag, Action::ACTION_DECLARE_FUNCTION2);
2376 	f_actions->Insert(-1, func);
2377 
2378 	// Optimizations:
2379 	//
2380 	// whenever a function has just one parameter we just create
2381 	// a function with one parameter in a register;
2382 	//
2383 	// if the function has any parameter defined as OUT, then we
2384 	// create a one parameter function which needs to be an array
2385 	// this is required to get the value back out (Flash is always
2386 	// passing parameters by value [or copy], but the content of
2387 	// an array is read/write)
2388 	//
2389 	// the user can also use the special attribute 'array'; this
2390 	// will force the use of an array for all the parameters
2391 	// even if it isn't required. This can save some space for
2392 	// functions using many parameters since the order in which
2393 	// parameters are stack is easier to handle.
2394 
2395 	as::Data& data = function.GetData();
2396 	if(use_name) {
2397 		// don't rename global functions
2398 		bool rename = true;
2399 		as::NodePtr& parent = function.GetParent();
2400 		as::Data& parent_data = parent.GetData();
2401 		if(parent_data.f_type == as::NODE_DIRECTIVE_LIST) {
2402 			as::NodePtr& program = parent.GetParent();
2403 			as::Data& program_data = program.GetData();
2404 			if(program_data.f_type == as::NODE_PROGRAM) {
2405 				rename = false;
2406 			}
2407 		}
2408 
2409 		char *name;
2410 		if(rename) {
2411 			FunctionData **fd;
2412 			AS_ASSERT(data.f_user_data.Size() == 0);
2413 
2414 			data.f_user_data.New((sizeof(FunctionData *) + sizeof(int) - 1) / sizeof(int));
2415 			fd = reinterpret_cast<FunctionData **>(data.f_user_data.Buffer());
2416 			fd[0] = new VariableData;
2417 			fd[0]->GenerateName("__f");
2418 			name = fd[0]->f_name.GetUTF8();
2419 		}
2420 		else {
2421 			name = data.f_str.GetUTF8();
2422 		}
2423 		func->SetName(name);
2424 		delete [] name;
2425 	}
2426 
2427 	// search for the parameters and directive list
2428 	as::NodePtr parameters, list;
2429 	int idx, max = function.GetChildCount();
2430 	for(idx = 0; idx < max; ++idx) {
2431 		as::NodePtr& child = function.GetChild(idx);
2432 		as::Data& data = child.GetData();
2433 		switch(data.f_type) {
2434 		case as::NODE_PARAMETERS:
2435 			parameters = child;
2436 			break;
2437 
2438 		case as::NODE_DIRECTIVE_LIST:
2439 			list = child;
2440 			break;
2441 
2442 		default:
2443 			// skip the type
2444 			break;
2445 
2446 		}
2447 	}
2448 
2449 	f_registers.Push(254);
2450 
2451 	FuncParam **p = 0;
2452 	max = parameters.GetChildCount();
2453 	if(max > 0) {
2454 		unsigned long flags = data.f_int.Get();
2455 		if((attrs & as::NODE_ATTR_ARRAY) != 0
2456 		|| (flags & as::NODE_FUNCTION_FLAG_OUT) != 0) {
2457 			// we want to use register 10 for the array parameter
2458 			int r = f_registers.AllocRegister(10);
2459 			func->AddParameter(0, r);
2460 
2461 			for(int idx = 0; idx < max; ++idx) {
2462 				as::NodePtr& param = parameters.GetChild(idx);
2463 				as::Data& param_data = param.GetData();
2464 
2465 				param_data.f_user_data.New((sizeof(FuncParam *) + sizeof(int) - 1) / sizeof(int));
2466 				p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
2467 				p[0] = new FuncParam;
2468 				p[0]->f_mode = FuncParam::MODE_ARRAY;
2469 				p[0]->f_reg = r;
2470 				p[0]->f_index = max - idx - 1;
2471 			}
2472 		}
2473 		else {
2474 			// make it a standard (which means we need to
2475 			// use many registers for calls...); standard
2476 			// calls a more compatible!
2477 			for(int idx = 0; idx < max; ++idx) {
2478 				as::NodePtr& param = parameters.GetChild(idx);
2479 				as::Data& param_data = param.GetData();
2480 
2481 				param_data.f_user_data.New((sizeof(FuncParam *) + sizeof(int) - 1) / sizeof(int));
2482 				p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
2483 				p[0] = new FuncParam;
2484 
2485 				int r = f_registers.AllocRegister(10);
2486 				if(r == -1) {
2487 					p[0]->f_mode = FuncParam::MODE_VARIABLE;
2488 
2489 					// over 244 parameters?!
2490 					// Flash will probably break on that one!
2491 					char *name = data.f_str.GetUTF8();
2492 					func->AddParameter(name);
2493 					delete [] name;
2494 				}
2495 				else {
2496 					p[0]->f_mode = FuncParam::MODE_REGISTER;
2497 					p[0]->f_reg = r;
2498 
2499 					// should we have the name too?
2500 					// TODO: add an option to request
2501 					//	 for names to be kept
2502 					//if(option[name])
2503 					if(0) {
2504 						as::NodePtr& param = parameters.GetChild(idx);
2505 						as::Data& data = param.GetData();
2506 						char *name = data.f_str.GetUTF8();
2507 						func->AddParameter(name, r);
2508 						delete [] name;
2509 					}
2510 					else {
2511 						func->AddParameter(0, r);
2512 					}
2513 				}
2514 			}
2515 		}
2516 	}
2517 
2518 	// TODO: we need to test the version and create the
2519 	//	 function itself after if we want to avoid
2520 	//	 version 7 always...
2521 	Vectors *current = f_actions;
2522 	f_actions = func->SubList();
2523 
2524 	if((attrs & as::NODE_ATTR_UNUSED) != 0) {
2525 		ActionPushData *pd = new ActionPushData(f_tag);
2526 		pd->AddString("A function marked 'unused' cannot be called.");
2527 		pd->AddInteger(1);
2528 		pd->AddString("Error");
2529 		f_actions->Insert(-1, pd);
2530 
2531 		Action *a = new Action(f_tag, Action::ACTION_NEW);
2532 		f_actions->Insert(-1, a);
2533 
2534 		a = new Action(f_tag, Action::ACTION_THROW);
2535 		f_actions->Insert(-1, a);
2536 	}
2537 	else {
2538 		DirectiveList(list, false);
2539 	}
2540 
2541 	f_actions = current;
2542 
2543 	f_registers.Pop();
2544 
2545 	for(int idx = 0; idx < max; ++idx) {
2546 		as::NodePtr& param = parameters.GetChild(idx);
2547 		as::Data& param_data = param.GetData();
2548 
2549 		p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
2550 		// registers don't need to be freed since there
2551 		// were restored by the Pop().
2552 		delete p[0];
2553 		param_data.f_user_data.New(0);
2554 	}
2555 }
2556 
2557 
2558 
2559 
2560 
Return(as::NodePtr & return_node)2561 void IntAssembler::Return(as::NodePtr& return_node)
2562 {
2563 	int max = return_node.GetChildCount();
2564 
2565 	if(max == 1) {
2566 		Expression(return_node.GetChild(0));
2567 	}
2568 	else {
2569 		// A function not returning anything generates
2570 		// "undefined" by default.
2571 		ActionPushData *pd = new ActionPushData(f_tag);
2572 		pd->AddUndefined();
2573 		f_actions->Insert(-1, pd);
2574 		// TODO: it could be that we don't actually need
2575 		// to add this undefined ourselves (tbd)
2576 	}
2577 
2578 	Action *a = new Action(f_tag, Action::ACTION_RETURN);
2579 	f_actions->Insert(-1, a);
2580 }
2581 
2582 
Var(as::NodePtr & var)2583 void IntAssembler::Var(as::NodePtr& var)
2584 {
2585 	int max = var.GetChildCount();
2586 	for(int idx = 0; idx < max; ++idx) {
2587 		as::NodePtr& child = var.GetChild(idx);
2588 		as::Data& data = child.GetData();
2589 		if(data.f_type != as::NODE_VARIABLE) {
2590 			continue;
2591 		}
2592 		int flags = data.f_int.Get();
2593 		if((flags & as::NODE_VAR_FLAG_INUSE) == 0) {
2594 			// this is either an attribute variable
2595 			// or a totally unreferenced variable
2596 			continue;
2597 		}
2598 		// a variable is transformed as:
2599 		//	push expression
2600 		//	push name
2601 		//	set [local] variable action
2602 		bool has_expr = false;
2603 		int jmax = child.GetChildCount();
2604 		for(int j = 0; j < jmax; ++j) {
2605 			as::NodePtr& node = child.GetChild(j);
2606 			as::Data& data = node.GetData();
2607 			if(data.f_type == as::NODE_SET) {
2608 				as::NodePtr& expr = node.GetChild(0);
2609 				if((flags & as::NODE_VAR_FLAG_ENUM) != 0
2610 				&& ExpressionIsConstant(expr)) {
2611 					// TODO:
2612 					// unless there is a bug, all
2613 					// variables should use this
2614 					// condition...
2615 					break;
2616 				}
2617 				has_expr = true;
2618 				Expression(expr);
2619 				break;
2620 			}
2621 		}
2622 		// we skip variable definitions
2623 		if(!has_expr) {
2624 			continue;
2625 		}
2626 
2627 		// we don't have any specific name here
2628 		as::NodePtr name;
2629 		Assignment(name, child, false);
2630 	}
2631 }
2632 
2633 
Label(as::String & label)2634 void IntAssembler::Label(as::String& label)
2635 {
2636 	char		buf[256];
2637 
2638 	snprintf(buf, sizeof(buf), "l%d", f_label);
2639 	label = buf;
2640 	f_label++;
2641 }
2642 
2643 
ExpressionIdentifierParam(as::NodePtr & instance,as::Data & inst_data)2644 void IntAssembler::ExpressionIdentifierParam(as::NodePtr& instance, as::Data& inst_data)
2645 {
2646 	// first check whether this param is a catch(); if it is
2647 	// then we use the f_catch_reg
2648 	if((inst_data.f_int.Get() & as::NODE_PARAMETERS_FLAG_CATCH) != 0) {
2649 		if(f_try_info == 0) {
2650 			f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, instance, "reached a NODE_PARAM of a 'catch' without a try info structure available.");
2651 			return;
2652 		}
2653 		if(f_try_info->f_reg >= 0) {
2654 			f_registers.LoadRegister(f_try_info->f_reg, false, f_tag, f_actions);
2655 		}
2656 		else {
2657 			ActionPushData *pd = new ActionPushData(f_tag);
2658 			pd->AddString(f_try_info->f_regname_str);
2659 			f_actions->Insert(-1, pd);
2660 			Action *a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2661 			f_actions->Insert(-1, a);
2662 		}
2663 		return;
2664 	}
2665 
2666 	// ha! this is a NODE_SET within a function list of
2667 	// parameters; the content of that variable may be
2668 	// in a register and for sure it isn't defined under
2669 	// the same name!
2670 	if(inst_data.f_user_data.Size() == 0) {
2671 		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, instance, "reached a NODE_PARAM without a user data buffer set.");
2672 		return;
2673 	}
2674 
2675 	FuncParam **p;
2676 	p = reinterpret_cast<FuncParam **>(inst_data.f_user_data.Buffer());
2677 
2678 	switch(p[0]->f_mode) {
2679 	case FuncParam::MODE_REGISTER:
2680 		f_registers.LoadRegister(p[0]->f_reg, false, f_tag, f_actions);
2681 		break;
2682 
2683 	case FuncParam::MODE_CONSTANT:
2684 		Expression(p[0]->f_constant);
2685 		break;
2686 
2687 	case FuncParam::MODE_ARRAY:
2688 	{
2689 		f_registers.LoadRegister(p[0]->f_reg, false, f_tag, f_actions);
2690 		ActionPushData *pd = new ActionPushData(f_tag);
2691 		pd->AddInteger(p[0]->f_index);
2692 		f_actions->Insert(-1, pd);
2693 		Action *a = new Action(f_tag, Action::ACTION_GET_MEMBER);
2694 		f_actions->Insert(-1, a);
2695 	}
2696 		break;
2697 
2698 	case FuncParam::MODE_VARIABLE:
2699 		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, instance, "IntAssembler::ExpressionIdentifierParam() MODE_VARIABLE not written yet.");
2700 		break;
2701 
2702 	default:
2703 		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);
2704 		break;
2705 
2706 	}
2707 }
2708 
2709 
2710 
ExpressionIdentifierType(as::NodePtr & id)2711 void IntAssembler::ExpressionIdentifierType(as::NodePtr& id)
2712 {
2713 	// in case of a type, we don't get any content,
2714 	// just the name of the type unless we are on
2715 	// the left side of a MEMBER ('a' in 'a.b')
2716 	as::Data& data = id.GetData();
2717 
2718 	char *str = data.f_str.GetUTF8();
2719 
2720 	ActionPushData *pd = new ActionPushData(f_tag);
2721 	pd->AddString(str);
2722 	f_actions->Insert(-1, pd);
2723 
2724 	delete [] str;
2725 
2726 	if(data.f_type != as::NODE_FUNCTION) {
2727 		// check the parent
2728 		as::NodePtr& parent = id.GetParent();
2729 		as::Data& data = parent.GetData();
2730 		if(data.f_type == as::NODE_MEMBER) {
2731 			Action *a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2732 			f_actions->Insert(-1, a);
2733 		}
2734 	}
2735 }
2736 
2737 
2738 
ExpressionIdentifierVariable(as::NodePtr & variable,as::Data & inst_data,bool with_object)2739 void IntAssembler::ExpressionIdentifierVariable(as::NodePtr& variable, as::Data& inst_data, bool with_object)
2740 {
2741 	ActionPushData		*pd;
2742 	Action			*a;
2743 	char			*str;
2744 	VariableData		**vd;
2745 
2746 	unsigned long attrs = variable.GetAttrs();
2747 
2748 	if(!with_object && (inst_data.f_int.Get() & as::NODE_VAR_FLAG_MEMBER) != 0) {
2749 		if((attrs & as::NODE_ATTR_STATIC) != 0) {
2750 			//	push <class name>
2751 			//	get variable
2752 			//	push <static member name>
2753 			//	get member
2754 			as::NodePtr class_node = variable;
2755 			as::Data *class_data = 0;
2756 			for(;;) {
2757 				class_node = class_node.GetParent();
2758 				if(!class_node.HasNode()) {
2759 					break;
2760 				}
2761 				class_data = &class_node.GetData();
2762 				if(class_data->f_type == as::NODE_CLASS
2763 				|| class_data->f_type == as::NODE_INTERFACE) {
2764 					break;
2765 				}
2766 			}
2767 			if(class_node.HasNode()) {
2768 				pd = new ActionPushData(f_tag);
2769 				str = class_data->f_str.GetUTF8();
2770 				pd->AddString(str);
2771 				delete [] str;
2772 				f_actions->Insert(-1, pd);
2773 				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2774 				f_actions->Insert(-1, a);
2775 			}
2776 			pd = new ActionPushData(f_tag);
2777 			str = inst_data.f_str.GetUTF8();
2778 			pd->AddString(str);
2779 			delete [] str;
2780 			f_actions->Insert(-1, pd);
2781 			if(class_node.HasNode()) {
2782 				a = new Action(f_tag, Action::ACTION_GET_MEMBER);
2783 			}
2784 			else {
2785 				a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2786 			}
2787 			f_actions->Insert(-1, a);
2788 			return;
2789 		}
2790 		// a member needs to be transformed to this.<name> whenever
2791 		// this wasn't specified by the user...
2792 		pd = new ActionPushData(f_tag);
2793 		pd->AddString("this");
2794 		f_actions->Insert(-1, pd);
2795 
2796 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2797 		f_actions->Insert(-1, a);
2798 
2799 		pd = new ActionPushData(f_tag);
2800 		str = inst_data.f_str.GetUTF8();
2801 		pd->AddString(str);
2802 		delete [] str;
2803 		f_actions->Insert(-1, pd);
2804 
2805 		a = new Action(f_tag, Action::ACTION_GET_MEMBER);
2806 		f_actions->Insert(-1, a);
2807 		return;
2808 	}
2809 
2810 	vd = 0;
2811 
2812 	if(inst_data.f_user_data.Size() == 0) {
2813 		if(!with_object && (inst_data.f_int.Get() & as::NODE_VAR_FLAG_MEMBER) == 0) {
2814 			if((attrs & (as::NODE_ATTR_INTRINSIC | as::NODE_ATTR_DYNAMIC)) == 0) {
2815 				// if we don't have any "variable data" structure
2816 				// then we have a problem since we are supposed to
2817 				// have written something in this variable already
2818 //fprintf(stderr, "WARNING: pushing 'undefined' since variable '%S' wasn't set yet.\n", inst_data.f_str.GetLength(), inst_data.f_str.Get());
2819 				pd = new ActionPushData(f_tag);
2820 				pd->AddUndefined();
2821 				f_actions->Insert(-1, pd);
2822 				return;
2823 			}
2824 		}
2825 	}
2826 	else {
2827 		vd = reinterpret_cast<VariableData **>(inst_data.f_user_data.Buffer());
2828 	}
2829 
2830 	if(vd && vd[0]->f_mode == VariableData::MODE_REGISTER) {
2831 		pd = new ActionPushData(f_tag);
2832 		pd->AddRegister(vd[0]->f_reg);
2833 		f_actions->Insert(-1, pd);
2834 	}
2835 	else {
2836 		pd = new ActionPushData(f_tag);
2837 		if(vd) {
2838 			str = vd[0]->f_name.GetUTF8();
2839 		}
2840 		else {
2841 			str = inst_data.f_str.GetUTF8();
2842 		}
2843 		pd->AddString(str);
2844 		delete [] str;
2845 		f_actions->Insert(-1, pd);
2846 
2847 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
2848 		f_actions->Insert(-1, a);
2849 	}
2850 }
2851 
2852 
ExpressionIdentifier(as::NodePtr & id)2853 void IntAssembler::ExpressionIdentifier(as::NodePtr& id)
2854 {
2855 	as::Data& data = id.GetData();
2856 	bool with_object = (data.f_int.Get() & as::NODE_IDENTIFIER_FLAG_WITH) != 0;
2857 
2858 	as::NodePtr& instance = id.GetLink(as::NodePtr::LINK_INSTANCE);
2859 
2860 	if(!instance.HasNode()) {
2861 		as::Data& data = id.GetData();
2862 		f_error_stream->ErrStrMsg(as::AS_ERR_INTERNAL_ERROR, id, "found identifier '%S' without an instance.", &data.f_str);
2863 		return;
2864 	}
2865 
2866 	as::Data& inst_data = instance.GetData();
2867 
2868 	switch(inst_data.f_type) {
2869 	case as::NODE_PARAM:
2870 		ExpressionIdentifierParam(instance, inst_data);
2871 		break;
2872 
2873 	case as::NODE_CLASS:
2874 	case as::NODE_INTERFACE:
2875 	case as::NODE_FUNCTION:
2876 		ExpressionIdentifierType(id);
2877 		break;
2878 
2879 	case as::NODE_VARIABLE:
2880 		ExpressionIdentifierVariable(instance, inst_data, with_object);
2881 		break;
2882 
2883 	default:
2884 		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, id, "unknown instance data type in IntAssembler::ExpressionIdentifier().");
2885 		break;
2886 
2887 	}
2888 }
2889 
2890 
2891 
ExprIn(as::NodePtr & expr)2892 void IntAssembler::ExprIn(as::NodePtr& expr)
2893 {
2894 	ActionPushData		*pd;
2895 	ActionBranch		*branch;
2896 	ActionLabel		*label;
2897 	Action			*a;
2898 	char			*str1, *str2, *str3, *str4;
2899 	as::String		l1, l2, l3, l4;
2900 
2901 	int cnt = expr.GetChildCount();
2902 	if(cnt == 3) {
2903 		// expr in expr .. expr
2904 		//
2905 		// test to perform:
2906 		// expr[0] >= expr[1] && expr[0] <= expr[2]
2907 		//
2908 		//	expr[0]
2909 		//	dup
2910 		//	expr[1]
2911 		//	less_than
2912 		//	branch_if_true branch_false
2913 		//	expr[2]
2914 		//	swap
2915 		//	greater_than
2916 		//	goto branch_done
2917 		// branch_false:
2918 		//	pop
2919 		//	push false
2920 		// branch_done:
2921 		//
2922 		Expression(expr.GetChild(0));
2923 		a = new Action(f_tag, Action::ACTION_DUPLICATE);
2924 		f_actions->Insert(-1, a);
2925 		Expression(expr.GetChild(1));
2926 		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
2927 		f_actions->Insert(-1, a);
2928 		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
2929 		Label(l1);
2930 		str1 = l1.GetUTF8();
2931 		branch->SetLabel(str1);
2932 		f_actions->Insert(-1, branch);
2933 		Expression(expr.GetChild(2));
2934 		a = new Action(f_tag, Action::ACTION_SWAP);
2935 		f_actions->Insert(-1, a);
2936 		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
2937 		f_actions->Insert(-1, a);
2938 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
2939 		f_actions->Insert(-1, a);
2940 		branch = new ActionBranch(f_tag);
2941 		str2 = l2.GetUTF8();
2942 		branch->SetLabel(str2);
2943 		f_actions->Insert(-1, branch);
2944 		label = new ActionLabel(f_tag);
2945 		label->SetLabel(str1);
2946 		f_actions->Insert(-1, label);
2947 		a = new Action(f_tag, Action::ACTION_POP);
2948 		f_actions->Insert(-1, a);
2949 		pd = new ActionPushData(f_tag);
2950 		pd->AddBoolean(false);
2951 		f_actions->Insert(-1, pd);
2952 		label = new ActionLabel(f_tag);
2953 		label->SetLabel(str2);
2954 		f_actions->Insert(-1, label);
2955 		delete [] str1;
2956 		delete [] str2;
2957 		return;
2958 	}
2959 
2960 	AS_ASSERT(cnt == 2);
2961 
2962 	// expr in expr
2963 	//	evaluate expr[0]
2964 	//	store reg_find
2965 	//	pop
2966 	//	evaluate expr[1]
2967 	//	enumerate object
2968 	// repeat:
2969 	//	store reg_name
2970 	//	push null
2971 	//	equal
2972 	//	branch if true, goto return_false
2973 	//	load reg_find
2974 	//	load reg_name
2975 	//	strictly equal
2976 	//	logical not
2977 	//	branch if true, goto repeat
2978 	// empty:
2979 	//	push null
2980 	//	equal
2981 	//	logical not
2982 	//	branch if true, goto empty
2983 	//	push true
2984 	//	goto done
2985 	// return_false:
2986 	//	push false
2987 	// done:
2988 
2989 	Label(l1);
2990 	Label(l2);
2991 	Label(l3);
2992 	Label(l4);
2993 
2994 	str1 = l1.GetUTF8();
2995 	str2 = l2.GetUTF8();
2996 	str3 = l3.GetUTF8();
2997 	str4 = l4.GetUTF8();
2998 
2999 	// evaluate the string (member name)
3000 	Expression(expr.GetChild(0));
3001 	int reg_find = f_registers.StoreRegister(f_tag, f_actions, true);
3002 
3003 	// evaluate the object
3004 	Expression(expr.GetChild(1));
3005 	a = new Action(f_tag, Action::ACTION_ENUMERATE_OBJECT);
3006 	f_actions->Insert(-1, a);
3007 
3008 	label = new ActionLabel(f_tag);
3009 	label->SetLabel(str1);
3010 	f_actions->Insert(-1, label);
3011 
3012 	int reg_name = f_registers.StoreRegister(f_tag, f_actions, false);
3013 
3014 	pd = new ActionPushData(f_tag);
3015 	pd->AddNull();
3016 	f_actions->Insert(-1, pd);
3017 
3018 	a = new Action(f_tag, Action::ACTION_EQUAL);
3019 	f_actions->Insert(-1, a);
3020 
3021 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
3022 	branch->SetLabel(str3);
3023 	f_actions->Insert(-1, branch);
3024 
3025 	f_registers.LoadRegister(reg_find, true, f_tag, f_actions);
3026 	f_registers.LoadRegister(reg_name, true, f_tag, f_actions);
3027 
3028 	a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
3029 	f_actions->Insert(-1, a);
3030 
3031 	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
3032 	f_actions->Insert(-1, a);
3033 
3034 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
3035 	branch->SetLabel(str1);
3036 	f_actions->Insert(-1, branch);
3037 
3038 	label = new ActionLabel(f_tag);
3039 	label->SetLabel(str2);
3040 	f_actions->Insert(-1, label);
3041 
3042 	pd = new ActionPushData(f_tag);
3043 	pd->AddNull();
3044 	f_actions->Insert(-1, pd);
3045 
3046 	a = new Action(f_tag, Action::ACTION_EQUAL);
3047 	f_actions->Insert(-1, a);
3048 
3049 	a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
3050 	f_actions->Insert(-1, a);
3051 
3052 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
3053 	branch->SetLabel(str2);
3054 	f_actions->Insert(-1, branch);
3055 
3056 	pd = new ActionPushData(f_tag);
3057 	pd->AddBoolean(true);
3058 	f_actions->Insert(-1, pd);
3059 
3060 	branch = new ActionBranch(f_tag);
3061 	branch->SetLabel(str4);
3062 	f_actions->Insert(-1, branch);
3063 
3064 	label = new ActionLabel(f_tag);
3065 	label->SetLabel(str3);
3066 	f_actions->Insert(-1, label);
3067 
3068 	pd = new ActionPushData(f_tag);
3069 	pd->AddBoolean(false);
3070 	f_actions->Insert(-1, pd);
3071 
3072 	label = new ActionLabel(f_tag);
3073 	label->SetLabel(str4);
3074 	f_actions->Insert(-1, label);
3075 
3076 	delete [] str1;
3077 	delete [] str2;
3078 	delete [] str3;
3079 	delete [] str4;
3080 }
3081 
3082 
3083 
ExpressionIsConstant(as::NodePtr & expr,int inclusive)3084 bool IntAssembler::ExpressionIsConstant(as::NodePtr& expr, int inclusive)
3085 {
3086 	as::Data& data = expr.GetData();
3087 	switch(data.f_type) {
3088 	case as::NODE_FLOAT64:
3089 		return (inclusive & INCLUSIVE_FLOAT) != 0;
3090 
3091 	case as::NODE_INT64:
3092 		return (inclusive & INCLUSIVE_INTEGER) != 0;
3093 
3094 	case as::NODE_STRING:
3095 		return (inclusive & INCLUSIVE_STRING) != 0;
3096 
3097 	case as::NODE_TRUE:
3098 	case as::NODE_FALSE:
3099 		return (inclusive & INCLUSIVE_BOOLEAN) != 0;
3100 
3101 	case as::NODE_UNDEFINED:
3102 		return (inclusive & INCLUSIVE_UNDEFINED) != 0;
3103 
3104 	case as::NODE_NULL:
3105 		return (inclusive & INCLUSIVE_NULL) != 0;
3106 
3107 	default:
3108 		return false;
3109 
3110 	}
3111 }
3112 
3113 
IsSpecial(as::NodePtr & function,as::Data & data)3114 const IntAssembler::special_function_t *IntAssembler::IsSpecial(as::NodePtr& function, as::Data& data)
3115 {
3116 	static const special_function_t special_functions[] = {
3117 		{
3118 			"Native", "duplicateMovieClip",
3119 			Action::ACTION_DUPLICATE_SPRITE,
3120 			special_function_t::STACK_ORDER_REVERSED,
3121 			false
3122 		},
3123 		{
3124 			"Native", "fscommand",
3125 			Action::ACTION_URL2,
3126 			special_function_t::STACK_ORDER_SPECIAL,
3127 			false
3128 		},
3129 		{
3130 			"Native", "fscommand2",
3131 			Action::ACTION_FSCOMMAND2,
3132 			special_function_t::STACK_ORDER_PERFECT_COUNT,
3133 			false
3134 		},
3135 		{
3136 			"Native", "getProperty",
3137 			Action::ACTION_GET_PROPERTY,
3138 			special_function_t::STACK_ORDER_REVERSED,
3139 			true
3140 		},
3141 		{
3142 			"Native", "getTimer",
3143 			Action::ACTION_GET_TIMER,
3144 			special_function_t::STACK_ORDER_SPECIAL, // we actually ignore this one
3145 			true
3146 		},
3147 		{
3148 			"Native", "getURL",
3149 			Action::ACTION_URL2,
3150 			special_function_t::STACK_ORDER_SPECIAL,
3151 			false
3152 		},
3153 		{
3154 			"Native", "gotoAndPlay",
3155 			Action::ACTION_GOTO_FRAME,
3156 			special_function_t::STACK_ORDER_SPECIAL,
3157 			false
3158 		},
3159 		{
3160 			"Native", "gotoAndStop",
3161 			Action::ACTION_GOTO_FRAME,
3162 			special_function_t::STACK_ORDER_SPECIAL,
3163 			false
3164 		},
3165 		{
3166 			"Native", "loadMovie",
3167 			Action::ACTION_URL2,
3168 			special_function_t::STACK_ORDER_SPECIAL,
3169 			false
3170 		},
3171 		{
3172 			"Native", "loadMovieNum",
3173 			Action::ACTION_URL2,
3174 			special_function_t::STACK_ORDER_SPECIAL,
3175 			false
3176 		},
3177 		{
3178 			"Native", "loadVariables",
3179 			Action::ACTION_URL2,
3180 			special_function_t::STACK_ORDER_SPECIAL,
3181 			false
3182 		},
3183 		{
3184 			"Native", "loadVariablesNum",
3185 			Action::ACTION_URL2,
3186 			special_function_t::STACK_ORDER_SPECIAL,
3187 			false
3188 		},
3189 		{
3190 			"Native", "nextFrame",
3191 			Action::ACTION_NEXT_FRAME,
3192 			special_function_t::STACK_ORDER_PERFECT,
3193 			false
3194 		},
3195 		{
3196 			"Native", "play",
3197 			Action::ACTION_PLAY,
3198 			special_function_t::STACK_ORDER_PERFECT,
3199 			false
3200 		},
3201 		{
3202 			"Native", "prevFrame",
3203 			Action::ACTION_PREVIOUS_FRAME,
3204 			special_function_t::STACK_ORDER_PERFECT,
3205 			false
3206 		},
3207 		{
3208 			"Native", "removeMovieClip",
3209 			Action::ACTION_REMOVE_SPRITE,
3210 			special_function_t::STACK_ORDER_PERFECT,
3211 			false
3212 		},
3213 		{
3214 			"Native", "setProperty",
3215 			Action::ACTION_SET_PROPERTY,
3216 			special_function_t::STACK_ORDER_REVERSED,
3217 			false
3218 		},
3219 		{
3220 			"Native", "startDrag",
3221 			Action::ACTION_START_DRAG,
3222 			special_function_t::STACK_ORDER_SPECIAL,
3223 			false
3224 		},
3225 		{
3226 			"Native", "stop",
3227 			Action::ACTION_STOP,
3228 			special_function_t::STACK_ORDER_PERFECT,
3229 			false
3230 		},
3231 		{
3232 			"Native", "stopAllSounds",
3233 			Action::ACTION_STOP_SOUND,
3234 			special_function_t::STACK_ORDER_PERFECT,
3235 			false
3236 		},
3237 		{
3238 			"Native", "stopDrag",
3239 			Action::ACTION_STOP_DRAG,
3240 			special_function_t::STACK_ORDER_PERFECT,
3241 			false
3242 		},
3243 		{
3244 			"Native", "targetpath",
3245 			Action::ACTION_GET_TARGET,
3246 			special_function_t::STACK_ORDER_PERFECT,
3247 			true
3248 		},
3249 		{
3250 			"Native", "unloadMovie",
3251 			Action::ACTION_URL,
3252 			special_function_t::STACK_ORDER_SPECIAL,
3253 			false
3254 		},
3255 		{
3256 			"Native", "unloadMovieNum",
3257 			Action::ACTION_URL,
3258 			special_function_t::STACK_ORDER_SPECIAL,
3259 			false
3260 		},
3261 		/* special functions still to be implemented
3262 		function fscommand(func : String, params : String) : Void; -> getURL('FSCommand:' + func, params);
3263 		function getURL(url : String, target : String) : Void;
3264 		function getTimer(Void) : Integer;
3265 		function nextScene(Void) : Void;
3266 		function nextScene(Void) : Void;
3267 		function on(event : mouse_event, ...) : Void;
3268 		function onClipEvent(event : movie_event) : Void;
3269 		function onUpdate(Void) : Void;
3270 		function prevScene(Void) : Void;
3271 		function print(target : Object, bounds : String) : Void;
3272 		function printAsBitmap(target : Object, bounds : String) : Void;
3273 		function printAsBitmapNum(level : Integer, bounds : String) : Void;
3274 		function printNum(level : Integer, bounds : String) : Void;
3275 		function unloadMovie(target : MovieClip) : Void;
3276 		function unloadMovie(target : String) : Void;
3277 		function unloadMovieNum(level : Integer) : Void;
3278 		function updateAfterEvent(Void) : Void;
3279 		*/
3280 	};
3281 
3282 	long length = data.f_str.GetLength();
3283 	if(length <= 0) {
3284 		// this should not happen...
3285 		return 0;
3286 	}
3287 
3288 	int i = 0;
3289 	int j = sizeof(special_functions) / sizeof(special_function_t);
3290 	int r, p;
3291 
3292 #if defined(_DEBUG) || defined(DEBUG)
3293 	for(p = 1; p < j; ++p) {
3294 		if(strcmp(special_functions[p - 1].f_function_name,
3295 			special_functions[p].f_function_name) >= 0) {
3296 fprintf(stderr, "INTERNAL ERROR: special functions are not listed in order (necessary for our binary search).\n");
3297 			AS_ASSERT(0);
3298 		}
3299 	}
3300 #endif
3301 
3302 	r = -1;	// avoid warnings
3303 	while(i < j) {
3304 		p = (j - i) / 2 + i;
3305 		r = data.f_str.Compare(special_functions[p].f_function_name);
3306 		if(r == 0) {
3307 
3308 //fprintf(stderr, "+++ Found '%s'\n", special_functions[p].f_function_name);
3309 
3310 			break;
3311 		}
3312 		if(r > 0) {
3313 			i = p + 1;
3314 		}
3315 		else {
3316 			j = p;
3317 		}
3318 	}
3319 	if(r != 0) {
3320 		// not found, this isn't an error
3321 		return 0;
3322 	}
3323 
3324 	const special_function_t *special = special_functions + p;
3325 
3326 	as::NodePtr parent = function.GetParent();
3327 	while(parent.HasNode()) {
3328 		as::Data& data = parent.GetData();
3329 		if(data.f_type == as::NODE_PACKAGE) {
3330 			if(data.f_str == special->f_package_name) {
3331 				return special;
3332 			}
3333 			// we cannot have more than one package
3334 			// at this time (i.e. depth 1)
3335 			break;
3336 		}
3337 		parent = parent.GetParent();
3338 	}
3339 
3340 	return 0;
3341 }
3342 
3343 
Member(as::NodePtr & member,Action::action_t action)3344 void IntAssembler::Member(as::NodePtr& member, Action::action_t action)
3345 {
3346 	ActionPushData	*pd;
3347 	Action		*a;
3348 	char		*str;
3349 
3350 	as::NodePtr& left = member.GetChild(0);
3351 #if 0
3352 	as::Data& left_data = left.GetData();
3353 	switch(left_data.f_type) {
3354 	case as::NODE_THIS:
3355 		pd = new ActionPushData(f_tag);
3356 		pd->AddString("this");
3357 		f_actions->Insert(-1, pd);
3358 
3359 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
3360 		f_actions->Insert(-1, a);
3361 		break;
3362 
3363 	case as::NODE_SUPER:
3364 		pd = new ActionPushData(f_tag);
3365 		pd->AddString("super");
3366 		f_actions->Insert(-1, pd);
3367 
3368 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
3369 		f_actions->Insert(-1, a);
3370 		break;
3371 
3372 	default:
3373 		Expression(left);
3374 		break;
3375 
3376 	}
3377 #endif
3378 	Expression(left);
3379 
3380 	// TODO: special case?! I'd like to make sure that this is
3381 	//	 really correct at some point... we may have to do
3382 	//	 that sort of special handling with other types too
3383 	as::NodePtr& left_type = left.GetLink(as::NodePtr::LINK_TYPE);
3384 	if(left_type.HasNode()) {
3385 		as::Data& left_type_data = left_type.GetData();
3386 		if(left_type_data.f_str == "String") {
3387 			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
3388 			f_actions->Insert(-1, a);
3389 		}
3390 	}
3391 
3392 	if(action == Action::ACTION_SET_MEMBER) {
3393 		a = new Action(f_tag, Action::ACTION_SWAP);
3394 		f_actions->Insert(-1, a);
3395 	}
3396 
3397 	as::NodePtr& right = member.GetChild(1);
3398 	as::Data& right_data = right.GetData();
3399 	switch(right_data.f_type) {
3400 	case as::NODE_IDENTIFIER:
3401 		// This is the direct and exact name of the
3402 		// variable member to access right now
3403 		pd = new ActionPushData(f_tag);
3404 		str = right_data.f_str.GetUTF8();
3405 		pd->AddString(str);
3406 		delete [] str;
3407 		f_actions->Insert(-1, pd);
3408 		break;
3409 
3410 #if 0
3411 	case as::NODE_CALL:
3412 		// this should be caught in the compiler!
3413 		if(action == Action::ACTION_SET_MEMBER) {
3414 fprintf(stderr, "ERROR: can't set a member call?!\n");
3415 			f_errcnt++;
3416 			return;
3417 		}
3418 		Call(right, Action::ACTION_CALL_METHOD);
3419 		return;
3420 #endif
3421 
3422 	case as::NODE_MEMBER:
3423 		Member(right, Action::ACTION_UNKNOWN);
3424 		return;
3425 
3426 	default:
3427 		Expression(right);
3428 		break;
3429 
3430 	}
3431 
3432 	if(action == Action::ACTION_SET_MEMBER) {
3433 		a = new Action(f_tag, Action::ACTION_SWAP);
3434 		f_actions->Insert(-1, a);
3435 	}
3436 
3437 	a = new Action(f_tag, action);
3438 	f_actions->Insert(-1, a);
3439 }
3440 
3441 
Array(as::NodePtr & array,Action::action_t action)3442 void IntAssembler::Array(as::NodePtr& array, Action::action_t action)
3443 {
3444 	ActionPushData		*pd;
3445 	Action			*a;
3446 
3447 	as::NodePtr& obj = array.GetChild(0);
3448 
3449 	int max = array.GetChildCount();
3450 	if(max == 1) {
3451 		// ha! special case of an empty array
3452 		if(obj.HasSideEffects()) {
3453 			// Compile because it could have side
3454 			// effects which the user may expect.
3455 			VoidExpression(obj);
3456 		}
3457 		// Create an empty array
3458 		//	push 0
3459 		//	declare array
3460 		pd = new ActionPushData(f_tag);
3461 		pd->AddInteger(0);
3462 		f_actions->Insert(-1, pd);
3463 		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
3464 		f_actions->Insert(-1, a);
3465 		return;
3466 	}
3467 
3468 	// get the array reference
3469 	Expression(obj);
3470 
3471 	if(action == Action::ACTION_SET_MEMBER) {
3472 		a = new Action(f_tag, Action::ACTION_SWAP);
3473 		f_actions->Insert(-1, a);
3474 	}
3475 
3476 	as::NodePtr& index = array.GetChild(1);
3477 	as::Data& data = index.GetData();
3478 	switch(data.f_type) {
3479 	case as::NODE_LIST:
3480 		// special case that generates an array from the
3481 		// items specified in the list
3482 		f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, array, "array list not implemented yet in IntAssembler::Array().");
3483 		return;
3484 
3485 	case as::NODE_ARRAY:
3486 		Array(index, Action::ACTION_GET_MEMBER);
3487 		break;
3488 
3489 	case as::NODE_MEMBER:
3490 		Member(index, Action::ACTION_GET_MEMBER);
3491 		break;
3492 
3493 	default:
3494 		Expression(index);
3495 		break;
3496 
3497 	}
3498 
3499 	if(action == Action::ACTION_SET_MEMBER) {
3500 		a = new Action(f_tag, Action::ACTION_SWAP);
3501 		f_actions->Insert(-1, a);
3502 	}
3503 
3504 	a = new Action(f_tag, action);
3505 	f_actions->Insert(-1, a);
3506 }
3507 
3508 
Call(as::NodePtr & call)3509 void IntAssembler::Call(as::NodePtr& call)
3510 {
3511 	ActionPushData	*pd;
3512 	Action		*a;
3513 
3514 	as::NodePtr& name = call.GetChild(0);
3515 	as::Data& name_data = name.GetData();
3516 
3517 	// get the name to see whether this is a special Flash
3518 	// function (i.e. a function which really returns Void
3519 	// and/or a function which has a special set of parameters)
3520 	as::NodePtr& function = call.GetLink(as::NodePtr::LINK_INSTANCE);
3521 	unsigned long attrs = 0;
3522 	unsigned long flags = 0;
3523 	const special_function_t *special = 0;
3524 	if(function.HasNode()) {
3525 		as::Data& data = function.GetData();
3526 		attrs = function.GetAttrs();
3527 		flags = data.f_int.Get();
3528 
3529 		// only intrinsic functions can be converted in
3530 		// a specialised byte code
3531 		if((attrs & as::NODE_ATTR_INTRINSIC) != 0
3532 		&& name_data.f_type == as::NODE_IDENTIFIER) {
3533 			special = IsSpecial(function, data);
3534 		}
3535 	}
3536 
3537 	// find the list of parameters
3538 	as::NodePtr list;
3539 	int max = call.GetChildCount();
3540 	// note: call.GetChild(0) is the name of the function to call
3541 	for(int idx = 1; idx < max; ++idx) {
3542 		as::NodePtr& child = call.GetChild(idx);
3543 		as::Data& data = child.GetData();
3544 		if(data.f_type == as::NODE_LIST) {
3545 			list = child;
3546 			break;
3547 		}
3548 	}
3549 
3550 	if(!list.HasNode()) {
3551 		return;
3552 	}
3553 
3554 	if(name_data.f_type == as::NODE_IDENTIFIER
3555 	&& name_data.f_str == "trace") {
3556 		if(f_options != 0
3557 		&& !f_options->GetOption(as::AS_OPTION_TRACE)) {
3558 			// no trace, just put undefined (which the next
3559 			// optimizer should be taking out for us...)
3560 			pd = new ActionPushData(f_tag);
3561 			pd->AddUndefined();
3562 			f_actions->Insert(-1, pd);
3563 			return;
3564 		}
3565 		if(f_options != 0
3566 		&& f_options->GetOption(as::AS_OPTION_TRACE_TO_OBJECT)) {
3567 			//	push __LINE__
3568 			//	push __FILENAME__
3569 			//	push "<package>::<class>::<function>"
3570 			//	push <expr> (user funcion parameter)
3571 			int max = list.GetChildCount();
3572 			if(max > 1) {
3573 				int idx = max;
3574 				while(idx > 1) {
3575 					// TODO: this is backward... (i.e.
3576 					//	 right to left stacking!)
3577 					//	 but debug stuff shouldn't
3578 					//	 have any side effects?!
3579 					--idx;
3580 					Expression(list.GetChild(idx));
3581 				}
3582 			}
3583 			pd = new ActionPushData(f_tag);
3584 			pd->AddInteger(call.GetLine());
3585 			const as::String& filename = call.GetFilename();
3586 			char *str = filename.GetUTF8();
3587 			pd->AddString(str);
3588 			delete [] str;
3589 			// we need the name of the function + class
3590 			as::String qualified_func;
3591 			as::NodePtr parent = call;
3592 			for(;;) {
3593 				parent = parent.GetParent();
3594 				if(!parent.HasNode()) {
3595 					break;
3596 				}
3597 				as::Data& data = parent.GetData();
3598 				if(data.f_type == as::NODE_PROGRAM
3599 				|| data.f_type == as::NODE_ROOT) {
3600 					break;
3601 				}
3602 				if(data.f_type == as::NODE_FUNCTION
3603 				|| data.f_type == as::NODE_CLASS
3604 				|| data.f_type == as::NODE_INTERFACE
3605 				|| data.f_type == as::NODE_PACKAGE) {
3606 					if(qualified_func.IsEmpty()) {
3607 						qualified_func = data.f_str;
3608 					}
3609 					else {
3610 						// TODO: create the + operator
3611 						//	 on String.
3612 						as::String p = data.f_str;
3613 						p += ".";
3614 						p += qualified_func;
3615 						qualified_func = p;
3616 					}
3617 					if(data.f_type == as::NODE_PACKAGE) {
3618 						// we don't really care if we
3619 						// are yet in another package
3620 						// at this time...
3621 						break;
3622 					}
3623 				}
3624 			}
3625 			str = qualified_func.GetUTF8();
3626 			pd->AddString(str);
3627 			delete [] str;
3628 			f_actions->Insert(-1, pd);
3629 			if(max >= 1) {
3630 				Expression(list.GetChild(0));
3631 			}
3632 			else /*if(max == 0)*/ {
3633 				// put a default
3634 				pd = new ActionPushData(f_tag);
3635 				pd->AddString("trace()");
3636 				f_actions->Insert(-1, pd);
3637 				max = 1;
3638 			}
3639 			pd = new ActionPushData(f_tag);
3640 			pd->AddInteger(max + 3);
3641 			pd->AddString("Trace");
3642 			f_actions->Insert(-1, pd);
3643 			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
3644 			f_actions->Insert(-1, a);
3645 			pd = new ActionPushData(f_tag);
3646 			pd->AddString("Message");
3647 			f_actions->Insert(-1, pd);
3648 			a = new Action(f_tag, Action::ACTION_CALL_METHOD);
3649 			f_actions->Insert(-1, a);
3650 			return;
3651 		}
3652 		// user wants the regular trace()...
3653 	}
3654 
3655 	// get the parameters
3656 	as::NodePtr parameters;
3657 	int max_func = function.GetChildCount();
3658 	for(int idx = 0; idx < max_func; ++idx) {
3659 		as::NodePtr& child = function.GetChild(idx);
3660 		as::Data& data = child.GetData();
3661 		if(data.f_type == as::NODE_PARAMETERS) {
3662 			parameters = child;
3663 			break;
3664 		}
3665 	}
3666 
3667 	// if the function requires an array to be called it is much
3668 	// different; we need to: create an array, fill it, call the
3669 	// function, read the 'out' variable if any, delete the array;
3670 	bool array = (attrs & as::NODE_ATTR_ARRAY) != 0
3671 			|| (flags & as::NODE_FUNCTION_FLAG_OUT) != 0;
3672 
3673 	if(array && special != 0) {
3674 		as::Data& data = function.GetData();
3675 		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);
3676 	}
3677 
3678 	if(array && name_data.f_type == as::NODE_SUPER) {
3679 		f_error_stream->ErrMsg(as::AS_ERR_INVALID_ARRAY_FUNCTION, call, "'super' cannot be used with arrays.");
3680 		array = false;
3681 	}
3682 
3683 	//
3684 	// okay, this is a standard call, but we need to compute
3685 	// the parameters from left to right which is the opposite
3686 	// of what Flash wants on the stack for user functions;
3687 	// so what we need to do is compute each expression and
3688 	// store them in registers and local variables as required,
3689 	// then push them backward on the stack;
3690 	//
3691 	// this doesn't hold for all the Flash special functions
3692 	// which often are declared the right way (i.e. the stacking
3693 	// and calling order are proper)
3694 	//
3695 	// NOTE: but this is really only necessary if we have calls
3696 	// within that list of parameters; in other words, if we
3697 	// only have direct operators, variables and constants, we
3698 	// can stack that in any order EXCEPT assignments which
3699 	// obviously need to be defined in the right order too;
3700 	// also we are supporting reuse of parameter values in
3701 	// the following parameters... and that could include
3702 	// calls, assignments, etc. and let's not forget the
3703 	// getters and setters!
3704 	//
3705 	//   Example:
3706 	//
3707 	// We're fine with (unless a, b or c is a getter, but that's
3708 	// already viewed as a function at thist time):
3709 	//
3710 	//	call(a, b, c);
3711 	//
3712 	// Here the function b() could change a and/or c thus we need
3713 	// to respect the order:
3714 	//
3715 	//	call(a, b(), c);
3716 	//
3717 	// A function that has parameters that are defined as the
3718 	// result of an expression including previous parameters:
3719 	//
3720 	//	function call(a, b = a * 2);
3721 	//	...
3722 	//	call(55);	becomes		call(55, 110);
3723 	//
3724 	// since this becomes equivalent to:
3725 	//
3726 	// 	temp_a = 55;
3727 	// 	temp_b = temp_a * 2;
3728 	// 	call(temp_a, temp_b);
3729 	//
3730 	// we also need to do that in order.
3731 	//
3732 	// Another one, is when the user specify the name of the
3733 	// parameters he wants to define in a call, this means the
3734 	// order in which the parameters are computed is actually
3735 	// different than the order in which the parameters are to
3736 	// be given to the function.
3737 	//
3738 	//	call(a: x(), c: z(), b: y());
3739 	//
3740 	// here the temporaries are computed in the order the user
3741 	// specified the parameters; it is important since calling
3742 	// y() first could make z() return a different result
3743 	//
3744 	//	temp_a = x();
3745 	//	temp_c = z();
3746 	//	temp_b = y();
3747 	//	call(temp_a, temp_b, temp_c);
3748 	//
3749 
3750 	struct reg_t {
3751 				reg_t(void)
3752 				{
3753 					f_defined = false;
3754 					f_referenced = false;
3755 					f_reg = -1;
3756 				}
3757 
3758 		bool		f_defined;
3759 		bool		f_referenced;
3760 		int		f_reg;
3761 	};
3762 
3763 // Get the array of indexes which converts
3764 // the list index into a parameter index
3765 	as::Data& call_data = call.GetData();
3766 	int size = call_data.f_user_data.Size();
3767 	bool ordered = true;
3768 	special_function_t::setup_t order;
3769 	if(special != 0) {
3770 		order = special->f_stack_order;
3771 	}
3772 	else {
3773 		order = special_function_t::STACK_ORDER_PERFECT;
3774 	}
3775 	int *indexes = 0;
3776 	if(size > 0) {
3777 		indexes = call_data.f_user_data.Buffer();
3778 
3779 		if(order == special_function_t::STACK_ORDER_PERFECT
3780 		|| order == special_function_t::STACK_ORDER_PERFECT_COUNT) {
3781 			for(int idx = 0; idx < size; ++idx) {
3782 				if(indexes[idx] != idx) {
3783 					ordered = false;
3784 					break;
3785 				}
3786 			}
3787 		}
3788 		else if(order == special_function_t::STACK_ORDER_REVERSED
3789 			|| order == special_function_t::STACK_ORDER_REVERSED_COUNT) {
3790 			for(int idx = 0; idx < size; ++idx) {
3791 				if(indexes[idx] != size - idx - 1) {
3792 					ordered = false;
3793 					break;
3794 				}
3795 			}
3796 		}
3797 	}
3798 	if(order != special_function_t::STACK_ORDER_PERFECT
3799 	&& order != special_function_t::STACK_ORDER_PERFECT_COUNT
3800 	&& order != special_function_t::STACK_ORDER_REVERSED
3801 	&& order != special_function_t::STACK_ORDER_REVERSED_COUNT) {
3802 		// TODO: handle special cases here?
3803 		ordered = false;
3804 	}
3805 
3806 // 1. compute parameters which aren't constants and save them in temporaries
3807 //    [but skip auto definitions]
3808 //
3809 //    NOTE: we define links back to the parameters in case we have some
3810 //    autos which use the previous parameters as variables to be computed.
3811 //
3812 	FuncParam **p = 0;
3813 	as::NodePtr param;
3814 	int pos;
3815 	int count = list.GetChildCount();
3816 	int max_params = parameters.GetChildCount();
3817 
3818 //fprintf(stderr, "Size = %d, max = %d\n", size, max_params);
3819 //	AS_ASSERT(size >= max_params);
3820 
3821 	reg_t *regs = new reg_t[count];
3822 	for(int idx = 0; idx < count; ++idx) {
3823 		as::NodePtr& expr = list.GetChild(idx);
3824 		as::Data& data = expr.GetData();
3825 
3826 		bool put_in_reg = false;
3827 		if(indexes != 0) {
3828 			pos = indexes[idx];
3829 			if(pos >= max_params) {
3830 				pos = max_params - 1;
3831 			}
3832 			param = parameters.GetChild(pos);
3833 			as::Data& param_data = param.GetData();
3834 			if((param_data.f_int.Get() & as::NODE_PARAMETERS_FLAG_PARAMREF) != 0) {
3835 				regs[idx].f_referenced = true;
3836 				put_in_reg = !ExpressionIsConstant(expr, INCLUSIVE_ALL & ~INCLUSIVE_STRING);
3837 			}
3838 			param_data.f_user_data.New((sizeof(FuncParam *) + sizeof(int) - 1) / sizeof(int));
3839 			p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
3840 			p[0] = new FuncParam;
3841 		}
3842 		if(array && p == 0 && ordered) {
3843 			Expression(expr);
3844 		}
3845 		else {
3846 			if(array && ordered) {
3847 				put_in_reg = true;
3848 			}
3849 			else if(!put_in_reg) {
3850 				// this can include an AUTO parameter
3851 				put_in_reg = expr.HasSideEffects();
3852 			}
3853 			else if(data.f_type == as::NODE_AUTO) {
3854 				// this is true in the next loop instead
3855 				put_in_reg = false;
3856 			}
3857 
3858 			if(put_in_reg) {
3859 				// if so, then compute it now
3860 				Expression(expr);
3861 				regs[idx].f_defined = true;
3862 				regs[idx].f_reg = f_registers.StoreRegister(f_tag, f_actions, !array || !ordered);
3863 				if(p != 0) {
3864 					p[0]->f_mode = FuncParam::MODE_REGISTER;
3865 					p[0]->f_reg = regs[idx].f_reg;
3866 
3867 //fprintf(stderr, "Setting p[0]->f_reg to %d\n", regs[idx].f_reg);
3868 
3869 				}
3870 			}
3871 			else if(data.f_type != as::NODE_AUTO) {
3872 				// this includes 'undefined' parameters
3873 				regs[idx].f_defined = true;
3874 				if(p != 0) {
3875 					p[0]->f_mode = FuncParam::MODE_CONSTANT;
3876 					p[0]->f_constant = expr;
3877 				}
3878 			}
3879 		}
3880 	}
3881 
3882 // 2. compute automatic parameters which require it (i.e. not just undefined)
3883 	if(!array || !ordered) for(int idx = 0; idx < count; ++idx) {
3884 		as::NodePtr& expr = list.GetChild(idx);
3885 		as::Data& data = expr.GetData();
3886 		if(data.f_type == as::NODE_AUTO
3887 		&& !regs[idx].f_defined) {
3888 			// if we have an auto we've got to have a valid
3889 			// function declaration and thus a list of indexes
3890 			AS_ASSERT(indexes != 0);
3891 
3892 			pos = indexes[idx];
3893 			if(pos >= max_params) {
3894 				pos = max_params - 1;
3895 			}
3896 			param = parameters.GetChild(pos);
3897 			as::Data& param_data = param.GetData();
3898 			p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
3899 
3900 			if(regs[idx].f_referenced || expr.HasSideEffects()
3901 			|| !ExpressionIsConstant(expr, INCLUSIVE_ALL & ~INCLUSIVE_STRING)) {
3902 				// if so, then compute it now
3903 				Expression(expr);
3904 				regs[idx].f_defined = true;
3905 				regs[idx].f_reg = f_registers.StoreRegister(f_tag, f_actions, true);
3906 				if(p != 0) {
3907 					p[0]->f_mode = FuncParam::MODE_REGISTER;
3908 					p[0]->f_reg = regs[idx].f_reg;
3909 				}
3910 			}
3911 			else {
3912 				regs[idx].f_defined = true;
3913 				if(p != 0) {
3914 					p[0]->f_mode = FuncParam::MODE_CONSTANT;
3915 					p[0]->f_constant = expr;
3916 				}
3917 			}
3918 		}
3919 	}
3920 
3921 // 3. put all of that on the stack in the right order
3922 	if(!array || !ordered) {
3923 		int idx, step, end;
3924 		idx = step = end = 0;
3925 		if(order == special_function_t::STACK_ORDER_PERFECT
3926 		|| order == special_function_t::STACK_ORDER_PERFECT_COUNT) {
3927 			idx = count - 1;
3928 			step = -1;
3929 			end = -1;
3930 		}
3931 		else if(order == special_function_t::STACK_ORDER_REVERSED
3932 			|| order == special_function_t::STACK_ORDER_REVERSED_COUNT) {
3933 			idx = 0;
3934 			step = 1;
3935 			end = count;
3936 		}
3937 		else if(order == special_function_t::STACK_ORDER_SPECIAL) {
3938 			switch(special->f_action) {
3939 			case Action::ACTION_START_DRAG:
3940 				idx = count - 1;
3941 				step = -1;
3942 				end = -1;
3943 				if(count <= 2) {
3944 					// rectangle flag (b3)
3945 					pd = new ActionPushData(f_tag);
3946 					pd->AddBoolean(false);
3947 					f_actions->Insert(-1, pd);
3948 				}
3949 				break;
3950 
3951 			case Action::ACTION_GOTO_FRAME:
3952 			{
3953 				// TODO: this will need loads of testing
3954 				//	 it feels to me that this is all wrong right
3955 				//	 now... (cool hey? {8-})
3956 				Action::action_t action = Action::ACTION_GOTO_EXPRESSION;
3957 				as::String sprite_name;
3958 				as::String frame_name;
3959 				as::String label_name;
3960 				int cnt = 2;
3961 				long frame_no = -1;
3962 				bool play = special->f_function_name[7] == 'P';
3963 
3964 				AS_ASSERT(count == 2);
3965 				AS_ASSERT(regs[0].f_defined);
3966 				AS_ASSERT(regs[1].f_defined);
3967 
3968 				if(indexes != 0) {
3969 					pos = indexes[0] == 0 ? 0 : 1;
3970 				}
3971 				else {
3972 					pos = 0;
3973 				}
3974 
3975 //fprintf(stderr, "[GotoFrame] Loading %d [%d]\n", pos, idx);
3976 
3977 				if(regs[pos].f_reg < 0) {
3978 					// compute the expression on the fly it has no
3979 					// side effect (constant or no call(), assignment, etc.)
3980 					as::NodePtr& expr = list.GetChild(pos);
3981 					as::Data& data = expr.GetData();
3982 					if(data.f_type == as::NODE_UNDEFINED) {
3983 						cnt = 1;
3984 					}
3985 					else if(data.f_type == as::NODE_STRING) {
3986 						sprite_name = data.f_str;
3987 						if(sprite_name.IsEmpty()) {
3988 							f_error_stream->ErrMsg(as::AS_ERR_INVALID_EXPRESSION, expr, "an empty string is an invalid sprite name.");
3989 						}
3990 					}
3991 					else {
3992 						Expression(expr);
3993 					}
3994 				}
3995 				else {
3996 					f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
3997 				}
3998 				pos ^= 1;
3999 				if(regs[pos].f_reg < 0) {
4000 					// compute the expression on the fly it has no
4001 					// side effect (constant or no call(), assignment, etc.)
4002 					as::NodePtr& expr = list.GetChild(pos);
4003 					as::Data& data = expr.GetData();
4004 					if(data.f_type == as::NODE_STRING && cnt == 1) {
4005 						label_name = data.f_str;
4006 						if(label_name.IsEmpty()) {
4007 							f_error_stream->ErrMsg(as::AS_ERR_INVALID_LABEL, expr, "an empty string is an invalid label name.");
4008 						}
4009 						action = Action::ACTION_GOTO_LABEL;
4010 					}
4011 					else if(data.f_type == as::NODE_INT64 && cnt == 1) {
4012 						frame_no = data.f_int.Get();
4013 						action = Action::ACTION_GOTO_FRAME;
4014 					}
4015 					else if(data.f_type == as::NODE_STRING && !sprite_name.IsEmpty()) {
4016 						frame_name = data.f_str;
4017 						if(frame_name.IsEmpty()) {
4018 							f_error_stream->ErrMsg(as::AS_ERR_INVALID_FRAME, expr, "an empty string is an invalid frame name.");
4019 						}
4020 					}
4021 					else if(data.f_type == as::NODE_INT64 && !sprite_name.IsEmpty()) {
4022 						frame_no = data.f_int.Get();
4023 					}
4024 					else {
4025 						if(!sprite_name.IsEmpty()) {
4026 							as::NodePtr& expr = list.GetChild(pos ^ 1);
4027 							Expression(expr);
4028 							sprite_name = "";
4029 						}
4030 						Expression(expr);
4031 					}
4032 				}
4033 				else {
4034 					if(!sprite_name.IsEmpty()) {
4035 						as::NodePtr& expr = list.GetChild(pos ^ 1);
4036 						Expression(expr);
4037 						sprite_name = "";
4038 					}
4039 					f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
4040 				}
4041 				if(sprite_name.IsEmpty() && cnt == 2) {
4042 					// we need to concatenate the names with ':' in between
4043 					pd = new ActionPushData(f_tag);
4044 					pd->AddString(":");
4045 					f_actions->Insert(-1, pd);
4046 					a = new Action(f_tag, Action::ACTION_SWAP);
4047 					f_actions->Insert(-1, a);
4048 					a = new Action(f_tag, Action::ACTION_CONCATENATE);
4049 					f_actions->Insert(-1, a);
4050 					//a = new Action(f_tag, Action::ACTION_SWAP);
4051 					//f_actions->Insert(-1, a);
4052 					a = new Action(f_tag, Action::ACTION_CONCATENATE);
4053 					f_actions->Insert(-1, a);
4054 				}
4055 				else if(action == Action::ACTION_GOTO_EXPRESSION) {
4056 					// we want to create the fullname right now
4057 					// and push it at once on the stack
4058 					sprite_name += ":";
4059 					if(!frame_name.IsEmpty()) {
4060 						sprite_name += frame_name;
4061 					}
4062 					else {
4063 						char buf[16];
4064 						sprintf(buf, "%ld", frame_no);
4065 						sprite_name += buf;
4066 					}
4067 					pd = new ActionPushData(f_tag);
4068 					char *str = sprite_name.GetUTF8();
4069 					pd->AddString(str);
4070 					delete [] str;
4071 					f_actions->Insert(-1, pd);
4072 				}
4073 
4074 				ActionGoto *action_goto;
4075 				if(action == Action::ACTION_GOTO_EXPRESSION) {
4076 					action_goto = new ActionGoto(f_tag, action);
4077 					action_goto->SetPlay(play);
4078 				}
4079 				else {
4080 					// we can't have the PLAY/STOP inside the instruction
4081 					// in this case so we apply it first
4082 					a = new Action(f_tag, play ? Action::ACTION_PLAY : Action::ACTION_STOP);
4083 					f_actions->Insert(-1, a);
4084 					action_goto = new ActionGoto(f_tag, action);
4085 					if(action == Action::ACTION_GOTO_FRAME) {
4086 						char buf[16];
4087 						sprintf(buf, "%ld", frame_no);
4088 						action_goto->SetFrameName(buf);
4089 					}
4090 					else {
4091 						char *str = label_name.GetUTF8();
4092 						action_goto->SetFrameName(str);
4093 						delete [] str;
4094 					}
4095 				}
4096 				f_actions->Insert(-1, action_goto);
4097 				// don't add anything on the stack
4098 				idx = 0;
4099 				end = 0;
4100 			}
4101 				break;
4102 
4103 			case Action::ACTION_URL:
4104 			{
4105 				AS_ASSERT(count == 1);
4106 				AS_ASSERT(regs[0].f_defined);
4107 
4108 				as::String target;
4109 				bool constant_target = false;
4110 
4111 				if(regs[0].f_reg < 0) {
4112 					// compute the expression on the fly it has no
4113 					// side effect (constant or no call(), assignment, etc.)
4114 					as::NodePtr& expr = list.GetChild(0);
4115 					as::Data& data = expr.GetData();
4116 					if(data.f_type == as::NODE_STRING) {
4117 						// constant string!
4118 						target = data.f_str;
4119 						constant_target = true;
4120 					}
4121 					else if(data.f_type == as::NODE_INT64) {
4122 						// constant string!
4123 						int target_no = data.f_int.Get();
4124 						char buf[32];
4125 						sprintf(buf, "_level%d", target_no);
4126 						target = buf;
4127 						constant_target = true;
4128 					}
4129 					else {
4130 						pd = new ActionPushData(f_tag);
4131 						pd->AddString("");
4132 						f_actions->Insert(-1, pd);
4133 						Expression(expr);
4134 					}
4135 				}
4136 				else {
4137 					pd = new ActionPushData(f_tag);
4138 					pd->AddString("");
4139 					f_actions->Insert(-1, pd);
4140 					f_registers.LoadRegister(regs[0].f_reg, true, f_tag, f_actions);
4141 				}
4142 
4143 				ActionURL *action_url = 0;
4144 				if(constant_target) {
4145 					// we can make use of ACTION_URL instead of ACTION_URL2
4146 					action_url = new ActionURL(f_tag, Action::ACTION_URL);
4147 					char *str = target.GetUTF8();
4148 					action_url->SetURL("", str);
4149 					delete [] str;
4150 				}
4151 				else {
4152 					action_url = new ActionURL(f_tag, Action::ACTION_URL2);
4153 					action_url->SetMethod(ActionURL::URL_METHOD_NOVARIABLES);
4154 				}
4155 				f_actions->Insert(-1, action_url);
4156 
4157 				// don't add anything on the stack
4158 				idx = 0;
4159 				end = 0;
4160 			}
4161 				break;
4162 
4163 			case Action::ACTION_URL2:
4164 			{
4165 				bool is_fscommand = strcmp(special->f_function_name, "fscommand") == 0;
4166 
4167 				AS_ASSERT(count == (is_fscommand ? 2 : 3));
4168 				AS_ASSERT(regs[0].f_defined);
4169 				AS_ASSERT(regs[1].f_defined);
4170 				AS_ASSERT(is_fscommand || regs[2].f_defined);
4171 
4172 				as::String url;
4173 				as::String target;
4174 				long url_pos = -1;
4175 				long target_pos = -1;
4176 				ActionURL::url_method_t method = ActionURL::URL_METHOD_NOVARIABLES;
4177 				bool constant_url = false;
4178 
4179 				for(idx = 0; idx < count; ++idx) {
4180 					if(indexes != 0) {
4181 						// we need an inverted table; note that allocated
4182 						// on the heap to have an inverted table should
4183 						// not be much faster than this loop since in most
4184 						// cases we'll have just 1 or 2 parameters
4185 						pos = -1;
4186 						for(int j = 0; j < count; ++j) {
4187 							if(indexes[j] == idx) {
4188 								pos = j;
4189 								break;
4190 							}
4191 						}
4192 						AS_ASSERT(pos >= 0);
4193 					}
4194 					else {
4195 						pos = idx;
4196 					}
4197 
4198 					switch(idx) {
4199 					case 0:
4200 						if(regs[pos].f_reg < 0) {
4201 							// compute the expression on the fly it has no
4202 							// side effect (constant or no call(), assignment, etc.)
4203 							as::NodePtr& expr = list.GetChild(pos);
4204 							as::Data& data = expr.GetData();
4205 							if(data.f_type == as::NODE_STRING) {
4206 								// constant string!
4207 								url_pos = pos;
4208 								url = is_fscommand ? "FSCommand:" : "";
4209 								url += data.f_str;
4210 								constant_url = true;
4211 							}
4212 							else {
4213 								if(is_fscommand) {
4214 									pd = new ActionPushData(f_tag);
4215 									pd->AddString("FSCommand:");
4216 									f_actions->Insert(-1, pd);
4217 									Expression(expr);
4218 									a = new Action(f_tag, Action::ACTION_CONCATENATE);
4219 									f_actions->Insert(-1, a);
4220 								}
4221 								else {
4222 									Expression(expr);
4223 								}
4224 							}
4225 						}
4226 						else {
4227 							f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
4228 						}
4229 						break;
4230 
4231 					case 1:
4232 						if(regs[pos].f_reg < 0) {
4233 							// compute the expression on the fly it has no
4234 							// side effect (constant or no call(), assignment, etc.)
4235 							as::NodePtr& expr = list.GetChild(pos);
4236 							as::Data& data = expr.GetData();
4237 							if(data.f_type == as::NODE_STRING && constant_url) {
4238 								// constant string!
4239 								target_pos = pos;
4240 								target = data.f_str;
4241 							}
4242 							else if(data.f_type == as::NODE_INT64 && constant_url && !is_fscommand) {
4243 								// level defined by number
4244 								// constant string!
4245 								target_pos = pos;
4246 								int target_no = data.f_int.Get();
4247 								char buf[32];
4248 								sprintf(buf, "_level%d", target_no);
4249 								target = buf;
4250 							}
4251 							else {
4252 								if(constant_url) {
4253 									// It is constant, so we don't need to call Expression()
4254 									// Also, the string may have "FSCommand:" pre-pended
4255 									//Expression(list.GetChild(url_pos));
4256 									pd = new ActionPushData(f_tag);
4257 									pd->AddString(url.GetUTF8());
4258 									f_actions->Insert(-1, pd);
4259 									constant_url = false;
4260 								}
4261 								Expression(expr);
4262 							}
4263 						}
4264 						else {
4265 							if(constant_url) {
4266 								Expression(list.GetChild(url_pos));
4267 								constant_url = false;
4268 							}
4269 							f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
4270 						}
4271 						break;
4272 
4273 					case 2:
4274 						if(regs[pos].f_reg < 0) {
4275 							// compute the expression on the fly it has no
4276 							// side effect (constant or no call(), assignment, etc.)
4277 							as::NodePtr& expr = list.GetChild(pos);
4278 							as::Data& data = expr.GetData();
4279 							if(data.f_type == as::NODE_UNDEFINED) {
4280 								// user didn't define, use default
4281 								method = ActionURL::URL_METHOD_NOVARIABLES;
4282 							}
4283 							else if(data.f_type == as::NODE_STRING) {
4284 								// constant string!
4285 								int len = data.f_str.GetLength();
4286 								if(len == 0) {
4287 									method = ActionURL::URL_METHOD_NOVARIABLES;
4288 								}
4289 								else {
4290 									const long *str = data.f_str.Get();
4291 									if(len == 3
4292 									&& towupper(str[0]) == 'G'
4293 									&& towupper(str[1]) == 'E'
4294 									&& towupper(str[2]) == 'T') {
4295 										method = ActionURL::URL_METHOD_GET;
4296 									}
4297 									else if(len == 4
4298 									&& towupper(str[0]) == 'P'
4299 									&& towupper(str[1]) == 'O'
4300 									&& towupper(str[2]) == 'S'
4301 									&& towupper(str[3]) == 'T') {
4302 										method = ActionURL::URL_METHOD_POST;
4303 									}
4304 									else {
4305 										f_error_stream->ErrMsg(as::AS_ERR_INVALID_EXPRESSION, expr, "invalid URL method, only an empty string, GET and POST are expected.");
4306 									}
4307 								}
4308 							}
4309 							else {
4310 								method = ActionURL::URL_METHOD_UNDEFINED;
4311 							}
4312 						}
4313 						else {
4314 							method = ActionURL::URL_METHOD_UNDEFINED;
4315 						}
4316 						break;
4317 
4318 					}
4319 				}
4320 				ActionURL *action_url = 0;
4321 				if(method == ActionURL::URL_METHOD_UNDEFINED) {
4322 					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.");
4323 				}
4324 				else if(constant_url && method == ActionURL::URL_METHOD_NOVARIABLES) {
4325 					// we can make use of ACTION_URL instead of ACTION_URL2
4326 					action_url = new ActionURL(f_tag, Action::ACTION_URL);
4327 					char *str1 = url.GetUTF8();
4328 					char *str2 = target.GetUTF8();
4329 					action_url->SetURL(str1, str2);
4330 					delete [] str1;
4331 					delete [] str2;
4332 				}
4333 				else {
4334 					if(constant_url) {
4335 						Expression(list.GetChild(url_pos));
4336 						Expression(list.GetChild(target_pos));
4337 					}
4338 					action_url = new ActionURL(f_tag, Action::ACTION_URL2);
4339 					action_url->SetMethod(method);
4340 				}
4341 				f_actions->Insert(-1, action_url);
4342 
4343 				// don't add anything on the stack
4344 				idx = 0;
4345 				end = 0;
4346 			}
4347 				break;
4348 
4349 			default:
4350 				// ignore others
4351 				break;
4352 
4353 			}
4354 		}
4355 		//int idx = count;
4356 		//while(idx > 0)
4357 		for(; idx != end; idx += step) {
4358 			if(indexes != 0) {
4359 				// we need an inverted table; note that allocated
4360 				// on the heap to have an inverted table should
4361 				// not be much faster than this loop since in most
4362 				// cases we'll have just 1 or 2 parameters
4363 				pos = -1;
4364 				for(int j = 0; j < count; ++j) {
4365 					if(indexes[j] == idx) {
4366 						pos = j;
4367 						break;
4368 					}
4369 				}
4370 
4371 #if defined(_DEBUG) || defined(DEBUG)
4372 if(pos == -1) {
4373 	fprintf(stderr, "INTERNAL ERROR: count = %d, idx = %d (end: %d, step: %d), indexes[0] = %d\n", count, idx, end, step, indexes[0]);
4374 }
4375 #endif
4376 
4377 				AS_ASSERT(pos >= 0);
4378 			}
4379 			else {
4380 				pos = idx;
4381 			}
4382 
4383 //printf("Loading %d [%d]\n", pos, idx);
4384 
4385 			AS_ASSERT(regs[pos].f_defined);
4386 			if(regs[pos].f_reg < 0) {
4387 				// compute the expression on the fly it has no
4388 				// side effect (constant or no call(), assignment, etc.)
4389 				as::NodePtr& expr = list.GetChild(pos);
4390 				Expression(expr);
4391 			}
4392 			else {
4393 				f_registers.LoadRegister(regs[pos].f_reg, true, f_tag, f_actions);
4394 			}
4395 
4396 			if(special != 0) {
4397 				switch(special->f_action) {
4398 				case Action::ACTION_START_DRAG:
4399 					if(idx == 2) {
4400 						// rectangle flag (b3)
4401 						pd = new ActionPushData(f_tag);
4402 						pd->AddBoolean(true);
4403 						f_actions->Insert(-1, pd);
4404 					}
4405 					break;
4406 
4407 				default:
4408 					// ignore others
4409 					break;
4410 
4411 				}
4412 			}
4413 		}
4414 	}
4415 
4416 	int array_reg = -1;
4417 	if(array) {
4418 		pd = new ActionPushData(f_tag);
4419 		pd->AddInteger(count);
4420 		f_actions->Insert(-1, pd);
4421 
4422 		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
4423 		f_actions->Insert(-1, a);
4424 
4425 		// for out parameters to be read back we need to
4426 		// save the register # and save a reference to
4427 		// this array
4428 		array_reg = f_registers.StoreRegister(f_tag, f_actions);
4429 	}
4430 
4431 	if(special == 0
4432 	|| order == special_function_t::STACK_ORDER_REVERSED_COUNT
4433 	|| order == special_function_t::STACK_ORDER_PERFECT_COUNT) {
4434 // 4. push the number of arguments
4435 		pd = new ActionPushData(f_tag);
4436 		pd->AddInteger(array ? 1 : count);
4437 		f_actions->Insert(-1, pd);
4438 	}
4439 
4440 	if(special == 0) {
4441 // 5. push the name of the function
4442 		if(name_data.f_type == as::NODE_SUPER) {
4443 			// the constructor function name is 'undefined'
4444 			pd = new ActionPushData(f_tag);
4445 			pd->AddString("super");
4446 			f_actions->Insert(-1, pd);
4447 			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
4448 			f_actions->Insert(-1, a);
4449 			pd = new ActionPushData(f_tag);
4450 			pd->AddUndefined();
4451 			f_actions->Insert(-1, pd);
4452 			a = new Action(f_tag, Action::ACTION_CALL_METHOD);
4453 			f_actions->Insert(-1, a);
4454 		}
4455 		else if(name_data.f_type == as::NODE_MEMBER) {
4456 			// when the parent of the CALL is a NEW
4457 			// then we are creating an object
4458 			as::NodePtr& parent = call.GetParent();
4459 			as::Data& parent_data = parent.GetData();
4460 			if(parent_data.f_type == as::NODE_NEW) {
4461 				Member(name, Action::ACTION_NEW_METHOD);
4462 			}
4463 			else {
4464 				Member(name, Action::ACTION_CALL_METHOD);
4465 			}
4466 // 6. call the method [right before exiting Member()]
4467 		}
4468 		else {
4469 			if(name_data.f_type == as::NODE_IDENTIFIER) {
4470 				pd = new ActionPushData(f_tag);
4471 				char *str = 0;
4472 				if(function.HasNode()) {
4473 					as::Data& data = function.GetData();
4474 					if(data.f_user_data.Size() != 0) {
4475 						FunctionData **fd;
4476 						fd = reinterpret_cast<FunctionData **>(data.f_user_data.Buffer());
4477 						str = fd[0]->f_name.GetUTF8();
4478 					}
4479 				}
4480 				if(str == 0) {
4481 					str = name_data.f_str.GetUTF8();
4482 				}
4483 				pd->AddString(str);
4484 				delete [] str;
4485 				f_actions->Insert(-1, pd);
4486 			}
4487 			else {
4488 				Expression(name);
4489 			}
4490 
4491 // 6. call the function
4492 			a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
4493 			f_actions->Insert(-1, a);
4494 		}
4495 	}
4496 	else {
4497 // 7. call the special function at once
4498 		// special functions don't require a call, they are
4499 		// "straight forward" functions
4500 		switch(special->f_action) {
4501 		case Action::ACTION_GOTO_FRAME:
4502 		case Action::ACTION_URL:
4503 		case Action::ACTION_URL2:
4504 			// those are done earlier because they can vary
4505 			// depending on the type of the parameters
4506 			break;
4507 
4508 		default:
4509 			a = new Action(f_tag, special->f_action);
4510 			f_actions->Insert(-1, a);
4511 			break;
4512 
4513 		}
4514 
4515 		// TODO:
4516 		// at this time, this is silly, but for us to have
4517 		// a valid stack we need to push undefined in case
4518 		// the special function does not otherwise return data?!
4519 		// [should be optimized by the future DoAction optimizer]
4520 		if(!special->f_returns) {
4521 			pd = new ActionPushData(f_tag);
4522 			pd->AddUndefined();
4523 			f_actions->Insert(-1, pd);
4524 		}
4525 	}
4526 
4527 // 8. read the "out" parameters back to our variables
4528 	if((flags & as::NODE_FUNCTION_FLAG_OUT) != 0) {
4529 		AS_ASSERT(indexes != 0);
4530 		AS_ASSERT(array);
4531 		// the parameters don't have to be in order...
4532 		// but we can read the array in any order
4533 		for(int idx = 0; idx < count; ++idx) {
4534 			pos = indexes[idx];
4535 			if(pos >= max_params) {
4536 				// because we can name the "rest"
4537 				// parameter, this needs to continue!
4538 				continue;
4539 			}
4540 			param = parameters.GetChild(pos);
4541 			as::Data& param_data = param.GetData();
4542 			if((param_data.f_int.Get() & as::NODE_PARAMETERS_FLAG_OUT) == 0) {
4543 				// is this one an out?!
4544 				continue;
4545 			}
4546 
4547 			as::NodePtr& expr = list.GetChild(idx);
4548 			as::Data& data = expr.GetData();
4549 			// got to be a variable name!
4550 			AS_ASSERT(data.f_type == as::NODE_IDENTIFIER);
4551 
4552 			pd = new ActionPushData(f_tag);
4553 			pd->AddRegister(array_reg);
4554 			pd->AddInteger(pos);
4555 			f_actions->Insert(-1, pd);
4556 
4557 			a = new Action(f_tag, Action::ACTION_GET_MEMBER);
4558 			f_actions->Insert(-1, a);
4559 
4560 			as::NodePtr instance;
4561 			Assignment(expr, instance, false);
4562 		}
4563 	}
4564 
4565 // 9. free the register used for the array
4566 	if(array_reg >= 0) {
4567 		// TODO: put nil in the array reference so it gets
4568 		//	 deleted (it probably doesn't matter much
4569 		//	 at this time)
4570 		/*
4571 		pd = new ActionPushData(f_tag);
4572 		pd->AddNull();
4573 		pd->AddRegister();
4574 		f_actions->Insert(-1, pd);
4575 		delete [] name;
4576 
4577 		a = new Action(f_tag, Action::ACTION_SET_LOCAL_VARIABLE);
4578 		f_actions->Insert(-1, a);
4579 		*/
4580 		f_registers.FreeRegister(array_reg);
4581 	}
4582 
4583 // 10. free all the registers used for the parameters
4584 	if(indexes != 0) {
4585 		for(int pos = 0; pos < max_params; ++pos) {
4586 			param = parameters.GetChild(pos);
4587 			as::Data& param_data = param.GetData();
4588 			p = reinterpret_cast<FuncParam **>(param_data.f_user_data.Buffer());
4589 			if(p[0]->f_mode == FuncParam::MODE_REGISTER) {
4590 				f_registers.FreeRegister(p[0]->f_reg);
4591 			}
4592 			delete p[0];
4593 			param_data.f_user_data.New(0);
4594 		}
4595 	}
4596 
4597 	delete [] regs;
4598 }
4599 
4600 
Add(as::NodePtr & expr,bool right_to_left)4601 void IntAssembler::Add(as::NodePtr& expr, bool right_to_left)
4602 {
4603 	Action		*a;
4604 
4605 	int cnt = expr.GetChildCount();
4606 	if(cnt == 1) {	// Positive
4607 		// do nothing about this one
4608 		// (should we do (expr + 0) instead?
4609 		// or maybe (expr).ToNumber();?)
4610 		Expression(expr.GetChild(0));
4611 		return;
4612 	}
4613 
4614 	as::NodePtr& right = expr.GetChild(1);
4615 	as::Data& right_data = right.GetData();
4616 	if(right_data.f_type == as::NODE_INT64) {
4617 		if(right_data.f_int.Get() == 1) {
4618 			Expression(expr.GetChild(0));
4619 			a = new Action(f_tag, Action::ACTION_INCREMENT);
4620 			f_actions->Insert(-1, a);
4621 			return;
4622 		}
4623 		if(right_data.f_int.Get() == -1) {
4624 			Expression(expr.GetChild(0));
4625 			a = new Action(f_tag, Action::ACTION_DECREMENT);
4626 			f_actions->Insert(-1, a);
4627 			return;
4628 		}
4629 	}
4630 	else if(right_data.f_type == as::NODE_FLOAT64) {
4631 		if(right_data.f_float.Get() == 1.0) {
4632 			Expression(expr.GetChild(0));
4633 			a = new Action(f_tag, Action::ACTION_INCREMENT);
4634 			f_actions->Insert(-1, a);
4635 			return;
4636 		}
4637 		if(right_data.f_float.Get() == -1.0) {
4638 			Expression(expr.GetChild(0));
4639 			a = new Action(f_tag, Action::ACTION_DECREMENT);
4640 			f_actions->Insert(-1, a);
4641 			return;
4642 		}
4643 	}
4644 
4645 	as::NodePtr& left = expr.GetChild(0);
4646 	as::Data& left_data = left.GetData();
4647 	if(left_data.f_type == as::NODE_INT64) {
4648 		if(left_data.f_int.Get() == 1) {
4649 			Expression(expr.GetChild(1));
4650 			a = new Action(f_tag, Action::ACTION_INCREMENT);
4651 			f_actions->Insert(-1, a);
4652 			return;
4653 		}
4654 		if(left_data.f_int.Get() == -1) {
4655 			Expression(expr.GetChild(1));
4656 			a = new Action(f_tag, Action::ACTION_DECREMENT);
4657 			f_actions->Insert(-1, a);
4658 			return;
4659 		}
4660 	}
4661 	else if(left_data.f_type == as::NODE_FLOAT64) {
4662 		if(left_data.f_float.Get() == 1.0) {
4663 			Expression(expr.GetChild(1));
4664 			a = new Action(f_tag, Action::ACTION_INCREMENT);
4665 			f_actions->Insert(-1, a);
4666 			return;
4667 		}
4668 		if(left_data.f_float.Get() == -1.0) {
4669 			Expression(expr.GetChild(1));
4670 			a = new Action(f_tag, Action::ACTION_DECREMENT);
4671 			f_actions->Insert(-1, a);
4672 			return;
4673 		}
4674 	}
4675 
4676 	if(right_to_left) {
4677 		Expression(expr.GetChild(1));
4678 		Expression(expr.GetChild(0));
4679 	}
4680 	else {
4681 		Expression(expr.GetChild(0));
4682 		Expression(expr.GetChild(1));
4683 	}
4684 	a = new Action(f_tag, Action::ACTION_ADD_TYPED);
4685 	f_actions->Insert(-1, a);
4686 }
4687 
4688 
Subtract(as::NodePtr & expr,bool right_to_left)4689 void IntAssembler::Subtract(as::NodePtr& expr, bool right_to_left)
4690 {
4691 	ActionPushData	*pd;
4692 	Action		*a;
4693 
4694 	int cnt = expr.GetChildCount();
4695 	if(cnt == 1) {
4696 		// there is not NEG in Flash do 0 - expr
4697 		// 0 is pushed as an integer so if expr is
4698 		// an integer, the result is an integer
4699 		pd = new ActionPushData(f_tag);
4700 		pd->AddInteger(0);
4701 		f_actions->Insert(-1, pd);
4702 		Expression(expr.GetChild(0));
4703 		a = new Action(f_tag, Action::ACTION_SUBTRACT);
4704 		f_actions->Insert(-1, a);
4705 		return;
4706 	}
4707 
4708 	as::NodePtr& right = expr.GetChild(1);
4709 	as::Data& right_data = right.GetData();
4710 	if(right_data.f_type == as::NODE_INT64) {
4711 		if(right_data.f_int.Get() == 1) {
4712 			Expression(expr.GetChild(0));
4713 			a = new Action(f_tag, Action::ACTION_DECREMENT);
4714 			f_actions->Insert(-1, a);
4715 			return;
4716 		}
4717 		if(right_data.f_int.Get() == -1) {
4718 			Expression(expr.GetChild(0));
4719 			a = new Action(f_tag, Action::ACTION_INCREMENT);
4720 			f_actions->Insert(-1, a);
4721 			return;
4722 		}
4723 	}
4724 	else if(right_data.f_type == as::NODE_FLOAT64) {
4725 		if(right_data.f_float.Get() == 1.0) {
4726 			Expression(expr.GetChild(0));
4727 			a = new Action(f_tag, Action::ACTION_INCREMENT);
4728 			f_actions->Insert(-1, a);
4729 			return;
4730 		}
4731 		if(right_data.f_float.Get() == -1.0) {
4732 			Expression(expr.GetChild(0));
4733 			a = new Action(f_tag, Action::ACTION_DECREMENT);
4734 			f_actions->Insert(-1, a);
4735 			return;
4736 		}
4737 	}
4738 
4739 	if(right_to_left) {
4740 		// for assignment we need to first compute the right
4741 		// side and not the left
4742 		Expression(expr.GetChild(1));
4743 		Expression(expr.GetChild(0));
4744 		a = new Action(f_tag, Action::ACTION_SWAP);
4745 		f_actions->Insert(-1, a);
4746 	}
4747 	else {
4748 		Expression(expr.GetChild(0));
4749 		Expression(expr.GetChild(1));
4750 	}
4751 	a = new Action(f_tag, Action::ACTION_SUBTRACT);
4752 	f_actions->Insert(-1, a);
4753 }
4754 
4755 
Multiply(as::NodePtr & expr)4756 void IntAssembler::Multiply(as::NodePtr& expr)
4757 {
4758 	Action		*a;
4759 
4760 	// Here we simplify 2 x X or X x 2 as X + X
4761 	// which is shorter in Flash
4762 
4763 	as::NodePtr& child0 = expr.GetChild(0);
4764 	as::Data& data0 = child0.GetData();
4765 	if(data0.f_type == as::NODE_INT64) {
4766 		if(data0.f_int.Get() == 2) {
4767 			// TODO: if expr1 is a string, this is wrong
4768 			Expression(expr.GetChild(1));
4769 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
4770 			f_actions->Insert(-1, a);
4771 			a = new Action(f_tag, Action::ACTION_ADD);
4772 			f_actions->Insert(-1, a);
4773 			return;
4774 		}
4775 	}
4776 	else if(data0.f_type == as::NODE_FLOAT64) {
4777 		if(data0.f_float.Get() == 2.0f) {
4778 			// TODO: if expr1 is a string, this is wrong
4779 			Expression(expr.GetChild(1));
4780 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
4781 			f_actions->Insert(-1, a);
4782 			a = new Action(f_tag, Action::ACTION_ADD);
4783 			f_actions->Insert(-1, a);
4784 			return;
4785 		}
4786 	}
4787 
4788 	as::NodePtr& child1 = expr.GetChild(1);
4789 	as::Data& data1 = child1.GetData();
4790 	if(data1.f_type == as::NODE_INT64) {
4791 		if(data1.f_int.Get() == 2) {
4792 			// TODO: if expr1 is a string, this is wrong
4793 			Expression(expr.GetChild(0));
4794 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
4795 			f_actions->Insert(-1, a);
4796 			a = new Action(f_tag, Action::ACTION_ADD);
4797 			f_actions->Insert(-1, a);
4798 			return;
4799 		}
4800 	}
4801 	else if(data1.f_type == as::NODE_FLOAT64) {
4802 		if(data1.f_float.Get() == 2.0f) {
4803 			// TODO: if expr1 is a string, this is wrong
4804 			Expression(expr.GetChild(0));
4805 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
4806 			f_actions->Insert(-1, a);
4807 			a = new Action(f_tag, Action::ACTION_ADD);
4808 			f_actions->Insert(-1, a);
4809 			return;
4810 		}
4811 	}
4812 
4813 	Expression(expr.GetChild(0));
4814 	Expression(expr.GetChild(1));
4815 	a = new Action(f_tag, Action::ACTION_MULTIPLY);
4816 	f_actions->Insert(-1, a);
4817 }
4818 
4819 
Power(as::NodePtr & expr,bool right_to_left)4820 void IntAssembler::Power(as::NodePtr& expr, bool right_to_left)
4821 {
4822 	Action			*a;
4823 
4824 	// NOTE: expr ** 0 and expr ** 1 were already optimized
4825 	//	 as was 1 ** expr
4826 
4827 	// Simplify 'expr ** 2' into 'expr * expr'
4828 	as::NodePtr& right = expr.GetChild(1);
4829 	as::Data& right_data = right.GetData();
4830 	if(right_data.f_type == as::NODE_INT64) {
4831 		if(right_data.f_int.Get() == 2) {
4832 			Expression(expr.GetChild(0));
4833 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
4834 			f_actions->Insert(-1, a);
4835 			a = new Action(f_tag, Action::ACTION_MULTIPLY);
4836 			f_actions->Insert(-1, a);
4837 			return;
4838 		}
4839 	}
4840 	else if(right_data.f_type == as::NODE_FLOAT64) {
4841 		if(right_data.f_float.Get() == 2.0) {
4842 			Expression(expr.GetChild(0));
4843 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
4844 			f_actions->Insert(-1, a);
4845 			a = new Action(f_tag, Action::ACTION_MULTIPLY);
4846 			f_actions->Insert(-1, a);
4847 			return;
4848 		}
4849 	}
4850 
4851 	if(right_to_left) {
4852 		Expression(expr.GetChild(1));
4853 		Expression(expr.GetChild(0));
4854 	}
4855 	else {
4856 		Expression(expr.GetChild(0));
4857 		Expression(expr.GetChild(1));
4858 		// TODO: make sure this is the right order for a function
4859 		// NOTE: we could test whether the expressions have side
4860 		//	 effects and put them in the right order at once
4861 		a = new Action(f_tag, Action::ACTION_SWAP);
4862 		f_actions->Insert(-1, a);
4863 	}
4864 	ActionPushData *pd = new ActionPushData(f_tag);
4865 	pd->AddInteger(2);
4866 	pd->AddString("Math.pow");
4867 	f_actions->Insert(-1, pd);
4868 	a = new Action(f_tag, Action::ACTION_CALL_FUNCTION);
4869 	f_actions->Insert(-1, a);
4870 }
4871 
4872 
VoidExpression(as::NodePtr & expr)4873 void IntAssembler::VoidExpression(as::NodePtr& expr)
4874 {
4875 	Expression(expr);
4876 	Action *a = new Action(f_tag, Action::ACTION_POP);
4877 	f_actions->Insert(-1, a);
4878 }
4879 
4880 
Assignment(as::NodePtr & name,as::NodePtr instance,bool duplicate)4881 void IntAssembler::Assignment(as::NodePtr& name, as::NodePtr instance, bool duplicate)
4882 {
4883 	char		*str;
4884 	Action		*a;
4885 	ActionPushData	*pd;
4886 
4887 	if(duplicate) {
4888 		a = new Action(f_tag, Action::ACTION_DUPLICATE);
4889 		f_actions->Insert(-1, a);
4890 	}
4891 
4892 	if(!instance.HasNode()) {
4893 		as::Data& name_data = name.GetData();
4894 		switch(name_data.f_type) {
4895 		case as::NODE_MEMBER:
4896 			Member(name, Action::ACTION_SET_MEMBER);
4897 			return;
4898 
4899 		case as::NODE_ARRAY:
4900 			Array(name, Action::ACTION_SET_MEMBER);
4901 			return;
4902 
4903 		case as::NODE_IDENTIFIER:
4904 			instance = name.GetLink(as::NodePtr::LINK_INSTANCE);
4905 			break;
4906 
4907 		default:
4908 			break;
4909 
4910 		}
4911 	}
4912 
4913 	if(instance.HasNode()) {
4914 		as::Data& inst_data = instance.GetData();
4915 
4916 		if(inst_data.f_type == as::NODE_PARAM) {
4917 			// this is not a variable, deal with this
4918 			// as a function parameter with the FuncParam
4919 			FuncParam **p;
4920 			p = reinterpret_cast<FuncParam **>(inst_data.f_user_data.Buffer());
4921 
4922 			switch(p[0]->f_mode) {
4923 			case FuncParam::MODE_REGISTER:
4924 				f_registers.Store(p[0]->f_reg, f_tag, f_actions, true);
4925 				break;
4926 
4927 			case FuncParam::MODE_CONSTANT:
4928 				f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, name, "IntAssembler::Assignment() cannot assign a constant function parameter.");
4929 				break;
4930 
4931 			case FuncParam::MODE_ARRAY:
4932 			{
4933 				f_registers.LoadRegister(p[0]->f_reg, false, f_tag, f_actions);
4934 				ActionPushData *pd = new ActionPushData(f_tag);
4935 				pd->AddInteger(p[0]->f_index);
4936 				f_actions->Insert(-1, pd);
4937 				Action *a = new Action(f_tag, Action::ACTION_SET_MEMBER);
4938 				f_actions->Insert(-1, a);
4939 			}
4940 				break;
4941 
4942 			case FuncParam::MODE_VARIABLE:
4943 				f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, name, "IntAssembler::Assignment() MODE_VARIABLE not written yet.");
4944 				break;
4945 
4946 			default:
4947 				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);
4948 				break;
4949 
4950 			}
4951 			return;
4952 		}
4953 
4954 		// special case when we are setting a variable member from
4955 		// a function in a class
4956 		if(inst_data.f_type == as::NODE_VARIABLE
4957 		&& (inst_data.f_int.Get() & as::NODE_VAR_FLAG_MEMBER) != 0) {
4958 			pd = new ActionPushData(f_tag);
4959 			pd->AddString("this");
4960 			f_actions->Insert(-1, pd);
4961 			a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
4962 			f_actions->Insert(-1, a);
4963 			a = new Action(f_tag, Action::ACTION_SWAP);
4964 			f_actions->Insert(-1, a);
4965 
4966 			pd = new ActionPushData(f_tag);
4967 			str = inst_data.f_str.GetUTF8();
4968 			pd->AddString(str);
4969 			delete [] str;
4970 			f_actions->Insert(-1, pd);
4971 			a = new Action(f_tag, Action::ACTION_SWAP);
4972 			f_actions->Insert(-1, a);
4973 
4974 			a = new Action(f_tag, Action::ACTION_SET_MEMBER);
4975 			f_actions->Insert(-1, a);
4976 			return;
4977 		}
4978 
4979 		if((instance.GetAttrs() & as::NODE_ATTR_DYNAMIC) != 0) {
4980 			// dynamic variables need to be accessed
4981 			// by their original name only
4982 			str = inst_data.f_str.GetUTF8();
4983 		}
4984 		else {
4985 			VariableData **vd;
4986 			if(inst_data.f_user_data.Size() == 0) {
4987 				inst_data.f_user_data.New((sizeof(VariableData *) + sizeof(int) - 1) / sizeof(int));
4988 				vd = reinterpret_cast<VariableData **>(inst_data.f_user_data.Buffer());
4989 				vd[0] = new VariableData;
4990 				if((inst_data.f_int.Get() & as::NODE_VAR_FLAG_LOCAL) == 0) {
4991 					// global variables need to be accessed by name
4992 					// (thought we change the name)
4993 					vd[0]->GenerateName("__g");
4994 				}
4995 				else {
4996 					// local variables we allocate a register if possible
4997 					vd[0]->f_reg = f_registers.AllocRegister();
4998 					if(vd[0]->f_reg >= 0) {
4999 						vd[0]->f_mode = VariableData::MODE_REGISTER;
5000 					}
5001 					else {
5002 						vd[0]->GenerateName("__l");
5003 					}
5004 				}
5005 			}
5006 			else {
5007 				vd = reinterpret_cast<VariableData **>(inst_data.f_user_data.Buffer());
5008 			}
5009 			if(vd[0]->f_mode == VariableData::MODE_REGISTER) {
5010 				f_registers.Store(vd[0]->f_reg, f_tag, f_actions, true);
5011 				return;
5012 			}
5013 			str = vd[0]->f_name.GetUTF8();
5014 		}
5015 
5016 		pd = new ActionPushData(f_tag);
5017 		pd->AddString(str);
5018 		f_actions->Insert(-1, pd);
5019 
5020 		delete [] str;
5021 	}
5022 	else {
5023 		// a dynamically defined variable name
5024 		Expression(name);
5025 	}
5026 
5027 
5028 	// ECMAScript says that first you need to computer
5029 	// the right handside of an assignment; makes sense
5030 	// to me too, but to set a variable you need that
5031 	// swapped in Flash...
5032 	a = new Action(f_tag, Action::ACTION_SWAP);
5033 	f_actions->Insert(-1, a);
5034 
5035 	if(instance.HasNode()) {
5036 		as::Data& inst_data = instance.GetData();
5037 		a = new Action(f_tag,
5038 			(inst_data.f_int.Get() & as::NODE_VAR_FLAG_LOCAL) == 0 ?
5039 				Action::ACTION_SET_VARIABLE
5040 				: Action::ACTION_SET_LOCAL_VARIABLE);
5041 	}
5042 	else {
5043 		a = new Action(f_tag, Action::ACTION_SET_VARIABLE);
5044 	}
5045 
5046 	f_actions->Insert(-1, a);
5047 }
5048 
5049 
ExpressionAssignment(as::NodePtr & expr,as::node_t type)5050 void IntAssembler::ExpressionAssignment(as::NodePtr& expr, as::node_t type)
5051 {
5052 	ActionPushData		*pd;
5053 	ActionBranch		*branch;
5054 	ActionLabel		*label;
5055 	Action			*a;
5056 	as::String		l1;
5057 	char			*str1;
5058 	int			reg;
5059 
5060 	// note that a = b returns a copy of a; if the
5061 	// expression is to return void, we should avoid
5062 	// the duplicate here... [optimized later?]
5063 	Expression(expr.GetChild(1));
5064 
5065 	if(type != as::NODE_ASSIGNMENT) {
5066 		reg = -1;
5067 
5068 		switch(type) {
5069 		case as::NODE_ASSIGNMENT_LOGICAL_XOR:
5070 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5071 			f_actions->Insert(-1, a);
5072 			break;
5073 
5074 		case as::NODE_ASSIGNMENT_MAXIMUM:
5075 		case as::NODE_ASSIGNMENT_MINIMUM:
5076 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
5077 			f_actions->Insert(-1, a);
5078 			break;
5079 
5080 		case as::NODE_ASSIGNMENT_ROTATE_LEFT:
5081 		case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
5082 			pd = new ActionPushData(f_tag);
5083 			pd->AddInteger(31);
5084 			f_actions->Insert(-1, pd);
5085 			a = new Action(f_tag, Action::ACTION_AND);
5086 			f_actions->Insert(-1, a);
5087 			reg = f_registers.StoreRegister(f_tag, f_actions);
5088 			a = new Action(f_tag, Action::ACTION_POP);
5089 			f_actions->Insert(-1, a);
5090 			break;
5091 
5092 		default:
5093 			// do nothing for the others
5094 			break;
5095 
5096 		}
5097 		Expression(expr.GetChild(0));
5098 		Action *a;
5099 		switch(type) {
5100 		case as::NODE_ASSIGNMENT_BITWISE_AND:
5101 			a = new Action(f_tag, Action::ACTION_AND);
5102 			f_actions->Insert(-1, a);
5103 			break;
5104 
5105 		case as::NODE_ASSIGNMENT_BITWISE_OR:
5106 			a = new Action(f_tag, Action::ACTION_OR);
5107 			f_actions->Insert(-1, a);
5108 			break;
5109 
5110 		case as::NODE_ASSIGNMENT_BITWISE_XOR:
5111 			a = new Action(f_tag, Action::ACTION_XOR);
5112 			f_actions->Insert(-1, a);
5113 			break;
5114 
5115 		case as::NODE_ASSIGNMENT_DIVIDE:
5116 			// TODO: test that expressions don't need to be swapped
5117 			a = new Action(f_tag, Action::ACTION_SWAP);
5118 			f_actions->Insert(-1, a);
5119 			a = new Action(f_tag, Action::ACTION_DIVIDE);
5120 			f_actions->Insert(-1, a);
5121 			break;
5122 
5123 		case as::NODE_ASSIGNMENT_LOGICAL_AND:
5124 			a = new Action(f_tag, Action::ACTION_LOGICAL_AND);
5125 			f_actions->Insert(-1, a);
5126 			break;
5127 
5128 		case as::NODE_ASSIGNMENT_LOGICAL_OR:
5129 			a = new Action(f_tag, Action::ACTION_LOGICAL_OR);
5130 			f_actions->Insert(-1, a);
5131 			break;
5132 
5133 		case as::NODE_ASSIGNMENT_LOGICAL_XOR:
5134 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5135 			f_actions->Insert(-1, a);
5136 			a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
5137 			f_actions->Insert(-1, a);
5138 			a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5139 			f_actions->Insert(-1, a);
5140 			break;
5141 
5142 		case as::NODE_ASSIGNMENT_MAXIMUM:
5143 		case as::NODE_ASSIGNMENT_MINIMUM:
5144 			//	expr[0]
5145 			//	dup
5146 			//	expr[1]
5147 			//	store_reg
5148 			//	if_greater_than done [MAXIMUM]
5149 			//	if_less_than done [MINIMUM]
5150 			//	pop
5151 			//	load_reg
5152 			// done:
5153 			reg = f_registers.StoreRegister(f_tag, f_actions);
5154 			a = new Action(f_tag, type == as::NODE_ASSIGNMENT_MAXIMUM ?
5155 					Action::ACTION_GREATER_THAN_TYPED
5156 						: Action::ACTION_LESS_THAN_TYPED);
5157 			f_actions->Insert(-1, a);
5158 			branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
5159 			Label(l1);
5160 			str1 = l1.GetUTF8();
5161 			branch->SetLabel(str1);
5162 			f_actions->Insert(-1, branch);
5163 			a = new Action(f_tag, Action::ACTION_POP);
5164 			f_actions->Insert(-1, a);
5165 			f_registers.LoadRegister(reg, true, f_tag, f_actions);
5166 			label = new ActionLabel(f_tag);
5167 			label->SetLabel(str1);
5168 			f_actions->Insert(-1, label);
5169 			delete [] str1;
5170 			break;
5171 
5172 		case as::NODE_ASSIGNMENT_MODULO:
5173 			// TODO: test that expressions don't need to be swapped
5174 			a = new Action(f_tag, Action::ACTION_SWAP);
5175 			f_actions->Insert(-1, a);
5176 			a = new Action(f_tag, Action::ACTION_MODULO);
5177 			f_actions->Insert(-1, a);
5178 			break;
5179 
5180 		case as::NODE_ASSIGNMENT_MULTIPLY:
5181 			a = new Action(f_tag, Action::ACTION_MULTIPLY);
5182 			f_actions->Insert(-1, a);
5183 			break;
5184 
5185 		case as::NODE_ASSIGNMENT_ROTATE_LEFT:
5186 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
5187 			f_actions->Insert(-1, a);
5188 			f_registers.LoadRegister(reg, false, f_tag, f_actions);
5189 			a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
5190 			f_actions->Insert(-1, a);
5191 			a = new Action(f_tag, Action::ACTION_SWAP);
5192 			f_actions->Insert(-1, a);
5193 			pd = new ActionPushData(f_tag);
5194 			pd->AddInteger(32);
5195 			f_actions->Insert(-1, pd);
5196 			f_registers.LoadRegister(reg, true, f_tag, f_actions);
5197 			a = new Action(f_tag, Action::ACTION_SUBTRACT);
5198 			f_actions->Insert(-1, a);
5199 			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
5200 			f_actions->Insert(-1, a);
5201 			a = new Action(f_tag, Action::ACTION_OR);
5202 			f_actions->Insert(-1, a);
5203 			break;
5204 
5205 		case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
5206 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
5207 			f_actions->Insert(-1, a);
5208 			f_registers.LoadRegister(reg, false, f_tag, f_actions);
5209 			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
5210 			f_actions->Insert(-1, a);
5211 			a = new Action(f_tag, Action::ACTION_SWAP);
5212 			f_actions->Insert(-1, a);
5213 			pd = new ActionPushData(f_tag);
5214 			pd->AddInteger(32);
5215 			f_actions->Insert(-1, pd);
5216 			f_registers.LoadRegister(reg, true, f_tag, f_actions);
5217 			a = new Action(f_tag, Action::ACTION_SUBTRACT);
5218 			f_actions->Insert(-1, a);
5219 			a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
5220 			f_actions->Insert(-1, a);
5221 			a = new Action(f_tag, Action::ACTION_OR);
5222 			f_actions->Insert(-1, a);
5223 			break;
5224 
5225 		case as::NODE_ASSIGNMENT_SHIFT_LEFT:
5226 			a = new Action(f_tag, Action::ACTION_SWAP);
5227 			f_actions->Insert(-1, a);
5228 			a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
5229 			f_actions->Insert(-1, a);
5230 			break;
5231 
5232 		case as::NODE_ASSIGNMENT_SHIFT_RIGHT:
5233 			a = new Action(f_tag, Action::ACTION_SWAP);
5234 			f_actions->Insert(-1, a);
5235 			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT);
5236 			f_actions->Insert(-1, a);
5237 			break;
5238 
5239 		case as::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
5240 			a = new Action(f_tag, Action::ACTION_SWAP);
5241 			f_actions->Insert(-1, a);
5242 			a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
5243 			f_actions->Insert(-1, a);
5244 			break;
5245 
5246 		default:
5247 			f_error_stream->ErrMsg(as::AS_ERR_INTERNAL_ERROR, expr, "unsupported assignment #%d in IntAssembler::ExpressionAssignment().", type);
5248 			break;
5249 
5250 		}
5251 	}
5252 
5253 	as::NodePtr instance;
5254 	Assignment(expr.GetChild(0), instance, true);
5255 }
5256 
5257 
ExpressionAssignmentAdd(as::NodePtr & expr)5258 void IntAssembler::ExpressionAssignmentAdd(as::NodePtr& expr)
5259 {
5260 	// first, compute a ** b making sure we first evaluate
5261 	// b and not a
5262 	Add(expr, true);
5263 
5264 	as::NodePtr instance;
5265 	Assignment(expr.GetChild(0), instance, true);
5266 }
5267 
5268 
ExpressionAssignmentSubtract(as::NodePtr & expr)5269 void IntAssembler::ExpressionAssignmentSubtract(as::NodePtr& expr)
5270 {
5271 	// first, compute a ** b making sure we first evaluate
5272 	// b and not a
5273 	Subtract(expr, true);
5274 
5275 	as::NodePtr instance;
5276 	Assignment(expr.GetChild(0), instance, true);
5277 }
5278 
5279 
ExpressionAssignmentPower(as::NodePtr & expr)5280 void IntAssembler::ExpressionAssignmentPower(as::NodePtr& expr)
5281 {
5282 	// first, compute a ** b making sure we first evaluate
5283 	// b and not a
5284 	Power(expr, true);
5285 
5286 	as::NodePtr instance;
5287 	Assignment(expr.GetChild(0), instance, true);
5288 }
5289 
5290 
ExpressionIncrement(as::NodePtr & expr,as::node_t type)5291 void IntAssembler::ExpressionIncrement(as::NodePtr& expr, as::node_t type)
5292 {
5293 	as::NodePtr		instance;
5294 
5295 	// ++a becomes a = a + 1
5296 	// however ++expr becomes expr + 1
5297 	as::NodePtr& child = expr.GetChild(0);
5298 	Expression(child);
5299 	Action *a = new Action(f_tag, type == as::NODE_INCREMENT ? Action::ACTION_INCREMENT : Action::ACTION_DECREMENT);
5300 	f_actions->Insert(-1, a);
5301 
5302 	as::Data& data = child.GetData();
5303 	switch(data.f_type) {
5304 	case as::NODE_IDENTIFIER:
5305 		Assignment(child, instance, true);
5306 		break;
5307 
5308 	case as::NODE_MEMBER:
5309 		Member(child, Action::ACTION_SET_MEMBER);
5310 		break;
5311 
5312 	default:
5313 		// there is nothing special to do with the value here
5314 		break;
5315 
5316 	}
5317 }
5318 
5319 
ExpressionPostIncrement(as::NodePtr & expr,as::node_t type)5320 void IntAssembler::ExpressionPostIncrement(as::NodePtr& expr, as::node_t type)
5321 {
5322 	Action		*a;
5323 	as::NodePtr	instance;
5324 
5325 	// a++ becomes t = a, a = a + 1, t
5326 	// however expr++ becomes expr
5327 	// note 1: non-intrinsic post in/decrement don't get here
5328 	// note 2: instead of using a temp, we use duplicate
5329 	as::NodePtr& child = expr.GetChild(0);
5330 	as::Data& child_data = child.GetData();
5331 	switch(child_data.f_type) {
5332 	case as::NODE_IDENTIFIER:
5333 		// <expr>
5334 		// dup
5335 		// increment or decrement
5336 		// <set variable>
5337 		ExpressionIdentifier(child);
5338 
5339 		a = new Action(f_tag, Action::ACTION_DUPLICATE);
5340 		f_actions->Insert(-1, a);
5341 
5342 		a = new Action(f_tag, type == as::NODE_POST_INCREMENT ? Action::ACTION_INCREMENT : Action::ACTION_DECREMENT);
5343 		f_actions->Insert(-1, a);
5344 
5345 		Assignment(child, instance, false);
5346 		break;
5347 
5348 	case as::NODE_MEMBER:
5349 		Member(child, Action::ACTION_GET_MEMBER);
5350 
5351 		a = new Action(f_tag, Action::ACTION_DUPLICATE);
5352 		f_actions->Insert(-1, a);
5353 
5354 		a = new Action(f_tag, type == as::NODE_POST_INCREMENT ? Action::ACTION_INCREMENT : Action::ACTION_DECREMENT);
5355 		f_actions->Insert(-1, a);
5356 
5357 		Member(child, Action::ACTION_SET_MEMBER);
5358 		break;
5359 
5360 	default:
5361 		// it's not necessary to do + 1 on a throw
5362 		// away value! [this may get optimized in
5363 		// the compiler one day; or it may have
5364 		// to become an error...]
5365 		Expression(child);
5366 		break;
5367 
5368 	}
5369 }
5370 
5371 
5372 
ExpressionConditional(as::NodePtr & expr)5373 void IntAssembler::ExpressionConditional(as::NodePtr& expr)
5374 {
5375 	ActionBranch		*branch;
5376 	ActionLabel		*label;
5377 	char			*str1, *str2;
5378 	as::String		l1, l2;
5379 
5380 	// note: this is compiled the other way around since we
5381 	// can branch if true and we can avoid a logical not in
5382 	// this way
5383 
5384 	Expression(expr.GetChild(0));
5385 	branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
5386 	Label(l1);
5387 	str1 = l1.GetUTF8();
5388 	branch->SetLabel(str1);
5389 	f_actions->Insert(-1, branch);
5390 	Expression(expr.GetChild(2));
5391 	branch = new ActionBranch(f_tag);
5392 	Label(l2);
5393 	str2 = l2.GetUTF8();
5394 	branch->SetLabel(str2);
5395 	f_actions->Insert(-1, branch);
5396 	label = new ActionLabel(f_tag);
5397 	label->SetLabel(str1);
5398 	f_actions->Insert(-1, label);
5399 	Expression(expr.GetChild(1));
5400 	label = new ActionLabel(f_tag);
5401 	label->SetLabel(str2);
5402 	f_actions->Insert(-1, label);
5403 	delete [] str1;
5404 	delete [] str2;
5405 }
5406 
5407 
ExpressionNew(as::NodePtr & expr)5408 void IntAssembler::ExpressionNew(as::NodePtr& expr)
5409 {
5410 	ActionPushData		*pd;
5411 	Action			*a;
5412 	char			*str;
5413 
5414 	as::Data& data = expr.GetData();
5415 	switch(data.f_type) {
5416 	case as::NODE_IDENTIFIER:
5417 		pd = new ActionPushData(f_tag);
5418 		pd->AddInteger(0);
5419 		f_actions->Insert(-1, pd);
5420 
5421 		pd = new ActionPushData(f_tag);
5422 		str = data.f_str.GetUTF8();
5423 		pd->AddString(str);
5424 		delete [] str;
5425 		f_actions->Insert(-1, pd);
5426 		break;
5427 
5428 	case as::NODE_MEMBER:
5429 		// special case which has no parameters
5430 		pd = new ActionPushData(f_tag);
5431 		pd->AddInteger(0);
5432 		f_actions->Insert(-1, pd);
5433 		Member(expr, Action::ACTION_NEW_METHOD);
5434 		return;
5435 
5436 	case as::NODE_CALL:
5437 		Expression(expr);
5438 		return;
5439 
5440 	default:
5441 		pd = new ActionPushData(f_tag);
5442 		pd->AddInteger(0);
5443 		f_actions->Insert(-1, pd);
5444 
5445 		Expression(expr);
5446 		break;
5447 
5448 	}
5449 	a = new Action(f_tag, Action::ACTION_NEW);
5450 	f_actions->Insert(-1, a);
5451 }
5452 
5453 
ExpressionDelete(as::NodePtr & expr)5454 void IntAssembler::ExpressionDelete(as::NodePtr& expr)
5455 {
5456 	ActionPushData		*pd;
5457 	Action			*a;
5458 	char			*str;
5459 
5460 	as::Data& data = expr.GetData();
5461 	switch(data.f_type) {
5462 	case as::NODE_IDENTIFIER:
5463 		pd = new ActionPushData(f_tag);
5464 		//pd->AddUndefined();
5465 		pd->AddString("_root");
5466 		f_actions->Insert(-1, pd);
5467 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
5468 		f_actions->Insert(-1, a);
5469 
5470 		pd = new ActionPushData(f_tag);
5471 		str = data.f_str.GetUTF8();
5472 		pd->AddString(str);
5473 		delete [] str;
5474 		f_actions->Insert(-1, pd);
5475 		break;
5476 
5477 	case as::NODE_MEMBER:
5478 		Member(expr, Action::ACTION_DELETE);
5479 		return;
5480 
5481 	default:
5482 		pd = new ActionPushData(f_tag);
5483 		//pd->AddUndefined();
5484 		pd->AddString("_root");
5485 		f_actions->Insert(-1, pd);
5486 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
5487 		f_actions->Insert(-1, a);
5488 
5489 		Expression(expr);
5490 		break;
5491 
5492 	}
5493 	a = new Action(f_tag, Action::ACTION_DELETE);
5494 	f_actions->Insert(-1, a);
5495 }
5496 
5497 
ExpressionVoid(as::NodePtr & expr)5498 void IntAssembler::ExpressionVoid(as::NodePtr& expr)
5499 {
5500 	Expression(expr.GetChild(0));
5501 
5502 	// replace result value by undefined
5503 	Action *a = new Action(f_tag, Action::ACTION_POP);
5504 	f_actions->Insert(-1, a);
5505 	ActionPushData *pd = new ActionPushData(f_tag);
5506 	pd->AddUndefined();
5507 	f_actions->Insert(-1, pd);
5508 }
5509 
5510 
ExpressionAs(as::NodePtr & expr)5511 void IntAssembler::ExpressionAs(as::NodePtr& expr)
5512 {
5513 	Action		*a;
5514 
5515 	Expression(expr.GetChild(0));
5516 	Expression(expr.GetChild(1));
5517 	a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
5518 	f_actions->Insert(-1, a);
5519 	a = new Action(f_tag, Action::ACTION_SWAP);
5520 	f_actions->Insert(-1, a);
5521 	a = new Action(f_tag, Action::ACTION_CAST_OBJECT);
5522 	f_actions->Insert(-1, a);
5523 }
5524 
5525 
ExpressionList(as::NodePtr & expr)5526 void IntAssembler::ExpressionList(as::NodePtr& expr)
5527 {
5528 	int idx;
5529 	int max = expr.GetChildCount();
5530 	if(max > 0) {
5531 		for(idx = 0; idx < max; ++idx) {
5532 			// discard the result of all the expressions
5533 			VoidExpression(expr.GetChild(idx));
5534 		}
5535 		// except the last one
5536 		Expression(expr.GetChild(idx));
5537 	}
5538 }
5539 
5540 
ExpressionArrayLiteral(as::NodePtr & expr)5541 void IntAssembler::ExpressionArrayLiteral(as::NodePtr& expr)
5542 {
5543 	ActionPushData		*pd;
5544 	Action			*a;
5545 	int			idx, max;
5546 
5547 	// NOTE:
5548 	//	We can use the ACTION_DECLARE_ARRAY only if all our
5549 	//	values are constants, otherwise we can't predict the
5550 	//	result (i.e. whether some function calls could
5551 	//	have side effects). Thus we create an empty array
5552 	//	and start to fill it as required instead.
5553 
5554 	max = expr.GetChildCount();
5555 	as::NodePtr list = expr;
5556 	if(max == 1) {
5557 		list = expr.GetChild(0);
5558 		as::Data& data = list.GetData();
5559 		if(data.f_type != as::NODE_LIST) {
5560 			list = expr;
5561 		}
5562 		else {
5563 			max = list.GetChildCount();
5564 		}
5565 	}
5566 
5567 	if(!expr.HasSideEffects()) {
5568 		//
5569 		//	push item (backward)
5570 		//	...
5571 		//	push count
5572 		//	declare array
5573 		//
5574 		idx = max;
5575 		while(idx > 0) {
5576 			idx--;
5577 			Expression(list.GetChild(idx));
5578 		}
5579 		pd = new ActionPushData(f_tag);
5580 		pd->AddInteger(max);
5581 		f_actions->Insert(-1, pd);
5582 		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
5583 		f_actions->Insert(-1, a);
5584 	}
5585 	else {
5586 		//
5587 		//	push 0
5588 		//	declare array
5589 		// <this is not a label per say, just what we repeat in our loop>
5590 		// repeat:
5591 		//	duplicate
5592 		//	push index
5593 		//	push value
5594 		//	set member
5595 		//	<if more members, repeat>
5596 		//
5597 
5598 		// An empty array
5599 		pd = new ActionPushData(f_tag);
5600 		pd->AddInteger(0);
5601 		f_actions->Insert(-1, pd);
5602 		a = new Action(f_tag, Action::ACTION_DECLARE_ARRAY);
5603 		f_actions->Insert(-1, a);
5604 
5605 		for(idx = 0; idx < max; ++idx) {
5606 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
5607 			f_actions->Insert(-1, a);
5608 
5609 			pd = new ActionPushData(f_tag);
5610 			pd->AddInteger(idx);
5611 			f_actions->Insert(-1, pd);
5612 
5613 			Expression(list.GetChild(idx));
5614 
5615 			a = new Action(f_tag, Action::ACTION_SET_MEMBER);
5616 			f_actions->Insert(-1, a);
5617 		}
5618 	}
5619 }
5620 
5621 
ExpressionObjectLiteral(as::NodePtr & expr)5622 void IntAssembler::ExpressionObjectLiteral(as::NodePtr& expr)
5623 {
5624 	ActionPushData		*pd;
5625 	Action			*a;
5626 	char			*str;
5627 	int			idx, max;
5628 
5629 	// IMPORTANT NOTE:
5630 	//	The ACTION_DECLARE_OBJECT has one advantage: we don't
5631 	//	need any specific order to declare the object members.
5632 	//	This means we can do it in the right order without
5633 	//	having to worry about anything.
5634 
5635 	// <this is not a label per say, just what we repeat in our loop>
5636 	// repeat:
5637 	//	push name
5638 	//	push value
5639 	//	<if more members, repeat>
5640 	//	push count / 2
5641 	//	declare object
5642 	//
5643 	max = expr.GetChildCount();
5644 
5645 	for(idx = 0; idx < max; idx += 2) {
5646 		as::NodePtr& name = expr.GetChild(idx);
5647 		as::Data& name_data = name.GetData();
5648 		switch(name_data.f_type) {
5649 		case as::NODE_TYPE:
5650 			// dynamic name
5651 			Expression(name.GetChild(0));
5652 			break;
5653 
5654 		case as::NODE_IDENTIFIER:
5655 		case as::NODE_STRING:
5656 			pd = new ActionPushData(f_tag);
5657 			str = name_data.f_str.GetUTF8();
5658 			pd->AddString(str);
5659 			delete [] str;
5660 			f_actions->Insert(-1, pd);
5661 			break;
5662 
5663 		case as::NODE_INT64:
5664 			pd = new ActionPushData(f_tag);
5665 			pd->AddInteger(name_data.f_int.Get());
5666 			f_actions->Insert(-1, pd);
5667 			break;
5668 
5669 		case as::NODE_FLOAT64:
5670 			pd = new ActionPushData(f_tag);
5671 			pd->AddDouble(name_data.f_float.Get());
5672 			f_actions->Insert(-1, pd);
5673 			break;
5674 
5675 		default:
5676 			// unsupported type for the type of an object name
5677 			AS_ASSERT(0);
5678 			return;
5679 
5680 		}
5681 
5682 		Expression(expr.GetChild(idx + 1));
5683 
5684 		//a = new Action(f_tag, Action::ACTION_SWAP);
5685 		//f_actions->Insert(-1, a);
5686 	}
5687 
5688 	pd = new ActionPushData(f_tag);
5689 	pd->AddInteger(max / 2);
5690 	f_actions->Insert(-1, pd);
5691 
5692 	a = new Action(f_tag, Action::ACTION_DECLARE_OBJECT);
5693 	f_actions->Insert(-1, a);
5694 }
5695 
5696 
Expression(as::NodePtr & expr)5697 void IntAssembler::Expression(as::NodePtr& expr)
5698 {
5699 	ActionPushData		*pd;
5700 	ActionBranch		*branch;
5701 	ActionLabel		*label;
5702 	Action			*a;
5703 	char			*str, *str1;
5704 	int			reg;
5705 	as::String		l1, l2;
5706 
5707 	as::Data& data = expr.GetData();
5708 
5709 	switch(data.f_type) {
5710 	case as::NODE_TRUE:
5711 		pd = new ActionPushData(f_tag);
5712 		pd->AddBoolean(true);
5713 		f_actions->Insert(-1, pd);
5714 		break;
5715 
5716 	case as::NODE_FALSE:
5717 		pd = new ActionPushData(f_tag);
5718 		pd->AddBoolean(false);
5719 		f_actions->Insert(-1, pd);
5720 		break;
5721 
5722 	case as::NODE_UNDEFINED:
5723 		pd = new ActionPushData(f_tag);
5724 		pd->AddUndefined();
5725 		f_actions->Insert(-1, pd);
5726 		break;
5727 
5728 	case as::NODE_NULL:
5729 		pd = new ActionPushData(f_tag);
5730 		pd->AddNull();
5731 		f_actions->Insert(-1, pd);
5732 		break;
5733 
5734 	case as::NODE_ARRAY_LITERAL:
5735 		ExpressionArrayLiteral(expr);
5736 		break;
5737 
5738 	case as::NODE_OBJECT_LITERAL:
5739 		ExpressionObjectLiteral(expr);
5740 		break;
5741 
5742 	case as::NODE_VOID:
5743 		ExpressionVoid(expr);
5744 		break;
5745 
5746 	case as::NODE_FUNCTION:
5747 		Function(expr, false);
5748 		break;
5749 
5750 	case as::NODE_INT64:
5751 		pd = new ActionPushData(f_tag);
5752 		pd->AddInteger(data.f_int.Get());
5753 		f_actions->Insert(-1, pd);
5754 		break;
5755 
5756 	case as::NODE_FLOAT64:
5757 		pd = new ActionPushData(f_tag);
5758 		pd->AddDouble(data.f_float.Get());
5759 		f_actions->Insert(-1, pd);
5760 		break;
5761 
5762 	case as::NODE_STRING:
5763 		pd = new ActionPushData(f_tag);
5764 		str = data.f_str.GetUTF8();
5765 		pd->AddString(str);
5766 		delete [] str;
5767 		f_actions->Insert(-1, pd);
5768 		break;
5769 
5770 	case as::NODE_IDENTIFIER:
5771 	case as::NODE_VIDENTIFIER:
5772 		ExpressionIdentifier(expr);
5773 		break;
5774 
5775 	case as::NODE_THIS:
5776 		pd = new ActionPushData(f_tag);
5777 		pd->AddString("this");
5778 		f_actions->Insert(-1, pd);
5779 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
5780 		f_actions->Insert(-1, a);
5781 		break;
5782 
5783 	case as::NODE_SUPER:
5784 		pd = new ActionPushData(f_tag);
5785 		pd->AddString("super");
5786 		f_actions->Insert(-1, pd);
5787 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
5788 		f_actions->Insert(-1, a);
5789 		break;
5790 
5791 	case as::NODE_ARRAY:
5792 		Array(expr, Action::ACTION_GET_MEMBER);
5793 		break;
5794 
5795 	case as::NODE_MEMBER:
5796 		Member(expr, Action::ACTION_GET_MEMBER);
5797 		break;
5798 
5799 	case as::NODE_CALL:
5800 		Call(expr);
5801 		break;
5802 
5803 	case as::NODE_ADD:
5804 		Add(expr, false);
5805 		break;
5806 
5807 	case as::NODE_SUBTRACT:
5808 		Subtract(expr, false);
5809 		break;
5810 
5811 	case as::NODE_BITWISE_NOT:
5812 		// TODO: test validity with floats...
5813 		// in Flash, there isn't a bitwise not, use the XOR
5814 		// instead
5815 		pd = new ActionPushData(f_tag);
5816 		pd->AddInteger(-1);
5817 		f_actions->Insert(-1, pd);
5818 		Expression(expr.GetChild(0));
5819 		a = new Action(f_tag, Action::ACTION_XOR);
5820 		f_actions->Insert(-1, a);
5821 		break;
5822 
5823 	case as::NODE_DECREMENT:
5824 	case as::NODE_INCREMENT:
5825 		ExpressionIncrement(expr, data.f_type);
5826 		break;
5827 
5828 	case as::NODE_POST_DECREMENT:
5829 	case as::NODE_POST_INCREMENT:
5830 		ExpressionPostIncrement(expr, data.f_type);
5831 		break;
5832 
5833 	case as::NODE_LOGICAL_NOT:
5834 		Expression(expr.GetChild(0));
5835 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5836 		f_actions->Insert(-1, a);
5837 		break;
5838 
5839 	case as::NODE_LOGICAL_AND:
5840 		Expression(expr.GetChild(0));
5841 		Expression(expr.GetChild(1));
5842 		a = new Action(f_tag, Action::ACTION_LOGICAL_AND);
5843 		f_actions->Insert(-1, a);
5844 		break;
5845 
5846 	case as::NODE_LOGICAL_OR:
5847 		Expression(expr.GetChild(0));
5848 		Expression(expr.GetChild(1));
5849 		a = new Action(f_tag, Action::ACTION_LOGICAL_OR);
5850 		f_actions->Insert(-1, a);
5851 		break;
5852 
5853 	case as::NODE_LOGICAL_XOR:
5854 		Expression(expr.GetChild(0));
5855 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5856 		f_actions->Insert(-1, a);
5857 		Expression(expr.GetChild(1));
5858 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5859 		f_actions->Insert(-1, a);
5860 		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
5861 		f_actions->Insert(-1, a);
5862 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5863 		f_actions->Insert(-1, a);
5864 		break;
5865 
5866 	case as::NODE_INSTANCEOF:
5867 	case as::NODE_IS:		// TODO: this is only slightly different...
5868 		Expression(expr.GetChild(0));
5869 		Expression(expr.GetChild(1));
5870 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
5871 		f_actions->Insert(-1, a);
5872 		a = new Action(f_tag, Action::ACTION_INSTANCE_OF);
5873 		f_actions->Insert(-1, a);
5874 		break;
5875 
5876 	case as::NODE_TYPEOF:
5877 		Expression(expr.GetChild(0));
5878 		a = new Action(f_tag, Action::ACTION_TYPE_OF);
5879 		f_actions->Insert(-1, a);
5880 		break;
5881 
5882 	case as::NODE_BITWISE_AND:
5883 		Expression(expr.GetChild(0));
5884 		Expression(expr.GetChild(1));
5885 		a = new Action(f_tag, Action::ACTION_AND);
5886 		f_actions->Insert(-1, a);
5887 		break;
5888 
5889 	case as::NODE_BITWISE_OR:
5890 		Expression(expr.GetChild(0));
5891 		Expression(expr.GetChild(1));
5892 		a = new Action(f_tag, Action::ACTION_OR);
5893 		f_actions->Insert(-1, a);
5894 		break;
5895 
5896 	case as::NODE_BITWISE_XOR:
5897 		Expression(expr.GetChild(0));
5898 		Expression(expr.GetChild(1));
5899 		a = new Action(f_tag, Action::ACTION_XOR);
5900 		f_actions->Insert(-1, a);
5901 		break;
5902 
5903 	case as::NODE_CONDITIONAL:
5904 		ExpressionConditional(expr);
5905 		break;
5906 
5907 	case as::NODE_DIVIDE:
5908 		// TODO: test that it doesn't need to be swapped
5909 		Expression(expr.GetChild(0));
5910 		Expression(expr.GetChild(1));
5911 		a = new Action(f_tag, Action::ACTION_DIVIDE);
5912 		f_actions->Insert(-1, a);
5913 		break;
5914 
5915 	case as::NODE_EQUAL:
5916 		Expression(expr.GetChild(0));
5917 		Expression(expr.GetChild(1));
5918 		a = new Action(f_tag, Action::ACTION_EQUAL_TYPED);
5919 		f_actions->Insert(-1, a);
5920 		break;
5921 
5922 	case as::NODE_GREATER:
5923 		Expression(expr.GetChild(0));
5924 		Expression(expr.GetChild(1));
5925 		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
5926 		f_actions->Insert(-1, a);
5927 		break;
5928 
5929 	case as::NODE_GREATER_EQUAL:
5930 		// a >= b <=> !(a < b)
5931 		Expression(expr.GetChild(0));
5932 		Expression(expr.GetChild(1));
5933 		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
5934 		f_actions->Insert(-1, a);
5935 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5936 		f_actions->Insert(-1, a);
5937 		break;
5938 
5939 	case as::NODE_IN:
5940 		// here we need to enumerate and then compare
5941 		// each item one by one...
5942 		// or test if value is in range
5943 		ExprIn(expr);
5944 		break;
5945 
5946 	case as::NODE_LESS:
5947 		Expression(expr.GetChild(0));
5948 		Expression(expr.GetChild(1));
5949 		a = new Action(f_tag, Action::ACTION_LESS_THAN_TYPED);
5950 		f_actions->Insert(-1, a);
5951 		break;
5952 
5953 	case as::NODE_LESS_EQUAL:
5954 		// a <= b <=> !(a > b)
5955 		Expression(expr.GetChild(0));
5956 		Expression(expr.GetChild(1));
5957 		a = new Action(f_tag, Action::ACTION_GREATER_THAN_TYPED);
5958 		f_actions->Insert(-1, a);
5959 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
5960 		f_actions->Insert(-1, a);
5961 		break;
5962 
5963 	case as::NODE_MAXIMUM:
5964 	case as::NODE_MINIMUM:
5965 		//	expr[0]
5966 		//	dup
5967 		//	expr[1]
5968 		//	store_reg
5969 		//	if_greater_than done [MAXIMUM]
5970 		//	if_less_than done [MINIMUM]
5971 		//	pop
5972 		//	load_reg
5973 		// done:
5974 		Expression(expr.GetChild(0));
5975 		a = new Action(f_tag, Action::ACTION_DUPLICATE);
5976 		f_actions->Insert(-1, a);
5977 		Expression(expr.GetChild(1));
5978 		reg = f_registers.StoreRegister(f_tag, f_actions);
5979 		a = new Action(f_tag, data.f_type == as::NODE_MAXIMUM ?
5980 				Action::ACTION_GREATER_THAN_TYPED
5981 					: Action::ACTION_LESS_THAN_TYPED);
5982 		f_actions->Insert(-1, a);
5983 		branch = new ActionBranch(f_tag, Action::ACTION_BRANCH_IF_TRUE);
5984 		Label(l1);
5985 		str1 = l1.GetUTF8();
5986 		branch->SetLabel(str1);
5987 		f_actions->Insert(-1, branch);
5988 		a = new Action(f_tag, Action::ACTION_POP);
5989 		f_actions->Insert(-1, a);
5990 		f_registers.LoadRegister(reg, true, f_tag, f_actions);
5991 		label = new ActionLabel(f_tag);
5992 		label->SetLabel(str1);
5993 		f_actions->Insert(-1, label);
5994 		delete [] str1;
5995 		break;
5996 
5997 	case as::NODE_MODULO:
5998 		// TODO: test that expressions don't need to be swapped
5999 		Expression(expr.GetChild(0));
6000 		Expression(expr.GetChild(1));
6001 		a = new Action(f_tag, Action::ACTION_MODULO);
6002 		f_actions->Insert(-1, a);
6003 		break;
6004 
6005 	case as::NODE_MULTIPLY:
6006 		Multiply(expr);
6007 		break;
6008 
6009 	case as::NODE_NOT_EQUAL:
6010 		Expression(expr.GetChild(0));
6011 		Expression(expr.GetChild(1));
6012 		a = new Action(f_tag, Action::ACTION_EQUAL_TYPED);
6013 		f_actions->Insert(-1, a);
6014 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
6015 		f_actions->Insert(-1, a);
6016 		break;
6017 
6018 	case as::NODE_POWER:
6019 		Power(expr, false);
6020 		break;
6021 
6022 	case as::NODE_ROTATE_LEFT:
6023 		Expression(expr.GetChild(0));
6024 		a = new Action(f_tag, Action::ACTION_DUPLICATE);
6025 		f_actions->Insert(-1, a);
6026 		Expression(expr.GetChild(1));
6027 		pd = new ActionPushData(f_tag);
6028 		pd->AddInteger(31);
6029 		f_actions->Insert(-1, pd);
6030 		a = new Action(f_tag, Action::ACTION_AND);
6031 		f_actions->Insert(-1, a);
6032 		reg = f_registers.StoreRegister(f_tag, f_actions);
6033 		a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
6034 		f_actions->Insert(-1, a);
6035 		a = new Action(f_tag, Action::ACTION_SWAP);
6036 		f_actions->Insert(-1, a);
6037 		pd = new ActionPushData(f_tag);
6038 		pd->AddInteger(32);
6039 		f_actions->Insert(-1, pd);
6040 		f_registers.LoadRegister(reg, true, f_tag, f_actions);
6041 		a = new Action(f_tag, Action::ACTION_SUBTRACT);
6042 		f_actions->Insert(-1, a);
6043 		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
6044 		f_actions->Insert(-1, a);
6045 		a = new Action(f_tag, Action::ACTION_OR);
6046 		f_actions->Insert(-1, a);
6047 		break;
6048 
6049 	case as::NODE_ROTATE_RIGHT:
6050 		Expression(expr.GetChild(0));
6051 		a = new Action(f_tag, Action::ACTION_DUPLICATE);
6052 		f_actions->Insert(-1, a);
6053 		Expression(expr.GetChild(1));
6054 		pd = new ActionPushData(f_tag);
6055 		pd->AddInteger(31);
6056 		f_actions->Insert(-1, pd);
6057 		a = new Action(f_tag, Action::ACTION_AND);
6058 		f_actions->Insert(-1, a);
6059 		reg = f_registers.StoreRegister(f_tag, f_actions);
6060 		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
6061 		f_actions->Insert(-1, a);
6062 		a = new Action(f_tag, Action::ACTION_SWAP);
6063 		f_actions->Insert(-1, a);
6064 		pd = new ActionPushData(f_tag);
6065 		pd->AddInteger(32);
6066 		f_actions->Insert(-1, pd);
6067 		f_registers.LoadRegister(reg, true, f_tag, f_actions);
6068 		a = new Action(f_tag, Action::ACTION_SUBTRACT);
6069 		f_actions->Insert(-1, a);
6070 		a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
6071 		f_actions->Insert(-1, a);
6072 		a = new Action(f_tag, Action::ACTION_OR);
6073 		f_actions->Insert(-1, a);
6074 		break;
6075 
6076 	case as::NODE_SHIFT_LEFT:
6077 		Expression(expr.GetChild(0));
6078 		Expression(expr.GetChild(1));
6079 		a = new Action(f_tag, Action::ACTION_SHIFT_LEFT);
6080 		f_actions->Insert(-1, a);
6081 		break;
6082 
6083 	case as::NODE_SHIFT_RIGHT:
6084 		Expression(expr.GetChild(0));
6085 		Expression(expr.GetChild(1));
6086 		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT);
6087 		f_actions->Insert(-1, a);
6088 		break;
6089 
6090 	case as::NODE_SHIFT_RIGHT_UNSIGNED:
6091 		Expression(expr.GetChild(0));
6092 		Expression(expr.GetChild(1));
6093 		a = new Action(f_tag, Action::ACTION_SHIFT_RIGHT_UNSIGNED);
6094 		f_actions->Insert(-1, a);
6095 		break;
6096 
6097 	case as::NODE_STRICTLY_EQUAL:
6098 		Expression(expr.GetChild(0));
6099 		Expression(expr.GetChild(1));
6100 		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
6101 		f_actions->Insert(-1, a);
6102 		break;
6103 
6104 	case as::NODE_STRICTLY_NOT_EQUAL:
6105 		Expression(expr.GetChild(0));
6106 		Expression(expr.GetChild(1));
6107 		a = new Action(f_tag, Action::ACTION_STRICT_EQUAL);
6108 		f_actions->Insert(-1, a);
6109 		a = new Action(f_tag, Action::ACTION_LOGICAL_NOT);
6110 		f_actions->Insert(-1, a);
6111 		break;
6112 
6113 	case as::NODE_NEW:
6114 		ExpressionNew(expr.GetChild(0));
6115 		break;
6116 
6117 	case as::NODE_DELETE:
6118 		ExpressionDelete(expr.GetChild(0));
6119 		break;
6120 
6121 	case as::NODE_ASSIGNMENT:
6122 	case as::NODE_ASSIGNMENT_BITWISE_AND:
6123 	case as::NODE_ASSIGNMENT_BITWISE_OR:
6124 	case as::NODE_ASSIGNMENT_BITWISE_XOR:
6125 	case as::NODE_ASSIGNMENT_DIVIDE:
6126 	case as::NODE_ASSIGNMENT_LOGICAL_AND:
6127 	case as::NODE_ASSIGNMENT_LOGICAL_OR:
6128 	case as::NODE_ASSIGNMENT_LOGICAL_XOR:
6129 	case as::NODE_ASSIGNMENT_MAXIMUM:
6130 	case as::NODE_ASSIGNMENT_MINIMUM:
6131 	case as::NODE_ASSIGNMENT_MODULO:
6132 	case as::NODE_ASSIGNMENT_MULTIPLY:
6133 	case as::NODE_ASSIGNMENT_ROTATE_LEFT:
6134 	case as::NODE_ASSIGNMENT_ROTATE_RIGHT:
6135 	case as::NODE_ASSIGNMENT_SHIFT_LEFT:
6136 	case as::NODE_ASSIGNMENT_SHIFT_RIGHT:
6137 	case as::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
6138 		ExpressionAssignment(expr, data.f_type);
6139 		break;
6140 
6141 	case as::NODE_ASSIGNMENT_ADD:
6142 		ExpressionAssignmentAdd(expr);
6143 		break;
6144 
6145 	case as::NODE_ASSIGNMENT_SUBTRACT:
6146 		ExpressionAssignmentSubtract(expr);
6147 		break;
6148 
6149 	case as::NODE_ASSIGNMENT_POWER:
6150 		ExpressionAssignmentPower(expr);
6151 		break;
6152 
6153 	case as::NODE_AUTO:
6154 	{
6155 		// function parameters auto-assignment of undefined entries
6156 		as::NodePtr& auto_expr = expr.GetLink(as::NodePtr::LINK_INSTANCE);
6157 		Expression(auto_expr);
6158 	}
6159 		break;
6160 
6161 	case as::NODE_AS:
6162 		ExpressionAs(expr);
6163 		break;
6164 
6165 	case as::NODE_LIST:
6166 		ExpressionList(expr);
6167 		break;
6168 
6169 	case as::NODE_RANGE:
6170 	case as::NODE_MATCH:
6171 	default:
6172 		f_error_stream->ErrMsg(as::AS_ERR_NOT_SUPPORTED, expr, "expression type (%d) not yet implemented in IntAssembler::Expression().", data.f_type);
6173 		break;
6174 
6175 	}
6176 }
6177 
6178 
6179 
6180 
6181 //**********************************************************************
6182 //***  REGISTERS STACK  ************************************************
6183 //**********************************************************************
Registers(void)6184 IntAssembler::Registers::Registers(void)
6185 {
6186 	f_previous = 0;
6187 
6188 	f_reg = 4;
6189 	f_reg_max = 4;		// in a function it goes to 254 (v7)
6190 	memset(f_regs, 0, sizeof(f_regs));
6191 }
6192 
Registers(const Registers & src)6193 IntAssembler::Registers::Registers(const Registers& src)
6194 {
6195 	f_previous = src.f_previous;
6196 
6197 	f_reg = src.f_reg;
6198 	f_reg_max = src.f_reg_max;
6199 	memcpy(f_regs, src.f_regs, sizeof(f_regs));
6200 }
6201 
~Registers()6202 IntAssembler::Registers::~Registers()
6203 {
6204 	if(f_previous) {
6205 		delete f_previous;
6206 	}
6207 }
6208 
Push(int max)6209 void IntAssembler::Registers::Push(int max)
6210 {
6211 	f_previous = new Registers(*this);
6212 
6213 	f_reg = max;
6214 	f_reg_max = max;
6215 	memset(f_regs, 0, sizeof(f_regs));
6216 }
6217 
Pop(void)6218 void IntAssembler::Registers::Pop(void)
6219 {
6220 	Registers *p = f_previous;
6221 
6222 	AS_ASSERT(p != 0);
6223 
6224 	f_reg = p->f_reg;
6225 	f_reg_max = p->f_reg_max;
6226 	memcpy(f_regs, p->f_regs, sizeof(f_regs));
6227 	f_previous = p->f_previous;
6228 
6229 	p->f_previous = 0;
6230 	delete p;
6231 }
6232 
AllocRegister(int start)6233 int IntAssembler::Registers::AllocRegister(int start)
6234 {
6235 	int		r;
6236 
6237 	for(r = start; r < f_reg_max; ++r) {
6238 		if(f_regs[r] == 0) {
6239 			f_regs[r] = 1;
6240 			return r;
6241 		}
6242 	}
6243 
6244 	return -1;
6245 }
6246 
Store(int r,TagBase * f_tag,Vectors * f_actions,bool pop)6247 void IntAssembler::Registers::Store(int r, TagBase *f_tag, Vectors *f_actions, bool pop)
6248 {
6249 	ActionStoreRegister	*store_register;
6250 	Action			*a;
6251 
6252 	store_register = new ActionStoreRegister(f_tag);
6253 	store_register->SetRegister(r);
6254 	f_actions->Insert(-1, store_register);
6255 
6256 	if(pop) {
6257 		a = new Action(f_tag, Action::ACTION_POP);
6258 		f_actions->Insert(-1, a);
6259 	}
6260 }
6261 
StoreRegister(TagBase * f_tag,Vectors * f_actions,bool pop)6262 int IntAssembler::Registers::StoreRegister(TagBase *f_tag, Vectors *f_actions, bool pop)
6263 {
6264 	ActionPushData	*pd;
6265 	Action		*a;
6266 	char		buf[256];
6267 	int		r;
6268 
6269 	r = AllocRegister();
6270 
6271 	if(r < 0) {
6272 		// f_reg starts at f_reg_max
6273 		// (i.e. 4 in a global context and 254 in a function)
6274 		r = f_reg;
6275 		f_reg++;
6276 
6277 		// the store doesn't eat the input, a set var does
6278 		if(!pop) {
6279 			a = new Action(f_tag, Action::ACTION_DUPLICATE);
6280 			f_actions->Insert(-1, a);
6281 		}
6282 
6283 		// no more reg available, use a temporary variable
6284 		snprintf(buf, sizeof(buf), "__t%d", r);
6285 		pd = new ActionPushData(f_tag);
6286 		pd->AddString(buf);
6287 		f_actions->Insert(-1, pd);
6288 
6289 		a = new Action(f_tag, Action::ACTION_SWAP);
6290 		f_actions->Insert(-1, a);
6291 		a = new Action(f_tag, Action::ACTION_SET_LOCAL_VARIABLE);
6292 		f_actions->Insert(-1, a);
6293 	}
6294 	else {
6295 		Store(r, f_tag, f_actions, pop);
6296 	}
6297 
6298 	return r;
6299 }
6300 
LoadRegister(int r,bool to_free,TagBase * f_tag,Vectors * f_actions)6301 void IntAssembler::Registers::LoadRegister(int r, bool to_free, TagBase *f_tag, Vectors *f_actions)
6302 {
6303 	ActionPushData	*pd;
6304 	Action		*a;
6305 	char		buf[256];
6306 
6307 	// the load does the equivalent to a push data from a register
6308 	if(r >= f_reg_max) {
6309 		// if we are releasing the last register allocated
6310 		// we can get it back so as to reuse it!
6311 		if(r == f_reg - 1 && to_free) {
6312 			--f_reg;
6313 		}
6314 
6315 		// load the temporary variable
6316 		snprintf(buf, sizeof(buf), "__t%d", r);
6317 		pd = new ActionPushData(f_tag);
6318 		pd->AddString(buf);
6319 		f_actions->Insert(-1, pd);
6320 
6321 		a = new Action(f_tag, Action::ACTION_GET_VARIABLE);
6322 		f_actions->Insert(-1, a);
6323 	}
6324 	else {
6325 		pd = new ActionPushData(f_tag);
6326 		pd->AddRegister(r);
6327 		f_actions->Insert(-1, pd);
6328 
6329 		if(to_free) {
6330 			f_regs[r] = 0;
6331 		}
6332 	}
6333 }
6334 
FreeRegister(int r)6335 void IntAssembler::Registers::FreeRegister(int r)
6336 {
6337 	// the load does the equivalent to a push data from a register
6338 	if(r >= f_reg_max) {
6339 		// if we are releasing the last register allocated
6340 		// we can get it back so as to reuse it!
6341 		if(r == f_reg - 1) {
6342 			--f_reg;
6343 		}
6344 	}
6345 	else if(r >= 0) {
6346 		f_regs[r] = 0;
6347 	}
6348 }
6349 
6350 
6351 
6352 //**********************************************************************
6353 //***  VARIABLE DATA  **************************************************
6354 //**********************************************************************
6355 int IntAssembler::VariableData::g_unique;
6356 
GenerateName(const char * introducer)6357 void IntAssembler::VariableData::GenerateName(const char *introducer)
6358 {
6359 	char		buf[256];
6360 
6361 	g_unique++;
6362 	snprintf(buf, sizeof(buf) - 1, "%s%d", introducer, g_unique);
6363 	buf[sizeof(buf) - 1] = '\0';
6364 
6365 	f_mode = MODE_VARIABLE;
6366 	f_name = buf;
6367 }
6368 
6369 
6370 
6371 };	// namespace asas
6372 };	// namespace sswf
6373