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