From e08b8f0f86aff76f2ba9159e755a7234dc9c625b Mon Sep 17 00:00:00 2001 From: Robert Wilhelm Date: Tue, 14 Sep 2021 13:18:41 +0200 Subject: [PATCH] vbscript: Support date and time literals. Date literals, which are enclosed in number signs in vbscript, will be lexed, pushed throught parser and compiler and finally converted to VT_Date Variant in interpreter. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51503 Signed-off-by: Robert Wilhelm Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard (cherry picked from commit bf5f7a7b7bef24f8a0d9c3fa30342e31c9c9c8ca) Signed-off-by: Michael Stefaniuc --- dlls/vbscript/compile.c | 22 ++++++++++++++++++ dlls/vbscript/interp.c | 13 +++++++++++ dlls/vbscript/lex.c | 44 ++++++++++++++++++++++++++++++++++++ dlls/vbscript/parse.h | 7 ++++++ dlls/vbscript/parser.y | 16 +++++++++++++ dlls/vbscript/tests/lang.vbs | 1 + dlls/vbscript/vbscript.h | 5 +++- 7 files changed, 107 insertions(+), 1 deletion(-) diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 0d1960d8ca1..821d85310b6 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -92,6 +92,7 @@ static void dump_instr_arg(instr_arg_type_t type, instr_arg_t *arg) case ARG_ADDR: TRACE_(vbscript_disas)("\t%u", arg->uint); break; + case ARG_DATE: case ARG_DOUBLE: TRACE_(vbscript_disas)("\t%lf", *arg->dbl); break; @@ -238,6 +239,24 @@ static HRESULT push_instr_double(compile_ctx_t *ctx, vbsop_t op, double arg) return S_OK; } +static HRESULT push_instr_date(compile_ctx_t *ctx, vbsop_t op, DATE arg) +{ + unsigned instr; + DATE *d; + + d = compiler_alloc(ctx->code, sizeof(DATE)); + if(!d) + return E_OUTOFMEMORY; + + instr = push_instr(ctx, op); + if(!instr) + return E_OUTOFMEMORY; + + *d = arg; + instr_ptr(ctx, instr)->arg1.date = d; + return S_OK; +} + static BSTR alloc_bstr_arg(compile_ctx_t *ctx, const WCHAR *str) { if(!ctx->code->bstr_pool_size) { @@ -530,6 +549,8 @@ static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr) return compile_call_expression(ctx, (call_expression_t*)expr, TRUE); case EXPR_CONCAT: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_concat); + case EXPR_DATE: + return push_instr_date(ctx, OP_date, ((date_expression_t*)expr)->value); case EXPR_DIV: return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_div); case EXPR_DOT: @@ -1962,6 +1983,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *item item->ref++; } + ctx.parser.lcid = script->lcid; hres = parse_script(&ctx.parser, code->source, delimiter, flags); if(FAILED(hres)) { if(ctx.parser.error_loc != -1) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 11d95e57758..f648f073bc8 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -1637,6 +1637,19 @@ static HRESULT interp_string(exec_ctx_t *ctx) return stack_push(ctx, &v); } +static HRESULT interp_date(exec_ctx_t *ctx) +{ + const DATE *d = ctx->instr->arg1.date; + VARIANT v; + + TRACE("%lf\n",*d); + + V_VT(&v) = VT_DATE; + V_DATE(&v) = *d; + + return stack_push(ctx, &v); +} + static HRESULT interp_int(exec_ctx_t *ctx) { const LONG arg = ctx->instr->arg1.lng; diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c index 357cad7158c..09b073fb773 100644 --- a/dlls/vbscript/lex.c +++ b/dlls/vbscript/lex.c @@ -204,6 +204,48 @@ static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret) return tString; } +static int parse_date_literal(parser_ctx_t *ctx, DATE *ret) +{ + const WCHAR *ptr = ++ctx->ptr; + WCHAR *rptr; + int len = 0; + HRESULT res; + + while(ctx->ptr < ctx->end) { + if(*ctx->ptr == '\n' || *ctx->ptr == '\r') { + FIXME("newline inside date literal\n"); + return 0; + } + + if(*ctx->ptr == '#') + break; + ctx->ptr++; + } + + if(ctx->ptr == ctx->end) { + FIXME("unterminated date literal\n"); + return 0; + } + + len += ctx->ptr-ptr; + + rptr = heap_alloc((len+1)*sizeof(WCHAR)); + if(!rptr) + return 0; + + memcpy( rptr, ptr, len * sizeof(WCHAR)); + rptr[len] = 0; + res = VarDateFromStr(rptr, ctx->lcid, 0, ret); + heap_free(rptr); + if (!SUCCEEDED(res)) { + FIXME("Invalid date literal\n"); + return 0; + } + + ctx->ptr++; + return tDate; +} + static int parse_numeric_literal(parser_ctx_t *ctx, void **ret) { BOOL use_int = TRUE; @@ -429,6 +471,8 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx) return tEXPRLBRACKET; case '"': return parse_string_literal(ctx, lval); + case '#': + return parse_date_literal(ctx, lval); case '&': if(*++ctx->ptr == 'h' || *ctx->ptr == 'H') return parse_hex_literal(ctx, lval); diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h index 2888ea3b546..32cfcfe75c5 100644 --- a/dlls/vbscript/parse.h +++ b/dlls/vbscript/parse.h @@ -23,6 +23,7 @@ typedef enum { EXPR_BRACKETS, EXPR_CALL, EXPR_CONCAT, + EXPR_DATE, EXPR_DIV, EXPR_DOT, EXPR_DOUBLE, @@ -70,6 +71,11 @@ typedef struct { LONG value; } int_expression_t; +typedef struct { + expression_t expr; + DATE value; +} date_expression_t; + typedef struct { expression_t expr; double value; @@ -287,6 +293,7 @@ typedef struct { BOOL is_html; HRESULT hres; int error_loc; + LCID lcid; int last_token; unsigned last_nl; diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index 37b14f05e14..796e9d5ee5e 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -34,6 +34,7 @@ static void source_add_class(parser_ctx_t*,class_decl_t*); static void *new_expression(parser_ctx_t*,expression_type_t,size_t); static expression_t *new_bool_expression(parser_ctx_t*,VARIANT_BOOL); +static expression_t *new_date_expression(parser_ctx_t*,DATE); static expression_t *new_string_expression(parser_ctx_t*,const WCHAR*); static expression_t *new_long_expression(parser_ctx_t*,expression_type_t,LONG); static expression_t *new_double_expression(parser_ctx_t*,double); @@ -107,6 +108,7 @@ static statement_t *link_statements(statement_t*,statement_t*); LONG integer; BOOL boolean; double dbl; + DATE date; } %token tEXPRESSION tNL tEMPTYBRACKETS tEXPRLBRACKET @@ -129,6 +131,7 @@ static statement_t *link_statements(statement_t*,statement_t*); %token tDEFAULT tERROR tEXPLICIT tPROPERTY tSTEP %token tInt %token tDouble +%token tDate %type Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt %type GlobalDimDeclaration @@ -416,6 +419,7 @@ LiteralExpression : tTRUE { $$ = new_bool_expression(ctx, VARIANT_TRUE); CHECK_ERROR; } | tFALSE { $$ = new_bool_expression(ctx, VARIANT_FALSE); CHECK_ERROR; } | tString { $$ = new_string_expression(ctx, $1); CHECK_ERROR; } + | tDate { $$ = new_date_expression(ctx, $1); CHECK_ERROR; } | NumericLiteralExpression { $$ = $1; } | tEMPTY { $$ = new_expression(ctx, EXPR_EMPTY, 0); CHECK_ERROR; } | tNULL { $$ = new_expression(ctx, EXPR_NULL, 0); CHECK_ERROR; } @@ -594,6 +598,18 @@ static expression_t *new_string_expression(parser_ctx_t *ctx, const WCHAR *value return &expr->expr; } +static expression_t *new_date_expression(parser_ctx_t *ctx, DATE value) +{ + date_expression_t *expr; + + expr = new_expression(ctx, EXPR_DATE, sizeof(*expr)); + if(!expr) + return NULL; + + expr->value = value; + return &expr->expr; +} + static expression_t *new_long_expression(parser_ctx_t *ctx, expression_type_t type, LONG value) { int_expression_t *expr; diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index a716cdbc65f..d7865301784 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -107,6 +107,7 @@ Call ok(getVT(&hffFFffFF&) = "VT_I2", "getVT(&hffFFffFF&) is not VT_I2") Call ok(getVT(&hffFFffFE&) = "VT_I2", "getVT(&hffFFffFE &) is not VT_I2") Call ok(getVT(&hffF&) = "VT_I2", "getVT(&hffFF&) is not VT_I2") Call ok(getVT(&hffFF&) = "VT_I4", "getVT(&hffFF&) is not VT_I4") +Call ok(getVT(# 1/1/2011 #) = "VT_DATE", "getVT(# 1/1/2011 #) is not VT_DATE") Call ok(getVT(1e2) = "VT_R8", "getVT(1e2) is not VT_R8") Call ok(getVT(1e0) = "VT_R8", "getVT(1e0) is not VT_R8") Call ok(getVT(0.1e2) = "VT_R8", "getVT(0.1e2) is not VT_R8") diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index afcce5eb9b8..9ef2cae81e5 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -212,7 +212,8 @@ typedef enum { ARG_INT, ARG_UINT, ARG_ADDR, - ARG_DOUBLE + ARG_DOUBLE, + ARG_DATE } instr_arg_type_t; #define OP_LIST \ @@ -225,6 +226,7 @@ typedef enum { X(case, 0, ARG_ADDR, 0) \ X(concat, 1, 0, 0) \ X(const, 1, ARG_BSTR, 0) \ + X(date, 1, ARG_DATE, 0) \ X(deref, 1, 0, 0) \ X(dim, 1, ARG_BSTR, ARG_UINT) \ X(div, 1, 0, 0) \ @@ -293,6 +295,7 @@ typedef union { unsigned uint; LONG lng; double *dbl; + DATE *date; } instr_arg_t; typedef struct {