Bug 623379: runtests: Check for java binary before asc invokes (r=fklockii)
[tamarin-stm.git] / eval / eval-cogen-expr.cpp
blob7c42cb163d5f62c3ec919b4379fc55d58c971bd7
1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2008
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Adobe AS3 Team
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "avmplus.h"
42 #ifdef VMCFG_EVAL
44 #include "eval.h"
46 namespace avmplus
48 namespace RTC
50 using namespace ActionBlockConstants;
52 // Abstracts the name computation. For stack allocation.
54 class Name {
55 public:
56 Name(Cogen* cogen, Ctx* ctx, Expr* expr, bool strict);
57 Name(Cogen* cogen, Ctx* ctx, QualifiedName* name);
58 ~Name();
60 void setup();
62 Cogen * const cogen;
63 uint32_t nsreg;
64 uint32_t namereg;
65 uint32_t sym;
67 private:
68 void computeName(QualifiedName* qname, Ctx* ctx);
71 // Compute the base object (on the stack) and the name information.
72 Name::Name(Cogen* cogen, Ctx* ctx, Expr* expr, bool strict)
73 : cogen(cogen)
74 , nsreg(0)
75 , namereg(0)
77 Tag tag = expr->tag();
78 AvmAssert( tag == TAG_objectRef || tag == TAG_qualifiedName );
79 if (tag == TAG_objectRef)
80 ((ObjectRef*)expr)->obj->cogen(cogen, ctx);
81 computeName((tag == TAG_objectRef ? ((ObjectRef*)expr)->name : (QualifiedName*)expr), ctx);
82 if (tag == TAG_qualifiedName) {
83 if (strict)
84 cogen->I_findpropstrict(sym);
85 else
86 cogen->I_findproperty(sym);
90 // Compute the name information.
91 Name::Name(Cogen* cogen, Ctx* ctx, QualifiedName* qname)
92 : cogen(cogen)
93 , nsreg(0)
94 , namereg(0)
96 computeName(qname, ctx);
99 // Significant performance improvements for qualified names if the namespace can be resolved at compile time.
100 // See notes in the implementation of the 'namespace' definition; the machinery has to be implemented for
101 // 'use default namespace' in any case.
103 void Name::computeName(QualifiedName* qname, Ctx* ctx)
105 Compiler* compiler = cogen->compiler;
106 bool ns_wildcard = false;
107 if (qname->qualifier != NULL) {
108 switch (qname->qualifier->tag()) {
109 case TAG_simpleName: {
110 uint32_t id = cogen->abc->addQName(compiler->NS_public,
111 cogen->emitString(((SimpleName*)(qname->qualifier))->name),
112 false);
113 nsreg = cogen->getTemp();
114 cogen->I_findpropstrict(id);
115 cogen->I_getproperty(id);
116 cogen->I_coerce(compiler->ID_Namespace);
117 cogen->I_setlocal(nsreg);
118 break;
120 case TAG_wildcardName:
121 ns_wildcard = true;
122 break;
123 default:
124 compiler->internalError(qname->pos, "QName qualifiers can't be computed names");
127 NameComponent* name = qname->name;
128 switch (name->tag()) {
129 case TAG_simpleName:
130 if (nsreg != 0) {
131 AvmAssert(!ns_wildcard);
132 sym = cogen->abc->addRTQName(cogen->emitString(((SimpleName*)name)->name),
133 qname->is_attr);
135 else {
136 VarScopeCtx* vs = ctx->findVarScope();
137 // here we either have just the public namespace, or the public namespace
138 // plus some open namespaces; in the latter case we need to generate a
139 // multiname presumably. We don't want to have to call addNsset here
140 // every time so be sure to cache the nsset for the current scope somewhere.
141 if (vs->nsset != 0 && ns_wildcard == 0 && !qname->is_attr)
142 sym = cogen->abc->addMultiname(vs->nsset,
143 cogen->emitString(((SimpleName*)name)->name),
144 false);
145 else
146 sym = cogen->abc->addQName((ns_wildcard ? 0 : compiler->NS_public),
147 cogen->emitString(((SimpleName*)name)->name),
148 qname->is_attr);
150 break;
151 case TAG_wildcardName:
152 if (nsreg != 0)
153 sym = cogen->abc->addRTQName(0, qname->is_attr);
154 else
155 sym = cogen->abc->addMultiname(compiler->NSS_public, 0, qname->is_attr);
156 break;
157 case TAG_computedName:
158 if (ns_wildcard)
159 compiler->syntaxError(qname->pos, SYNTAXERR_ILLEGAL_QNAME);
160 namereg = cogen->getTemp();
161 ((ComputedName*)name)->expr->cogen(cogen, ctx);
162 cogen->I_setlocal(namereg);
163 if (nsreg != 0)
164 sym = cogen->abc->addRTQNameL(qname->is_attr);
165 else {
166 if (qname->is_attr)
167 sym = compiler->MNL_public_attr;
168 else
169 sym = compiler->MNL_public;
171 break;
175 Name::~Name()
177 if (nsreg != 0) cogen->I_kill(nsreg);
178 if (namereg != 0) cogen->I_kill(namereg);
181 void Name::setup()
183 if (nsreg)
184 cogen->I_getlocal(nsreg);
185 if (namereg)
186 cogen->I_getlocal(namereg);
189 void QualifiedName::cogen(Cogen* cogen, Ctx* ctx)
191 (void)ctx;
192 Name n(cogen, ctx, this);
193 n.setup();
194 cogen->I_findpropstrict(n.sym);
195 n.setup();
196 cogen->I_getproperty(n.sym);
199 void ObjectRef::cogen(Cogen* cogen, Ctx* ctx)
201 obj->cogen(cogen, ctx);
202 if ((name->qualifier == NULL || name->qualifier->tag() == TAG_wildcardName) && name->name->tag() == TAG_wildcardName && !name->is_attr)
203 cogen->I_callproperty(cogen->compiler->ID_children, 0);
204 else {
205 Name n(cogen, ctx, name);
206 n.setup();
207 cogen->I_getproperty(n.sym);
211 void RefLocalExpr::cogen(Cogen* cogen, Ctx* ctx)
213 (void)ctx;
214 cogen->I_getlocal(local);
217 void ConditionalExpr::cogen(Cogen* cogen, Ctx* ctx)
219 Label* L0 = cogen->newLabel();
220 Label* L1 = cogen->newLabel();
222 e1->cogen(cogen, ctx);
223 cogen->I_iffalse(L0);
224 e2->cogen(cogen, ctx);
225 cogen->I_coerce_a();
226 cogen->I_jump(L1);
227 cogen->I_label(L0);
228 e3->cogen(cogen, ctx);
229 cogen->I_coerce_a();
230 cogen->I_label(L1);
233 void AssignExpr::cogen(Cogen* cogen, Ctx* ctx)
235 AvmAssert( lhs->tag() == TAG_objectRef || lhs->tag() == TAG_qualifiedName );
237 // Compute the object onto the stack, and elements of the name into locals if necessary
238 bool is_assign = op == OPR_assign || op == OPR_init;
239 Name n(cogen, ctx, lhs, !is_assign);
241 // Read the value if we need it
242 if (!is_assign) {
243 cogen->I_dup();
244 n.setup();
245 cogen->I_getproperty(n.sym);
248 // Compute the rhs
249 rhs->cogen(cogen, ctx);
251 // Compute the operator if we need it
252 if (!is_assign) {
253 bool isNegated;
254 cogen->I_opcode(cogen->binopToOpcode(op, &isNegated));
255 if (isNegated)
256 cogen->I_not();
259 // Perform the update and generate the result
260 uint32_t t = cogen->getTemp();
261 cogen->I_setlocal(t);
262 n.setup();
263 cogen->I_getlocal(t);
264 if (op == OPR_assign)
265 cogen->I_setproperty(n.sym);
266 else
267 cogen->I_initproperty(n.sym);
268 cogen->I_getlocal(t);
269 cogen->I_kill(t);
272 void BinaryExpr::cogen(Cogen* cogen, Ctx* ctx)
274 if (op == OPR_logicalAnd) {
275 Label* L0 = cogen->newLabel();
277 lhs->cogen(cogen, ctx);
278 cogen->I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
279 cogen->I_dup();
280 cogen->I_coerce_b();
281 cogen->I_iffalse(L0);
282 cogen->I_pop();
283 rhs->cogen(cogen, ctx);
284 cogen->I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
285 cogen->I_label(L0);
287 else if (op == OPR_logicalOr) {
288 Label* L0 = cogen->newLabel();
290 lhs->cogen(cogen, ctx);
291 cogen->I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
292 cogen->I_dup();
293 cogen->I_coerce_b();
294 cogen->I_iftrue(L0);
295 cogen->I_pop();
296 rhs->cogen(cogen, ctx);
297 cogen->I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
298 cogen->I_label(L0);
300 else if (op == OPR_comma) {
301 lhs->cogen(cogen, ctx);
302 cogen->I_pop();
303 rhs->cogen(cogen, ctx);
305 else {
306 lhs->cogen(cogen, ctx);
307 rhs->cogen(cogen, ctx);
308 bool isNegated;
309 cogen->I_opcode(cogen->binopToOpcode(op, &isNegated));
310 if (isNegated)
311 cogen->I_not();
315 void UnaryExpr::cogen(Cogen* cogen, Ctx* ctx)
317 Compiler* compiler = cogen->compiler;
318 switch (op) {
319 case OPR_delete: {
320 if (expr->tag() == TAG_qualifiedName || expr->tag() == TAG_objectRef) {
321 Name n(cogen, ctx, expr, false);
322 n.setup();
323 cogen->I_deleteproperty(n.sym);
325 else {
326 // FIXME: e4x requires that if the value computed here is an XMLList then a TypeError (ID 1119) is thrown.
327 expr->cogen(cogen, ctx);
328 cogen->I_pop();
329 cogen->I_pushtrue();
331 break;
334 case OPR_void:
335 expr->cogen(cogen, ctx);
336 cogen->I_pop();
337 cogen->I_pushundefined();
338 break;
340 case OPR_typeof:
341 if (expr->tag() == TAG_qualifiedName) {
342 Name n(cogen, ctx, (QualifiedName*)expr);
343 n.setup();
344 cogen->I_findproperty(n.sym);
345 n.setup();
346 cogen->I_getproperty(n.sym);
348 else
349 expr->cogen(cogen, ctx);
350 cogen->I_typeof();
351 break;
353 case OPR_preIncr:
354 incdec(cogen, ctx, true, true);
355 break;
357 case OPR_preDecr:
358 incdec(cogen, ctx, true, false);
359 break;
361 case OPR_postIncr:
362 incdec(cogen, ctx, false, true);
363 break;
365 case OPR_postDecr:
366 incdec(cogen, ctx, false, false);
367 break;
369 case OPR_unplus:
370 expr->cogen(cogen, ctx);
371 cogen->I_coerce_d();
372 break;
374 case OPR_unminus:
375 expr->cogen(cogen, ctx);
376 cogen->I_negate();
377 break;
379 case OPR_bitwiseNot:
380 expr->cogen(cogen, ctx);
381 cogen->I_bitnot();
382 break;
384 case OPR_not:
385 expr->cogen(cogen, ctx);
386 cogen->I_not();
387 break;
389 default:
390 compiler->internalError(pos, "Unrecognized unary operation");
394 void UnaryExpr::incdec(Cogen* cogen, Ctx* ctx, bool pre, bool inc)
396 (void)ctx;
397 Name n(cogen, ctx, expr, true);
398 cogen->I_dup();
399 n.setup();
400 cogen->I_getproperty(n.sym);
402 uint32_t t = cogen->getTemp();
404 if (pre) {
405 if (inc)
406 cogen->I_increment();
407 else
408 cogen->I_decrement();
409 cogen->I_dup();
410 cogen->I_setlocal(t);
412 else {
413 // Postfix ops return value after conversion to number.
414 cogen->I_coerce_d();
415 cogen->I_dup();
416 cogen->I_setlocal(t);
417 if (inc)
418 cogen->I_increment();
419 else
420 cogen->I_decrement();
423 n.setup();
424 cogen->I_setproperty(n.sym);
426 cogen->I_getlocal(t);
427 cogen->I_kill(t);
430 void ThisExpr::cogen(Cogen* cogen, Ctx* ctx)
432 (void)ctx;
433 cogen->I_getlocal(0);
436 void LiteralFunction::cogen(Cogen* cogen, Ctx* ctx)
438 if (function->name != NULL) {
439 // For a named function expression F with name N, create a new
440 // expression (function() { F; return N })() and generate code
441 // for that instead. Note that F then becomes a local function
442 // definition.
443 Allocator* allocator = cogen->allocator;
444 Expr* e = ALLOC(CallExpr,
445 (ALLOC(LiteralFunction,
446 (ALLOC(FunctionDefn,
447 (NULL,
448 ALLOC(Seq<Binding*>,
449 (ALLOC(Binding,
450 (function->name, NULL, TAG_varBinding)))),
451 NULL,
453 NULL,
454 NULL,
455 ALLOC(Seq<FunctionDefn*>,
456 (function)),
457 NULL,
458 NULL,
459 ALLOC(Seq<Stmt*>,
460 (ALLOC(ReturnStmt,
461 (0, ALLOC(QualifiedName,
462 (NULL, ALLOC(SimpleName,
463 (function->name)),
464 false,
465 0)))))),
466 false,
467 false,
468 false)))),
469 NULL,
470 0));
471 e->cogen(cogen, ctx);
473 else {
474 ABCMethodInfo* fn_info;
475 ABCMethodBodyInfo* fn_body;
476 function->cogenGuts(cogen->compiler, ctx, &fn_info, &fn_body);
477 cogen->I_newfunction(fn_info->index);
481 void LiteralObject::cogen(Cogen* cogen, Ctx* ctx)
483 (void)ctx;
484 uint32_t i=0;
485 for ( Seq<LiteralField*>* fields = this->fields ; fields != NULL ; fields = fields->tl ) {
486 cogen->I_pushstring(cogen->emitString(fields->hd->name));
487 fields->hd->value->cogen(cogen, ctx);
488 i++;
490 cogen->I_newobject(i);
493 void LiteralArray::cogen(Cogen* cogen, Ctx* ctx)
495 uint32_t i = 0;
496 Seq<Expr*>* exprs = elements;
497 Compiler* compiler = cogen->compiler;
499 // Use newarray to construct the dense prefix
500 for ( ; exprs != NULL ; exprs = exprs->tl ) {
501 Expr* e = exprs->hd;
502 if (e == NULL)
503 break;
504 e->cogen(cogen, ctx);
505 i++;
507 cogen->I_newarray(i);
509 // Then init the other defined slots one by one
510 if (exprs != NULL) {
511 bool last_was_undefined = false;
512 for ( ; exprs != NULL ; exprs = exprs->tl, i++ ) {
513 Expr* e = exprs->hd;
514 if (e != NULL) {
515 cogen->I_dup();
516 e->cogen(cogen, ctx);
517 cogen->I_setproperty(cogen->abc->addQName(compiler->NS_public,cogen->emitString(compiler->intern(i))));
518 last_was_undefined = false;
520 else
521 last_was_undefined = true;
523 if (last_was_undefined) {
524 cogen->I_dup();
525 cogen->I_pushint(cogen->emitInt(i));
526 cogen->I_setproperty(compiler->ID_length);
531 void LiteralRegExp::cogen(Cogen* cogen, Ctx* ctx)
533 (void)ctx;
535 Compiler* compiler = cogen->compiler;
537 // value is "/.../flags"
539 // OPTIMIZEME: silly to recompile the regular expression every time it's evaluated, even if
540 // ES3.1 allows it (not sure what AS3 allows / requires; ES3 requires compilation once).
541 const wchar* s = value->s;
542 const wchar* t = s + value->length - 1;
543 while (*t != '/')
544 t--;
546 // Creating a new RegExp object every time is not compatible with ES3, but it is
547 // what ASC does, and with luck ES3.1 will change to match this behavior.
549 // FIXME: semantics: findpropstrict(""::RegExp) is not quite right here.
550 // Doing so creates a spoofing hole / surprising trap. We want an OP_newregexp instruction.
551 cogen->I_findpropstrict(compiler->ID_RegExp);
552 cogen->I_pushstring(cogen->emitString(compiler->intern(s+1, uint32_t(t-s-1))));
553 cogen->I_pushstring(cogen->emitString(compiler->intern(t+1, uint32_t(value->length-(t-s+1)))));
554 cogen->I_constructprop(compiler->ID_RegExp, 2);
557 void LiteralNull::cogen(Cogen* cogen, Ctx* ctx)
559 (void)ctx;
560 cogen->I_pushnull();
563 void LiteralUndefined::cogen(Cogen* cogen, Ctx* ctx)
565 (void)ctx;
566 cogen->I_pushundefined();
569 void LiteralInt::cogen(Cogen* cogen, Ctx* ctx)
571 (void)ctx;
572 if (value >= -128 && value < 128)
573 cogen->I_pushbyte((uint8_t)(value & 0xFF));
574 else
575 cogen->I_pushint(cogen->emitInt(value));
578 void LiteralUInt::cogen(Cogen* cogen, Ctx* ctx)
580 (void)ctx;
581 if (value < 128)
582 cogen->I_pushbyte((uint8_t)(value & 0xFF));
583 else
584 cogen->I_pushuint(cogen->emitUInt(value));
587 void LiteralDouble::cogen(Cogen* cogen, Ctx* ctx)
589 (void)ctx;
590 if (MathUtils::isNaN(value))
591 cogen->I_pushnan();
592 else
593 cogen->I_pushdouble(cogen->emitDouble(value));
596 void LiteralBoolean::cogen(Cogen* cogen, Ctx* ctx)
598 (void)ctx;
599 if (value)
600 cogen->I_pushtrue();
601 else
602 cogen->I_pushfalse();
605 void LiteralString::cogen(Cogen* cogen, Ctx* ctx)
607 (void)ctx;
608 cogen->I_pushstring(cogen->emitString(value));
611 uint32_t Cogen::arguments(Seq<Expr*>* args, Ctx* ctx)
613 uint32_t i = 0;
614 for ( ; args != NULL ; args = args->tl, i++ )
615 args->hd->cogen(this, ctx);
616 return i;
619 void CallExpr::cogen(Cogen* cogen, Ctx* ctx)
621 switch (fn->tag()) {
622 case TAG_qualifiedName: {
623 // This code is incorrect if the name that's being referenced is
624 // bound by 'with', because in that case the binding object should be
625 // pushed as the receiver object (according to ES-262). But the AVM+
626 // does not have an instruction that performs the correct operation:
627 // callproplex passes NULL as the receiver object, while callproperty
628 // passes a non-NULL object. So in the context of a WITH we would
629 // have to simulate the correct behavior by performing a scope chain
630 // walk, querying each WITH object for the property and calling it
631 // if present, otherwise calling the function if it is lexically bound,
632 // otherwise calling the global function. ASC has the same problem
633 // (and also does not solve it), so no actual bug here, just an
634 // incompatibility.
635 Name n(cogen, ctx, fn, true);
636 n.setup();
637 cogen->I_callproplex(n.sym, cogen->arguments(arguments, ctx));
638 break;
640 case TAG_objectRef: {
641 Name n(cogen, ctx, fn, false);
642 n.setup();
643 cogen->I_callproperty(n.sym, cogen->arguments(arguments, ctx));
644 break;
646 default:
647 fn->cogen(cogen, ctx);
648 cogen->I_pushnull();
649 cogen->I_call(cogen->arguments(arguments, ctx));
653 void NewExpr::cogen(Cogen* cogen, Ctx* ctx)
655 fn->cogen(cogen, ctx);
656 cogen->I_construct(cogen->arguments(arguments, ctx));
659 void XmlInitializer::cogen(Cogen* cogen, Ctx* ctx)
661 Compiler* compiler = cogen->compiler;
662 uint32_t id = is_list ? compiler->ID_XMLList : compiler->ID_XML;
664 cogen->I_findpropstrict(id);
665 cogen->I_getproperty(id);
666 cogen->I_pushstring(cogen->emitString(compiler->SYM_));
667 for ( Seq<Expr*>* exprs = this->exprs ; exprs != NULL ; exprs = exprs->tl ) {
668 exprs->hd->cogen(cogen, ctx);
669 cogen->I_convert_s();
670 cogen->I_add();
672 #if 0 && defined DEBUG
673 cogen->I_dup();
674 cogen->I_findpropstrict(compiler->ID_print);
675 cogen->I_swap();
676 cogen->I_callpropvoid(compiler->ID_print, 1);
677 #endif
678 cogen->I_construct(1);
681 void EscapeExpr::cogen(Cogen* cogen, Ctx* ctx)
683 expr->cogen(cogen, ctx);
684 switch (esc) {
685 case ESC_attributeValue:
686 cogen->I_esc_xattr();
687 break;
688 case ESC_elementValue:
689 cogen->I_esc_xelem();
690 break;
691 default:
692 break;
696 // OPTIMIZEME? A more space-conserving method would be to pass a predicate
697 // and an object to a common filter function. But it only makes a difference
698 // if filter expressions are very common, and they probably aren't.
700 void FilterExpr::cogen(Cogen* cogen, Ctx* ctx)
702 Compiler* compiler = cogen->compiler;
703 uint32_t t_xmllist = cogen->getTemp();
704 uint32_t t_length = cogen->getTemp();
705 uint32_t t_result = cogen->getTemp();
706 uint32_t t_result_index = cogen->getTemp();
707 uint32_t t_index = cogen->getTemp();
708 uint32_t t_scope = cogen->getTemp();
709 uint32_t t_item = cogen->getTemp();
710 Label* L_again = cogen->newLabel();
711 Label* L_skip = cogen->newLabel();
712 Label* L_done = cogen->newLabel();
714 obj->cogen(cogen, ctx);
715 cogen->I_checkfilter();
717 // convert to XMLList
718 cogen->I_coerce_a();
719 cogen->I_setlocal(t_xmllist);
720 cogen->I_findpropstrict(compiler->ID_XMLList);
721 cogen->I_getproperty(compiler->ID_XMLList);
722 cogen->I_pushnull();
723 cogen->I_getlocal(t_xmllist);
724 cogen->I_call(1);
725 cogen->I_coerce_a();
726 cogen->I_setlocal(t_xmllist);
728 // get the length of the list and save it
729 cogen->I_getlocal(t_xmllist);
730 cogen->I_callproperty(compiler->ID_length, 0);
731 cogen->I_coerce_a();
732 cogen->I_setlocal(t_length);
734 // create a new, empty list for the result
735 cogen->I_findpropstrict(compiler->ID_XMLList);
736 cogen->I_getproperty(compiler->ID_XMLList);
737 cogen->I_construct(0);
738 cogen->I_coerce_a();
739 cogen->I_setlocal(t_result);
740 cogen->I_pushbyte(0);
741 cogen->I_setlocal(t_result_index);
743 // set up loop
744 cogen->I_pushbyte(0);
745 cogen->I_setlocal(t_index);
747 // iterate across the list
748 cogen->I_label(L_again);
750 // while index < length
751 cogen->I_getlocal(t_index);
752 cogen->I_getlocal(t_length);
753 cogen->I_ifge(L_done);
755 // item := list[index]
756 cogen->I_getlocal(t_xmllist);
757 cogen->I_getlocal(t_index);
758 cogen->I_getproperty(compiler->MNL_public);
759 cogen->I_coerce_a();
760 cogen->I_setlocal(t_item);
762 // with (item) b := <filter>
763 cogen->I_getlocal(t_item);
764 cogen->I_pushwith();
765 filter->cogen(cogen, ctx);
766 cogen->I_popscope();
768 // if b result += item
769 cogen->I_iffalse(L_skip);
770 // Add it
771 cogen->I_getlocal(t_result);
772 cogen->I_getlocal(t_result_index);
773 cogen->I_getlocal(t_item);
774 cogen->I_setproperty(compiler->MNL_public);
775 cogen->I_inclocal_i(t_result_index);
777 cogen->I_label(L_skip);
779 // index++;
780 cogen->I_inclocal_i(t_index);
781 cogen->I_jump(L_again);
783 // post-loop
784 cogen->I_label(L_done);
785 cogen->I_getlocal(t_result);
786 cogen->I_kill(t_xmllist);
787 cogen->I_kill(t_length);
788 cogen->I_kill(t_result);
789 cogen->I_kill(t_result_index);
790 cogen->I_kill(t_index);
791 cogen->I_kill(t_scope);
792 cogen->I_kill(t_item);
795 void DescendantsExpr::cogen(Cogen* cogen, Ctx* ctx)
797 obj->cogen(cogen, ctx);
798 Name n(cogen, ctx, name);
799 n.setup();
800 cogen->I_getdescendants(n.sym);
803 void SuperExpr::cogen(Cogen* cogen, Ctx* ctx)
805 (void)ctx;
806 Compiler* compiler = cogen->compiler;
807 compiler->internalError(pos, "Unimplemented: superExpr");
812 #endif // VMCFG_EVAL