mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-22 07:03:36 +08:00
Encapsulate all regexp state in js_Regexp struct.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
typedef struct js_Regexp js_Regexp;
|
||||
typedef struct js_Value js_Value;
|
||||
typedef struct js_Object js_Object;
|
||||
typedef struct js_Ast js_Ast;
|
||||
@@ -38,13 +39,13 @@ void jsS_freestrings(js_State *J);
|
||||
void js_newfunction(js_State *J, js_Function *function, js_Environment *scope);
|
||||
void js_newscript(js_State *J, js_Function *function);
|
||||
|
||||
void *js_toregexp(js_State *J, int idx, int *flags);
|
||||
js_Regexp *js_toregexp(js_State *J, int idx);
|
||||
|
||||
void js_dup(js_State *J);
|
||||
void js_rot2(js_State *J);
|
||||
void js_rot3(js_State *J);
|
||||
|
||||
int js_RegExp_prototype_exec(js_State *J, int idx, const char *text);
|
||||
int js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text);
|
||||
|
||||
/* Exception handling */
|
||||
|
||||
|
||||
+85
-112
@@ -6,49 +6,6 @@
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
int js_RegExp_prototype_exec(js_State *J, int idx, const char *text)
|
||||
{
|
||||
js_Object *obj;
|
||||
int flags, opts, last;
|
||||
regex_t *prog;
|
||||
regmatch_t m[10];
|
||||
int i;
|
||||
|
||||
prog = js_toregexp(J, idx, &flags);
|
||||
obj = js_toobject(J, idx);
|
||||
|
||||
opts = 0;
|
||||
if (flags & JS_REGEXP_G) {
|
||||
last = obj->u.r.last;
|
||||
if (last < 0 || last > strlen(text)) {
|
||||
obj->u.r.last = 0;
|
||||
js_pushnull(J);
|
||||
return 1;
|
||||
}
|
||||
if (last > 0) {
|
||||
text += last;
|
||||
opts |= REG_NOTBOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!regexec(prog, text, nelem(m), m, opts)) {
|
||||
js_newarray(J);
|
||||
for (i = 0; i < nelem(m) && m[i].rm_so >= 0; ++i) {
|
||||
js_pushlstring(J, text + m[i].rm_so, m[i].rm_eo - m[i].rm_so);
|
||||
js_setindex(J, -2, i);
|
||||
}
|
||||
if (flags & JS_REGEXP_G)
|
||||
obj->u.r.last = last + m[0].rm_eo;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (flags & JS_REGEXP_G)
|
||||
obj->u.r.last = 0;
|
||||
|
||||
js_pushnull(J);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void js_newregexp(js_State *J, const char *pattern, int flags)
|
||||
{
|
||||
char msg[256];
|
||||
@@ -71,34 +28,98 @@ void js_newregexp(js_State *J, const char *pattern, int flags)
|
||||
}
|
||||
|
||||
obj->u.r.prog = prog;
|
||||
obj->u.r.source = pattern;
|
||||
obj->u.r.flags = flags;
|
||||
obj->u.r.last = 0;
|
||||
js_pushobject(J, obj);
|
||||
}
|
||||
|
||||
js_pushstring(J, pattern);
|
||||
js_defproperty(J, -2, "source", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
|
||||
js_pushboolean(J, flags & JS_REGEXP_G);
|
||||
js_defproperty(J, -2, "global", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
|
||||
js_pushboolean(J, flags & JS_REGEXP_I);
|
||||
js_defproperty(J, -2, "ignoreCase", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
|
||||
js_pushboolean(J, flags & JS_REGEXP_M);
|
||||
js_defproperty(J, -2, "multiline", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
|
||||
int js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text)
|
||||
{
|
||||
regmatch_t m[10];
|
||||
int opts;
|
||||
int i;
|
||||
|
||||
// TODO: lastIndex
|
||||
opts = 0;
|
||||
if (re->flags & JS_REGEXP_G) {
|
||||
if (re->last < 0 || re->last > strlen(text)) {
|
||||
re->last = 0;
|
||||
js_pushnull(J);
|
||||
return 1;
|
||||
}
|
||||
if (re->last > 0) {
|
||||
text += re->last;
|
||||
opts |= REG_NOTBOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!regexec(re->prog, text, nelem(m), m, opts)) {
|
||||
js_newarray(J);
|
||||
for (i = 0; i < nelem(m) && m[i].rm_so >= 0; ++i) {
|
||||
js_pushlstring(J, text + m[i].rm_so, m[i].rm_eo - m[i].rm_so);
|
||||
js_setindex(J, -2, i);
|
||||
}
|
||||
if (re->flags & JS_REGEXP_G)
|
||||
re->last = re->last + m[0].rm_eo;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (re->flags & JS_REGEXP_G)
|
||||
re->last = 0;
|
||||
|
||||
js_pushnull(J);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Rp_test(js_State *J, int argc)
|
||||
{
|
||||
js_Regexp *re;
|
||||
const char *text;
|
||||
regmatch_t m[10];
|
||||
int opts;
|
||||
|
||||
re = js_toregexp(J, 0);
|
||||
text = js_tostring(J, 1);
|
||||
|
||||
opts = 0;
|
||||
if (re->flags & JS_REGEXP_G) {
|
||||
if (re->last < 0 || re->last > strlen(text)) {
|
||||
re->last = 0;
|
||||
js_pushboolean(J, 0);
|
||||
return 1;
|
||||
}
|
||||
if (re->last > 0) {
|
||||
text += re->last;
|
||||
opts |= REG_NOTBOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!regexec(re->prog, text, nelem(m), m, opts)) {
|
||||
if (re->flags & JS_REGEXP_G)
|
||||
re->last = re->last + m[0].rm_eo;
|
||||
js_pushboolean(J, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (re->flags & JS_REGEXP_G)
|
||||
re->last = 0;
|
||||
|
||||
js_pushboolean(J, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int jsB_new_RegExp(js_State *J, int argc)
|
||||
{
|
||||
js_Regexp *old;
|
||||
const char *pattern;
|
||||
int flags;
|
||||
|
||||
if (js_isregexp(J, 1)) {
|
||||
if (argc > 1)
|
||||
js_typeerror(J, "cannot supply flags when creating one RegExp from another");
|
||||
js_toregexp(J, 1, &flags);
|
||||
js_getproperty(J, 1, "source");
|
||||
pattern = js_tostring(J, -1);
|
||||
js_pop(J, 1);
|
||||
old = js_toregexp(J, 1);
|
||||
pattern = old->source;
|
||||
flags = old->flags;
|
||||
} else if (js_isundefined(J, 1)) {
|
||||
pattern = "";
|
||||
flags = 0;
|
||||
@@ -138,26 +159,18 @@ static int jsB_RegExp(js_State *J, int argc)
|
||||
|
||||
static int Rp_toString(js_State *J, int argc)
|
||||
{
|
||||
const char *source;
|
||||
int flags;
|
||||
js_Regexp *re;
|
||||
char *out;
|
||||
|
||||
js_Object *self = js_toobject(J, 0);
|
||||
if (self->type != JS_CREGEXP)
|
||||
js_typeerror(J, "not a regexp");
|
||||
re = js_toregexp(J, 0);
|
||||
|
||||
flags = self->u.r.flags;
|
||||
|
||||
js_getproperty(J, 0, "source");
|
||||
source = js_tostring(J, -1);
|
||||
|
||||
out = malloc(strlen(source) + 6); /* extra space for //gim */
|
||||
out = malloc(strlen(re->source) + 6); /* extra space for //gim */
|
||||
strcpy(out, "/");
|
||||
strcat(out, source);
|
||||
strcat(out, re->source);
|
||||
strcat(out, "/");
|
||||
if (flags & JS_REGEXP_G) strcat(out, "g");
|
||||
if (flags & JS_REGEXP_I) strcat(out, "i");
|
||||
if (flags & JS_REGEXP_M) strcat(out, "m");
|
||||
if (re->flags & JS_REGEXP_G) strcat(out, "g");
|
||||
if (re->flags & JS_REGEXP_I) strcat(out, "i");
|
||||
if (re->flags & JS_REGEXP_M) strcat(out, "m");
|
||||
|
||||
if (js_try(J)) {
|
||||
free(out);
|
||||
@@ -172,47 +185,7 @@ static int Rp_toString(js_State *J, int argc)
|
||||
|
||||
static int Rp_exec(js_State *J, int argc)
|
||||
{
|
||||
return js_RegExp_prototype_exec(J, 0, js_tostring(J, 1));
|
||||
}
|
||||
|
||||
static int Rp_test(js_State *J, int argc)
|
||||
{
|
||||
int flags, opts, last;
|
||||
js_Object *obj;
|
||||
regmatch_t m[10];
|
||||
regex_t *prog;
|
||||
const char *text;
|
||||
|
||||
prog = js_toregexp(J, 0, &flags);
|
||||
obj = js_toobject(J, 0);
|
||||
text = js_tostring(J, 1);
|
||||
|
||||
opts = 0;
|
||||
if (flags & JS_REGEXP_G) {
|
||||
last = obj->u.r.last;
|
||||
if (last < 0 || last > strlen(text)) {
|
||||
obj->u.r.last = 0;
|
||||
js_pushboolean(J, 0);
|
||||
return 1;
|
||||
}
|
||||
if (last > 0) {
|
||||
text += last;
|
||||
opts |= REG_NOTBOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!regexec(prog, text, nelem(m), m, opts)) {
|
||||
if (flags & JS_REGEXP_G)
|
||||
obj->u.r.last = last + m[0].rm_eo;
|
||||
js_pushboolean(J, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (flags & JS_REGEXP_G)
|
||||
obj->u.r.last = 0;
|
||||
|
||||
js_pushboolean(J, 0);
|
||||
return 1;
|
||||
return js_RegExp_prototype_exec(J, js_toregexp(J, 0), js_tostring(J, 1));
|
||||
}
|
||||
|
||||
void jsB_initregexp(js_State *J)
|
||||
|
||||
@@ -207,11 +207,11 @@ js_Value js_toprimitive(js_State *J, int idx, int hint)
|
||||
return jsV_toprimitive(J, stackidx(J, idx), hint);
|
||||
}
|
||||
|
||||
void *js_toregexp(js_State *J, int idx, int *flags)
|
||||
js_Regexp *js_toregexp(js_State *J, int idx)
|
||||
{
|
||||
const js_Value *v = stackidx(J, idx);
|
||||
if (v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP)
|
||||
return *flags = v->u.object->u.r.flags, v->u.object->u.r.prog;
|
||||
return &v->u.object->u.r;
|
||||
js_typeerror(J, "not a regexp");
|
||||
}
|
||||
|
||||
|
||||
+27
-30
@@ -318,10 +318,9 @@ static int S_fromCharCode(js_State *J, int argc)
|
||||
|
||||
static int Sp_match(js_State *J, int argc)
|
||||
{
|
||||
js_Regexp *re;
|
||||
regmatch_t m[10];
|
||||
const char *text;
|
||||
regmatch_t m;
|
||||
regex_t *prog;
|
||||
int flags;
|
||||
unsigned int len, a, b, c, e;
|
||||
|
||||
text = js_tostring(J, 0);
|
||||
@@ -333,9 +332,9 @@ static int Sp_match(js_State *J, int argc)
|
||||
else
|
||||
js_newregexp(J, js_tostring(J, 1), 0);
|
||||
|
||||
prog = js_toregexp(J, -1, &flags);
|
||||
if (!(flags & JS_REGEXP_G))
|
||||
return js_RegExp_prototype_exec(J, -1, text);
|
||||
re = js_toregexp(J, -1);
|
||||
if (!(re->flags & JS_REGEXP_G))
|
||||
return js_RegExp_prototype_exec(J, re, text);
|
||||
|
||||
js_newarray(J);
|
||||
|
||||
@@ -343,11 +342,11 @@ static int Sp_match(js_State *J, int argc)
|
||||
len = 0;
|
||||
a = 0;
|
||||
while (a <= e) {
|
||||
if (regexec(prog, text + a, 1, &m, a > 0 ? REG_NOTBOL : 0))
|
||||
if (regexec(re->prog, text + a, nelem(m), m, a > 0 ? REG_NOTBOL : 0))
|
||||
break;
|
||||
|
||||
b = a + m.rm_so;
|
||||
c = a + m.rm_eo;
|
||||
b = a + m[0].rm_so;
|
||||
c = a + m[0].rm_eo;
|
||||
|
||||
js_pushlstring(J, text + b, c - b);
|
||||
js_setindex(J, -2, len++);
|
||||
@@ -362,10 +361,9 @@ static int Sp_match(js_State *J, int argc)
|
||||
|
||||
static int Sp_search(js_State *J, int argc)
|
||||
{
|
||||
js_Regexp *re;
|
||||
regmatch_t m[10];
|
||||
const char *text;
|
||||
regmatch_t m;
|
||||
regex_t *prog;
|
||||
int flags;
|
||||
|
||||
text = js_tostring(J, 0);
|
||||
|
||||
@@ -376,10 +374,10 @@ static int Sp_search(js_State *J, int argc)
|
||||
else
|
||||
js_newregexp(J, js_tostring(J, 1), 0);
|
||||
|
||||
prog = js_toregexp(J, -1, &flags);
|
||||
re = js_toregexp(J, -1);
|
||||
|
||||
if (!regexec(prog, text, 1, &m, 0))
|
||||
js_pushnumber(J, m.rm_so); // TODO: convert to utf-8 index offset
|
||||
if (!regexec(re->prog, text, nelem(m), m, 0))
|
||||
js_pushnumber(J, m[0].rm_so); // TODO: convert to utf-8 index offset
|
||||
else
|
||||
js_pushnumber(J, -1);
|
||||
|
||||
@@ -388,17 +386,16 @@ static int Sp_search(js_State *J, int argc)
|
||||
|
||||
static int Sp_replace_regexp(js_State *J, int argc)
|
||||
{
|
||||
const char *source, *s, *r;
|
||||
js_Regexp *re;
|
||||
regmatch_t m[10];
|
||||
regex_t *prog;
|
||||
int flags;
|
||||
const char *source, *s, *r;
|
||||
struct sbuffer *sb = NULL;
|
||||
int n, x;
|
||||
|
||||
source = js_tostring(J, 0);
|
||||
prog = js_toregexp(J, 1, &flags);
|
||||
re = js_toregexp(J, 1);
|
||||
|
||||
if (regexec(prog, source, nelem(m), m, 0)) {
|
||||
if (regexec(re->prog, source, nelem(m), m, 0)) {
|
||||
js_copy(J, 0);
|
||||
return 1;
|
||||
}
|
||||
@@ -453,7 +450,7 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & JS_REGEXP_G) {
|
||||
if (re->flags & JS_REGEXP_G) {
|
||||
source = source + m[0].rm_eo;
|
||||
if (n == 0) {
|
||||
if (*source)
|
||||
@@ -461,7 +458,7 @@ loop:
|
||||
else
|
||||
goto end;
|
||||
}
|
||||
if (!regexec(prog, source, nelem(m), m, REG_NOTBOL))
|
||||
if (!regexec(re->prog, source, nelem(m), m, REG_NOTBOL))
|
||||
goto loop;
|
||||
}
|
||||
|
||||
@@ -548,15 +545,15 @@ static int Sp_replace(js_State *J, int argc)
|
||||
|
||||
static int Sp_split_regexp(js_State *J, int argc)
|
||||
{
|
||||
const char *str = js_tostring(J, 0);
|
||||
unsigned int limit = !js_isundefined(J, 2) ? js_touint32(J, 2) : 1 << 30;
|
||||
js_Regexp *re;
|
||||
regmatch_t m[10];
|
||||
regex_t *prog;
|
||||
int flags;
|
||||
unsigned int len, k, e;
|
||||
const char *str;
|
||||
unsigned int limit, len, k, e;
|
||||
unsigned int p, a, b, c;
|
||||
|
||||
prog = js_toregexp(J, 1, &flags);
|
||||
str = js_tostring(J, 0);
|
||||
re = js_toregexp(J, 1);
|
||||
limit = !js_isundefined(J, 2) ? js_touint32(J, 2) : 1 << 30;
|
||||
|
||||
js_newarray(J);
|
||||
len = 0;
|
||||
@@ -565,7 +562,7 @@ static int Sp_split_regexp(js_State *J, int argc)
|
||||
|
||||
/* splitting the empty string */
|
||||
if (e == 0) {
|
||||
if (regexec(prog, str, nelem(m), m, 0)) {
|
||||
if (regexec(re->prog, str, nelem(m), m, 0)) {
|
||||
if (len == limit) return 1;
|
||||
js_pushliteral(J, "");
|
||||
js_setindex(J, -2, 0);
|
||||
@@ -575,7 +572,7 @@ static int Sp_split_regexp(js_State *J, int argc)
|
||||
|
||||
p = a = 0;
|
||||
while (a < e) {
|
||||
if (regexec(prog, str + a, nelem(m), m, a > 0 ? REG_NOTBOL : 0))
|
||||
if (regexec(re->prog, str + a, nelem(m), m, a > 0 ? REG_NOTBOL : 0))
|
||||
break; /* no match */
|
||||
|
||||
b = a + m[0].rm_so;
|
||||
|
||||
@@ -44,6 +44,14 @@ struct js_Value
|
||||
} u;
|
||||
};
|
||||
|
||||
struct js_Regexp
|
||||
{
|
||||
void *prog;
|
||||
const char *source;
|
||||
unsigned short flags;
|
||||
unsigned short last;
|
||||
};
|
||||
|
||||
struct js_Object
|
||||
{
|
||||
js_Class type;
|
||||
@@ -65,11 +73,7 @@ struct js_Object
|
||||
js_CFunction function;
|
||||
js_CFunction constructor;
|
||||
} c;
|
||||
struct {
|
||||
void *prog;
|
||||
unsigned short flags;
|
||||
unsigned short last;
|
||||
} r;
|
||||
js_Regexp r;
|
||||
struct {
|
||||
js_Object *target;
|
||||
js_Iterator *head;
|
||||
|
||||
Reference in New Issue
Block a user