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 <robert.wilhelm@gmx.net>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
(cherry picked from commit bf5f7a7b7b)
Signed-off-by: Michael Stefaniuc <mstefani@winehq.org>
This commit is contained in:
Robert Wilhelm 2021-09-14 13:18:41 +02:00 committed by Michael Stefaniuc
parent fe6c5b9305
commit e08b8f0f86
7 changed files with 107 additions and 1 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 <string> tDEFAULT tERROR tEXPLICIT tPROPERTY tSTEP
%token <integer> tInt
%token <dbl> tDouble
%token <date> tDate
%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt
%type <statement> 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;

View File

@ -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")

View File

@ -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 {