mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-27 22:37:47 +08:00
Preserve regexp flags. Escape more characters when dumping strings.
This commit is contained in:
@@ -13,6 +13,10 @@ typedef struct js_State js_State;
|
|||||||
typedef struct js_StringNode js_StringNode;
|
typedef struct js_StringNode js_StringNode;
|
||||||
typedef struct js_Ast js_Ast;
|
typedef struct js_Ast js_Ast;
|
||||||
|
|
||||||
|
#define JS_REGEXP_G 1
|
||||||
|
#define JS_REGEXP_I 2
|
||||||
|
#define JS_REGEXP_M 4
|
||||||
|
|
||||||
typedef int (*js_CFunction)(js_State *J);
|
typedef int (*js_CFunction)(js_State *J);
|
||||||
|
|
||||||
js_State *js_newstate(void);
|
js_State *js_newstate(void);
|
||||||
|
|||||||
@@ -92,17 +92,29 @@ static void pobject(int d, js_Ast *list)
|
|||||||
|
|
||||||
static void pstr(const char *s)
|
static void pstr(const char *s)
|
||||||
{
|
{
|
||||||
|
int c;
|
||||||
pc('"');
|
pc('"');
|
||||||
while (*s) {
|
while ((c = *s++)) {
|
||||||
if (*s == '"')
|
switch (c) {
|
||||||
ps("\\\"");
|
case '"': ps("\\\""); break;
|
||||||
else
|
case '\\': ps("\\\\"); break;
|
||||||
pc(*s);
|
case '\n': ps("\\n"); break;
|
||||||
++s;
|
default: pc(c); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pc('"');
|
pc('"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pregexp(const char *prog, int flags)
|
||||||
|
{
|
||||||
|
pc('/');
|
||||||
|
ps(prog);
|
||||||
|
pc('/');
|
||||||
|
if (flags & JS_REGEXP_G) pc('g');
|
||||||
|
if (flags & JS_REGEXP_I) pc('i');
|
||||||
|
if (flags & JS_REGEXP_M) pc('m');
|
||||||
|
}
|
||||||
|
|
||||||
static void pbin(int d, int i, js_Ast *exp, const char *op)
|
static void pbin(int d, int i, js_Ast *exp, const char *op)
|
||||||
{
|
{
|
||||||
if (i) pc('(');
|
if (i) pc('(');
|
||||||
@@ -127,7 +139,7 @@ static void pexpi(int d, int i, js_Ast *exp)
|
|||||||
case AST_IDENTIFIER: ps(exp->string); break;
|
case AST_IDENTIFIER: ps(exp->string); break;
|
||||||
case AST_NUMBER: printf("%.9g", exp->number); break;
|
case AST_NUMBER: printf("%.9g", exp->number); break;
|
||||||
case AST_STRING: pstr(exp->string); break;
|
case AST_STRING: pstr(exp->string); break;
|
||||||
case AST_REGEXP: pc('/'); ps(exp->string); pc('/'); break;
|
case AST_REGEXP: pregexp(exp->string, exp->number); break;
|
||||||
|
|
||||||
case EXP_NULL: ps("null"); break;
|
case EXP_NULL: ps("null"); break;
|
||||||
case EXP_TRUE: ps("true"); break;
|
case EXP_TRUE: ps("true"); break;
|
||||||
@@ -516,7 +528,7 @@ static void snode(int d, js_Ast *node)
|
|||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case AST_IDENTIFIER: pc(' '); ps(node->string); break;
|
case AST_IDENTIFIER: pc(' '); ps(node->string); break;
|
||||||
case AST_STRING: pc(' '); pstr(node->string); break;
|
case AST_STRING: pc(' '); pstr(node->string); break;
|
||||||
case AST_REGEXP: printf(" /%s/", node->string); break;
|
case AST_REGEXP: pc(' '); pregexp(node->string, node->number); break;
|
||||||
case AST_NUMBER: printf(" %.9g", node->number); break;
|
case AST_NUMBER: printf(" %.9g", node->number); break;
|
||||||
case STM_BLOCK: afun = sblock; break;
|
case STM_BLOCK: afun = sblock; break;
|
||||||
case STM_FUNC: case EXP_FUNC: cfun = sblock; break;
|
case STM_FUNC: case EXP_FUNC: cfun = sblock; break;
|
||||||
|
|||||||
@@ -361,6 +361,7 @@ static int isregexpcontext(int last)
|
|||||||
static int lexregexp(js_State *J, const char **sp)
|
static int lexregexp(js_State *J, const char **sp)
|
||||||
{
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
|
int g, m, i;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
textinit(J);
|
textinit(J);
|
||||||
@@ -386,21 +387,25 @@ static int lexregexp(js_State *J, const char **sp)
|
|||||||
s = textend(J);
|
s = textend(J);
|
||||||
|
|
||||||
/* regexp flags */
|
/* regexp flags */
|
||||||
J->flags.g = J->flags.i = J->flags.m = 0;
|
g = i = m = 0;
|
||||||
|
|
||||||
c = PEEK();
|
c = PEEK();
|
||||||
while (isidentifierpart(c)) {
|
while (isidentifierpart(c)) {
|
||||||
if (c == 'g') J->flags.g ++;
|
if (c == 'g') ++g;
|
||||||
else if (c == 'i') J->flags.i ++;
|
else if (c == 'i') ++i;
|
||||||
else if (c == 'm') J->flags.m ++;
|
else if (c == 'm') ++m;
|
||||||
else return jsP_error(J, "illegal flag in regular expression: %c", c);
|
else return jsP_error(J, "illegal flag in regular expression: %c", c);
|
||||||
c = NEXTPEEK();
|
c = NEXTPEEK();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (J->flags.g > 1 || J->flags.i > 1 || J->flags.m > 1)
|
if (g > 1 || i > 1 || m > 1)
|
||||||
return jsP_error(J, "duplicated flag in regular expression");
|
return jsP_error(J, "duplicated flag in regular expression");
|
||||||
|
|
||||||
J->text = js_intern(J, s);
|
J->text = js_intern(J, s);
|
||||||
|
J->number = 0;
|
||||||
|
if (g) J->number += JS_REGEXP_G;
|
||||||
|
if (i) J->number += JS_REGEXP_I;
|
||||||
|
if (m) J->number += JS_REGEXP_M;
|
||||||
return TK_REGEXP;
|
return TK_REGEXP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ static js_Ast *primary(js_State *J)
|
|||||||
}
|
}
|
||||||
if (J->lookahead == TK_REGEXP) {
|
if (J->lookahead == TK_REGEXP) {
|
||||||
a = jsP_newstrnode(J, AST_REGEXP, J->text);
|
a = jsP_newstrnode(J, AST_REGEXP, J->text);
|
||||||
// TODO: flags
|
a->number = J->number;
|
||||||
next(J);
|
next(J);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ struct js_State
|
|||||||
int lookahead;
|
int lookahead;
|
||||||
const char *text;
|
const char *text;
|
||||||
double number;
|
double number;
|
||||||
struct { char g, i, m; } flags;
|
|
||||||
js_Ast *ast; /* list of allocated nodes to free after parsing */
|
js_Ast *ast; /* list of allocated nodes to free after parsing */
|
||||||
|
|
||||||
int strict;
|
int strict;
|
||||||
|
|||||||
Reference in New Issue
Block a user