jscript: Added parser support for regular expressions.
[wine] / dlls / jscript / regexp.c
1 /*
2  * Copyright 2008 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 "jscript.h"
20
21 #include "wine/debug.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
24
25 #define JSREG_FOLD      0x01    /* fold uppercase to lowercase */
26 #define JSREG_GLOB      0x02    /* global exec, creates array of matches */
27 #define JSREG_MULTILINE 0x04    /* treat ^ and $ as begin and end of line */
28 #define JSREG_STICKY    0x08    /* only match starting at lastIndex */
29
30 typedef struct {
31     DispatchEx dispex;
32 } RegExpInstance;
33
34 static const WCHAR sourceW[] = {'s','o','u','r','c','e',0};
35 static const WCHAR globalW[] = {'g','l','o','b','a','l',0};
36 static const WCHAR ignoreCaseW[] = {'i','g','n','o','r','e','C','a','s','e',0};
37 static const WCHAR multilineW[] = {'m','u','l','t','i','l','i','n','e',0};
38 static const WCHAR lastIndexW[] = {'l','a','s','t','I','n','d','e','x',0};
39 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
40 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
41 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
42 static const WCHAR propertyIsEnumerableW[] =
43     {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
44 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
45 static const WCHAR execW[] = {'e','x','e','c',0};
46
47 static HRESULT RegExp_source(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
48         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
49 {
50     FIXME("\n");
51     return E_NOTIMPL;
52 }
53
54 static HRESULT RegExp_global(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
55         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
56 {
57     FIXME("\n");
58     return E_NOTIMPL;
59 }
60
61 static HRESULT RegExp_ignoreCase(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
62         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
63 {
64     FIXME("\n");
65     return E_NOTIMPL;
66 }
67
68 static HRESULT RegExp_multiline(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
69         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
70 {
71     FIXME("\n");
72     return E_NOTIMPL;
73 }
74
75 static HRESULT RegExp_lastIndex(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
76         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
77 {
78     FIXME("\n");
79     return E_NOTIMPL;
80 }
81
82 static HRESULT RegExp_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
83         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
84 {
85     FIXME("\n");
86     return E_NOTIMPL;
87 }
88
89 static HRESULT RegExp_toLocaleString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
90         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
91 {
92     FIXME("\n");
93     return E_NOTIMPL;
94 }
95
96 static HRESULT RegExp_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
97         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
98 {
99     FIXME("\n");
100     return E_NOTIMPL;
101 }
102
103 static HRESULT RegExp_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
104         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
105 {
106     FIXME("\n");
107     return E_NOTIMPL;
108 }
109
110 static HRESULT RegExp_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
111         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
112 {
113     FIXME("\n");
114     return E_NOTIMPL;
115 }
116
117 static HRESULT RegExp_exec(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
118         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
119 {
120     FIXME("\n");
121     return E_NOTIMPL;
122 }
123
124 static HRESULT RegExp_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
125         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
126 {
127     FIXME("\n");
128     return E_NOTIMPL;
129 }
130
131 static void RegExp_destructor(DispatchEx *dispex)
132 {
133     heap_free(dispex);
134 }
135
136 static const builtin_prop_t RegExp_props[] = {
137     {execW,                  RegExp_exec,                  PROPF_METHOD},
138     {globalW,                RegExp_global,                0},
139     {hasOwnPropertyW,        RegExp_hasOwnProperty,        PROPF_METHOD},
140     {ignoreCaseW,            RegExp_ignoreCase,            0},
141     {isPrototypeOfW,         RegExp_isPrototypeOf,         PROPF_METHOD},
142     {lastIndexW,             RegExp_lastIndex,             0},
143     {multilineW,             RegExp_multiline,             0},
144     {propertyIsEnumerableW,  RegExp_propertyIsEnumerable,  PROPF_METHOD},
145     {sourceW,                RegExp_source,                0},
146     {toLocaleStringW,        RegExp_toLocaleString,        PROPF_METHOD},
147     {toStringW,              RegExp_toString,              PROPF_METHOD}
148 };
149
150 static const builtin_info_t RegExp_info = {
151     JSCLASS_REGEXP,
152     {NULL, RegExp_value, 0},
153     sizeof(RegExp_props)/sizeof(*RegExp_props),
154     RegExp_props,
155     RegExp_destructor,
156     NULL
157 };
158
159 static HRESULT alloc_regexp(script_ctx_t *ctx, BOOL use_constr, RegExpInstance **ret)
160 {
161     RegExpInstance *regexp;
162     HRESULT hres;
163
164     regexp = heap_alloc_zero(sizeof(RegExpInstance));
165     if(!regexp)
166         return E_OUTOFMEMORY;
167
168     if(use_constr)
169         hres = init_dispex_from_constr(&regexp->dispex, ctx, &RegExp_info, ctx->regexp_constr);
170     else
171         hres = init_dispex(&regexp->dispex, ctx, &RegExp_info, NULL);
172
173     if(FAILED(hres)) {
174         heap_free(regexp);
175         return hres;
176     }
177
178     *ret = regexp;
179     return S_OK;
180 }
181
182 static HRESULT create_regexp(script_ctx_t *ctx, const WCHAR *exp, int len, DWORD flags, DispatchEx **ret)
183 {
184     FIXME("\n");
185     return E_NOTIMPL;
186 }
187
188 static HRESULT RegExpConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
189         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
190 {
191     FIXME("\n");
192     return E_NOTIMPL;
193 }
194
195 HRESULT create_regexp_constr(script_ctx_t *ctx, DispatchEx **ret)
196 {
197     RegExpInstance *regexp;
198     HRESULT hres;
199
200     hres = alloc_regexp(ctx, FALSE, &regexp);
201     if(FAILED(hres))
202         return hres;
203
204     hres = create_builtin_function(ctx, RegExpConstr_value, PROPF_CONSTR, &regexp->dispex, ret);
205
206     jsdisp_release(&regexp->dispex);
207     return hres;
208 }
209
210 HRESULT create_regexp_str(script_ctx_t *ctx, const WCHAR *exp, DWORD exp_len, const WCHAR *opt,
211         DWORD opt_len, DispatchEx **ret)
212 {
213     const WCHAR *p;
214     DWORD flags = 0;
215
216     if(opt) {
217         for (p = opt; p < opt+opt_len; p++) {
218             switch (*p) {
219             case 'g':
220                 flags |= JSREG_GLOB;
221                 break;
222             case 'i':
223                 flags |= JSREG_FOLD;
224                 break;
225             case 'm':
226                 flags |= JSREG_MULTILINE;
227                 break;
228             case 'y':
229                 flags |= JSREG_STICKY;
230                 break;
231             default:
232                 WARN("wrong flag %c\n", *p);
233                 return E_FAIL;
234             }
235         }
236     }
237
238     return create_regexp(ctx, exp, exp_len, flags, ret);
239 }