jscript: Beginning support for conditional compilation.
This commit is contained in:
parent
74416052ce
commit
45e33ec280
|
@ -70,6 +70,8 @@ void script_release(script_ctx_t *ctx)
|
|||
if(--ctx->ref)
|
||||
return;
|
||||
|
||||
if(ctx->cc)
|
||||
release_cc(ctx->cc);
|
||||
jsheap_free(&ctx->tmp_heap);
|
||||
SysFreeString(ctx->last_match);
|
||||
heap_free(ctx);
|
||||
|
|
|
@ -266,6 +266,14 @@ typedef struct named_item_t {
|
|||
struct named_item_t *next;
|
||||
} named_item_t;
|
||||
|
||||
typedef struct _cc_var_t cc_var_t;
|
||||
|
||||
typedef struct {
|
||||
cc_var_t *vars;
|
||||
} cc_ctx_t;
|
||||
|
||||
void release_cc(cc_ctx_t*);
|
||||
|
||||
struct _script_ctx_t {
|
||||
LONG ref;
|
||||
|
||||
|
@ -277,6 +285,7 @@ struct _script_ctx_t {
|
|||
DWORD safeopt;
|
||||
DWORD version;
|
||||
LCID lcid;
|
||||
cc_ctx_t *cc;
|
||||
|
||||
jsheap_t tmp_heap;
|
||||
|
||||
|
@ -448,6 +457,7 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags)
|
|||
#define JS_E_MISSING_LBRACKET MAKE_JSERROR(IDS_LBRACKET)
|
||||
#define JS_E_MISSING_RBRACKET MAKE_JSERROR(IDS_RBRACKET)
|
||||
#define JS_E_UNTERMINATED_STRING MAKE_JSERROR(IDS_UNTERMINATED_STR)
|
||||
#define JS_E_DISABLED_CC MAKE_JSERROR(IDS_DISABLED_CC)
|
||||
#define JS_E_FUNCTION_EXPECTED MAKE_JSERROR(IDS_NOT_FUNC)
|
||||
#define JS_E_DATE_EXPECTED MAKE_JSERROR(IDS_NOT_DATE)
|
||||
#define JS_E_NUMBER_EXPECTED MAKE_JSERROR(IDS_NOT_NUM)
|
||||
|
|
|
@ -34,6 +34,7 @@ STRINGTABLE
|
|||
IDS_LBRACKET "Expected '('"
|
||||
IDS_RBRACKET "Expected ')'"
|
||||
IDS_UNTERMINATED_STR "Unterminated string constant"
|
||||
IDS_DISABLED_CC "Conditional compilation is turned off"
|
||||
IDS_NOT_FUNC "Function expected"
|
||||
IDS_NOT_DATE "'[object]' is not a date object"
|
||||
IDS_NOT_NUM "Number expected"
|
||||
|
|
|
@ -125,7 +125,8 @@ static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lva
|
|||
if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
|
||||
return 1;
|
||||
|
||||
*lval = ctx->ptr;
|
||||
if(lval)
|
||||
*lval = ctx->ptr;
|
||||
ctx->ptr = p1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -194,12 +195,23 @@ static BOOL skip_html_comment(parser_ctx_t *ctx)
|
|||
|
||||
static BOOL skip_comment(parser_ctx_t *ctx)
|
||||
{
|
||||
if(ctx->ptr+1 >= ctx->end || *ctx->ptr != '/')
|
||||
if(ctx->ptr+1 >= ctx->end)
|
||||
return FALSE;
|
||||
|
||||
if(*ctx->ptr != '/') {
|
||||
if(*ctx->ptr == '@' && ctx->ptr+2 < ctx->end && ctx->ptr[1] == '*' && ctx->ptr[2] == '/') {
|
||||
ctx->ptr += 3;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch(ctx->ptr[1]) {
|
||||
case '*':
|
||||
ctx->ptr += 2;
|
||||
if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
|
||||
return FALSE;
|
||||
while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/'))
|
||||
ctx->ptr++;
|
||||
|
||||
|
@ -212,6 +224,8 @@ static BOOL skip_comment(parser_ctx_t *ctx)
|
|||
break;
|
||||
case '/':
|
||||
ctx->ptr += 2;
|
||||
if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
|
||||
return FALSE;
|
||||
while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr))
|
||||
ctx->ptr++;
|
||||
break;
|
||||
|
@ -533,12 +547,8 @@ static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
|
|||
return tNumericLiteral;
|
||||
}
|
||||
|
||||
int parser_lex(void *lval, parser_ctx_t *ctx)
|
||||
static int next_token(parser_ctx_t *ctx, void *lval)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ctx->nl = ctx->ptr == ctx->begin;
|
||||
|
||||
do {
|
||||
skip_spaces(ctx);
|
||||
if(ctx->ptr == ctx->end)
|
||||
|
@ -546,7 +556,7 @@ int parser_lex(void *lval, parser_ctx_t *ctx)
|
|||
}while(skip_comment(ctx) || skip_html_comment(ctx));
|
||||
|
||||
if(isalphaW(*ctx->ptr)) {
|
||||
ret = check_keywords(ctx, lval);
|
||||
int ret = check_keywords(ctx, lval);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
|
@ -764,12 +774,190 @@ int parser_lex(void *lval, parser_ctx_t *ctx)
|
|||
case '_':
|
||||
case '$':
|
||||
return parse_identifier(ctx, lval);
|
||||
|
||||
case '@':
|
||||
return '@';
|
||||
}
|
||||
|
||||
WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct _cc_var_t {
|
||||
BOOL is_num;
|
||||
union {
|
||||
VARIANT_BOOL b;
|
||||
DOUBLE n;
|
||||
} u;
|
||||
struct _cc_var_t *next;
|
||||
unsigned name_len;
|
||||
WCHAR name[0];
|
||||
};
|
||||
|
||||
void release_cc(cc_ctx_t *cc)
|
||||
{
|
||||
cc_var_t *iter, *next;
|
||||
|
||||
for(iter = cc->vars; iter; iter = next) {
|
||||
next = iter->next;
|
||||
heap_free(iter);
|
||||
}
|
||||
|
||||
heap_free(cc);
|
||||
}
|
||||
|
||||
static BOOL add_cc_var(cc_ctx_t *cc, const WCHAR *name, cc_var_t *v)
|
||||
{
|
||||
cc_var_t *new_v;
|
||||
unsigned len;
|
||||
|
||||
len = strlenW(name);
|
||||
|
||||
new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
|
||||
if(!new_v)
|
||||
return FALSE;
|
||||
|
||||
memcpy(new_v, v, sizeof(*v));
|
||||
memcpy(new_v->name, name, (len+1)*sizeof(WCHAR));
|
||||
new_v->name_len = len;
|
||||
new_v->next = cc->vars;
|
||||
cc->vars = new_v;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
|
||||
{
|
||||
cc_var_t *iter;
|
||||
|
||||
for(iter = cc->vars; iter; iter = iter->next) {
|
||||
if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR)))
|
||||
return iter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int init_cc(parser_ctx_t *ctx)
|
||||
{
|
||||
cc_ctx_t *cc;
|
||||
cc_var_t v;
|
||||
|
||||
static const WCHAR _win32W[] = {'_','w','i','n','3','2',0};
|
||||
static const WCHAR _win64W[] = {'_','w','i','n','6','4',0};
|
||||
static const WCHAR _x86W[] = {'_','x','8','6',0};
|
||||
static const WCHAR _amd64W[] = {'_','a','m','d','6','4',0};
|
||||
static const WCHAR _jscriptW[] = {'_','j','s','c','r','i','p','t',0};
|
||||
static const WCHAR _jscript_buildW[] = {'_','j','s','c','r','i','p','t','_','b','u','i','l','d',0};
|
||||
static const WCHAR _jscript_versionW[] = {'_','j','s','c','r','i','p','t','_','v','e','r','s','i','o','n',0};
|
||||
|
||||
if(ctx->script->cc)
|
||||
return 0;
|
||||
|
||||
cc = heap_alloc(sizeof(cc_ctx_t));
|
||||
if(!cc)
|
||||
return lex_error(ctx, E_OUTOFMEMORY);
|
||||
|
||||
cc->vars = NULL;
|
||||
v.is_num = FALSE;
|
||||
v.u.b = VARIANT_TRUE;
|
||||
if(!add_cc_var(cc, _jscriptW, &v)
|
||||
|| !add_cc_var(cc, sizeof(void*) == 8 ? _win64W : _win32W, &v)
|
||||
|| !add_cc_var(cc, sizeof(void*) == 8 ? _amd64W : _x86W, &v)) {
|
||||
release_cc(cc);
|
||||
return lex_error(ctx, E_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
v.is_num = TRUE;
|
||||
v.u.n = JSCRIPT_BUILD_VERSION;
|
||||
if(!add_cc_var(cc, _jscript_buildW, &v)) {
|
||||
release_cc(cc);
|
||||
return lex_error(ctx, E_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
v.u.n = JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0;
|
||||
if(!add_cc_var(cc, _jscript_versionW, &v)) {
|
||||
release_cc(cc);
|
||||
return lex_error(ctx, E_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
ctx->script->cc = cc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cc_token(parser_ctx_t *ctx, void *lval)
|
||||
{
|
||||
unsigned id_len = 0;
|
||||
cc_var_t *var;
|
||||
|
||||
static const WCHAR cc_onW[] = {'c','c','_','o','n',0};
|
||||
static const WCHAR setW[] = {'s','e','t',0};
|
||||
static const WCHAR elifW[] = {'e','l','i','f',0};
|
||||
static const WCHAR endW[] = {'e','n','d',0};
|
||||
|
||||
ctx->ptr++;
|
||||
|
||||
if(!check_keyword(ctx, cc_onW, NULL))
|
||||
return init_cc(ctx);
|
||||
|
||||
if(!check_keyword(ctx, setW, NULL)) {
|
||||
FIXME("@set not implemented\n");
|
||||
return lex_error(ctx, E_NOTIMPL);
|
||||
}
|
||||
|
||||
if(!check_keyword(ctx, ifW, NULL)) {
|
||||
FIXME("@if not implemented\n");
|
||||
return lex_error(ctx, E_NOTIMPL);
|
||||
}
|
||||
|
||||
if(!check_keyword(ctx, elifW, NULL)) {
|
||||
FIXME("@elif not implemented\n");
|
||||
return lex_error(ctx, E_NOTIMPL);
|
||||
}
|
||||
|
||||
if(!check_keyword(ctx, elseW, NULL)) {
|
||||
FIXME("@else not implemented\n");
|
||||
return lex_error(ctx, E_NOTIMPL);
|
||||
}
|
||||
|
||||
if(!check_keyword(ctx, endW, NULL)) {
|
||||
FIXME("@end not implemented\n");
|
||||
return lex_error(ctx, E_NOTIMPL);
|
||||
}
|
||||
|
||||
if(!ctx->script->cc)
|
||||
return lex_error(ctx, JS_E_DISABLED_CC);
|
||||
|
||||
while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
|
||||
id_len++;
|
||||
if(!id_len)
|
||||
return '@';
|
||||
|
||||
TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
|
||||
|
||||
var = find_cc_var(ctx->script->cc, ctx->ptr, id_len);
|
||||
ctx->ptr += id_len;
|
||||
if(!var || var->is_num) {
|
||||
*(literal_t**)lval = new_double_literal(ctx, var ? var->u.n : ret_nan());
|
||||
return tNumericLiteral;
|
||||
}
|
||||
|
||||
*(literal_t**)lval = new_boolean_literal(ctx, var->u.b);
|
||||
return tBooleanLiteral;
|
||||
}
|
||||
|
||||
int parser_lex(void *lval, parser_ctx_t *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ctx->nl = ctx->ptr == ctx->begin;
|
||||
|
||||
do {
|
||||
ret = next_token(ctx, lval);
|
||||
} while(ret == '@' && !(ret = cc_token(ctx, lval)));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
literal_t *parse_regexp(parser_ctx_t *ctx)
|
||||
{
|
||||
const WCHAR *re, *flags_ptr;
|
||||
|
|
|
@ -177,7 +177,7 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
|
|||
/* tokens */
|
||||
%token <identifier> tIdentifier
|
||||
%token <ival> tAssignOper tEqOper tShiftOper tRelOper
|
||||
%token <literal> tNumericLiteral
|
||||
%token <literal> tNumericLiteral tBooleanLiteral
|
||||
%token <wstr> tStringLiteral
|
||||
%token tEOF
|
||||
|
||||
|
@ -811,6 +811,7 @@ Literal
|
|||
BooleanLiteral
|
||||
: kTRUE { $$ = new_boolean_literal(ctx, VARIANT_TRUE); }
|
||||
| kFALSE { $$ = new_boolean_literal(ctx, VARIANT_FALSE); }
|
||||
| tBooleanLiteral { $$ = $1; }
|
||||
|
||||
semicolon_opt
|
||||
: ';'
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define IDS_LBRACKET 0x03ED
|
||||
#define IDS_RBRACKET 0x03EE
|
||||
#define IDS_UNTERMINATED_STR 0x03F7
|
||||
#define IDS_DISABLED_CC 0x0406
|
||||
#define IDS_NOT_FUNC 0x138A
|
||||
#define IDS_NOT_DATE 0x138E
|
||||
#define IDS_NOT_NUM 0x1389
|
||||
|
|
Loading…
Reference in New Issue