vbscript: Add support for the SCRIPTTEXT_ISEXPRESSION flag in ParseScriptText.
To simplify the amount of special cases both in ParseScriptText and ParseProcedureText, add a new pseudo statement and opcode to return the expression and value at the top of the stack, respectively. Script texts that have this flag will be parsed specially as a single expression with such a statement at the end. Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f3c1123aec
commit
8037b13078
|
@ -1196,6 +1196,21 @@ static HRESULT compile_onerror_statement(compile_ctx_t *ctx, onerror_statement_t
|
||||||
return push_instr_int(ctx, OP_errmode, stat->resume_next);
|
return push_instr_int(ctx, OP_errmode, stat->resume_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT compile_retval_statement(compile_ctx_t *ctx, retval_statement_t *stat)
|
||||||
|
{
|
||||||
|
HRESULT hres;
|
||||||
|
|
||||||
|
hres = compile_expression(ctx, stat->expr);
|
||||||
|
if(FAILED(hres))
|
||||||
|
return hres;
|
||||||
|
|
||||||
|
hres = push_instr(ctx, OP_retval);
|
||||||
|
if(FAILED(hres))
|
||||||
|
return hres;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat)
|
static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx, statement_t *stat)
|
||||||
{
|
{
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
@ -1267,6 +1282,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx,
|
||||||
case STAT_WHILELOOP:
|
case STAT_WHILELOOP:
|
||||||
hres = compile_while_statement(ctx, (while_statement_t*)stat);
|
hres = compile_while_statement(ctx, (while_statement_t*)stat);
|
||||||
break;
|
break;
|
||||||
|
case STAT_RETVAL:
|
||||||
|
hres = compile_retval_statement(ctx, (retval_statement_t*)stat);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FIXME("Unimplemented statement type %d\n", stat->type);
|
FIXME("Unimplemented statement type %d\n", stat->type);
|
||||||
hres = E_NOTIMPL;
|
hres = E_NOTIMPL;
|
||||||
|
@ -1795,7 +1813,7 @@ static void release_compiler(compile_ctx_t *ctx)
|
||||||
release_vbscode(ctx->code);
|
release_vbscode(ctx->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *delimiter, vbscode_t **ret)
|
HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *delimiter, DWORD flags, vbscode_t **ret)
|
||||||
{
|
{
|
||||||
function_t *new_func;
|
function_t *new_func;
|
||||||
function_decl_t *func_decl;
|
function_decl_t *func_decl;
|
||||||
|
@ -1804,7 +1822,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *deli
|
||||||
vbscode_t *code;
|
vbscode_t *code;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
hres = parse_script(&ctx.parser, src, delimiter);
|
hres = parse_script(&ctx.parser, src, delimiter, flags);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
|
|
|
@ -1258,6 +1258,30 @@ static HRESULT interp_ret(exec_ctx_t *ctx)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT interp_retval(exec_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
variant_val_t val;
|
||||||
|
HRESULT hres;
|
||||||
|
|
||||||
|
TRACE("\n");
|
||||||
|
|
||||||
|
hres = stack_pop_val(ctx, &val);
|
||||||
|
if(FAILED(hres))
|
||||||
|
return hres;
|
||||||
|
|
||||||
|
if(val.owned) {
|
||||||
|
VariantClear(&ctx->ret_val);
|
||||||
|
ctx->ret_val = *val.v;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hres = VariantCopy(&ctx->ret_val, val.v);
|
||||||
|
if(FAILED(hres))
|
||||||
|
return hres;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT interp_stop(exec_ctx_t *ctx)
|
static HRESULT interp_stop(exec_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
WARN("\n");
|
WARN("\n");
|
||||||
|
@ -2179,8 +2203,6 @@ HRESULT exec_script(script_ctx_t *ctx, function_t *func, vbdisp_t *vbthis, DISPP
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!exec.top);
|
assert(!exec.top);
|
||||||
if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
|
|
||||||
assert(V_VT(&exec.ret_val) == VT_EMPTY);
|
|
||||||
|
|
||||||
if(SUCCEEDED(hres) && res) {
|
if(SUCCEEDED(hres) && res) {
|
||||||
*res = exec.ret_val;
|
*res = exec.ret_val;
|
||||||
|
|
|
@ -493,6 +493,12 @@ int parser_lex(void *lval, parser_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (ctx->last_token == tEXPRESSION)
|
||||||
|
{
|
||||||
|
ctx->last_token = tNL;
|
||||||
|
return tEXPRESSION;
|
||||||
|
}
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
ret = parse_next_token(lval, ctx);
|
ret = parse_next_token(lval, ctx);
|
||||||
if(ret == '_') {
|
if(ret == '_') {
|
||||||
|
|
|
@ -118,7 +118,8 @@ typedef enum {
|
||||||
STAT_STOP,
|
STAT_STOP,
|
||||||
STAT_UNTIL,
|
STAT_UNTIL,
|
||||||
STAT_WHILE,
|
STAT_WHILE,
|
||||||
STAT_WHILELOOP
|
STAT_WHILELOOP,
|
||||||
|
STAT_RETVAL
|
||||||
} statement_type_t;
|
} statement_type_t;
|
||||||
|
|
||||||
typedef struct _statement_t {
|
typedef struct _statement_t {
|
||||||
|
@ -248,6 +249,11 @@ typedef struct {
|
||||||
case_clausule_t *case_clausules;
|
case_clausule_t *case_clausules;
|
||||||
} select_statement_t;
|
} select_statement_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
statement_t stat;
|
||||||
|
expression_t *expr;
|
||||||
|
} retval_statement_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const WCHAR *code;
|
const WCHAR *code;
|
||||||
const WCHAR *ptr;
|
const WCHAR *ptr;
|
||||||
|
@ -268,7 +274,7 @@ typedef struct {
|
||||||
heap_pool_t heap;
|
heap_pool_t heap;
|
||||||
} parser_ctx_t;
|
} parser_ctx_t;
|
||||||
|
|
||||||
HRESULT parse_script(parser_ctx_t*,const WCHAR*,const WCHAR*) DECLSPEC_HIDDEN;
|
HRESULT parse_script(parser_ctx_t*,const WCHAR*,const WCHAR*,DWORD) DECLSPEC_HIDDEN;
|
||||||
void parser_release(parser_ctx_t*) DECLSPEC_HIDDEN;
|
void parser_release(parser_ctx_t*) DECLSPEC_HIDDEN;
|
||||||
int parser_lex(void*,parser_ctx_t*) DECLSPEC_HIDDEN;
|
int parser_lex(void*,parser_ctx_t*) DECLSPEC_HIDDEN;
|
||||||
void *parser_alloc(parser_ctx_t*,size_t) DECLSPEC_HIDDEN;
|
void *parser_alloc(parser_ctx_t*,size_t) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -28,6 +28,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
|
||||||
static int parser_error(parser_ctx_t *,const char*);
|
static int parser_error(parser_ctx_t *,const char*);
|
||||||
|
|
||||||
static void parse_complete(parser_ctx_t*,BOOL);
|
static void parse_complete(parser_ctx_t*,BOOL);
|
||||||
|
static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr);
|
||||||
|
|
||||||
static void source_add_statement(parser_ctx_t*,statement_t*);
|
static void source_add_statement(parser_ctx_t*,statement_t*);
|
||||||
static void source_add_class(parser_ctx_t*,class_decl_t*);
|
static void source_add_class(parser_ctx_t*,class_decl_t*);
|
||||||
|
@ -102,7 +103,7 @@ static statement_t *link_statements(statement_t*,statement_t*);
|
||||||
double dbl;
|
double dbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
%token tEOF tNL tEMPTYBRACKETS
|
%token tEXPRESSION tEOF tNL tEMPTYBRACKETS
|
||||||
%token tLTEQ tGTEQ tNEQ
|
%token tLTEQ tGTEQ tNEQ
|
||||||
%token tSTOP tME tREM
|
%token tSTOP tME tREM
|
||||||
%token <string> tTRUE tFALSE
|
%token <string> tTRUE tFALSE
|
||||||
|
@ -123,7 +124,7 @@ static statement_t *link_statements(statement_t*,statement_t*);
|
||||||
%token <dbl> tDouble
|
%token <dbl> tDouble
|
||||||
|
|
||||||
%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt
|
%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt
|
||||||
%type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression
|
%type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression ExpressionNl_opt
|
||||||
%type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression
|
%type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression
|
||||||
%type <expression> NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression
|
%type <expression> NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression
|
||||||
%type <expression> ConstExpression NumericLiteralExpression
|
%type <expression> ConstExpression NumericLiteralExpression
|
||||||
|
@ -145,6 +146,7 @@ static statement_t *link_statements(statement_t*,statement_t*);
|
||||||
|
|
||||||
Program
|
Program
|
||||||
: OptionExplicit_opt SourceElements tEOF { parse_complete(ctx, $1); }
|
: OptionExplicit_opt SourceElements tEOF { parse_complete(ctx, $1); }
|
||||||
|
| tEXPRESSION ExpressionNl_opt tEOF { handle_isexpression_script(ctx, $2); }
|
||||||
|
|
||||||
OptionExplicit_opt
|
OptionExplicit_opt
|
||||||
: /* empty */ { $$ = FALSE; }
|
: /* empty */ { $$ = FALSE; }
|
||||||
|
@ -155,6 +157,10 @@ SourceElements
|
||||||
| SourceElements StatementNl { source_add_statement(ctx, $2); }
|
| SourceElements StatementNl { source_add_statement(ctx, $2); }
|
||||||
| SourceElements ClassDeclaration { source_add_class(ctx, $2); }
|
| SourceElements ClassDeclaration { source_add_class(ctx, $2); }
|
||||||
|
|
||||||
|
ExpressionNl_opt
|
||||||
|
: /* empty */ { $$ = NULL; }
|
||||||
|
| Expression tNL { $$ = $1; }
|
||||||
|
|
||||||
BodyStatements
|
BodyStatements
|
||||||
: /* empty */ { $$ = NULL; }
|
: /* empty */ { $$ = NULL; }
|
||||||
| Statement { $$ = $1; }
|
| Statement { $$ = $1; }
|
||||||
|
@ -553,6 +559,22 @@ static void parse_complete(parser_ctx_t *ctx, BOOL option_explicit)
|
||||||
ctx->option_explicit = option_explicit;
|
ctx->option_explicit = option_explicit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr)
|
||||||
|
{
|
||||||
|
retval_statement_t *stat;
|
||||||
|
|
||||||
|
ctx->parse_complete = TRUE;
|
||||||
|
if(!expr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stat = new_statement(ctx, STAT_RETVAL, sizeof(*stat));
|
||||||
|
if(!stat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stat->expr = expr;
|
||||||
|
ctx->stats = &stat->stat;
|
||||||
|
}
|
||||||
|
|
||||||
static void *new_expression(parser_ctx_t *ctx, expression_type_t type, size_t size)
|
static void *new_expression(parser_ctx_t *ctx, expression_type_t type, size_t size)
|
||||||
{
|
{
|
||||||
expression_t *expr;
|
expression_t *expr;
|
||||||
|
@ -1033,7 +1055,7 @@ void *parser_alloc(parser_ctx_t *ctx, size_t size)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter)
|
HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter, DWORD flags)
|
||||||
{
|
{
|
||||||
static const WCHAR html_delimiterW[] = {'<','/','s','c','r','i','p','t','>',0};
|
static const WCHAR html_delimiterW[] = {'<','/','s','c','r','i','p','t','>',0};
|
||||||
|
|
||||||
|
@ -1052,6 +1074,9 @@ HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimite
|
||||||
ctx->option_explicit = FALSE;
|
ctx->option_explicit = FALSE;
|
||||||
ctx->is_html = delimiter && !wcsicmp(delimiter, html_delimiterW);
|
ctx->is_html = delimiter && !wcsicmp(delimiter, html_delimiterW);
|
||||||
|
|
||||||
|
if(flags & SCRIPTTEXT_ISEXPRESSION)
|
||||||
|
ctx->last_token = tEXPRESSION;
|
||||||
|
|
||||||
parser_parse(ctx);
|
parser_parse(ctx);
|
||||||
|
|
||||||
if(FAILED(ctx->hres))
|
if(FAILED(ctx->hres))
|
||||||
|
|
|
@ -76,14 +76,14 @@ static inline BOOL is_started(VBScript *This)
|
||||||
|| This->state == SCRIPTSTATE_DISCONNECTED;
|
|| This->state == SCRIPTSTATE_DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code)
|
static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res)
|
||||||
{
|
{
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
|
|
||||||
code->pending_exec = FALSE;
|
code->pending_exec = FALSE;
|
||||||
|
|
||||||
IActiveScriptSite_OnEnterScript(ctx->site);
|
IActiveScriptSite_OnEnterScript(ctx->site);
|
||||||
hres = exec_script(ctx, &code->main_code, NULL, NULL, NULL);
|
hres = exec_script(ctx, &code->main_code, NULL, NULL, res);
|
||||||
IActiveScriptSite_OnLeaveScript(ctx->site);
|
IActiveScriptSite_OnLeaveScript(ctx->site);
|
||||||
|
|
||||||
return hres;
|
return hres;
|
||||||
|
@ -95,7 +95,7 @@ static void exec_queued_code(script_ctx_t *ctx)
|
||||||
|
|
||||||
LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) {
|
LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) {
|
||||||
if(iter->pending_exec)
|
if(iter->pending_exec)
|
||||||
exec_global_code(ctx, iter);
|
exec_global_code(ctx, iter, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,19 +719,19 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hres = compile_script(This->ctx, pstrCode, pstrDelimiter, &code);
|
hres = compile_script(This->ctx, pstrCode, pstrDelimiter, dwFlags, &code);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
if(context)
|
if(context)
|
||||||
IDispatch_AddRef(code->context = context);
|
IDispatch_AddRef(code->context = context);
|
||||||
|
|
||||||
if(!is_started(This)) {
|
if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) {
|
||||||
code->pending_exec = TRUE;
|
code->pending_exec = TRUE;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exec_global_code(This->ctx, code);
|
return exec_global_code(This->ctx, code, pvarResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const IActiveScriptParseVtbl VBScriptParseVtbl = {
|
static const IActiveScriptParseVtbl VBScriptParseVtbl = {
|
||||||
|
@ -782,7 +782,7 @@ static HRESULT WINAPI VBScriptParseProcedure_ParseProcedureText(IActiveScriptPar
|
||||||
if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED)
|
if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED)
|
||||||
return E_UNEXPECTED;
|
return E_UNEXPECTED;
|
||||||
|
|
||||||
hres = compile_script(This->ctx, pstrCode, pstrDelimiter, &code);
|
hres = compile_script(This->ctx, pstrCode, pstrDelimiter, dwFlags, &code);
|
||||||
if(FAILED(hres))
|
if(FAILED(hres))
|
||||||
return hres;
|
return hres;
|
||||||
|
|
||||||
|
|
|
@ -270,6 +270,7 @@ typedef enum {
|
||||||
X(or, 1, 0, 0) \
|
X(or, 1, 0, 0) \
|
||||||
X(pop, 1, ARG_UINT, 0) \
|
X(pop, 1, ARG_UINT, 0) \
|
||||||
X(ret, 0, 0, 0) \
|
X(ret, 0, 0, 0) \
|
||||||
|
X(retval, 1, 0, 0) \
|
||||||
X(set_ident, 1, ARG_BSTR, ARG_UINT) \
|
X(set_ident, 1, ARG_BSTR, ARG_UINT) \
|
||||||
X(set_member, 1, ARG_BSTR, ARG_UINT) \
|
X(set_member, 1, ARG_BSTR, ARG_UINT) \
|
||||||
X(step, 0, ARG_ADDR, ARG_BSTR) \
|
X(step, 0, ARG_ADDR, ARG_BSTR) \
|
||||||
|
@ -353,7 +354,7 @@ struct _vbscode_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN;
|
void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN;
|
||||||
HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,vbscode_t**) DECLSPEC_HIDDEN;
|
HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,vbscode_t**) DECLSPEC_HIDDEN;
|
||||||
HRESULT exec_script(script_ctx_t*,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN;
|
HRESULT exec_script(script_ctx_t*,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN;
|
||||||
void release_dynamic_vars(dynamic_var_t*) DECLSPEC_HIDDEN;
|
void release_dynamic_vars(dynamic_var_t*) DECLSPEC_HIDDEN;
|
||||||
IDispatch *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned) DECLSPEC_HIDDEN;
|
IDispatch *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned) DECLSPEC_HIDDEN;
|
||||||
|
|
Loading…
Reference in New Issue