serious bugfix in Raise_IdxError (number got formatted as string, causing a segmentat...
[vox.git] / src / stdlib / regexp.cpp
blobb46c1b058d2b1ffe8f325fe925aa2009630e7372
2 /* important: don't move boost.xpressive include
3 instruction to helper.hpp, otherwise compilation
4 speed goes down the drain */
5 #include <cstdio>
6 #include <boost/xpressive/xpressive.hpp>
7 #include "vox.h"
9 #define SETUP_REX(vm, selfname) \
10 RexObj* selfname = NULL; \
11 if(VX_FAILED(vm->GetInstanceUp(1, (VXUserPointer *)&selfname,0))) \
12 { \
13 vm->ThrowError("regex: GetInstanceUp failed!"); \
16 struct RexObj
18 boost::xpressive::sregex rex;
21 VXInteger rexhelp_compile(VXState* v, RexObj* self, const std::string& pattern)
23 try
25 self->rex = boost::xpressive::sregex::compile(pattern);
27 catch(boost::xpressive::regex_error& err)
29 return v->ThrowError(err.what());
31 return VX_OK;
34 template<typename Type>
35 VXArrayObj* rexhelp_array_from_match(VXState* v, Type& what)
37 VXInteger artop;
38 size_t i;
39 VXArrayObj* arr = v->NewArray();
40 for(i=0; i<what.size(); i++)
42 std::string submatch(what[i].first, what[i].second);
43 if(submatch.length() > 0)
45 arr->Append(v->NewString(submatch.c_str(), submatch.length()));
48 return arr;
51 VXArrayObj* rexhelp_findall(VXState* v, RexObj* self, const std::string& subject)
53 VXArrayObj* arr = v->NewArray();
54 std::string::const_iterator begin = subject.begin();
55 std::string::const_iterator end = subject.end();
56 boost::xpressive::match_results<std::string::const_iterator> what;
57 while(boost::xpressive::regex_search(begin, end, what, self->rex))
59 VXInteger newtop;
60 std::string str;
61 str = what.str();
62 VXTableObj* tb = v->NewTable();
64 /* the primary matched string */
65 tb->NewSlot(v->NewString("string"), v->NewString(str.c_str(), str.length()));
68 /* matched substrings (eg, from groups) */
69 tb->NewSlot(v->NewString("submatches"), rexhelp_array_from_match(v, what));
72 /* where the matched string starts */
73 tb->NewSlot(v->NewString("position"), VXInteger(what.position()));
75 /* absolute length of the matched string */
76 tb->NewSlot(v->NewString("length"), VXInteger(what.length()));
78 arr->Append(tb);
79 begin = what[0].second;
81 return arr;
85 VXInteger rexfunc_replace(VXState* v)
87 std::string pat;
88 std::string sub;
89 std::string rep;
90 std::string result;
91 VXInteger status;
92 RexObj* self = new RexObj;
93 v->GetString(2, &sub);
94 v->GetString(3, &pat);
95 v->GetString(4, &rep);
96 if((status = rexhelp_compile(v, self, pat)) != VX_OK)
98 delete self;
99 return status;
101 else
105 result = boost::xpressive::regex_replace(
106 sub,
107 self->rex,
108 rep,
109 boost::xpressive::regex_constants::format_all);
110 v->Push(v->NewString(result.c_str(), result.length()));
111 delete self;
112 return 1;
114 catch(boost::xpressive::regex_error& err)
116 delete self;
117 return v->ThrowError(err.what());
120 return 0;
124 VXInteger rexfunc_match(VXState* v)
126 std::string sub;
127 std::string pat;
128 VXInteger status;
129 RexObj* self = new RexObj;
130 v->GetString(2, &sub);
131 v->GetString(3, &pat);
132 if((status = rexhelp_compile(v, self, pat)) != VX_OK)
134 delete self;
135 return status;
137 else
139 boost::xpressive::match_results<std::string::const_iterator> what;
140 if(boost::xpressive::regex_match(sub, what, self->rex))
142 v->Push(rexhelp_array_from_match(v, what));
143 delete self;
144 return 1;
146 return 0;
148 return 0;
151 VXInteger rexfunc_search(VXState* v)
153 std::string sub;
154 std::string pat;
155 VXInteger status;
156 RexObj* self = new RexObj;
157 v->GetString(2, &sub);
158 v->GetString(3, &pat);
159 if((status = rexhelp_compile(v, self, pat)) != VX_OK)
161 delete self;
162 return status;
164 else
166 boost::xpressive::match_results<std::string::const_iterator> what;
167 if(boost::xpressive::regex_search(sub, what, self->rex))
169 v->Push(rexhelp_array_from_match(v, what));
170 delete self;
171 return 1;
173 return 0;
175 return 0;
178 static VXInteger rexclass_typeof(VXState* v)
180 v->Push(v->NewString("regexp"));
181 return 1;
184 static VXInteger rexclass_release(VXUserPointer p, VXInteger size)
186 (void)size;
187 RexObj* rex = (RexObj*)p;
188 delete rex;
189 return 1;
192 VXInteger rexclass_match(VXState* v)
194 SETUP_REX(v, self)
195 std::string subject;
196 boost::xpressive::match_results<std::string::const_iterator> what;
197 v->GetString(2, &subject);
198 if(boost::xpressive::regex_match(subject, what, self->rex))
200 v->Push(rexhelp_array_from_match(v, what));
201 return 1;
203 return 0;
206 VXInteger rexclass_group(VXState* v)
208 SETUP_REX(v, self)
209 std::string subject;
210 std::string groupname;
211 v->GetString(2, &subject);
212 v->GetString(3, &groupname);
213 boost::xpressive::smatch what;
214 if(regex_search(subject, what, self->rex))
218 std::string matched = what[groupname];
219 v->Push(v->NewString(matched.c_str(), matched.length()));
221 catch(boost::xpressive::regex_error& err)
223 return v->ThrowError(err.what());
225 return 1;
227 return 0;
230 VXInteger rexclass_findall(VXState* v)
232 SETUP_REX(v, self)
233 std::string opt;
234 v->GetString(2, &opt);
235 v->Push(rexhelp_findall(v, self, opt));
236 return 1;
239 static VXInteger rexclass_constructor(VXState* v)
241 RexObj* self = new RexObj;
242 std::string pat;
243 VXInteger status;
244 v->GetString(2, &pat);
245 if((status = rexhelp_compile(v, self, pat)) != VX_OK)
247 return status;
249 v->SetInstanceUp(1, (VXUserPointer*)&self);
250 v->SetReleaseHook(1, rexclass_release);
251 return 0;
254 VXRegFunction rexclass_funcs[] =
256 {"constructor", rexclass_constructor, 2, ".s"},
257 {"findall", rexclass_findall, 2, ".s"},
258 {"match", rexclass_match, 2, ".s"},
259 {"group", rexclass_group, 3, ".ss"},
260 {"__typeof__", rexclass_typeof, 1, "x"},
261 {0, 0, 0, 0},
265 static VXRegFunction regexlib_funcs[]=
267 {"match", rexfunc_match, 3, ".ss"},
268 {"search", rexfunc_search, 3, ".ss"},
269 {"replace", rexfunc_replace, 4, ".sss"},
270 {0, 0, 0, 0}
274 VXInteger voxstd_register_regexlib(VXState* v)
276 VXTableObj* tb = v->NewTable();
277 tb->NewSlot(v->NewString("compile"), v->RegClass(rexclass_funcs));
278 v->RegisterLib("regexp", regexlib_funcs, true, tb);
279 return 1;