jscript: Beginning support for conditional compilation.
diff --git a/dlls/jscript/lex.c b/dlls/jscript/lex.c
index 135c1d1..0329fa4 100644
--- a/dlls/jscript/lex.c
+++ b/dlls/jscript/lex.c
@@ -125,7 +125,8 @@
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_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 @@
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 @@
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 @@
}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 @@
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;