[PATCH v2] vbscript: Support date and time literals.

Robert Wilhelm robert.wilhelm at gmx.net
Fri Sep 10 15:04:17 CDT 2021


Date literals, which are enclosed in number signs in vbscript,
will be converted to DATE in lexer, pushed throught parser and compiler and
finally a VT_Date Variant will be created in interpreter.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51503
Signed-off-by: Robert Wilhelm <robert.wilhelm at gmx.net>
---
v2:
Conversion to DATE moved to lexer.
---
 dlls/vbscript/compile.c      | 20 ++++++++++++++++
 dlls/vbscript/interp.c       | 13 +++++++++++
 dlls/vbscript/lex.c          | 44 ++++++++++++++++++++++++++++++++++++
 dlls/vbscript/parse.h        |  6 +++++
 dlls/vbscript/parser.y       | 16 +++++++++++++
 dlls/vbscript/tests/lang.vbs |  1 +
 dlls/vbscript/vbscript.h     |  5 +++-
 7 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 0d1960d8ca1..fb732dd2b40 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -238,6 +238,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 +548,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:
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..399e57901ca 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, LOCALE_USER_DEFAULT, 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..71bfd7906ca 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;
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 <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;
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 {
--
2.31.1






More information about the wine-devel mailing list