mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-23 00:38:31 +08:00
Add RegExp class (with no actual regex implementation hooked up).
This commit is contained in:
@@ -118,6 +118,7 @@ void js_newerror(js_State *J, const char *message);
|
||||
void js_newcfunction(js_State *J, js_CFunction fun, int length);
|
||||
void js_newcconstructor(js_State *J, js_CFunction fun, js_CFunction con, int length);
|
||||
void js_newuserdata(js_State *J, const char *tag, void *data);
|
||||
void js_newregexp(js_State *J, const char *pattern, int flags);
|
||||
|
||||
int js_isundefined(js_State *J, int idx);
|
||||
int js_isnull(js_State *J, int idx);
|
||||
@@ -127,6 +128,7 @@ int js_isstring(js_State *J, int idx);
|
||||
int js_isprimitive(js_State *J, int idx);
|
||||
int js_isobject(js_State *J, int idx);
|
||||
int js_isarray(js_State *J, int idx);
|
||||
int js_isregexp(js_State *J, int idx);
|
||||
int js_iscallable(js_State *J, int idx);
|
||||
int js_isuserdata(js_State *J, const char *tag, int idx);
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ void jsB_init(js_State *J)
|
||||
J->Boolean_prototype = jsV_newobject(J, JS_CBOOLEAN, J->Object_prototype);
|
||||
J->Number_prototype = jsV_newobject(J, JS_CNUMBER, J->Object_prototype);
|
||||
J->String_prototype = jsV_newobject(J, JS_CSTRING, J->Object_prototype);
|
||||
J->RegExp_prototype = jsV_newobject(J, JS_COBJECT, J->Object_prototype);
|
||||
J->Date_prototype = jsV_newobject(J, JS_CDATE, J->Object_prototype);
|
||||
|
||||
/* All the native error types */
|
||||
@@ -93,6 +94,7 @@ void jsB_init(js_State *J)
|
||||
jsB_initboolean(J);
|
||||
jsB_initnumber(J);
|
||||
jsB_initstring(J);
|
||||
jsB_initregexp(J);
|
||||
jsB_initerror(J);
|
||||
jsB_initmath(J);
|
||||
jsB_initdate(J);
|
||||
|
||||
@@ -8,6 +8,7 @@ void jsB_initfunction(js_State *J);
|
||||
void jsB_initboolean(js_State *J);
|
||||
void jsB_initnumber(js_State *J);
|
||||
void jsB_initstring(js_State *J);
|
||||
void jsB_initregexp(js_State *J);
|
||||
void jsB_initerror(js_State *J);
|
||||
void jsB_initmath(js_State *J);
|
||||
void jsB_initdate(js_State *J);
|
||||
|
||||
@@ -402,6 +402,12 @@ static void cexp(JF, js_Ast *exp)
|
||||
case EXP_FALSE: emit(J, F, OP_FALSE); break;
|
||||
case EXP_THIS: emit(J, F, OP_THIS); break;
|
||||
|
||||
case AST_REGEXP:
|
||||
emit(J, F, OP_NEWREGEXP);
|
||||
emitraw(J, F, addstring(J, F, exp->string));
|
||||
emitraw(J, F, exp->number);
|
||||
break;
|
||||
|
||||
case EXP_OBJECT:
|
||||
emit(J, F, OP_NEWOBJECT);
|
||||
cobject(J, F, exp->a);
|
||||
|
||||
@@ -26,6 +26,7 @@ enum js_OpCode
|
||||
|
||||
OP_NEWARRAY,
|
||||
OP_NEWOBJECT,
|
||||
OP_NEWREGEXP,
|
||||
|
||||
OP_UNDEF,
|
||||
OP_NULL,
|
||||
|
||||
@@ -642,6 +642,11 @@ void jsC_dumpfunction(js_State *J, js_Function *F)
|
||||
pc(' ');
|
||||
pstr(F->strtab[*p++]);
|
||||
break;
|
||||
case OP_NEWREGEXP:
|
||||
pc(' ');
|
||||
pregexp(F->strtab[p[0]], p[1]);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
case OP_FUNDEC:
|
||||
case OP_VARDEC:
|
||||
|
||||
@@ -38,6 +38,8 @@ 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);
|
||||
|
||||
void js_dup(js_State *J);
|
||||
void js_rot2(js_State *J);
|
||||
void js_rot3(js_State *J);
|
||||
@@ -97,6 +99,7 @@ struct js_State
|
||||
js_Object *Boolean_prototype;
|
||||
js_Object *Number_prototype;
|
||||
js_Object *String_prototype;
|
||||
js_Object *RegExp_prototype;
|
||||
js_Object *Date_prototype;
|
||||
|
||||
js_Object *Error_prototype;
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
#include "jsi.h"
|
||||
#include "jsvalue.h"
|
||||
#include "jsbuiltin.h"
|
||||
|
||||
void js_newregexp(js_State *J, const char *pattern, int flags)
|
||||
{
|
||||
js_Object *obj;
|
||||
|
||||
obj = jsV_newobject(J, JS_CREGEXP, J->RegExp_prototype);
|
||||
obj->u.r.prog = NULL;
|
||||
obj->u.r.flags = flags;
|
||||
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);
|
||||
|
||||
// TODO: lastIndex
|
||||
}
|
||||
|
||||
static int jsB_new_RegExp(js_State *J, int argc)
|
||||
{
|
||||
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);
|
||||
} else if (js_isundefined(J, 1)) {
|
||||
pattern = "";
|
||||
} else {
|
||||
pattern = js_tostring(J, 1);
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
const char *s = js_tostring(J, 2);
|
||||
int g = 0, i = 0, m = 0;
|
||||
while (*s) {
|
||||
if (*s == 'g') ++g;
|
||||
else if (*s == 'i') ++i;
|
||||
else if (*s == 'm') ++m;
|
||||
else js_syntaxerror(J, "invalid regular expression flag: '%c'", *s);
|
||||
++s;
|
||||
}
|
||||
if (g > 1) js_syntaxerror(J, "invalid regular expression flag: 'g'");
|
||||
if (i > 1) js_syntaxerror(J, "invalid regular expression flag: 'i'");
|
||||
if (m > 1) js_syntaxerror(J, "invalid regular expression flag: 'm'");
|
||||
if (g) flags |= JS_REGEXP_G;
|
||||
if (i) flags |= JS_REGEXP_I;
|
||||
if (m) flags |= JS_REGEXP_M;
|
||||
}
|
||||
|
||||
js_newregexp(J, pattern, flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int jsB_RegExp(js_State *J, int argc)
|
||||
{
|
||||
if (js_isregexp(J, 1) && argc == 1)
|
||||
return 1;
|
||||
return jsB_new_RegExp(J, argc);
|
||||
}
|
||||
|
||||
static int Rp_toString(js_State *J, int argc)
|
||||
{
|
||||
const char *source;
|
||||
int flags;
|
||||
char *out;
|
||||
|
||||
js_Object *self = js_toobject(J, 0);
|
||||
if (self->type != JS_CREGEXP)
|
||||
js_typeerror(J, "not a regexp");
|
||||
|
||||
flags = self->u.r.flags;
|
||||
|
||||
js_getproperty(J, 0, "source");
|
||||
source = js_tostring(J, -1);
|
||||
|
||||
out = malloc(strlen(source) + 6); /* extra space for //gim */
|
||||
strcpy(out, "/");
|
||||
strcat(out, 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 (js_try(J)) {
|
||||
free(out);
|
||||
js_throw(J);
|
||||
}
|
||||
js_pop(J, 0);
|
||||
js_pushstring(J, out);
|
||||
js_endtry(J);
|
||||
free(out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Rp_exec(js_State *J, int argc)
|
||||
{
|
||||
js_pushnull(J);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Rp_test(js_State *J, int argc)
|
||||
{
|
||||
js_pushboolean(J, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void jsB_initregexp(js_State *J)
|
||||
{
|
||||
js_pushobject(J, J->RegExp_prototype);
|
||||
{
|
||||
jsB_propf(J, "toString", Rp_toString, 0);
|
||||
jsB_propf(J, "test", Rp_test, 0);
|
||||
jsB_propf(J, "exec", Rp_exec, 0);
|
||||
}
|
||||
js_newcconstructor(J, jsB_RegExp, jsB_new_RegExp, 1);
|
||||
js_defglobal(J, "RegExp", JS_DONTENUM);
|
||||
}
|
||||
@@ -104,6 +104,12 @@ int js_isarray(js_State *J, int idx)
|
||||
return v->type == JS_TOBJECT && v->u.object->type == JS_CARRAY;
|
||||
}
|
||||
|
||||
int js_isregexp(js_State *J, int idx)
|
||||
{
|
||||
const js_Value *v = stackidx(J, idx);
|
||||
return v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP;
|
||||
}
|
||||
|
||||
int js_isiterator(js_State *J, int idx)
|
||||
{
|
||||
const js_Value *v = stackidx(J, idx);
|
||||
@@ -176,6 +182,14 @@ 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)
|
||||
{
|
||||
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;
|
||||
js_typeerror(J, "not a regexp");
|
||||
}
|
||||
|
||||
void *js_touserdata(js_State *J, const char *tag, int idx)
|
||||
{
|
||||
const js_Value *v = stackidx(J, idx);
|
||||
@@ -743,6 +757,7 @@ static void jsR_run(js_State *J, js_Function *F)
|
||||
case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break;
|
||||
case OP_NEWOBJECT: js_newobject(J); break;
|
||||
case OP_NEWARRAY: js_newarray(J); break;
|
||||
case OP_NEWREGEXP: js_newregexp(J, ST[pc[0]], pc[1]); pc += 2; break;
|
||||
|
||||
case OP_UNDEF: js_pushundefined(J); break;
|
||||
case OP_NULL: js_pushnull(J); break;
|
||||
|
||||
Reference in New Issue
Block a user