Add RegExp class (with no actual regex implementation hooked up).

This commit is contained in:
Tor Andersson
2014-01-28 17:19:09 +01:00
parent 01cab639cb
commit 8e10640e9e
10 changed files with 168 additions and 0 deletions
+2
View File
@@ -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);
+2
View File
@@ -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);
+1
View File
@@ -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);
+6
View File
@@ -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);
+1
View File
@@ -26,6 +26,7 @@ enum js_OpCode
OP_NEWARRAY,
OP_NEWOBJECT,
OP_NEWREGEXP,
OP_UNDEF,
OP_NULL,
+5
View File
@@ -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:
+3
View File
@@ -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
View File
@@ -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);
}
+15
View File
@@ -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;
+4
View File
@@ -65,6 +65,10 @@ struct js_Object
js_CFunction function;
js_CFunction constructor;
} c;
struct {
void *prog;
int flags;
} r;
struct {
js_Object *target;
js_Iterator *head;