vbscript: Added 'or' expression parser/compiler 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
44     dim_decl_t *dim_decls;
45     dynamic_var_t *global_vars;
46
47     function_t *func;
48     function_t *funcs;
49     function_decl_t *func_decls;
50 } compile_ctx_t;
51
52 static HRESULT compile_expression(compile_ctx_t*,expression_t*);
53 static HRESULT compile_statement(compile_ctx_t*,statement_t*);
54
55 static const struct {
56     const char *op_str;
57     instr_arg_type_t arg1_type;
58     instr_arg_type_t arg2_type;
59 } instr_info[] = {
60 #define X(n,a,b,c) {#n,b,c},
61 OP_LIST
62 #undef X
63 };
64
65 static void dump_instr_arg(instr_arg_type_t type, instr_arg_t *arg)
66 {
67     switch(type) {
68     case ARG_STR:
69     case ARG_BSTR:
70         TRACE_(vbscript_disas)("\t%s", debugstr_w(arg->str));
71         break;
72     case ARG_INT:
73         TRACE_(vbscript_disas)("\t%d", arg->uint);
74         break;
75     case ARG_UINT:
76     case ARG_ADDR:
77         TRACE_(vbscript_disas)("\t%u", arg->uint);
78         break;
79     case ARG_DOUBLE:
80         TRACE_(vbscript_disas)("\t%lf", *arg->dbl);
81         break;
82     case ARG_NONE:
83         break;
84     default:
85         assert(0);
86     }
87 }
88
89 static void dump_code(compile_ctx_t *ctx)
90 {
91     instr_t *instr;
92
93     for(instr = ctx->code->instrs; instr < ctx->code->instrs+ctx->instr_cnt; instr++) {
94         TRACE_(vbscript_disas)("%d:\t%s", instr-ctx->code->instrs, instr_info[instr->op].op_str);
95         dump_instr_arg(instr_info[instr->op].arg1_type, &instr->arg1);
96         dump_instr_arg(instr_info[instr->op].arg2_type, &instr->arg2);
97         TRACE_(vbscript_disas)("\n");
98     }
99 }
100
101 static inline void *compiler_alloc(vbscode_t *vbscode, size_t size)
102 {
103     return vbsheap_alloc(&vbscode->heap, size);
104 }
105
106 static WCHAR *compiler_alloc_string(vbscode_t *vbscode, const WCHAR *str)
107 {
108     size_t size;
109     WCHAR *ret;
110
111     size = (strlenW(str)+1)*sizeof(WCHAR);
112     ret = compiler_alloc(vbscode, size);
113     if(ret)
114         memcpy(ret, str, size);
115     return ret;
116 }
117
118 static inline instr_t *instr_ptr(compile_ctx_t *ctx, unsigned id)
119 {
120     assert(id < ctx->instr_cnt);
121     return ctx->code->instrs + id;
122 }
123
124 static unsigned push_instr(compile_ctx_t *ctx, vbsop_t op)
125 {
126     assert(ctx->instr_size && ctx->instr_size >= ctx->instr_cnt);
127
128     if(ctx->instr_size == ctx->instr_cnt) {
129         instr_t *new_instr;
130
131         new_instr = heap_realloc(ctx->code->instrs, ctx->instr_size*2*sizeof(instr_t));
132         if(!new_instr)
133             return -1;
134
135         ctx->code->instrs = new_instr;
136         ctx->instr_size *= 2;
137     }
138
139     ctx->code->instrs[ctx->instr_cnt].op = op;
140     return ctx->instr_cnt++;
141 }
142
143 static HRESULT push_instr_int(compile_ctx_t *ctx, vbsop_t op, LONG arg)
144 {
145     unsigned ret;
146
147     ret = push_instr(ctx, op);
148     if(ret == -1)
149         return E_OUTOFMEMORY;
150
151     instr_ptr(ctx, ret)->arg1.lng = arg;
152     return S_OK;
153 }
154
155 static HRESULT push_instr_addr(compile_ctx_t *ctx, vbsop_t op, unsigned arg)
156 {
157     unsigned ret;
158
159     ret = push_instr(ctx, op);
160     if(ret == -1)
161         return E_OUTOFMEMORY;
162
163     instr_ptr(ctx, ret)->arg1.uint = arg;
164     return S_OK;
165 }
166
167 static HRESULT push_instr_str(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg)
168 {
169     unsigned instr;
170     WCHAR *str;
171
172     str = compiler_alloc_string(ctx->code, arg);
173     if(!str)
174         return E_OUTOFMEMORY;
175
176     instr = push_instr(ctx, op);
177     if(instr == -1)
178         return E_OUTOFMEMORY;
179
180     instr_ptr(ctx, instr)->arg1.str = str;
181     return S_OK;
182 }
183
184 static HRESULT push_instr_double(compile_ctx_t *ctx, vbsop_t op, double arg)
185 {
186     unsigned instr;
187     double *d;
188
189     d = compiler_alloc(ctx->code, sizeof(double));
190     if(!d)
191         return E_OUTOFMEMORY;
192
193     instr = push_instr(ctx, op);
194     if(instr == -1)
195         return E_OUTOFMEMORY;
196
197     *d = arg;
198     instr_ptr(ctx, instr)->arg1.dbl = d;
199     return S_OK;
200 }
201
202 static BSTR alloc_bstr_arg(compile_ctx_t *ctx, const WCHAR *str)
203 {
204     if(!ctx->code->bstr_pool_size) {
205         ctx->code->bstr_pool = heap_alloc(8 * sizeof(BSTR));
206         if(!ctx->code->bstr_pool)
207             return NULL;
208         ctx->code->bstr_pool_size = 8;
209     }else if(ctx->code->bstr_pool_size == ctx->code->bstr_cnt) {
210        BSTR *new_pool;
211
212         new_pool = heap_realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR));
213         if(!new_pool)
214             return NULL;
215
216         ctx->code->bstr_pool = new_pool;
217         ctx->code->bstr_pool_size *= 2;
218     }
219
220     ctx->code->bstr_pool[ctx->code->bstr_cnt] = SysAllocString(str);
221     if(!ctx->code->bstr_pool[ctx->code->bstr_cnt])
222         return NULL;
223
224     return ctx->code->bstr_pool[ctx->code->bstr_cnt++];
225 }
226
227 static HRESULT push_instr_bstr(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg)
228 {
229     unsigned instr;
230     BSTR bstr;
231
232     bstr = alloc_bstr_arg(ctx, arg);
233     if(!bstr)
234         return E_OUTOFMEMORY;
235
236     instr = push_instr(ctx, op);
237     if(instr == -1)
238         return E_OUTOFMEMORY;
239
240     instr_ptr(ctx, instr)->arg1.bstr = bstr;
241     return S_OK;
242 }
243
244 static HRESULT push_instr_bstr_uint(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg1, unsigned arg2)
245 {
246     unsigned instr;
247     BSTR bstr;
248
249     bstr = alloc_bstr_arg(ctx, arg1);
250     if(!bstr)
251         return E_OUTOFMEMORY;
252
253     instr = push_instr(ctx, op);
254     if(instr == -1)
255         return E_OUTOFMEMORY;
256
257     instr_ptr(ctx, instr)->arg1.bstr = bstr;
258     instr_ptr(ctx, instr)->arg2.uint = arg2;
259     return S_OK;
260 }
261
262 #define LABEL_FLAG 0x80000000
263
264 static unsigned alloc_label(compile_ctx_t *ctx)
265 {
266     if(!ctx->labels_size) {
267         ctx->labels = heap_alloc(8 * sizeof(*ctx->labels));
268         if(!ctx->labels)
269             return -1;
270         ctx->labels_size = 8;
271     }else if(ctx->labels_size == ctx->labels_cnt) {
272         unsigned *new_labels;
273
274         new_labels = heap_realloc(ctx->labels, 2*ctx->labels_size*sizeof(*ctx->labels));
275         if(!new_labels)
276             return -1;
277
278         ctx->labels = new_labels;
279         ctx->labels_size *= 2;
280     }
281
282     return ctx->labels_cnt++ | LABEL_FLAG;
283 }
284
285 static inline void label_set_addr(compile_ctx_t *ctx, unsigned label)
286 {
287     assert(label & LABEL_FLAG);
288     ctx->labels[label & ~LABEL_FLAG] = ctx->instr_cnt;
289 }
290
291 static HRESULT compile_args(compile_ctx_t *ctx, expression_t *args, unsigned *ret)
292 {
293     unsigned arg_cnt = 0;
294     HRESULT hres;
295
296     while(args) {
297         hres = compile_expression(ctx, args);
298         if(FAILED(hres))
299             return hres;
300
301         arg_cnt++;
302         args = args->next;
303     }
304
305     *ret = arg_cnt;
306     return S_OK;
307 }
308
309 static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t *expr, BOOL ret_val)
310 {
311     unsigned arg_cnt = 0;
312     HRESULT hres;
313
314     hres = compile_args(ctx, expr->args, &arg_cnt);
315     if(FAILED(hres))
316         return hres;
317
318     if(expr->obj_expr) {
319         FIXME("obj_expr not implemented\n");
320         hres = E_NOTIMPL;
321     }else {
322         hres = push_instr_bstr_uint(ctx, ret_val ? OP_icall : OP_icallv, expr->identifier, arg_cnt);
323     }
324
325     return hres;
326 }
327
328 static HRESULT compile_unary_expression(compile_ctx_t *ctx, unary_expression_t *expr, vbsop_t op)
329 {
330     HRESULT hres;
331
332     hres = compile_expression(ctx, expr->subexpr);
333     if(FAILED(hres))
334         return hres;
335
336     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
337 }
338
339 static HRESULT compile_binary_expression(compile_ctx_t *ctx, binary_expression_t *expr, vbsop_t op)
340 {
341     HRESULT hres;
342
343     hres = compile_expression(ctx, expr->left);
344     if(FAILED(hres))
345         return hres;
346
347     hres = compile_expression(ctx, expr->right);
348     if(FAILED(hres))
349         return hres;
350
351     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
352 }
353
354 static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr)
355 {
356     switch(expr->type) {
357     case EXPR_ADD:
358         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_add);
359     case EXPR_AND:
360         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_and);
361     case EXPR_BOOL:
362         return push_instr_int(ctx, OP_bool, ((bool_expression_t*)expr)->value);
363     case EXPR_CONCAT:
364         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_concat);
365     case EXPR_DIV:
366         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_div);
367     case EXPR_DOUBLE:
368         return push_instr_double(ctx, OP_double, ((double_expression_t*)expr)->value);
369     case EXPR_EMPTY:
370         return push_instr(ctx, OP_empty) != -1 ? S_OK : E_OUTOFMEMORY;
371     case EXPR_EQUAL:
372         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_equal);
373     case EXPR_EXP:
374         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_exp);
375     case EXPR_IDIV:
376         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_idiv);
377     case EXPR_MEMBER:
378         return compile_member_expression(ctx, (member_expression_t*)expr, TRUE);
379     case EXPR_MOD:
380         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mod);
381     case EXPR_MUL:
382         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_mul);
383     case EXPR_NEG:
384         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_neg);
385     case EXPR_NEQUAL:
386         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_nequal);
387     case EXPR_NOT:
388         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_not);
389     case EXPR_NULL:
390         return push_instr(ctx, OP_null) != -1 ? S_OK : E_OUTOFMEMORY;
391     case EXPR_OR:
392         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_or);
393     case EXPR_STRING:
394         return push_instr_str(ctx, OP_string, ((string_expression_t*)expr)->value);
395     case EXPR_SUB:
396         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_sub);
397     case EXPR_USHORT:
398         return push_instr_int(ctx, OP_short, ((int_expression_t*)expr)->value);
399     case EXPR_ULONG:
400         return push_instr_int(ctx, OP_long, ((int_expression_t*)expr)->value);
401     default:
402         FIXME("Unimplemented expression type %d\n", expr->type);
403         return E_NOTIMPL;
404     }
405
406     return S_OK;
407 }
408
409 static HRESULT compile_if_statement(compile_ctx_t *ctx, if_statement_t *stat)
410 {
411     unsigned cnd_jmp, endif_label = -1;
412     elseif_decl_t *elseif_decl;
413     HRESULT hres;
414
415     hres = compile_expression(ctx, stat->expr);
416     if(FAILED(hres))
417         return hres;
418
419     cnd_jmp = push_instr(ctx, OP_jmp_false);
420     if(cnd_jmp == -1)
421         return E_OUTOFMEMORY;
422
423     hres = compile_statement(ctx, stat->if_stat);
424     if(FAILED(hres))
425         return hres;
426
427     if(stat->else_stat || stat->elseifs) {
428         endif_label = alloc_label(ctx);
429         if(endif_label == -1)
430             return E_OUTOFMEMORY;
431
432         hres = push_instr_addr(ctx, OP_jmp, endif_label);
433         if(FAILED(hres))
434             return hres;
435     }
436
437     for(elseif_decl = stat->elseifs; elseif_decl; elseif_decl = elseif_decl->next) {
438         instr_ptr(ctx, cnd_jmp)->arg1.uint = ctx->instr_cnt;
439
440         hres = compile_expression(ctx, elseif_decl->expr);
441         if(FAILED(hres))
442             return hres;
443
444         cnd_jmp = push_instr(ctx, OP_jmp_false);
445         if(cnd_jmp == -1)
446             return E_OUTOFMEMORY;
447
448         hres = compile_statement(ctx, elseif_decl->stat);
449         if(FAILED(hres))
450             return hres;
451
452         hres = push_instr_addr(ctx, OP_jmp, endif_label);
453         if(FAILED(hres))
454             return hres;
455     }
456
457     instr_ptr(ctx, cnd_jmp)->arg1.uint = ctx->instr_cnt;
458
459     if(stat->else_stat) {
460         hres = compile_statement(ctx, stat->else_stat);
461         if(FAILED(hres))
462             return hres;
463     }
464
465     if(endif_label != -1)
466         label_set_addr(ctx, endif_label);
467     return S_OK;
468 }
469
470 static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *stat)
471 {
472     HRESULT hres;
473
474     hres = compile_expression(ctx, stat->value_expr);
475     if(FAILED(hres))
476         return hres;
477
478     if(stat->member_expr->args) {
479         FIXME("arguments support not implemented\n");
480         return E_NOTIMPL;
481     }
482
483     if(stat->member_expr->obj_expr) {
484         hres = compile_expression(ctx, stat->member_expr->obj_expr);
485         if(FAILED(hres))
486             return hres;
487
488         hres = push_instr_bstr(ctx, OP_assign_member, stat->member_expr->identifier);
489     }else {
490         hres = push_instr_bstr(ctx, OP_assign_ident, stat->member_expr->identifier);
491     }
492
493     return hres;
494 }
495
496 static BOOL lookup_dim_decls(compile_ctx_t *ctx, const WCHAR *name)
497 {
498     dim_decl_t *dim_decl;
499
500     for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
501         if(!strcmpiW(dim_decl->name, name))
502             return TRUE;
503     }
504
505     return FALSE;
506 }
507
508 static BOOL lookup_args_name(compile_ctx_t *ctx, const WCHAR *name)
509 {
510     unsigned i;
511
512     for(i = 0; i < ctx->func->arg_cnt; i++) {
513         if(!strcmpiW(ctx->func->args[i].name, name))
514             return TRUE;
515     }
516
517     return FALSE;
518 }
519
520 static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat)
521 {
522     dim_decl_t *dim_decl = stat->dim_decls;
523
524     while(1) {
525         if(lookup_dim_decls(ctx, dim_decl->name) || lookup_args_name(ctx, dim_decl->name)) {
526             FIXME("dim %s name redefined\n", debugstr_w(dim_decl->name));
527             return E_FAIL;
528         }
529
530         if(!dim_decl->next)
531             break;
532         dim_decl = dim_decl->next;
533     }
534
535     dim_decl->next = ctx->dim_decls;
536     ctx->dim_decls = stat->dim_decls;
537     ctx->func->var_cnt++;
538     return S_OK;
539 }
540
541 static HRESULT compile_function_statement(compile_ctx_t *ctx, function_statement_t *stat)
542 {
543     if(ctx->func != &ctx->code->global_code) {
544         FIXME("Function is not in the global code\n");
545         return E_FAIL;
546     }
547
548     stat->func_decl->next = ctx->func_decls;
549     ctx->func_decls = stat->func_decl;
550     return S_OK;
551 }
552
553 static HRESULT compile_exitsub_statement(compile_ctx_t *ctx)
554 {
555     if(ctx->sub_end_label == -1) {
556         FIXME("Exit Sub outside Sub?\n");
557         return E_FAIL;
558     }
559
560     return push_instr_addr(ctx, OP_jmp, ctx->sub_end_label);
561 }
562
563 static HRESULT compile_exitfunc_statement(compile_ctx_t *ctx)
564 {
565     if(ctx->func_end_label == -1) {
566         FIXME("Exit Function outside Function?\n");
567         return E_FAIL;
568     }
569
570     return push_instr_addr(ctx, OP_jmp, ctx->func_end_label);
571 }
572
573 static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
574 {
575     HRESULT hres;
576
577     while(stat) {
578         switch(stat->type) {
579         case STAT_ASSIGN:
580             hres = compile_assign_statement(ctx, (assign_statement_t*)stat);
581             break;
582         case STAT_CALL:
583             hres = compile_member_expression(ctx, ((call_statement_t*)stat)->expr, FALSE);
584             break;
585         case STAT_DIM:
586             hres = compile_dim_statement(ctx, (dim_statement_t*)stat);
587             break;
588         case STAT_EXITFUNC:
589             hres = compile_exitfunc_statement(ctx);
590             break;
591         case STAT_EXITSUB:
592             hres = compile_exitsub_statement(ctx);
593             break;
594         case STAT_FUNC:
595             hres = compile_function_statement(ctx, (function_statement_t*)stat);
596             break;
597         case STAT_IF:
598             hres = compile_if_statement(ctx, (if_statement_t*)stat);
599             break;
600         default:
601             FIXME("Unimplemented statement type %d\n", stat->type);
602             hres = E_NOTIMPL;
603         }
604
605         if(FAILED(hres))
606             return hres;
607         stat = stat->next;
608     }
609
610     return S_OK;
611 }
612
613 static void resolve_labels(compile_ctx_t *ctx, unsigned off)
614 {
615     instr_t *instr;
616
617     for(instr = ctx->code->instrs+off; instr < ctx->code->instrs+ctx->instr_cnt; instr++) {
618         if(instr_info[instr->op].arg1_type == ARG_ADDR && (instr->arg1.uint & LABEL_FLAG)) {
619             assert((instr->arg1.uint & ~LABEL_FLAG) < ctx->labels_cnt);
620             instr->arg1.uint = ctx->labels[instr->arg1.uint & ~LABEL_FLAG];
621         }
622         assert(instr_info[instr->op].arg2_type != ARG_ADDR);
623     }
624
625     ctx->labels_cnt = 0;
626 }
627
628 static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *func)
629 {
630     HRESULT hres;
631
632     func->code_off = ctx->instr_cnt;
633
634     ctx->sub_end_label = -1;
635     ctx->func_end_label = -1;
636
637     switch(func->type) {
638     case FUNC_FUNCTION:
639         ctx->func_end_label = alloc_label(ctx);
640         if(ctx->func_end_label == -1)
641             return E_OUTOFMEMORY; /* FIXME ! */
642         break;
643     case FUNC_SUB:
644         ctx->sub_end_label = alloc_label(ctx);
645         if(ctx->sub_end_label == -1)
646             return E_OUTOFMEMORY;
647         break;
648     case FUNC_GLOBAL:
649         break;
650     }
651
652     ctx->func = func;
653     ctx->dim_decls = NULL;
654     hres = compile_statement(ctx, stat);
655     ctx->func = NULL;
656     if(FAILED(hres))
657         return hres;
658
659     if(ctx->sub_end_label != -1)
660         label_set_addr(ctx, ctx->sub_end_label);
661     if(ctx->func_end_label != -1)
662         label_set_addr(ctx, ctx->func_end_label);
663
664     if(push_instr(ctx, OP_ret) == -1)
665         return E_OUTOFMEMORY;
666
667     resolve_labels(ctx, func->code_off);
668
669     if(func->var_cnt) {
670         dim_decl_t *dim_decl;
671
672         if(func->type == FUNC_GLOBAL) {
673             dynamic_var_t *new_var;
674
675             func->var_cnt = 0;
676
677             for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) {
678                 new_var = compiler_alloc(ctx->code, sizeof(*new_var));
679                 if(!new_var)
680                     return E_OUTOFMEMORY;
681
682                 new_var->name = compiler_alloc_string(ctx->code, dim_decl->name);
683                 if(!new_var->name)
684                     return E_OUTOFMEMORY;
685
686                 V_VT(&new_var->v) = VT_EMPTY;
687
688                 new_var->next = ctx->global_vars;
689                 ctx->global_vars = new_var;
690             }
691         }else {
692             unsigned i;
693
694             func->vars = compiler_alloc(ctx->code, func->var_cnt * sizeof(var_desc_t));
695             if(!func->vars)
696                 return E_OUTOFMEMORY;
697
698             for(dim_decl = ctx->dim_decls, i=0; dim_decl; dim_decl = dim_decl->next, i++) {
699                 func->vars[i].name = compiler_alloc_string(ctx->code, dim_decl->name);
700                 if(!func->vars[i].name)
701                     return E_OUTOFMEMORY;
702             }
703
704             assert(i == func->var_cnt);
705         }
706     }
707
708     return S_OK;
709 }
710
711 static BOOL lookup_funcs_name(compile_ctx_t *ctx, const WCHAR *name)
712 {
713     function_t *iter;
714
715     for(iter = ctx->funcs; iter; iter = iter->next) {
716         if(!strcmpiW(iter->name, name))
717             return TRUE;
718     }
719
720     return FALSE;
721 }
722
723 static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, function_t **ret)
724 {
725     function_t *func;
726     HRESULT hres;
727
728     if(lookup_dim_decls(ctx, decl->name) || lookup_funcs_name(ctx, decl->name)) {
729         FIXME("%s: redefinition\n", debugstr_w(decl->name));
730         return E_FAIL;
731     }
732
733     func = compiler_alloc(ctx->code, sizeof(*func));
734     if(!func)
735         return E_OUTOFMEMORY;
736
737     func->name = compiler_alloc_string(ctx->code, decl->name);
738     if(!func->name)
739         return E_OUTOFMEMORY;
740
741     func->vars = NULL;
742     func->var_cnt = 0;
743     func->code_ctx = ctx->code;
744     func->type = decl->type;
745
746     func->arg_cnt = 0;
747     if(decl->args) {
748         arg_decl_t *arg;
749         unsigned i;
750
751         for(arg = decl->args; arg; arg = arg->next)
752             func->arg_cnt++;
753
754         func->args = compiler_alloc(ctx->code, func->arg_cnt * sizeof(arg_desc_t));
755         if(!func->args)
756             return E_OUTOFMEMORY;
757
758         for(i = 0, arg = decl->args; arg; arg = arg->next, i++) {
759             func->args[i].name = compiler_alloc_string(ctx->code, arg->name);
760             if(!func->args[i].name)
761                 return E_OUTOFMEMORY;
762             func->args[i].by_ref = arg->by_ref;
763         }
764     }else {
765         func->args = NULL;
766     }
767
768     hres = compile_func(ctx, decl->body, func);
769     if(FAILED(hres))
770         return hres;
771
772     *ret = func;
773     return S_OK;
774 }
775
776 static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier)
777 {
778     dynamic_var_t *var;
779     function_t *func;
780
781     for(var = script->global_vars; var; var = var->next) {
782         if(!strcmpiW(var->name, identifier))
783             return TRUE;
784     }
785
786     for(func = script->global_funcs; func; func = func->next) {
787         if(!strcmpiW(func->name, identifier))
788             return TRUE;
789     }
790
791     return FALSE;
792 }
793
794 static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
795 {
796     dynamic_var_t *var;
797     function_t *func;
798
799     for(var = ctx->global_vars; var; var = var->next) {
800         if(lookup_script_identifier(script, var->name)) {
801             FIXME("%s: redefined\n", debugstr_w(var->name));
802             return E_FAIL;
803         }
804     }
805
806     for(func = ctx->funcs; func; func = func->next) {
807         if(lookup_script_identifier(script, func->name)) {
808             FIXME("%s: redefined\n", debugstr_w(func->name));
809             return E_FAIL;
810         }
811     }
812
813     return S_OK;
814 }
815
816 void release_vbscode(vbscode_t *code)
817 {
818     unsigned i;
819
820     list_remove(&code->entry);
821
822     for(i=0; i < code->bstr_cnt; i++)
823         SysFreeString(code->bstr_pool[i]);
824
825     vbsheap_free(&code->heap);
826
827     heap_free(code->bstr_pool);
828     heap_free(code->source);
829     heap_free(code->instrs);
830     heap_free(code);
831 }
832
833 static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source)
834 {
835     vbscode_t *ret;
836
837     ret = heap_alloc(sizeof(*ret));
838     if(!ret)
839         return NULL;
840
841     ret->source = heap_strdupW(source);
842     if(!ret->source) {
843         heap_free(ret);
844         return NULL;
845     }
846
847     ret->instrs = heap_alloc(32*sizeof(instr_t));
848     if(!ret->instrs) {
849         release_vbscode(ret);
850         return NULL;
851     }
852
853     ctx->instr_cnt = 0;
854     ctx->instr_size = 32;
855     vbsheap_init(&ret->heap);
856
857     ret->option_explicit = ctx->parser.option_explicit;
858
859     ret->bstr_pool = NULL;
860     ret->bstr_pool_size = 0;
861     ret->bstr_cnt = 0;
862     ret->global_executed = FALSE;
863
864     ret->global_code.type = FUNC_GLOBAL;
865     ret->global_code.name = NULL;
866     ret->global_code.code_ctx = ret;
867     ret->global_code.vars = NULL;
868     ret->global_code.var_cnt = 0;
869     ret->global_code.arg_cnt = 0;
870     ret->global_code.args = NULL;
871
872     list_init(&ret->entry);
873     return ret;
874 }
875
876 static void release_compiler(compile_ctx_t *ctx)
877 {
878     parser_release(&ctx->parser);
879     heap_free(ctx->labels);
880     if(ctx->code)
881         release_vbscode(ctx->code);
882 }
883
884 HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
885 {
886     function_t *new_func;
887     function_decl_t *func_decl;
888     compile_ctx_t ctx;
889     vbscode_t *code;
890     HRESULT hres;
891
892     hres = parse_script(&ctx.parser, src);
893     if(FAILED(hres))
894         return hres;
895
896     code = ctx.code = alloc_vbscode(&ctx, src);
897     if(!ctx.code)
898         return E_OUTOFMEMORY;
899
900     ctx.funcs = NULL;
901     ctx.func_decls = NULL;
902     ctx.global_vars = NULL;
903     ctx.dim_decls = NULL;
904     ctx.labels = NULL;
905     ctx.labels_cnt = ctx.labels_size = 0;
906
907     hres = compile_func(&ctx, ctx.parser.stats, &ctx.code->global_code);
908     if(FAILED(hres)) {
909         release_compiler(&ctx);
910         return hres;
911     }
912
913     for(func_decl = ctx.func_decls; func_decl; func_decl = func_decl->next) {
914         hres = create_function(&ctx, func_decl, &new_func);
915         if(FAILED(hres)) {
916             release_compiler(&ctx);
917             return hres;
918         }
919
920         new_func->next = ctx.funcs;
921         ctx.funcs = new_func;
922     }
923
924     hres = check_script_collisions(&ctx, script);
925     if(FAILED(hres)) {
926         release_compiler(&ctx);
927         return hres;
928     }
929
930     if(ctx.global_vars) {
931         dynamic_var_t *var;
932
933         for(var = ctx.global_vars; var->next; var = var->next);
934
935         var->next = script->global_vars;
936         script->global_vars = ctx.global_vars;
937     }
938
939     if(ctx.funcs) {
940         for(new_func = ctx.funcs; new_func->next; new_func = new_func->next);
941
942         new_func->next = script->global_funcs;
943         script->global_funcs = ctx.funcs;
944     }
945
946     if(TRACE_ON(vbscript_disas))
947         dump_code(&ctx);
948
949     ctx.code = NULL;
950     release_compiler(&ctx);
951
952     list_add_tail(&script->code_list, &code->entry);
953     *ret = code;
954     return S_OK;
955 }