📄 b_regexp.c
字号:
+ ctx->regs.start[i],
ctx->regs.end[i] - ctx->regs.start[i]);
}
}
/* ********************************************************************** */
else if (property == ctx->s_leftContext)
{
if (set)
goto immutable;
if (ctx->input.type != JS_STRING
|| ctx->regs.end[0] > ctx->input.u.vstring->len)
node->type = JS_UNDEFINED;
else
js_vm_make_string (vm, node, (char*)ctx->input.u.vstring->data,
ctx->regs.start[0]);
}
/* ********************************************************************** */
else if (property == ctx->s_multiline)
{
goto not_implemented_yet;
}
/* ********************************************************************** */
else if (property == ctx->s_rightContext)
{
if (set)
goto immutable;
if (ctx->input.type != JS_STRING
|| ctx->regs.end[0] > ctx->input.u.vstring->len)
node->type = JS_UNDEFINED;
else
js_vm_make_string (vm, node,
(char*)ctx->input.u.vstring->data + ctx->regs.end[0],
ctx->input.u.vstring->len - ctx->regs.end[0]);
}
/* ********************************************************************** */
else if (ictx)
{
/* Properties. */
if (property == ctx->s_global)
{
if (set)
goto immutable;
node->type = JS_BOOLEAN;
node->u.vboolean = ictx->global;
}
/* ***************************************************************** */
else if (property == ctx->s_ignoreCase)
{
if (set)
goto immutable;
node->type = JS_BOOLEAN;
node->u.vboolean = ictx->ignore_case;
}
/* ***************************************************************** */
else if (property == ctx->s_lastIndex)
{
if (set)
{
if (ictx->immutable)
goto immutable_object;
if (node->type != JS_INTEGER)
goto argument_type_error;
ictx->last_index = node->u.vinteger;
}
else
{
node->type = JS_INTEGER;
node->u.vinteger = ictx->last_index;
}
}
/* ***************************************************************** */
else if (property == ctx->s_source)
{
if (set)
goto immutable;
js_vm_make_string (vm, node, ictx->source, ictx->source_len);
}
/* ***************************************************************** */
else
{
if (!set)
node->type = JS_UNDEFINED;
return JS_PROPERTY_UNKNOWN;
}
}
/* ********************************************************************** */
else
{
if (!set)
node->type = JS_UNDEFINED;
return JS_PROPERTY_UNKNOWN;
}
return JS_PROPERTY_FOUND;
/* Error handling. */
argument_type_error:
sprintf (vm->error, "RegExp.%s: illegal value",
js_vm_symname (vm, property));
js_vm_error (vm);
not_implemented_yet:
sprintf (vm->error, "RegExp.%s: not implemented yet",
js_vm_symname (vm, property));
js_vm_error (vm);
immutable:
sprintf (vm->error, "RegExp.%s: immutable property",
js_vm_symname (vm, property));
js_vm_error (vm);
immutable_object:
sprintf (vm->error, "RegExp.%s: immutable object",
js_vm_symname (vm, property));
js_vm_error (vm);
/* NOTREACHED */
return 0;
}
/* New proc. */
static void
new_proc (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, JSNode *args,
JSNode *result_return)
{
unsigned int flags = 0;
char *source;
unsigned int source_len;
int i;
if (args->u.vinteger > 2)
{
sprintf (vm->error, "new RegExp(): illegal amount of arguments");
js_vm_error (vm);
}
if (args->u.vinteger == 0)
{
source = "";
source_len = 0;
}
else
{
if (args[1].type != JS_STRING)
{
argument_type_error:
sprintf (vm->error, "new RegExp(): illegal argument");
js_vm_error (vm);
}
source = (char*)args[1].u.vstring->data;
source_len = args[1].u.vstring->len;
}
if (args->u.vinteger == 2)
{
if (args[2].type != JS_STRING)
goto argument_type_error;
for (i = 0; i < args[2].u.vstring->len; i++)
switch (args[2].u.vstring->data[i])
{
case 'g':
flags |= JS_REGEXP_FLAG_G;
break;
case 'i':
flags |= JS_REGEXP_FLAG_I;
break;
default:
sprintf (vm->error, "new RegExp(): illegal flag `%c'",
args[2].u.vstring->data[i]);
js_vm_error (vm);
break;
}
}
js_builtin_RegExp_new (vm, source, source_len, flags, 0, builtin_info,
result_return);
}
/* Delete proc. */
static void
delete_proc (JSBuiltinInfo *builtin_info, void *instance_context)
{
RegexpInstanceCtx *ictx = instance_context;
if (ictx)
{
js_free (ictx->source);
if (ictx->compiled.buffer)
js_free (ictx->compiled.buffer);
if (ictx->compiled.fastmap)
js_free (ictx->compiled.fastmap);
js_free (ictx);
}
}
/* Mark proc. */
static void
mark (JSBuiltinInfo *builtin_info, void *instance_context)
{
RegexpCtx *ctx = builtin_info->obj_context;
js_vm_mark (&ctx->input);
}
/*
* Global functions.
*/
void
js_builtin_RegExp (JSVirtualMachine *vm)
{
JSBuiltinInfo *info;
RegexpCtx *ctx;
JSNode *n;
ctx = js_calloc (vm, 1, sizeof (*ctx));
ctx->s_S1 = js_vm_intern (vm, "$1");
ctx->s_S2 = js_vm_intern (vm, "$2");
ctx->s_S3 = js_vm_intern (vm, "$3");
ctx->s_S4 = js_vm_intern (vm, "$4");
ctx->s_S5 = js_vm_intern (vm, "$5");
ctx->s_S6 = js_vm_intern (vm, "$6");
ctx->s_S7 = js_vm_intern (vm, "$7");
ctx->s_S8 = js_vm_intern (vm, "$8");
ctx->s_S9 = js_vm_intern (vm, "$9");
ctx->s_S_ = js_vm_intern (vm, "$_");
ctx->s_input = js_vm_intern (vm, "input");
ctx->s_lastMatch = js_vm_intern (vm, "lastMatch");
ctx->s_lastParen = js_vm_intern (vm, "lastParen");
ctx->s_leftContext = js_vm_intern (vm, "leftContext");
ctx->s_multiline = js_vm_intern (vm, "multiline");
ctx->s_rightContext = js_vm_intern (vm, "rightContext");
ctx->s_global = js_vm_intern (vm, "global");
ctx->s_ignoreCase = js_vm_intern (vm, "ignoreCase");
ctx->s_lastIndex = js_vm_intern (vm, "lastIndex");
ctx->s_source = js_vm_intern (vm, "source");
ctx->s_compile = js_vm_intern (vm, "compile");
ctx->s_exec = js_vm_intern (vm, "exec");
ctx->s_test = js_vm_intern (vm, "test");
/* Object information. */
info = js_vm_builtin_info_create (vm);
info->global_method_proc = global_method;
info->method_proc = method;
info->property_proc = property;
info->new_proc = new_proc;
info->delete_proc = delete_proc;
info->mark_proc = mark;
info->obj_context = ctx;
info->obj_context_delete = js_free;
/* Define it. */
n = &vm->globals[js_vm_intern (vm, "RegExp")];
js_vm_builtin_create (vm, n, info, NULL);
}
void
js_builtin_RegExp_new (JSVirtualMachine *vm, char *source,
unsigned int source_len, unsigned int flags,
int immutable, JSBuiltinInfo *info,
JSNode *result_return)
{
RegexpInstanceCtx *instance;
const char *error;
instance = js_calloc (vm, 1, sizeof (*instance));
instance->source_len = source_len;
/* +1 to avoid zero allocation. */
instance->source = js_malloc (vm, instance->source_len + 1);
memcpy (instance->source, source, instance->source_len);
instance->global = (flags & JS_REGEXP_FLAG_G) != 0;
instance->ignore_case = (flags & JS_REGEXP_FLAG_I) != 0;
instance->immutable = immutable;
if (instance->ignore_case)
instance->compiled.translate = js_latin1_tolower;
error = re_compile_pattern (instance->source, instance->source_len,
&instance->compiled);
if (error)
{
js_free (instance->source);
js_free (instance);
sprintf (vm->error,
"new RegExp(): compilation of the expression failed: %s",
error);
js_vm_error (vm);
}
instance->compiled.fastmap = js_malloc (vm, 256);
re_compile_fastmap (&instance->compiled);
if (info == NULL)
{
JSNode *n;
n = &vm->globals[js_vm_intern (vm, "RegExp")];
info = n->u.vbuiltin->info;
}
/* Create a new object. */
js_vm_builtin_create (vm, result_return, info, instance);
}
#define EMIT_TO_RESULT(md, mdl) \
do { \
result_return->u.vstring->data \
= js_vm_realloc (vm, result_return->u.vstring->data, \
result_return->u.vstring->len + (mdl)); \
memcpy (result_return->u.vstring->data \
+ result_return->u.vstring->len, \
(md), (mdl)); \
result_return->u.vstring->len += (mdl); \
} while (0)
void
js_builtin_RegExp_replace (JSVirtualMachine *vm, char *data,
unsigned int datalen, JSNode *regexp,
char *repl, unsigned int repllen,
JSNode *result_return)
{
int i, j;
RegexpInstanceCtx *ictx = regexp->u.vbuiltin->instance_context;
struct re_registers regs = {0};
unsigned int substs = 0;
unsigned int pos = 0;
/*
* Allocate the result string, Let's guess that we need at least
* <datalen> bytes of data.
*/
js_vm_make_string (vm, result_return, NULL, datalen);
result_return->u.vstring->len = 0;
/* Do searches. */
while (pos < datalen)
{
i = re_search (&ictx->compiled, data, datalen, pos, datalen - pos,
®s);
/* Check what we got. */
if (i >= 0)
{
/* Emit all up to the first matched character. */
EMIT_TO_RESULT (data + pos, regs.start[0] - pos);
/* Check for empty matches. */
if (regs.end[0] == regs.start[0])
{
pos = regs.end[0];
/* Still something left to search? */
if (pos < datalen)
{
/* Go one character forward. */
EMIT_TO_RESULT (data + pos, 1);
pos++;
}
}
else
{
int start;
/* Not an empty match. */
substs++;
/* Interpret replace string. */
start = 0;
for (i = 0; i < repllen; i++)
{
if (repl[i] == '$')
{
if (i + 1 >= repllen)
/* The last character is '$'. Just emit it. */
continue;
/* First, emit all we have collected so far. */
EMIT_TO_RESULT (repl + start, i - start);
start = i++;
/* Check tag. */
switch (repl[i])
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* n:th subexpression. */
j = repl[i] - '0';
if (regs.start[j] >= 0)
EMIT_TO_RESULT (data + regs.start[j],
regs.end[j] - regs.start[j]);
start = i + 1;
break;
case '`':
/* Left context. */
EMIT_TO_RESULT (data, regs.start[0]);
start = i + 1;
break;
case '\'':
/* Right context. */
EMIT_TO_RESULT (data + regs.end[0],
datalen - regs.end[0]);
start = i + 1;
break;
case '&':
/* Last match. */
EMIT_TO_RESULT (data + regs.start[0],
regs.end[0] - regs.start[0]);
start = i + 1;
break;
case '$':
/* The dollar sign. */
EMIT_TO_RESULT ("$", 1);
start = i + 1;
break;
case '+':
default:
/* Ignore. */
start = i - 1;
break;
}
}
}
/* Emit all leftovers. */
EMIT_TO_RESULT (repl + start, i - start);
/* Update search position. */
pos = regs.end[0];
}
}
else
break;
if (!ictx->global && substs > 0)
/* Substitute only the first match. */
break;
}
/* No more matches. Emit the rest of the string to the result. */
EMIT_TO_RESULT (data + pos, datalen - pos);
if (regs.start)
js_free (regs.start);
if (regs.end)
js_free (regs.end);
}
void
js_builtin_RegExp_match (JSVirtualMachine *vm, char *data,
unsigned int datalen, JSNode *regexp,
JSNode *result_return)
{
do_exec (vm, regexp->u.vbuiltin->info->obj_context,
regexp->u.vbuiltin->instance_context, data, datalen,
result_return);
}
void
js_builtin_RegExp_search (JSVirtualMachine *vm, char *data,
unsigned int datalen, JSNode *regexp,
JSNode *result_return)
{
RegexpCtx *ctx = regexp->u.vbuiltin->info->obj_context;
RegexpInstanceCtx *ictx = regexp->u.vbuiltin->instance_context;
result_return->type = JS_INTEGER;
result_return->u.vinteger = re_search (&ictx->compiled, data, datalen,
ictx->global ? ictx->last_index : 0,
datalen, &ctx->regs);
if (result_return->u.vinteger >= 0)
ictx->last_index = ctx->regs.end[0];
}
void
js_builtin_RegExp_split (JSVirtualMachine *vm, char *data,
unsigned int datalen, JSNode *regexp,
unsigned int limit, JSNode *result_return)
{
unsigned int start = 0, pos;
unsigned int alen = 0;
RegexpInstanceCtx *ictx = regexp->u.vbuiltin->instance_context;
struct re_registers regs = {0};
int i;
js_vm_make_array (vm, result_return, alen);
for (pos = 0; alen < limit && pos <= datalen; )
{
i = re_search (&ictx->compiled, data, datalen, pos, datalen - pos,
®s);
if (i < 0)
{
pos = datalen;
break;
}
/* Found the separator. */
js_vm_expand_array (vm, result_return, alen + 1);
js_vm_make_string (vm, &result_return->u.varray->data[alen],
data + start, regs.start[0] - start);
alen++;
if (regs.end[0] == pos)
{
/* We didn't advance in the string. */
start = regs.end[0];
pos++;
}
else
pos = start = regs.end[0];
}
if (alen < limit)
{
/* Insert all leftovers. */
js_vm_expand_array (vm, result_return, alen + 1);
js_vm_make_string (vm, &result_return->u.varray->data[alen],
data + start, datalen - start);
}
if (regs.start)
js_free (regs.start);
if (regs.end)
js_free (regs.end);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -