From 45e33ec280f97d36d436fabd8b915c2be65f5d02 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 28 Dec 2010 15:40:00 +0100 Subject: [PATCH] jscript: Beginning support for conditional compilation. --- dlls/jscript/jscript.c | 2 + dlls/jscript/jscript.h | 10 ++ dlls/jscript/jscript_En.rc | 1 + dlls/jscript/lex.c | 204 +++++++++++++++++++++++++++++++++++-- dlls/jscript/parser.y | 3 +- dlls/jscript/resource.h | 1 + 6 files changed, 212 insertions(+), 9 deletions(-) diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index ab56696f344..d682746f716 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -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); diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 0ee13bd481a..429fcd3fe91 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -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) diff --git a/dlls/jscript/jscript_En.rc b/dlls/jscript/jscript_En.rc index 3ba373f7ee6..cff24bf7513 100644 --- a/dlls/jscript/jscript_En.rc +++ b/dlls/jscript/jscript_En.rc @@ -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" diff --git a/dlls/jscript/lex.c b/dlls/jscript/lex.c index 135c1d1b40b..0329fa473b2 100644 --- a/dlls/jscript/lex.c +++ b/dlls/jscript/lex.c @@ -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; diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index dbbd682b92b..8f2db142a68 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -177,7 +177,7 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state /* tokens */ %token tIdentifier %token tAssignOper tEqOper tShiftOper tRelOper -%token tNumericLiteral +%token tNumericLiteral tBooleanLiteral %token 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 : ';' diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index c4153a4a1f4..de6c37ed7cb 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -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