vbscript: Allow most keywords to be used as 'dot' identifiers.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46318 Signed-off-by: Brendan McGrath <brendan@redmandi.com> Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b49b78db49
commit
78078b65b2
|
@ -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 <string> tTRUE tFALSE
|
||||
%token <string> tNOT tAND tOR tXOR tEQV tIMP
|
||||
%token <string> tIS tMOD
|
||||
%token <string> tCALL tDIM tSUB tFUNCTION tGET tLET tCONST
|
||||
%token <string> tIF tELSE tELSEIF tEND tTHEN tEXIT
|
||||
%token <string> tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tEACH tIN
|
||||
%token <string> tSELECT tCASE
|
||||
%token <string> tBYREF tBYVAL
|
||||
%token <string> tOPTION
|
||||
%token <string> tNOTHING tEMPTY tNULL
|
||||
%token <string> tCLASS tSET tNEW tPUBLIC tPRIVATE
|
||||
%token <string> tNEXT tON tRESUME tGOTO
|
||||
%token <string> tIdentifier tString
|
||||
%token <string> tDEFAULT tERROR tEXPLICIT tPROPERTY tSTEP
|
||||
%token <lng> tLong tShort
|
||||
|
@ -137,7 +138,7 @@ static statement_t *link_statements(statement_t*,statement_t*);
|
|||
%type <dim_decl> DimDeclList DimDecl
|
||||
%type <dim_list> DimList
|
||||
%type <const_decl> ConstDecl ConstDeclList
|
||||
%type <string> Identifier
|
||||
%type <string> Identifier DotIdentifier
|
||||
%type <case_clausule> 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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue