vbscript: Added compiler/parser support for call expressions.
[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
29 typedef struct {
30     parser_ctx_t parser;
31
32     unsigned instr_cnt;
33     unsigned instr_size;
34     vbscode_t *code;
35 } compile_ctx_t;
36
37 static HRESULT compile_expression(compile_ctx_t*,expression_t*);
38
39 static inline instr_t *instr_ptr(compile_ctx_t *ctx, unsigned id)
40 {
41     assert(id < ctx->instr_cnt);
42     return ctx->code->instrs + id;
43 }
44
45 static unsigned push_instr(compile_ctx_t *ctx, vbsop_t op)
46 {
47     assert(ctx->instr_size && ctx->instr_size >= ctx->instr_cnt);
48
49     if(ctx->instr_size == ctx->instr_cnt) {
50         instr_t *new_instr;
51
52         new_instr = heap_realloc(ctx->code->instrs, ctx->instr_size*2*sizeof(instr_t));
53         if(!new_instr)
54             return -1;
55
56         ctx->code->instrs = new_instr;
57         ctx->instr_size *= 2;
58     }
59
60     ctx->code->instrs[ctx->instr_cnt].op = op;
61     return ctx->instr_cnt++;
62 }
63
64 static HRESULT push_instr_int(compile_ctx_t *ctx, vbsop_t op, LONG arg)
65 {
66     unsigned ret;
67
68     ret = push_instr(ctx, op);
69     if(ret == -1)
70         return E_OUTOFMEMORY;
71
72     instr_ptr(ctx, ret)->arg1.lng = arg;
73     return S_OK;
74 }
75
76 static HRESULT push_instr_str(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg)
77 {
78     unsigned ret;
79
80     ret = push_instr(ctx, op);
81     if(ret == -1)
82         return E_OUTOFMEMORY;
83
84     instr_ptr(ctx, ret)->arg1.str = arg;
85     return S_OK;
86 }
87
88 static BSTR alloc_bstr_arg(compile_ctx_t *ctx, const WCHAR *str)
89 {
90     if(!ctx->code->bstr_pool_size) {
91         ctx->code->bstr_pool = heap_alloc(8 * sizeof(BSTR));
92         if(!ctx->code->bstr_pool)
93             return NULL;
94         ctx->code->bstr_pool_size = 8;
95     }else if(ctx->code->bstr_pool_size == ctx->code->bstr_cnt) {
96        BSTR *new_pool;
97
98         new_pool = heap_realloc(ctx->code->bstr_pool, ctx->code->bstr_pool_size*2*sizeof(BSTR));
99         if(!new_pool)
100             return NULL;
101
102         ctx->code->bstr_pool = new_pool;
103         ctx->code->bstr_pool_size *= 2;
104     }
105
106     ctx->code->bstr_pool[ctx->code->bstr_cnt] = SysAllocString(str);
107     if(!ctx->code->bstr_pool[ctx->code->bstr_cnt])
108         return NULL;
109
110     return ctx->code->bstr_pool[ctx->code->bstr_cnt++];
111 }
112
113 static HRESULT push_instr_bstr_uint(compile_ctx_t *ctx, vbsop_t op, const WCHAR *arg1, unsigned arg2)
114 {
115     unsigned instr;
116     BSTR bstr;
117
118     bstr = alloc_bstr_arg(ctx, arg1);
119     if(!bstr)
120         return E_OUTOFMEMORY;
121
122     instr = push_instr(ctx, op);
123     if(instr == -1)
124         return E_OUTOFMEMORY;
125
126     instr_ptr(ctx, instr)->arg1.bstr = bstr;
127     instr_ptr(ctx, instr)->arg2.uint = arg2;
128     return S_OK;
129 }
130
131 static HRESULT compile_args(compile_ctx_t *ctx, expression_t *args, unsigned *ret)
132 {
133     unsigned arg_cnt = 0;
134     HRESULT hres;
135
136     while(args) {
137         hres = compile_expression(ctx, args);
138         if(FAILED(hres))
139             return hres;
140
141         arg_cnt++;
142         args = args->next;
143     }
144
145     *ret = arg_cnt;
146     return S_OK;
147 }
148
149 static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t *expr, BOOL ret_val)
150 {
151     unsigned arg_cnt = 0;
152     HRESULT hres;
153
154     hres = compile_args(ctx, expr->args, &arg_cnt);
155     if(FAILED(hres))
156         return hres;
157
158     if(expr->obj_expr) {
159         FIXME("obj_expr not implemented\n");
160         hres = E_NOTIMPL;
161     }else {
162         hres = push_instr_bstr_uint(ctx, ret_val ? OP_icall : OP_icallv, expr->identifier, arg_cnt);
163     }
164
165     return hres;
166 }
167
168 static HRESULT compile_unary_expression(compile_ctx_t *ctx, unary_expression_t *expr, vbsop_t op)
169 {
170     HRESULT hres;
171
172     hres = compile_expression(ctx, expr->subexpr);
173     if(FAILED(hres))
174         return hres;
175
176     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
177 }
178
179 static HRESULT compile_binary_expression(compile_ctx_t *ctx, binary_expression_t *expr, vbsop_t op)
180 {
181     HRESULT hres;
182
183     hres = compile_expression(ctx, expr->left);
184     if(FAILED(hres))
185         return hres;
186
187     hres = compile_expression(ctx, expr->right);
188     if(FAILED(hres))
189         return hres;
190
191     return push_instr(ctx, op) == -1 ? E_OUTOFMEMORY : S_OK;
192 }
193
194 static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr)
195 {
196     switch(expr->type) {
197     case EXPR_BOOL:
198         return push_instr_int(ctx, OP_bool, ((bool_expression_t*)expr)->value);
199     case EXPR_EQUAL:
200         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_equal);
201     case EXPR_MEMBER:
202         return compile_member_expression(ctx, (member_expression_t*)expr, TRUE);
203     case EXPR_NOT:
204         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_not);
205     case EXPR_STRING:
206         return push_instr_str(ctx, OP_string, ((string_expression_t*)expr)->value);
207     default:
208         FIXME("Unimplemented expression type %d\n", expr->type);
209         return E_NOTIMPL;
210     }
211
212     return S_OK;
213 }
214
215 static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
216 {
217     HRESULT hres;
218
219     while(stat) {
220         switch(stat->type) {
221         case STAT_CALL:
222             hres = compile_member_expression(ctx, ((call_statement_t*)stat)->expr, FALSE);
223             break;
224         default:
225             FIXME("Unimplemented statement type %d\n", stat->type);
226             hres = E_NOTIMPL;
227         }
228
229         if(FAILED(hres))
230             return hres;
231         stat = stat->next;
232     }
233
234     return S_OK;
235 }
236
237 static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *func)
238 {
239     HRESULT hres;
240
241     func->code_off = ctx->instr_cnt;
242
243     hres = compile_statement(ctx, stat);
244     if(FAILED(hres))
245         return hres;
246
247     if(push_instr(ctx, OP_ret) == -1)
248         return E_OUTOFMEMORY;
249
250     return S_OK;
251 }
252
253 void release_vbscode(vbscode_t *code)
254 {
255     unsigned i;
256
257     list_remove(&code->entry);
258
259     for(i=0; i < code->bstr_cnt; i++)
260         SysFreeString(code->bstr_pool[i]);
261
262     heap_free(code->bstr_pool);
263     heap_free(code->source);
264     heap_free(code->instrs);
265     heap_free(code);
266 }
267
268 static vbscode_t *alloc_vbscode(compile_ctx_t *ctx, const WCHAR *source)
269 {
270     vbscode_t *ret;
271
272     ret = heap_alloc(sizeof(*ret));
273     if(!ret)
274         return NULL;
275
276     ret->source = heap_strdupW(source);
277     if(!ret->source) {
278         heap_free(ret);
279         return NULL;
280     }
281
282     ret->instrs = heap_alloc(32*sizeof(instr_t));
283     if(!ret->instrs) {
284         release_vbscode(ret);
285         return NULL;
286     }
287
288     ctx->instr_cnt = 0;
289     ctx->instr_size = 32;
290
291     ret->option_explicit = ctx->parser.option_explicit;
292
293     ret->bstr_pool = NULL;
294     ret->bstr_pool_size = 0;
295     ret->bstr_cnt = 0;
296
297     ret->global_code.code_ctx = ret;
298
299     list_init(&ret->entry);
300     return ret;
301 }
302
303 HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
304 {
305     compile_ctx_t ctx;
306     HRESULT hres;
307
308     hres = parse_script(&ctx.parser, src);
309     if(FAILED(hres))
310         return hres;
311
312     ctx.code = alloc_vbscode(&ctx, src);
313     if(!ctx.code)
314         return E_OUTOFMEMORY;
315
316     hres = compile_func(&ctx, ctx.parser.stats, &ctx.code->global_code);
317     if(FAILED(hres)) {
318         release_vbscode(ctx.code);
319         return hres;
320     }
321
322     list_add_tail(&script->code_list, &ctx.code->entry);
323     *ret = ctx.code;
324     return S_OK;
325 }