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:
parent
fe6c5b9305
commit
e08b8f0f86
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue