Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #include "jsi.h"
  2. #include "jsvalue.h"
  3. #include "jsbuiltin.h"
  4. #include "regexp.h"
  5.  
  6. void js_newregexp(js_State *J, const char *pattern, int flags)
  7. {
  8.         const char *error;
  9.         js_Object *obj;
  10.         Reprog *prog;
  11.         int opts;
  12.  
  13.         obj = jsV_newobject(J, JS_CREGEXP, J->RegExp_prototype);
  14.  
  15.         opts = 0;
  16.         if (flags & JS_REGEXP_I) opts |= REG_ICASE;
  17.         if (flags & JS_REGEXP_M) opts |= REG_NEWLINE;
  18.  
  19.         prog = js_regcompx(J->alloc, J->actx, pattern, opts, &error);
  20.         if (!prog)
  21.                 js_syntaxerror(J, "regular expression: %s", error);
  22.  
  23.         obj->u.r.prog = prog;
  24.         obj->u.r.source = js_strdup(J, pattern);
  25.         obj->u.r.flags = flags;
  26.         obj->u.r.last = 0;
  27.         js_pushobject(J, obj);
  28. }
  29.  
  30. void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text)
  31. {
  32.         int result;
  33.         int i;
  34.         int opts;
  35.         Resub m;
  36.  
  37.         opts = 0;
  38.         if (re->flags & JS_REGEXP_G) {
  39.                 if (re->last > strlen(text)) {
  40.                         re->last = 0;
  41.                         js_pushnull(J);
  42.                         return;
  43.                 }
  44.                 if (re->last > 0) {
  45.                         text += re->last;
  46.                         opts |= REG_NOTBOL;
  47.                 }
  48.         }
  49.  
  50.         result = js_regexec(re->prog, text, &m, opts);
  51.         if (result < 0)
  52.                 js_error(J, "regexec failed");
  53.         if (result == 0) {
  54.                 js_newarray(J);
  55.                 js_pushstring(J, text);
  56.                 js_setproperty(J, -2, "input");
  57.                 js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp));
  58.                 js_setproperty(J, -2, "index");
  59.                 for (i = 0; i < m.nsub; ++i) {
  60.                         js_pushlstring(J, m.sub[i].sp, m.sub[i].ep - m.sub[i].sp);
  61.                         js_setindex(J, -2, i);
  62.                 }
  63.                 if (re->flags & JS_REGEXP_G)
  64.                         re->last = re->last + (m.sub[0].ep - text);
  65.                 return;
  66.         }
  67.  
  68.         if (re->flags & JS_REGEXP_G)
  69.                 re->last = 0;
  70.  
  71.         js_pushnull(J);
  72. }
  73.  
  74. static void Rp_test(js_State *J)
  75. {
  76.         js_Regexp *re;
  77.         const char *text;
  78.         int result;
  79.         int opts;
  80.         Resub m;
  81.  
  82.         re = js_toregexp(J, 0);
  83.         text = js_tostring(J, 1);
  84.  
  85.         opts = 0;
  86.         if (re->flags & JS_REGEXP_G) {
  87.                 if (re->last > strlen(text)) {
  88.                         re->last = 0;
  89.                         js_pushboolean(J, 0);
  90.                         return;
  91.                 }
  92.                 if (re->last > 0) {
  93.                         text += re->last;
  94.                         opts |= REG_NOTBOL;
  95.                 }
  96.         }
  97.  
  98.         result = js_regexec(re->prog, text, &m, opts);
  99.         if (result < 0)
  100.                 js_error(J, "regexec failed");
  101.         if (result == 0) {
  102.                 if (re->flags & JS_REGEXP_G)
  103.                         re->last = re->last + (m.sub[0].ep - text);
  104.                 js_pushboolean(J, 1);
  105.                 return;
  106.         }
  107.  
  108.         if (re->flags & JS_REGEXP_G)
  109.                 re->last = 0;
  110.  
  111.         js_pushboolean(J, 0);
  112. }
  113.  
  114. static void jsB_new_RegExp(js_State *J)
  115. {
  116.         js_Regexp *old;
  117.         const char *pattern;
  118.         int flags;
  119.  
  120.         if (js_isregexp(J, 1)) {
  121.                 if (js_isdefined(J, 2))
  122.                         js_typeerror(J, "cannot supply flags when creating one RegExp from another");
  123.                 old = js_toregexp(J, 1);
  124.                 pattern = old->source;
  125.                 flags = old->flags;
  126.         } else if (js_isundefined(J, 1)) {
  127.                 pattern = "(?:)";
  128.                 flags = 0;
  129.         } else {
  130.                 pattern = js_tostring(J, 1);
  131.                 flags = 0;
  132.         }
  133.  
  134.         if (strlen(pattern) == 0)
  135.                 pattern = "(?:)";
  136.  
  137.         if (js_isdefined(J, 2)) {
  138.                 const char *s = js_tostring(J, 2);
  139.                 int g = 0, i = 0, m = 0;
  140.                 while (*s) {
  141.                         if (*s == 'g') ++g;
  142.                         else if (*s == 'i') ++i;
  143.                         else if (*s == 'm') ++m;
  144.                         else js_syntaxerror(J, "invalid regular expression flag: '%c'", *s);
  145.                         ++s;
  146.                 }
  147.                 if (g > 1) js_syntaxerror(J, "invalid regular expression flag: 'g'");
  148.                 if (i > 1) js_syntaxerror(J, "invalid regular expression flag: 'i'");
  149.                 if (m > 1) js_syntaxerror(J, "invalid regular expression flag: 'm'");
  150.                 if (g) flags |= JS_REGEXP_G;
  151.                 if (i) flags |= JS_REGEXP_I;
  152.                 if (m) flags |= JS_REGEXP_M;
  153.         }
  154.  
  155.         js_newregexp(J, pattern, flags);
  156. }
  157.  
  158. static void jsB_RegExp(js_State *J)
  159. {
  160.         if (js_isregexp(J, 1))
  161.                 return;
  162.         jsB_new_RegExp(J);
  163. }
  164.  
  165. static void Rp_toString(js_State *J)
  166. {
  167.         js_Regexp *re;
  168.         char *out;
  169.  
  170.         re = js_toregexp(J, 0);
  171.  
  172.         out = js_malloc(J, strlen(re->source) + 6); /* extra space for //gim */
  173.         strcpy(out, "/");
  174.         strcat(out, re->source);
  175.         strcat(out, "/");
  176.         if (re->flags & JS_REGEXP_G) strcat(out, "g");
  177.         if (re->flags & JS_REGEXP_I) strcat(out, "i");
  178.         if (re->flags & JS_REGEXP_M) strcat(out, "m");
  179.  
  180.         if (js_try(J)) {
  181.                 js_free(J, out);
  182.                 js_throw(J);
  183.         }
  184.         js_pop(J, 0);
  185.         js_pushstring(J, out);
  186.         js_endtry(J);
  187.         js_free(J, out);
  188. }
  189.  
  190. static void Rp_exec(js_State *J)
  191. {
  192.         js_RegExp_prototype_exec(J, js_toregexp(J, 0), js_tostring(J, 1));
  193. }
  194.  
  195. void jsB_initregexp(js_State *J)
  196. {
  197.         js_pushobject(J, J->RegExp_prototype);
  198.         {
  199.                 jsB_propf(J, "RegExp.prototype.toString", Rp_toString, 0);
  200.                 jsB_propf(J, "RegExp.prototype.test", Rp_test, 0);
  201.                 jsB_propf(J, "RegExp.prototype.exec", Rp_exec, 0);
  202.         }
  203.         js_newcconstructor(J, jsB_RegExp, jsB_new_RegExp, "RegExp", 1);
  204.         js_defglobal(J, "RegExp", JS_DONTENUM);
  205. }
  206.