vbscript: Added while..wend statement implementation.
[wine] / dlls / vbscript / compile.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22 #include "parse.h"
23 #include "parser.tab.h"
24
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
28 WINE_DECLARE_DEBUG_CHANNEL(vbscript_disas);
29
30 typedef struct {
31     parser_ctx_t parser;
32
33     unsigned instr_cnt;
34     unsigned instr_size;
35     vbscode_t *code;
36
37     unsigned *labels;
38     unsigned labels_size;
39     unsigned labels_cnt;
40
41     unsigned sub_end_label;
42     unsigned func_end_label;
43     unsigned prop_end_label;
44
45     dim_decl_t *dim_decls;
46     dynamic_var_t *global_vars;
47
48     function_t *func;
49     function_t *funcs;
50     function_decl_t *func_decls;
51
52     class_desc_t *classes;
53 } compile_ctx_t;
54
55 static HRESULT compile_expression(compile_ctx_t*,expression_t*);
56 static HRESULT compile_statement(compile_ctx_t*,statement_t*);
57
58 static const struct {
59     const char *op_str;
60     instr_arg_type_t arg1_type;
61     instr_arg_type_t arg2_type;
62 } instr_info[] = {
63 #define X(n,a,b,c) {#n,b,c},
64 OP_LIST
65 #undef X
66 };
67
68 static void dump_instr_arg(instr_arg_type_t type, instr_arg_t *arg)
69 {
70     switch(type) {
71     case ARG_STR:
72     case ARG_BSTR:
73         TRACE_(vbscript_disas)("\t%s", debugstr_w(arg->str));
74         break;
75     case ARG_INT:
76         TRACE_(vbscript_disas)("\t%d", arg->uint);
77         break;
78     case ARG_UINT:
79     case ARG_ADDR:
80         TRACE_(vbscript_disas)("\t%u", arg->uint);
81         break;
82     case ARG_DOUBLE:
83         TRACE_(vbscript_disas)("\t%lf", *arg->dbl);
84         break;
85     case ARG_NONE:
86         break;
87     default:
88         assert(0);
89     }
90 }
91
92 static void dump_code(compile_ctx_t *ctx)
93 {
94     instr_t *instr;
95
96     for(instr = ctx->code->instrs; instr < ctx->code->instrs+ctx->instr_cnt; instr++) {
97         TRACE_(vbscript_disas)("%d:\t%s", instr-ctx->code->instrs, instr_info[instr->op].op_str);
98         dump_instr_arg(instr_info[instr->op].arg1_type, &instr->arg1);
99         dump_instr_arg(instr_info[instr->op].arg2_type, &instr->arg2);
100         TRACE_(vbscript_disas)("\n");
101     }
102 }
103
104 static inline void *compiler_alloc(vbscode_t *vbscode, size_t size)
105 {
106     return vbsheap_alloc(&vbscode->heap, size);
107 }
108
109 static WCHAR *compiler_alloc_string(vbscode_t *vbscode, const WCHAR *str)
110 {
111     size_t size;
112     WCHAR *ret;
113
114     size = (strlenW(str)+1)*sizeof(WCHAR);
115     ret = compiler_alloc(vbscode, size);
116     if(ret)
117         memcpy(ret, str, size);
118     return ret;
119 }
120
121 static inline instr_t *instr_ptr(compile_ctx_t *ctx, unsigned id)
122 {
123     assert(id < ctx->instr_cnt);
124     return ctx->code->instrs + id;
125 }
126
127 static unsigned push_instr(compile_ctx_t *ctx, vbsop_t op)
128 {
129     assert(ctx->instr_size && ctx->instr_size >= ctx->instr_cnt);
130
131     if(ctx->instr_size == ctx->instr_cnt) {
132         instr_t *new_instr;
133
134         new_instr = heap_realloc(ctx->code->instrs, ctx->instr_size*2*sizeof(instr_t));
135         if(!new_instr)
136             return -1;
137
138         ctx->code->instrs = new_instr;
139         ctx->instr_size *= 2;
140     }
141
142     ctx->code->instrs[ctx->instr_cnt].op = op;
143     return ctx->instr_cnt++;
144 }
145
146 static HRESULT push_instr_int(compile_ctx_t *ctx, vbsop_t op, LONG arg)
147 {
148     unsigned ret;
149
150     ret = push_instr(ctx, op);
151     if(ret == -1)
152         return E_OUTOFMEMORY;
153
154     instr_ptr(ctx, ret)->arg1.lng = arg;
155     return S_OK;
156 }
157
158 static HRESULT push_instr_addr(compile_ctx_t *ctx, vbsop_t op, unsigned arg)
159 {
160     unsigned ret;
161
162     ret = push_instr(ctx, op);
163     if(ret == -1)
164         return E_OUTOFMEMORY;
165
166     instr_ptr(ctx, ret)->arg1.uint = arg;
167     return S_OK;
168 }
169
170 static HRESULT push_instr_str(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg)
171 {
172     unsigned instr;
173     WCHAR *str;
174
175     str = compiler_alloc_string(ctx->code, arg);
176     if(!str)
177         return E_OUTOFMEMORY;
178
179     instr = push_instr(ctx, op);
180     if(instr == -1)
181         return E_OUTOFMEMORY;
182
183     instr_ptr(ctx, instr)->arg1.str = str;
184     return S_OK;
185 }
186
187 static HRESULT push_instr_double(compile_ctx_t *ctx, vbsop_t op, double arg)
188 {
189     unsigned instr;
190     double *d;
191
192     d = compiler_alloc(ctx->code, sizeof(double));
193     if(!d)
194         return E_OUTOFMEMORY;
195
196     instr = push_instr(ctx, op);
197     if(instr == -1)
198         return E_OUTOFMEMORY;
199
200     *d = arg;
201     instr_ptr(ctx, instr)->arg1.dbl = d;
202     return S_OK;
203 }
204
205 static BSTR alloc_bstr_arg(compile_ctx_t *ctx, const WCHAR *str)
206 {
207     if(!ctx->code->bstr_pool_size) {
208         ctx->code->bstr_pool = heap_alloc(8 * sizeof(BSTR));
209         if(!ctx->code->bstr_pool)
210             return NULL;
211         ctx->code->bstr_pool_size = 8;
212     }else if(ctx->code->bstr_pool_size == ctx->code->bstr_cnt) {
213        BSTR *new_pool;
214
215         new_pool = heap_realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR));
216         if(!new_pool)
217             return NULL;
218
219         ctx->code->bstr_pool = new_pool;
220         ctx->code->bstr_pool_size *= 2;
221     }
222
223     ctx->code->bstr_pool[ctx->code->bstr_cnt] = SysAllocString(str);
224     if(!ctx->code->bstr_pool[ctx->code->bstr_cnt])
225         return NULL;
226
227     return ctx->code->bstr_pool[ctx->code->bstr_cnt++];
228 }
229
230 static HRESULT push_instr_bstr(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg)
231 {
232     unsigned instr;
233     BSTR bstr;
234
235     bstr = alloc_bstr_arg(ctx, arg);
236     if(!bstr)
237         return E_OUTOFMEMORY;
238
239     instr = push_instr(ctx, op);
240     if(instr == -1)
241         return E_OUTOFMEMORY;
242
243     instr_ptr(ctx, instr)->arg1.bstr = bstr;
244     return S_OK;
245 }
246
247 static HRESULT push_instr_bstr_uint(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg1, unsigned arg2)
248 {
249     unsigned instr;
250     BSTR bstr;
251
252     bstr = alloc_bstr_arg(ctx, arg1);
253     if(!bstr)
254         return E_OUTOFMEMORY;
255
256     instr = push_instr(ctx, op);
257     if(instr == -1)
258         return E_OUTOFMEMORY;
259
260     instr_ptr(ctx, instr)->arg1.bstr = bstr;
261     instr_ptr(ctx, instr)->arg2.uint = arg2;
262     return S_OK;
263 }
264
265 #define LABEL_FLAG 0x80000000
266
267 static unsigned alloc_label(compile_ctx_t *ctx)
268 {
269     if(!ctx->labels_size) {
270         ctx->labels = heap_alloc(8 * sizeof(*ctx->labels));
271         if(!ctx->labels)
272             return -1;
273         ctx->labels_size = 8;
274     }else if(ctx->labels_size == ctx->labels_cnt) {
275         unsigned *new_labels;
276
277         new_labels = heap_realloc(ctx->labels, 2*ctx->labels_size*sizeof(*ctx->labels));
278         if(!new_labels)
279             return -1;
280
281         ctx->labels = new_labels;
282         ctx->labels_size *= 2;
283     }
284
285     return ctx->labels_cnt++ | LABEL_FLAG;
286 }
287
288 static inline void label_set_addr(compile_ctx_t *ctx, unsigned label)
289 {
290     assert(label & LABEL_FLAG);
291     ctx->labels[label & ~LABEL_FLAG] = ctx->instr_cnt;
292 }
293
294 static HRESULT compile_args(compile_ctx_t *ctx, expression_t *args, unsigned *ret)
295 {
296     unsigned arg_cnt = 0;
297     HRESULT hres;
298
299     while(args) {
300         hres = compile_expression(ctx, args);
301         if(FAILED(hres))
302             return hres;
303
304         arg_cnt++;
305         args = args->next;
306     }
307
308     *ret = arg_cnt;
309     return S_OK;
310 }
311
312 static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t *expr, BOOL ret_val)
313 {
314     unsigned arg_cnt = 0;
315     HRESULT hres;
316
317     hres = compile_args(ctx, expr->args, &arg_cnt);
318     if(FAILED(hres))
319         return hres;
320
321     if(expr->obj_expr) {
322         hres = compile_expression(ctx, expr->obj_expr);
323         if(FAILED(hres))
324             return hres;
325
326         hres = push_instr_bstr_uint(ctx, ret_val ? OP_mcall : OP_mcallv, expr->identifier, arg_cnt);
327     }else {
328         hres = push_instr_bstr_uint(ctx, ret_val ? OP_icall : OP_icallv, expr->identifier, arg_cnt);
329     }
330
331     return hres;
332 }
333
334 static HRESULT compile_unary_expression(compile_ctx_t *ctx, unary_expression_t *expr, vbsop_t op)
335 {
336     HRESULT hres;
337
338     hres = compile_expression(ctx, expr->subexpr);
339     if(FAILED(hres))
340         return hres;
341
342     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
343 }
344
345 static HRESULT compile_binary_expression(compile_ctx_t *ctx, binary_expression_t *expr, vbsop_t op)
346 {
347     HRESULT hres;
348
349     hres = compile_expression(ctx, expr->left);
350     if(FAILED(hres))
351         return hres;
352
353     hres = compile_expression(ctx, expr->right);
354     if(FAILED(hres))
355         return hres;
356
357     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
358 }
359
360 static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr)
361 {
362     switch(expr->type) {
363     case EXPR_ADD:
364         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_add);
365     case EXPR_AND:
366         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_and);
367     case EXPR_BOOL:
368         return push_instr_int(ctx, OP_bool, ((bool_expression_t*)expr)->value);
369     case EXPR_CONCAT:
370         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_concat);
371     case EXPR_DIV:
372         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_div);
373     case EXPR_DOUBLE:
374         return push_instr_double(ctx, OP_double, ((double_expression_t*)expr)->value);
375     case EXPR_EMPTY:
376         return push_instr(ctx, OP_empty) != -1 ? S_OK : E_OUTOFMEMORY;
377     case EXPR_EQUAL:
378         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_equal);
379     case EXPR_EQV:
380         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_eqv);
381     case EXPR_EXP:
382         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_exp);
383     case EXPR_IDIV:
384         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_idiv);
385     case EXPR_IMP:
386         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_imp);
387     case EXPR_MEMBER:
388         return compile_member_expression(ctx, (member_expression_t*)expr, TRUE);
389     case EXPR_MOD:
390         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mod);
391     case EXPR_MUL:
392         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mul);
393     case EXPR_NEG:
394         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_neg);
395     case EXPR_NEQUAL:
396         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_nequal);
397     case EXPR_NEW:
398         return push_instr_str(ctx, OP_new, ((string_expression_t*)expr)->value);
399     case EXPR_NOT:
400         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_not);
401     case EXPR_NOTHING:
402         return push_instr(ctx, OP_nothing) != -1 ? S_OK : E_OUTOFMEMORY;
403     case EXPR_NULL:
404         return push_instr(ctx, OP_null) != -1 ? S_OK : E_OUTOFMEMORY;
405     case EXPR_OR:
406         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_or);
407     case EXPR_STRING:
408         return push_instr_str(ctx, OP_string, ((string_expression_t*)expr)->value);
409     case EXPR_SUB:
410         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_sub);
411     case EXPR_USHORT:
412         return push_instr_int(ctx, OP_short, ((int_expression_t*)expr)->value);
413     case EXPR_ULONG:
414         return push_instr_int(ctx, OP_long, ((int_expression_t*)expr)->value);
415     case EXPR_XOR:
416         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_xor);
417     default:
418         FIXME("Unimplemented expression type %d\n", expr->type);
419         return E_NOTIMPL;
420     }
421
422     return S_OK;
423 }
424
425 static HRESULT compile_if_statement(compile_ctx_t *ctx, if_statement_t *stat)
426 {
427     unsigned cnd_jmp, endif_label = -1;
428     elseif_decl_t *elseif_decl;
429     HRESULT hres;
430
431     hres = compile_expression(ctx, stat->expr);
432     if(FAILED(hres))
433         return hres;
434
435     cnd_jmp = push_instr(ctx, OP_jmp_false);
436     if(cnd_jmp == -1)
437         return E_OUTOFMEMORY;
438
439     hres = compile_statement(ctx, stat->if_stat);
440     if(FAILED(hres))
441         return hres;
442
443     if(stat->else_stat || stat->elseifs) {
444         endif_label = alloc_label(ctx);
445         if(endif_label == -1)
446             return E_OUTOFMEMORY;
447
448         hres = push_instr_addr(ctx, OP_jmp, endif_label);
449         if(FAILED(hres))
450             return hres;
451     }
452
453     for(elseif_decl = stat->elseifs; elseif_decl; elseif_decl = elseif_decl->next) {
454         instr_ptr(ctx, cnd_jmp)->arg1.uint = ctx->instr_cnt;
455
456         hres = compile_expression(ctx, elseif_decl->expr);
457         if(FAILED(hres))
458             return hres;
459
460         cnd_jmp = push_instr(ctx, OP_jmp_false);
461         if(cnd_jmp == -1)
462             return E_OUTOFMEMORY;
463
464         hres = compile_statement(ctx, elseif_decl->stat);
465         if(FAILED(hres))
466             return hres;
467
468         hres = push_instr_addr(ctx, OP_jmp, endif_label);
469         if(FAILED(hres))
470             return hres;
471     }
472
473     instr_ptr(ctx, cnd_jmp)->arg1.uint = ctx->instr_cnt;
474
475     if(stat->else_stat) {
476         hres = compile_statement(ctx, stat->else_stat);
477         if(FAILED(hres))
478             return hres;
479     }
480
481     if(endif_label != -1)
482         label_set_addr(ctx, endif_label);
483     return S_OK;
484 }
485
486 static HRESULT compile_while_statement(compile_ctx_t *ctx, while_statement_t *stat)
487 {
488     unsigned start_addr;
489     unsigned jmp_end;
490     HRESULT hres;
491
492     start_addr = ctx->instr_cnt;
493
494     hres = compile_expression(ctx, stat->expr);
495     if(FAILED(hres))
496         return hres;
497
498     jmp_end = push_instr(ctx, OP_jmp_false);
499     if(jmp_end == -1)
500         return E_OUTOFMEMORY;
501
502     hres = compile_statement(ctx, stat->body);
503     if(FAILED(hres))
504         return hres;
505
506     hres = push_instr_addr(ctx, OP_jmp, start_addr);
507     if(FAILED(hres))
508         return hres;
509
510     instr_ptr(ctx, jmp_end)->arg1.uint = ctx->instr_cnt;
511     return S_OK;
512 }
513
514 static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *stat, BOOL is_set)
515 {
516     HRESULT hres;
517
518     hres = compile_expression(ctx, stat->value_expr);
519     if(FAILED(hres))
520         return hres;
521
522     if(stat->member_expr->args) {
523         FIXME("arguments support not implemented\n");
524         return E_NOTIMPL;
525     }
526
527     if(stat->member_expr->obj_expr) {
528         hres = compile_expression(ctx, stat->member_expr->obj_expr);
529         if(FAILED(hres))
530             return hres;
531
532         hres = push_instr_bstr(ctx, is_set ? OP_set_member : OP_assign_member, stat->member_expr->identifier);
533     }else {
534         hres = push_instr_bstr(ctx, is_set ? OP_set_ident : OP_assign_ident, stat->member_expr->identifier);
535     }
536
537     return hres;
538 }
539
540 static BOOL lookup_dim_decls(compile_ctx_t *ctx, const WCHAR *name)
541 {
542     dim_decl_t *dim_decl;
543
544     for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
545         if(!strcmpiW(dim_decl->name, name))
546             return TRUE;
547     }
548
549     return FALSE;
550 }
551
552 static BOOL lookup_args_name(compile_ctx_t *ctx, const WCHAR *name)
553 {
554     unsigned i;
555
556     for(i = 0; i < ctx->func->arg_cnt; i++) {
557         if(!strcmpiW(ctx->func->args[i].name, name))
558             return TRUE;
559     }
560
561     return FALSE;
562 }
563
564 static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat)
565 {
566     dim_decl_t *dim_decl = stat->dim_decls;
567
568     while(1) {
569         if(lookup_dim_decls(ctx, dim_decl->name) || lookup_args_name(ctx, dim_decl->name)) {
570             FIXME("dim %s name redefined\n", debugstr_w(dim_decl->name));
571             return E_FAIL;
572         }
573
574         if(!dim_decl->next)
575             break;
576         dim_decl = dim_decl->next;
577     }
578
579     dim_decl->next = ctx->dim_decls;
580     ctx->dim_decls = stat->dim_decls;
581     ctx->func->var_cnt++;
582     return S_OK;
583 }
584
585 static HRESULT compile_function_statement(compile_ctx_t *ctx, function_statement_t *stat)
586 {
587     if(ctx->func != &ctx->code->global_code) {
588         FIXME("Function is not in the global code\n");
589         return E_FAIL;
590     }
591
592     stat->func_decl->next = ctx->func_decls;
593     ctx->func_decls = stat->func_decl;
594     return S_OK;
595 }
596
597 static HRESULT compile_exitsub_statement(compile_ctx_t *ctx)
598 {
599     if(ctx->sub_end_label == -1) {
600         FIXME("Exit Sub outside Sub?\n");
601         return E_FAIL;
602     }
603
604     return push_instr_addr(ctx, OP_jmp, ctx->sub_end_label);
605 }
606
607 static HRESULT compile_exitfunc_statement(compile_ctx_t *ctx)
608 {
609     if(ctx->func_end_label == -1) {
610         FIXME("Exit Function outside Function?\n");
611         return E_FAIL;
612     }
613
614     return push_instr_addr(ctx, OP_jmp, ctx->func_end_label);
615 }
616
617 static HRESULT compile_exitprop_statement(compile_ctx_t *ctx)
618 {
619     if(ctx->prop_end_label == -1) {
620         FIXME("Exit Property outside Property?\n");
621         return E_FAIL;
622     }
623
624     return push_instr_addr(ctx, OP_jmp, ctx->prop_end_label);
625 }
626
627 static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
628 {
629     HRESULT hres;
630
631     while(stat) {
632         switch(stat->type) {
633         case STAT_ASSIGN:
634             hres = compile_assign_statement(ctx, (assign_statement_t*)stat, FALSE);
635             break;
636         case STAT_CALL:
637             hres = compile_member_expression(ctx, ((call_statement_t*)stat)->expr, FALSE);
638             break;
639         case STAT_DIM:
640             hres = compile_dim_statement(ctx, (dim_statement_t*)stat);
641             break;
642         case STAT_EXITFUNC:
643             hres = compile_exitfunc_statement(ctx);
644             break;
645         case STAT_EXITPROP:
646             hres = compile_exitprop_statement(ctx);
647             break;
648         case STAT_EXITSUB:
649             hres = compile_exitsub_statement(ctx);
650             break;
651         case STAT_FUNC:
652             hres = compile_function_statement(ctx, (function_statement_t*)stat);
653             break;
654         case STAT_IF:
655             hres = compile_if_statement(ctx, (if_statement_t*)stat);
656             break;
657         case STAT_SET:
658             hres = compile_assign_statement(ctx, (assign_statement_t*)stat, TRUE);
659             break;
660         case STAT_STOP:
661             hres = push_instr(ctx, OP_stop) == -1 ? E_OUTOFMEMORY : S_OK;
662             break;
663         case STAT_WHILE:
664             hres = compile_while_statement(ctx, (while_statement_t*)stat);
665             break;
666         default:
667             FIXME("Unimplemented statement type %d\n", stat->type);
668             hres = E_NOTIMPL;
669         }
670
671         if(FAILED(hres))
672             return hres;
673         stat = stat->next;
674     }
675
676     return S_OK;
677 }
678
679 static void resolve_labels(compile_ctx_t *ctx, unsigned off)
680 {
681     instr_t *instr;
682
683     for(instr = ctx->code->instrs+off; instr < ctx->code->instrs+ctx->instr_cnt; instr++) {
684         if(instr_info[instr->op].arg1_type == ARG_ADDR && (instr->arg1.uint & LABEL_FLAG)) {
685             assert((instr->arg1.uint & ~LABEL_FLAG) < ctx->labels_cnt);
686             instr->arg1.uint = ctx->labels[instr->arg1.uint & ~LABEL_FLAG];
687         }
688         assert(instr_info[instr->op].arg2_type != ARG_ADDR);
689     }
690
691     ctx->labels_cnt = 0;
692 }
693
694 static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *func)
695 {
696     HRESULT hres;
697
698     func->code_off = ctx->instr_cnt;
699
700     ctx->sub_end_label = -1;
701     ctx->func_end_label = -1;
702     ctx->prop_end_label = -1;
703
704     switch(func->type) {
705     case FUNC_FUNCTION:
706         ctx->func_end_label = alloc_label(ctx);
707         if(ctx->func_end_label == -1)
708             return E_OUTOFMEMORY; /* FIXME ! */
709         break;
710     case FUNC_SUB:
711         ctx->sub_end_label = alloc_label(ctx);
712         if(ctx->sub_end_label == -1)
713             return E_OUTOFMEMORY;
714         break;
715     case FUNC_PROPGET:
716     case FUNC_PROPLET:
717     case FUNC_PROPSET:
718     case FUNC_DEFGET:
719         ctx->prop_end_label = alloc_label(ctx);
720         if(ctx->prop_end_label == -1)
721             return E_OUTOFMEMORY;
722         break;
723     case FUNC_GLOBAL:
724         break;
725     }
726
727     ctx->func = func;
728     ctx->dim_decls = NULL;
729     hres = compile_statement(ctx, stat);
730     ctx->func = NULL;
731     if(FAILED(hres))
732         return hres;
733
734     if(ctx->sub_end_label != -1)
735         label_set_addr(ctx, ctx->sub_end_label);
736     if(ctx->func_end_label != -1)
737         label_set_addr(ctx, ctx->func_end_label);
738     if(ctx->prop_end_label != -1)
739         label_set_addr(ctx, ctx->prop_end_label);
740
741     if(push_instr(ctx, OP_ret) == -1)
742         return E_OUTOFMEMORY;
743
744     resolve_labels(ctx, func->code_off);
745
746     if(func->var_cnt) {
747         dim_decl_t *dim_decl;
748
749         if(func->type == FUNC_GLOBAL) {
750             dynamic_var_t *new_var;
751
752             func->var_cnt = 0;
753
754             for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
755                 new_var = compiler_alloc(ctx->code, sizeof(*new_var));
756                 if(!new_var)
757                     return E_OUTOFMEMORY;
758
759                 new_var->name = compiler_alloc_string(ctx->code, dim_decl->name);
760                 if(!new_var->name)
761                     return E_OUTOFMEMORY;
762
763                 V_VT(&new_var->v) = VT_EMPTY;
764
765                 new_var->next = ctx->global_vars;
766                 ctx->global_vars = new_var;
767             }
768         }else {
769             unsigned i;
770
771             func->vars = compiler_alloc(ctx->code, func->var_cnt * sizeof(var_desc_t));
772             if(!func->vars)
773                 return E_OUTOFMEMORY;
774
775             for(dim_decl = ctx->dim_decls, i=0; dim_decl; dim_decl = dim_decl->next, i++) {
776                 func->vars[i].name = compiler_alloc_string(ctx->code, dim_decl->name);
777                 if(!func->vars[i].name)
778                     return E_OUTOFMEMORY;
779             }
780
781             assert(i == func->var_cnt);
782         }
783     }
784
785     return S_OK;
786 }
787
788 static BOOL lookup_funcs_name(compile_ctx_t *ctx, const WCHAR *name)
789 {
790     function_t *iter;
791
792     for(iter = ctx->funcs; iter; iter = iter->next) {
793         if(!strcmpiW(iter->name, name))
794             return TRUE;
795     }
796
797     return FALSE;
798 }
799
800 static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, function_t **ret)
801 {
802     function_t *func;
803     HRESULT hres;
804
805     if(lookup_dim_decls(ctx, decl->name) || lookup_funcs_name(ctx, decl->name)) {
806         FIXME("%s: redefinition\n", debugstr_w(decl->name));
807         return E_FAIL;
808     }
809
810     func = compiler_alloc(ctx->code, sizeof(*func));
811     if(!func)
812         return E_OUTOFMEMORY;
813
814     func->name = compiler_alloc_string(ctx->code, decl->name);
815     if(!func->name)
816         return E_OUTOFMEMORY;
817
818     func->vars = NULL;
819     func->var_cnt = 0;
820     func->code_ctx = ctx->code;
821     func->type = decl->type;
822     func->is_public = decl->is_public;
823
824     func->arg_cnt = 0;
825     if(decl->args) {
826         arg_decl_t *arg;
827         unsigned i;
828
829         for(arg = decl->args; arg; arg = arg->next)
830             func->arg_cnt++;
831
832         func->args = compiler_alloc(ctx->code, func->arg_cnt * sizeof(arg_desc_t));
833         if(!func->args)
834             return E_OUTOFMEMORY;
835
836         for(i = 0, arg = decl->args; arg; arg = arg->next, i++) {
837             func->args[i].name = compiler_alloc_string(ctx->code, arg->name);
838             if(!func->args[i].name)
839                 return E_OUTOFMEMORY;
840             func->args[i].by_ref = arg->by_ref;
841         }
842     }else {
843         func->args = NULL;
844     }
845
846     hres = compile_func(ctx, decl->body, func);
847     if(FAILED(hres))
848         return hres;
849
850     *ret = func;
851     return S_OK;
852 }
853
854 static BOOL lookup_class_name(compile_ctx_t *ctx, const WCHAR *name)
855 {
856     class_desc_t *iter;
857
858     for(iter = ctx->classes; iter; iter = iter->next) {
859         if(!strcmpiW(iter->name, name))
860             return TRUE;
861     }
862
863     return FALSE;
864 }
865
866 static HRESULT create_class_funcprop(compile_ctx_t *ctx, function_decl_t *func_decl, vbdisp_funcprop_desc_t *desc)
867 {
868     vbdisp_invoke_type_t invoke_type;
869     function_decl_t *funcprop_decl;
870     HRESULT hres;
871
872     desc->name = compiler_alloc_string(ctx->code, func_decl->name);
873     if(!desc->name)
874         return E_OUTOFMEMORY;
875
876     for(funcprop_decl = func_decl; funcprop_decl; funcprop_decl = funcprop_decl->next_prop_func) {
877         switch(funcprop_decl->type) {
878         case FUNC_FUNCTION:
879         case FUNC_SUB:
880         case FUNC_PROPGET:
881         case FUNC_DEFGET:
882             invoke_type = VBDISP_CALLGET;
883             break;
884         case FUNC_PROPLET:
885             invoke_type = VBDISP_LET;
886             break;
887         case FUNC_PROPSET:
888             invoke_type = VBDISP_SET;
889             break;
890         default:
891             assert(0);
892         }
893
894         assert(!desc->entries[invoke_type]);
895
896         if(funcprop_decl->is_public)
897             desc->is_public = TRUE;
898
899         hres = create_function(ctx, funcprop_decl, desc->entries+invoke_type);
900         if(FAILED(hres))
901             return hres;
902     }
903
904     return S_OK;
905 }
906
907 static BOOL lookup_class_funcs(class_desc_t *class_desc, const WCHAR *name)
908 {
909     unsigned i;
910
911     for(i=0; i < class_desc->func_cnt; i++) {
912         if(class_desc->funcs[i].name && !strcmpiW(class_desc->funcs[i].name, name))
913             return TRUE;
914     }
915
916     return FALSE;
917 }
918
919 static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
920 {
921     function_decl_t *func_decl, *func_prop_decl;
922     class_prop_decl_t *prop_decl;
923     class_desc_t *class_desc;
924     unsigned i;
925     HRESULT hres;
926
927     static const WCHAR class_initializeW[] = {'c','l','a','s','s','_','i','n','i','t','i','a','l','i','z','e',0};
928     static const WCHAR class_terminateW[] = {'c','l','a','s','s','_','t','e','r','m','i','n','a','t','e',0};
929
930     if(lookup_dim_decls(ctx, class_decl->name) || lookup_funcs_name(ctx, class_decl->name)
931             || lookup_class_name(ctx, class_decl->name)) {
932         FIXME("%s: redefinition\n", debugstr_w(class_decl->name));
933         return E_FAIL;
934     }
935
936     class_desc = compiler_alloc(ctx->code, sizeof(*class_desc));
937     if(!class_desc)
938         return E_OUTOFMEMORY;
939
940     class_desc->name = compiler_alloc_string(ctx->code, class_decl->name);
941     if(!class_desc->name)
942         return E_OUTOFMEMORY;
943
944     class_desc->func_cnt = 1; /* always allocate slot for default getter */
945     class_desc->prop_cnt = 0;
946     class_desc->class_initialize_id = 0;
947     class_desc->class_terminate_id = 0;
948
949     for(func_decl = class_decl->funcs; func_decl; func_decl = func_decl->next) {
950         for(func_prop_decl = func_decl; func_prop_decl; func_prop_decl = func_prop_decl->next_prop_func) {
951             if(func_prop_decl->type == FUNC_DEFGET)
952                 break;
953         }
954         if(!func_prop_decl)
955             class_desc->func_cnt++;
956     }
957
958     class_desc->funcs = compiler_alloc(ctx->code, class_desc->func_cnt*sizeof(*class_desc->funcs));
959     if(!class_desc->funcs)
960         return E_OUTOFMEMORY;
961     memset(class_desc->funcs, 0, class_desc->func_cnt*sizeof(*class_desc->funcs));
962
963     for(func_decl = class_decl->funcs, i=1; func_decl; func_decl = func_decl->next, i++) {
964         for(func_prop_decl = func_decl; func_prop_decl; func_prop_decl = func_prop_decl->next_prop_func) {
965             if(func_prop_decl->type == FUNC_DEFGET) {
966                 i--;
967                 break;
968             }
969         }
970
971         if(!strcmpiW(class_initializeW, func_decl->name)) {
972             if(func_decl->type != FUNC_SUB) {
973                 FIXME("class initializer is not sub\n");
974                 return E_FAIL;
975             }
976
977             class_desc->class_initialize_id = i;
978         }else  if(!strcmpiW(class_terminateW, func_decl->name)) {
979             if(func_decl->type != FUNC_SUB) {
980                 FIXME("class terminator is not sub\n");
981                 return E_FAIL;
982             }
983
984             class_desc->class_terminate_id = i;
985         }
986
987         hres = create_class_funcprop(ctx, func_decl, class_desc->funcs + (func_prop_decl ? 0 : i));
988         if(FAILED(hres))
989             return hres;
990     }
991
992     for(prop_decl = class_decl->props; prop_decl; prop_decl = prop_decl->next)
993         class_desc->prop_cnt++;
994
995     class_desc->props = compiler_alloc(ctx->code, class_desc->prop_cnt*sizeof(*class_desc->props));
996     if(!class_desc->props)
997         return E_OUTOFMEMORY;
998
999     for(prop_decl = class_decl->props, i=0; prop_decl; prop_decl = prop_decl->next, i++) {
1000         if(lookup_class_funcs(class_desc, prop_decl->name)) {
1001             FIXME("Property %s redefined\n", debugstr_w(prop_decl->name));
1002             return E_FAIL;
1003         }
1004
1005         class_desc->props[i].name = compiler_alloc_string(ctx->code, prop_decl->name);
1006         if(!class_desc->props[i].name)
1007             return E_OUTOFMEMORY;
1008
1009         class_desc->props[i].is_public = prop_decl->is_public;
1010     }
1011
1012     class_desc->next = ctx->classes;
1013     ctx->classes = class_desc;
1014     return S_OK;
1015 }
1016
1017 static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier)
1018 {
1019     class_desc_t *class;
1020     dynamic_var_t *var;
1021     function_t *func;
1022
1023     for(var = script->global_vars; var; var = var->next) {
1024         if(!strcmpiW(var->name, identifier))
1025             return TRUE;
1026     }
1027
1028     for(func = script->global_funcs; func; func = func->next) {
1029         if(!strcmpiW(func->name, identifier))
1030             return TRUE;
1031     }
1032
1033     for(class = script->classes; class; class = class->next) {
1034         if(!strcmpiW(class->name, identifier))
1035             return TRUE;
1036     }
1037
1038     return FALSE;
1039 }
1040
1041 static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
1042 {
1043     class_desc_t *class;
1044     dynamic_var_t *var;
1045     function_t *func;
1046
1047     for(var = ctx->global_vars; var; var = var->next) {
1048         if(lookup_script_identifier(script, var->name)) {
1049             FIXME("%s: redefined\n", debugstr_w(var->name));
1050             return E_FAIL;
1051         }
1052     }
1053
1054     for(func = ctx->funcs; func; func = func->next) {
1055         if(lookup_script_identifier(script, func->name)) {
1056             FIXME("%s: redefined\n", debugstr_w(func->name));
1057             return E_FAIL;
1058         }
1059     }
1060
1061     for(class = ctx->classes; class; class = class->next) {
1062         if(lookup_script_identifier(script, class->name)) {
1063             FIXME("%s: redefined\n", debugstr_w(class->name));
1064             return E_FAIL;
1065         }
1066     }
1067
1068     return S_OK;
1069 }
1070
1071 void release_vbscode(vbscode_t *code)
1072 {
1073     unsigned i;
1074
1075     list_remove(&code->entry);
1076
1077     for(i=0; i < code->bstr_cnt; i++)
1078         SysFreeString(code->bstr_pool[i]);
1079
1080     vbsheap_free(&code->heap);
1081
1082     heap_free(code->bstr_pool);
1083     heap_free(code->source);
1084     heap_free(code->instrs);
1085     heap_free(code);
1086 }
1087
1088 static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source)
1089 {
1090     vbscode_t *ret;
1091
1092     ret = heap_alloc(sizeof(*ret));
1093     if(!ret)
1094         return NULL;
1095
1096     ret->source = heap_strdupW(source);
1097     if(!ret->source) {
1098         heap_free(ret);
1099         return NULL;
1100     }
1101
1102     ret->instrs = heap_alloc(32*sizeof(instr_t));
1103     if(!ret->instrs) {
1104         release_vbscode(ret);
1105         return NULL;
1106     }
1107
1108     ctx->instr_cnt = 0;
1109     ctx->instr_size = 32;
1110     vbsheap_init(&ret->heap);
1111
1112     ret->option_explicit = ctx->parser.option_explicit;
1113
1114     ret->bstr_pool = NULL;
1115     ret->bstr_pool_size = 0;
1116     ret->bstr_cnt = 0;
1117     ret->global_executed = FALSE;
1118
1119     ret->global_code.type = FUNC_GLOBAL;
1120     ret->global_code.name = NULL;
1121     ret->global_code.code_ctx = ret;
1122     ret->global_code.vars = NULL;
1123     ret->global_code.var_cnt = 0;
1124     ret->global_code.arg_cnt = 0;
1125     ret->global_code.args = NULL;
1126
1127     list_init(&ret->entry);
1128     return ret;
1129 }
1130
1131 static void release_compiler(compile_ctx_t *ctx)
1132 {
1133     parser_release(&ctx->parser);
1134     heap_free(ctx->labels);
1135     if(ctx->code)
1136         release_vbscode(ctx->code);
1137 }
1138
1139 HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
1140 {
1141     function_t *new_func;
1142     function_decl_t *func_decl;
1143     class_decl_t *class_decl;
1144     compile_ctx_t ctx;
1145     vbscode_t *code;
1146     HRESULT hres;
1147
1148     hres = parse_script(&ctx.parser, src);
1149     if(FAILED(hres))
1150         return hres;
1151
1152     code = ctx.code = alloc_vbscode(&ctx, src);
1153     if(!ctx.code)
1154         return E_OUTOFMEMORY;
1155
1156     ctx.funcs = NULL;
1157     ctx.func_decls = NULL;
1158     ctx.global_vars = NULL;
1159     ctx.dim_decls = NULL;
1160     ctx.classes = NULL;
1161     ctx.labels = NULL;
1162     ctx.labels_cnt = ctx.labels_size = 0;
1163
1164     hres = compile_func(&ctx, ctx.parser.stats, &ctx.code->global_code);
1165     if(FAILED(hres)) {
1166         release_compiler(&ctx);
1167         return hres;
1168     }
1169
1170     for(func_decl = ctx.func_decls; func_decl; func_decl = func_decl->next) {
1171         hres = create_function(&ctx, func_decl, &new_func);
1172         if(FAILED(hres)) {
1173             release_compiler(&ctx);
1174             return hres;
1175         }
1176
1177         new_func->next = ctx.funcs;
1178         ctx.funcs = new_func;
1179     }
1180
1181     for(class_decl = ctx.parser.class_decls; class_decl; class_decl = class_decl->next) {
1182         hres = compile_class(&ctx, class_decl);
1183         if(FAILED(hres)) {
1184             release_compiler(&ctx);
1185             return hres;
1186         }
1187     }
1188
1189     hres = check_script_collisions(&ctx, script);
1190     if(FAILED(hres)) {
1191         release_compiler(&ctx);
1192         return hres;
1193     }
1194
1195     if(ctx.global_vars) {
1196         dynamic_var_t *var;
1197
1198         for(var = ctx.global_vars; var->next; var = var->next);
1199
1200         var->next = script->global_vars;
1201         script->global_vars = ctx.global_vars;
1202     }
1203
1204     if(ctx.funcs) {
1205         for(new_func = ctx.funcs; new_func->next; new_func = new_func->next);
1206
1207         new_func->next = script->global_funcs;
1208         script->global_funcs = ctx.funcs;
1209     }
1210
1211     if(ctx.classes) {
1212         class_desc_t *class = ctx.classes;
1213
1214         while(1) {
1215             class->ctx = script;
1216             if(!class->next)
1217                 break;
1218             class = class->next;
1219         }
1220
1221         class->next = script->classes;
1222         script->classes = ctx.classes;
1223     }
1224
1225     if(TRACE_ON(vbscript_disas))
1226         dump_code(&ctx);
1227
1228     ctx.code = NULL;
1229     release_compiler(&ctx);
1230
1231     list_add_tail(&script->code_list, &code->entry);
1232     *ret = code;
1233     return S_OK;
1234 }