root/trunk/minid/regexplib.d

Revision 421, 11.4 kB (checked in by JarrettBillingsley, 3 weeks ago)

Improved class allocation speed by 35%. Wee. Partly due to string creation being much faster (don't have to validate a string if it's already in the interning table). Fixed a bug with parsing of instance parameter type constraints. Updated some tests.

It's also come to my attention that something like "time.Timer()" doesn't work currently because the method lookup expects Timer to be a function. Hm...

Line 
1 /******************************************************************************
2 License:
3 Copyright (c) 2007 ideage lsina@126.com
4 and Copyright (c) 2008 Jarrett Billingsley
5
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the
8 use of this software.
9
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it freely,
12 subject to the following restrictions:
13
14     1. The origin of this software must not be misrepresented; you must not
15     claim that you wrote the original software. If you use this software in a
16     product, an acknowledgment in the product documentation would be
17     appreciated but is not required.
18
19     2. Altered source versions must be plainly marked as such, and must not
20     be misrepresented as being the original software.
21
22     3. This notice may not be removed or altered from any source distribution.
23 ******************************************************************************/
24
25 module minid.regexplib;
26
27 import tango.text.Regex;
28 import tango.text.Util;
29
30 import minid.ex;
31 import minid.interpreter;
32 import minid.types;
33 import minid.utils;
34
35 private alias RegExpT!(char) Regexd;
36
37 struct RegexpLib
38 {
39     public static void init(MDThread* t)
40     {
41         pushGlobal(t, "modules");
42         field(t, -1, "customLoaders");
43        
44         newFunction(t, function uword(MDThread* t, uword numParams)
45         {
46             RegexpObj.init(t);
47
48                 pushString(t, r"\w+([\-+.]\w+)*@\w+([\-.]\w+)*\.\w+([\-.]\w+)*");
49             newGlobal(t, "email");
50
51                 pushString(t, r"(([h|H][t|T]|[f|F])[t|T][p|P]([s|S]?)\:\/\/|~/|/)?([\w]+:\w+@)?(([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?)?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?([,]\w+)*((\?\w+=\w+)?(&\w+=\w+)*([,]\w*)*)?");
52             newGlobal(t, "url");
53
54             pushString(t, r"^[a-zA-Z_]+$");                        newGlobal(t, "alpha");
55             pushString(t, r"^\s+$");                               newGlobal(t, "space");
56             pushString(t, r"^\d+$");                               newGlobal(t, "digit");
57             pushString(t, r"^[0-9A-Fa-f]+$");                      newGlobal(t, "hexdigit");
58             pushString(t, r"^[0-7]+$");                            newGlobal(t, "octdigit");
59             pushString(t, r"^[\(\)\[\]\.,;=<>\+\-\*/&\^]+$");      newGlobal(t, "symbol");
60
61             pushString(t, "^[\u4e00-\u9fa5]+$");                   newGlobal(t, "chinese");
62             pushString(t, r"\d{3}-\d{8}|\d{4}-\d{7}");             newGlobal(t, "cnPhone");
63             pushString(t, r"^((\(\d{2,3}\))|(\d{3}\-))?13\d{9}$"); newGlobal(t, "cnMobile");
64             pushString(t, r"^\d{6}$");                             newGlobal(t, "cnZip");
65             pushString(t, r"\d{15}|\d{18}");                       newGlobal(t, "cnIDcard");
66
67             pushString(t, r"^((1-)?\d{3}-)?\d{3}-\d{4}$");         newGlobal(t, "usPhone");
68             pushString(t, r"^\d{5}$");                             newGlobal(t, "usZip");
69
70 //          "compile"d,    new MDClosure(lib, &regexpLib.compile, "regexp.compile"),
71 //          "test"d,       new MDClosure(lib, &test,              "regexp.test"),
72 //          "replace"d,    new MDClosure(lib, &regexpLib.replace, "regexp.replace"),
73 //          "split"d,      new MDClosure(lib, &split,             "regexp.split"),
74 //          "match"d,      new MDClosure(lib, &match,             "regexp.match")
75
76             return 0;
77         }, "regexp");
78
79         fielda(t, -2, "regexp");
80         importModule(t, "regexp");
81         pop(t, 3);
82     }
83
84 //  static uword test(MDThread* t, uword numParams)
85 //  {
86 //      auto pattern = s.getParam!(MDString)(0).mData;
87 //      auto src = s.getParam!(MDString)(1).mData;
88 //      dchar[] attributes = "";
89 //
90 //      if(numParams > 2)
91 //          attributes = s.getParam!(MDString)(2).mData;
92 //
93 //      scope rx = s.safeCode(Regexd(pattern, attributes));
94 //      s.push(s.safeCode(cast(bool)rx.test(src)));
95 //      return 1;
96 //  }
97 //
98 //  uword replace(MDThread* t, uword numParams)
99 //  {
100 //      auto pattern = s.getParam!(MDString)(0).mData;
101 //      auto src = s.getParam!(MDString)(1).mData;
102 //      dchar[] attributes = "";
103 //
104 //      if(numParams > 3)
105 //          attributes = s.getParam!(MDString)(3).mData;
106 //         
107 //      scope rx = s.safeCode(Regexd(pattern, attributes));
108 //
109 //      if(s.isParam!("string")(2))
110 //      {
111 //          auto rep = s.getParam!(MDString)(2).mData;
112 //          s.push(s.safeCode(rx.replaceAll(src, rep)));
113 //      }
114 //      else
115 //      {
116 //          auto rep = s.getParam!(MDClosure)(2);
117 //          scope temp = regexpClass.nativeClone();
118 //
119 //          s.push(s.safeCode(rx.replaceAll(src, (Regexd m)
120 //          {
121 //              temp.mRegexp = m;
122 //              s.callWith(rep, 1, s.getContext(), temp);
123 //              return s.pop!(MDString).mData;
124 //          })));
125 //      }
126 //
127 //      return 1;
128 //  }
129 //
130 //  static uword split(MDThread* t, uword numParams)
131 //  {
132 //      auto pattern = s.getParam!(MDString)(0).mData;
133 //      auto src = s.getParam!(MDString)(1).mData;
134 //      dchar[] attributes = "";
135 //
136 //      if(numParams > 2)
137 //          attributes = s.getParam!(MDString)(2).mData;
138 //
139 //      scope rx = s.safeCode(Regexd(pattern, attributes));
140 //      s.push(MDArray.fromArray(s.safeCode(rx.split(src))));
141 //      return 1;
142 //  }
143 //
144 //  static uword match(MDThread* t, uword numParams)
145 //  {
146 //      auto pattern = s.getParam!(MDString)(0).mData;
147 //      auto src = s.getParam!(MDString)(1).mData;
148 //      dchar[] attributes = "";
149 //
150 //      if(numParams > 2)
151 //          attributes = s.getParam!(MDString)(2).mData;
152 //
153 //      bool global = false;
154 //     
155 //      foreach(c; attributes)
156 //      {
157 //          if(c is 'g')
158 //          {
159 //              global = true;
160 //              break;
161 //          }
162 //      }
163 //     
164 //      scope r = s.safeCode(Regexd(pattern, attributes));
165 //      dchar[][] matches;
166 //
167 //      if(global)
168 //      {
169 //          for(auto cont = s.safeCode(r.test(src)); cont; cont = s.safeCode(r.test()))
170 //              matches ~= r.match(0);
171 //      }
172 //      else
173 //      {
174 //          if(s.safeCode(r.test(src)))
175 //              matches ~= r.match(0);
176 //      }
177 //
178 //      s.push(MDArray.fromArray(matches));
179 //      return 1;
180 //  }
181 //
182 //  uword compile(MDThread* t, uword numParams)
183 //  {
184 //      auto pattern = s.getParam!(MDString)(0).mData;
185 //      dchar[] attributes = "";
186 //
187 //      if(numParams > 1)
188 //          attributes = s.getParam!(MDString)(1).mData;
189 //
190 //      s.push(s.safeCode(regexpClass.nativeClone(pattern, attributes)));
191 //      return 1;
192 //  }
193 //
194     static struct RegexpObj
195     {
196     static:
197         enum Fields
198         {
199             regex,
200             global
201         }
202
203         public void init(MDThread* t)
204         {
205             CreateClass(t, "Regexp", (CreateClass* c)
206             {
207                 c.method("constructor", &constructor);
208                 c.method("test", &test);
209                 c.method("search", &search);
210                 c.method("match", &match);
211                 c.method("pre", &pre);
212                 c.method("post", &post);
213                 c.method("find", &find);
214                 c.method("split", &split);
215                 c.method("replace", &replace);
216
217                     newFunction(t, &iterator, "Regexp.iterator");
218                 c.method("opApply", &opApply, 1);
219             });
220            
221             newFunction(t, &allocator, "Regexp.allocator");
222             setAllocator(t, -2);
223
224             newGlobal(t, "Regexp");
225         }
226        
227         uword allocator(MDThread* t, uword numParams)
228         {
229             newInstance(t, 0, Fields.max + 1);
230
231             dup(t);
232             pushNull(t);
233             rotateAll(t, 3);
234             methodCall(t, 2, "constructor", 0);
235             return 1;
236         }
237        
238         private Regex getThis(MDThread* t)
239         {
240             bool dummy = void;
241             return getThis(t, dummy);
242         }
243
244         private Regex getThis(MDThread* t, out bool isGlobal)
245         {
246             checkInstParam(t, 0, "Regexp");
247             getExtraVal(t, 0, Fields.global);
248             isGlobal = getBool(t, -1);
249             pop(t);
250             getExtraVal(t, 0, Fields.regex);
251             auto ret = cast(Regex)cast(void*)getNativeObj(t, -1);
252             pop(t);
253             return ret;
254         }
255
256         public uword constructor(MDThread* t, uword numParams)
257         {
258             checkInstParam(t, 0, "Regexp");
259
260             auto pat = checkStringParam(t, 1);
261             auto attrs = optStringParam(t, 2, "");
262
263             pushNativeObj(t, safeCode(t, new Regex(pat, attrs))); setExtraVal(t, 0, Fields.regex);
264             pushBool(t, attrs.locate('g') != attrs.length);       setExtraVal(t, 0, Fields.global);
265
266             return 0;
267         }
268
269         public uword test(MDThread* t, uword numParams)
270         {
271             auto rex = getThis(t);
272
273             if(numParams > 0)
274             {
275                 auto str = checkStringParam(t, 1);
276                 pushBool(t, safeCode(t, rex.test(str)));
277             }
278             else
279                 pushBool(t, safeCode(t, rex.test()));
280
281             return 1;
282         }
283
284         public uword match(MDThread* t, uword numParams)
285         {
286             bool isGlobal = void;
287             auto rex = getThis(t, isGlobal);
288
289             if(numParams == 0)
290                 pushString(t, safeCode(t, rex.match(0)));
291             else if(isInt(t, 1))
292                 pushString(t, safeCode(t, rex.match(cast(uword)getInt(t, 1))));
293             else
294             {
295                 auto src = checkStringParam(t, 1);
296                 auto matches = newArray(t, 0);
297
298                 if(isGlobal)
299                 {
300                     for(auto cont = safeCode(t, rex.test(src)); cont; cont = safeCode(t, rex.test()))
301                     {
302                         pushString(t, rex.match(0));
303                         cateq(t, matches, 1);
304                     }
305                 }
306                 else
307                 {
308                     if(safeCode(t, rex.test(src)))
309                     {
310                         //dup(t, matches);
311                         pushString(t, rex.match(0));
312                         cateq(t, matches, 1);
313                     }
314                 }
315             }
316
317             return 1;
318         }
319
320         public uword search(MDThread* t, uword numParams)
321         {
322             auto rex = getThis(t);
323             auto str = checkStringParam(t, 1);
324             safeCode(t, rex.search(str));
325             dup(t, 0);
326             return 1;
327         }
328
329         public uword pre(MDThread* t, uword numParams)
330         {
331             auto rex = getThis(t);
332             pushString(t, safeCode(t, rex.pre()));
333             return 1;
334         }
335
336         public uword post(MDThread* t, uword numParams)
337         {
338             auto rex = getThis(t);
339             pushString(t, safeCode(t, rex.post()));
340             return 1;
341         }
342
343         public uword replace(MDThread* t, uword numParams)
344         {
345             auto rex = getThis(t);
346             auto src = checkStringParam(t, 1);
347
348             if(isString(t, 2))
349             {
350                 auto rep = getString(t, 2);
351                 pushString(t, safeCode(t, rex.replaceAll(src, rep)));
352             }
353             else
354             {
355                 checkParam(t, 2, MDValue.Type.Function);
356
357                 pushString(t, safeCode(t, rex.replaceAll(src, delegate char[](Regex m)
358                 {
359                     auto reg = dup(t, 2);
360                     pushNull(t);
361                     dup(t, 0);
362                     rawCall(t, reg, 1);
363                    
364                     if(!isString(t, -1))
365                     {
366                         pushTypeString(t, -1);
367                         throwException(t, "replacement function should return a 'string', not a '{}'", getString(t, -1));
368                     }
369                    
370                     auto ret = getString(t, -1);
371                     pop(t);
372                     return ret;
373                 })));
374             }
375
376             return 1;
377         }
378
379         public uword split(MDThread* t, uword numParams)
380         {
381             auto rex = getThis(t);
382             auto str = checkStringParam(t, 1);
383
384             auto ret = newArray(t, 0);
385             uword lastStart = 0;
386             char[] tmp = str;
387
388             foreach(r; rex.search(str))
389             {
390                 tmp = rex.pre();
391
392                 //dup(t, ret);
393                 pushString(t, tmp[lastStart .. $]);
394                 cateq(t, ret, 1);
395
396                 lastStart = r.match(0).ptr - str.ptr;
397                 tmp = rex.post();
398             }
399
400             //dup(t, ret);
401             pushString(t, tmp);
402             cateq(t, ret, 1);
403
404             return 1;
405         }
406
407         public uword find(MDThread* t, uword numParams)
408         {
409             auto rex = getThis(t);
410             auto str = checkStringParam(t, 1);
411
412             uword pos = str.length;
413
414             if(safeCode(t, rex.test(str)))
415                 pos = safeCode(t, rex.match(0)).ptr - str.ptr;
416
417             pushInt(t, pos);
418             return 1;
419         }
420
421         uword iterator(MDThread* t, uword numParams)
422         {
423             auto rex = getThis(t);
424             auto idx = getInt(t, 1) + 1;
425
426             if(!safeCode(t, rex.test()))
427                 return 0;
428                
429             pushInt(t, idx);
430             dup(t, 0);
431             return 2;
432         }
433
434         public uword opApply(MDThread* t, uword numParams)
435         {
436             checkInstParam(t, 0, "Regexp");
437             getUpval(t, 0);
438             dup(t, 0);
439             pushInt(t, -1);
440             return 3;
441         }
442     }
443 }
Note: See TracBrowser for help on using the browser.