diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index b81d7919662..52c98fca596 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -102,20 +102,21 @@ static statement_t *link_statements(statement_t*,statement_t*); double dbl; } -%token tEOF tNL tREM tEMPTYBRACKETS -%token tTRUE tFALSE -%token tNOT tAND tOR tXOR tEQV tIMP tNEQ -%token tIS tLTEQ tGTEQ tMOD -%token tCALL tDIM tSUB tFUNCTION tGET tLET tCONST -%token tIF tELSE tELSEIF tEND tTHEN tEXIT -%token tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tEACH tIN -%token tSELECT tCASE -%token tBYREF tBYVAL -%token tOPTION -%token tSTOP -%token tNOTHING tEMPTY tNULL -%token tCLASS tSET tNEW tPUBLIC tPRIVATE tME -%token tNEXT tON tRESUME tGOTO +%token tEOF tNL tEMPTYBRACKETS +%token tLTEQ tGTEQ tNEQ +%token tSTOP tME tREM +%token tTRUE tFALSE +%token tNOT tAND tOR tXOR tEQV tIMP +%token tIS tMOD +%token tCALL tDIM tSUB tFUNCTION tGET tLET tCONST +%token tIF tELSE tELSEIF tEND tTHEN tEXIT +%token tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tEACH tIN +%token tSELECT tCASE +%token tBYREF tBYVAL +%token tOPTION +%token tNOTHING tEMPTY tNULL +%token tCLASS tSET tNEW tPUBLIC tPRIVATE +%token tNEXT tON tRESUME tGOTO %token tIdentifier tString %token tDEFAULT tERROR tEXPLICIT tPROPERTY tSTEP %token tLong tShort @@ -137,7 +138,7 @@ static statement_t *link_statements(statement_t*,statement_t*); %type DimDeclList DimDecl %type DimList %type ConstDecl ConstDeclList -%type Identifier +%type Identifier DotIdentifier %type CaseClausules %% @@ -209,7 +210,7 @@ SimpleStatement MemberExpression : Identifier { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; } - | CallExpression '.' Identifier { $$ = new_member_expression(ctx, $1, $3); CHECK_ERROR; } + | CallExpression '.' DotIdentifier { $$ = new_member_expression(ctx, $1, $3); CHECK_ERROR; } DimDeclList : DimDecl { $$ = $1; } @@ -451,6 +452,59 @@ Identifier | tPROPERTY { $$ = $1; } | tSTEP { $$ = $1; } +/* most keywords can be an identifier after a dot */ +DotIdentifier + : Identifier { $$ = $1; } + | tTRUE { $$ = $1; } + | tFALSE { $$ = $1; } + | tNOT { $$ = $1; } + | tAND { $$ = $1; } + | tOR { $$ = $1; } + | tXOR { $$ = $1; } + | tEQV { $$ = $1; } + | tIMP { $$ = $1; } + | tIS { $$ = $1; } + | tMOD { $$ = $1; } + | tCALL { $$ = $1; } + | tDIM { $$ = $1; } + | tSUB { $$ = $1; } + | tFUNCTION { $$ = $1; } + | tGET { $$ = $1; } + | tLET { $$ = $1; } + | tCONST { $$ = $1; } + | tIF { $$ = $1; } + | tELSE { $$ = $1; } + | tELSEIF { $$ = $1; } + | tEND { $$ = $1; } + | tTHEN { $$ = $1; } + | tEXIT { $$ = $1; } + | tWHILE { $$ = $1; } + | tWEND { $$ = $1; } + | tDO { $$ = $1; } + | tLOOP { $$ = $1; } + | tUNTIL { $$ = $1; } + | tFOR { $$ = $1; } + | tTO { $$ = $1; } + | tEACH { $$ = $1; } + | tIN { $$ = $1; } + | tSELECT { $$ = $1; } + | tCASE { $$ = $1; } + | tBYREF { $$ = $1; } + | tBYVAL { $$ = $1; } + | tOPTION { $$ = $1; } + | tNOTHING { $$ = $1; } + | tEMPTY { $$ = $1; } + | tNULL { $$ = $1; } + | tCLASS { $$ = $1; } + | tSET { $$ = $1; } + | tNEW { $$ = $1; } + | tPUBLIC { $$ = $1; } + | tPRIVATE { $$ = $1; } + | tNEXT { $$ = $1; } + | tON { $$ = $1; } + | tRESUME { $$ = $1; } + | tGOTO { $$ = $1; } + /* Most statements accept both new line and ':' as separators */ StSep : tNL diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 15ad84a23ac..9f1d24c5400 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -1365,4 +1365,59 @@ sub test_identifiers end sub call test_identifiers() +sub test_dotIdentifiers + ' test keywords that can also be an indentifier after a dot + ' Call ok(testObj.rem = 10, "testObj.rem = " & testObj.rem & " expected 10") + Call ok(testObj.true = 10, "testObj.true = " & testObj.true & " expected 10") + Call ok(testObj.false = 10, "testObj.false = " & testObj.false & " expected 10") + Call ok(testObj.not = 10, "testObj.not = " & testObj.not & " expected 10") + Call ok(testObj.and = 10, "testObj.and = " & testObj.and & " expected 10") + Call ok(testObj.or = 10, "testObj.or = " & testObj.or & " expected 10") + Call ok(testObj.xor = 10, "testObj.xor = " & testObj.xor & " expected 10") + Call ok(testObj.eqv = 10, "testObj.eqv = " & testObj.eqv & " expected 10") + Call ok(testObj.imp = 10, "testObj.imp = " & testObj.imp & " expected 10") + Call ok(testObj.is = 10, "testObj.is = " & testObj.is & " expected 10") + Call ok(testObj.mod = 10, "testObj.mod = " & testObj.mod & " expected 10") + Call ok(testObj.call = 10, "testObj.call = " & testObj.call & " expected 10") + Call ok(testObj.dim = 10, "testObj.dim = " & testObj.dim & " expected 10") + Call ok(testObj.sub = 10, "testObj.sub = " & testObj.sub & " expected 10") + Call ok(testObj.function = 10, "testObj.function = " & testObj.function & " expected 10") + Call ok(testObj.get = 10, "testObj.get = " & testObj.get & " expected 10") + Call ok(testObj.let = 10, "testObj.let = " & testObj.let & " expected 10") + Call ok(testObj.const = 10, "testObj.const = " & testObj.const & " expected 10") + Call ok(testObj.if = 10, "testObj.if = " & testObj.if & " expected 10") + Call ok(testObj.else = 10, "testObj.else = " & testObj.else & " expected 10") + Call ok(testObj.elseif = 10, "testObj.elseif = " & testObj.elseif & " expected 10") + Call ok(testObj.end = 10, "testObj.end = " & testObj.end & " expected 10") + Call ok(testObj.then = 10, "testObj.then = " & testObj.then & " expected 10") + Call ok(testObj.exit = 10, "testObj.exit = " & testObj.exit & " expected 10") + Call ok(testObj.while = 10, "testObj.while = " & testObj.while & " expected 10") + Call ok(testObj.wend = 10, "testObj.wend = " & testObj.wend & " expected 10") + Call ok(testObj.do = 10, "testObj.do = " & testObj.do & " expected 10") + Call ok(testObj.loop = 10, "testObj.loop = " & testObj.loop & " expected 10") + Call ok(testObj.until = 10, "testObj.until = " & testObj.until & " expected 10") + Call ok(testObj.for = 10, "testObj.for = " & testObj.for & " expected 10") + Call ok(testObj.to = 10, "testObj.to = " & testObj.to & " expected 10") + Call ok(testObj.each = 10, "testObj.each = " & testObj.each & " expected 10") + Call ok(testObj.in = 10, "testObj.in = " & testObj.in & " expected 10") + Call ok(testObj.select = 10, "testObj.select = " & testObj.select & " expected 10") + Call ok(testObj.case = 10, "testObj.case = " & testObj.case & " expected 10") + Call ok(testObj.byref = 10, "testObj.byref = " & testObj.byref & " expected 10") + Call ok(testObj.byval = 10, "testObj.byval = " & testObj.byval & " expected 10") + Call ok(testObj.option = 10, "testObj.option = " & testObj.option & " expected 10") + Call ok(testObj.nothing = 10, "testObj.nothing = " & testObj.nothing & " expected 10") + Call ok(testObj.empty = 10, "testObj.empty = " & testObj.empty & " expected 10") + Call ok(testObj.null = 10, "testObj.null = " & testObj.null & " expected 10") + Call ok(testObj.class = 10, "testObj.class = " & testObj.class & " expected 10") + Call ok(testObj.set = 10, "testObj.set = " & testObj.set & " expected 10") + Call ok(testObj.new = 10, "testObj.new = " & testObj.new & " expected 10") + Call ok(testObj.public = 10, "testObj.public = " & testObj.public & " expected 10") + Call ok(testObj.private = 10, "testObj.private = " & testObj.private & " expected 10") + Call ok(testObj.next = 10, "testObj.next = " & testObj.next & " expected 10") + Call ok(testObj.on = 10, "testObj.on = " & testObj.on & " expected 10") + Call ok(testObj.resume = 10, "testObj.resume = " & testObj.resume & " expected 10") + Call ok(testObj.goto = 10, "testObj.goto = " & testObj.goto & " expected 10") +end sub +call test_dotIdentifiers + reportSuccess() diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 191f5a79a0d..103082fc042 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -58,6 +58,9 @@ extern const CLSID CLSID_VBScriptRegExp; #define SET_EXPECT(func) \ expect_ ## func = TRUE +#define REF_EXPECT(func) \ + (&expect_ ## func), (&called_ ## func) + #define CHECK_EXPECT2(func) \ do { \ ok(expect_ ##func, "unexpected call " #func "\n"); \ @@ -127,6 +130,7 @@ DEFINE_EXPECT(OnScriptError); #define DISPID_TESTOBJ_PROPGET 2000 #define DISPID_TESTOBJ_PROPPUT 2001 +#define DISPID_TESTOBJ_KEYWORD 2002 #define DISPID_COLLOBJ_RESET 3000 @@ -163,6 +167,13 @@ static int strcmp_wa(LPCWSTR strw, const char *stra) return lstrcmpA(buf, stra); } +static int stricmp_wa(LPCWSTR strw, const char *stra) +{ + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0); + return lstrcmpiA(buf, stra); +} + static const char *vt2a(VARIANT *v) { if(V_VT(v) == (VT_BYREF|VT_VARIANT)) { @@ -756,17 +767,80 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc static HRESULT WINAPI testObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) { - if(!strcmp_wa(bstrName, "propget")) { - CHECK_EXPECT(testobj_propget_d); - test_grfdex(grfdex, fdexNameCaseInsensitive); - *pid = DISPID_TESTOBJ_PROPGET; - return S_OK; - } - if(!strcmp_wa(bstrName, "propput")) { - CHECK_EXPECT(testobj_propput_d); - test_grfdex(grfdex, fdexNameCaseInsensitive); - *pid = DISPID_TESTOBJ_PROPPUT; - return S_OK; + typedef struct { + const char * const name; + DISPID pid; + BOOL *expect; + BOOL *called; + } dispid_t; + + dispid_t dispids[] = { + { "propget", DISPID_TESTOBJ_PROPGET, REF_EXPECT(testobj_propget_d) }, + { "propput", DISPID_TESTOBJ_PROPPUT, REF_EXPECT(testobj_propput_d) }, + { "rem", DISPID_TESTOBJ_KEYWORD, NULL }, + { "true", DISPID_TESTOBJ_KEYWORD, NULL }, + { "false", DISPID_TESTOBJ_KEYWORD, NULL }, + { "not", DISPID_TESTOBJ_KEYWORD, NULL }, + { "and", DISPID_TESTOBJ_KEYWORD, NULL }, + { "or", DISPID_TESTOBJ_KEYWORD, NULL }, + { "xor", DISPID_TESTOBJ_KEYWORD, NULL }, + { "eqv", DISPID_TESTOBJ_KEYWORD, NULL }, + { "imp", DISPID_TESTOBJ_KEYWORD, NULL }, + { "is", DISPID_TESTOBJ_KEYWORD, NULL }, + { "mod", DISPID_TESTOBJ_KEYWORD, NULL }, + { "call", DISPID_TESTOBJ_KEYWORD, NULL }, + { "dim", DISPID_TESTOBJ_KEYWORD, NULL }, + { "sub", DISPID_TESTOBJ_KEYWORD, NULL }, + { "function", DISPID_TESTOBJ_KEYWORD, NULL }, + { "get", DISPID_TESTOBJ_KEYWORD, NULL }, + { "let", DISPID_TESTOBJ_KEYWORD, NULL }, + { "const", DISPID_TESTOBJ_KEYWORD, NULL }, + { "if", DISPID_TESTOBJ_KEYWORD, NULL }, + { "else", DISPID_TESTOBJ_KEYWORD, NULL }, + { "elseif", DISPID_TESTOBJ_KEYWORD, NULL }, + { "end", DISPID_TESTOBJ_KEYWORD, NULL }, + { "then", DISPID_TESTOBJ_KEYWORD, NULL }, + { "exit", DISPID_TESTOBJ_KEYWORD, NULL }, + { "while", DISPID_TESTOBJ_KEYWORD, NULL }, + { "wend", DISPID_TESTOBJ_KEYWORD, NULL }, + { "do", DISPID_TESTOBJ_KEYWORD, NULL }, + { "loop", DISPID_TESTOBJ_KEYWORD, NULL }, + { "until", DISPID_TESTOBJ_KEYWORD, NULL }, + { "for", DISPID_TESTOBJ_KEYWORD, NULL }, + { "to", DISPID_TESTOBJ_KEYWORD, NULL }, + { "each", DISPID_TESTOBJ_KEYWORD, NULL }, + { "in", DISPID_TESTOBJ_KEYWORD, NULL }, + { "select", DISPID_TESTOBJ_KEYWORD, NULL }, + { "case", DISPID_TESTOBJ_KEYWORD, NULL }, + { "byref", DISPID_TESTOBJ_KEYWORD, NULL }, + { "byval", DISPID_TESTOBJ_KEYWORD, NULL }, + { "option", DISPID_TESTOBJ_KEYWORD, NULL }, + { "nothing", DISPID_TESTOBJ_KEYWORD, NULL }, + { "empty", DISPID_TESTOBJ_KEYWORD, NULL }, + { "null", DISPID_TESTOBJ_KEYWORD, NULL }, + { "class", DISPID_TESTOBJ_KEYWORD, NULL }, + { "set", DISPID_TESTOBJ_KEYWORD, NULL }, + { "new", DISPID_TESTOBJ_KEYWORD, NULL }, + { "public", DISPID_TESTOBJ_KEYWORD, NULL }, + { "private", DISPID_TESTOBJ_KEYWORD, NULL }, + { "next", DISPID_TESTOBJ_KEYWORD, NULL }, + { "on", DISPID_TESTOBJ_KEYWORD, NULL }, + { "resume", DISPID_TESTOBJ_KEYWORD, NULL }, + { "goto", DISPID_TESTOBJ_KEYWORD, NULL }, + }; + + for (int i = 0; i < ARRAY_SIZE(dispids); i++) { + if(!stricmp_wa(bstrName, dispids[i].name)) { + dispid_t *d = &dispids[i]; + if(d->expect) { + ok(*d->expect, "unexpected call %s\n", d->name); + *d->called = TRUE; + *d->expect = FALSE; + } + test_grfdex(grfdex, fdexNameCaseInsensitive); + *pid = d->pid; + return S_OK; + } } ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName)); @@ -831,6 +905,11 @@ static HRESULT WINAPI testObj_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, ok(V_VT(pdp->rgvarg) == VT_I2, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg)); ok(V_I2(pdp->rgvarg) == 1, "V_I2(psp->rgvargs) = %d\n", V_I2(pdp->rgvarg)); return S_OK; + + case DISPID_TESTOBJ_KEYWORD: + V_VT(pvarRes) = VT_I2; + V_I2(pvarRes) = 10; + return S_OK; } ok(0, "unexpected call %d\n", id);