From 5760eb808b17a8c80bbb42ea128499ace84b69af Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sun, 21 Sep 2008 15:47:47 +0200 Subject: [PATCH] jscript: Added Function.toString implementation. --- dlls/jscript/engine.c | 6 +++-- dlls/jscript/engine.h | 7 +++++- dlls/jscript/function.c | 50 ++++++++++++++++++++++++++++++++++++--- dlls/jscript/jscript.c | 2 +- dlls/jscript/lex.c | 14 +++++++---- dlls/jscript/parser.y | 23 ++++++++++++------ dlls/jscript/tests/api.js | 14 +++++++++++ 7 files changed, 97 insertions(+), 19 deletions(-) diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 5337b2475cd..bc0b525a8c9 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -367,7 +367,8 @@ HRESULT exec_source(exec_ctx_t *ctx, parser_ctx_t *parser, source_elements_t *so DispatchEx *func_obj; VARIANT var; - hres = create_source_function(parser, func->parameter_list, func->source_elements, ctx->scope_chain, &func_obj); + hres = create_source_function(parser, func->parameter_list, func->source_elements, + ctx->scope_chain, func->src_str, func->src_len, &func_obj); if(FAILED(hres)) return hres; @@ -1242,7 +1243,8 @@ HRESULT function_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD fla TRACE("\n"); - hres = create_source_function(ctx->parser, expr->parameter_list, expr->source_elements, ctx->scope_chain, &dispex); + hres = create_source_function(ctx->parser, expr->parameter_list, expr->source_elements, ctx->scope_chain, + expr->src_str, expr->src_len, &dispex); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/engine.h b/dlls/jscript/engine.h index 3f7fda86c9a..beabc9b12c2 100644 --- a/dlls/jscript/engine.h +++ b/dlls/jscript/engine.h @@ -98,7 +98,8 @@ typedef struct _statement_t statement_t; typedef struct _expression_t expression_t; typedef struct _parameter_t parameter_t; -HRESULT create_source_function(parser_ctx_t*,parameter_t*,source_elements_t*,scope_chain_t*,DispatchEx**); +HRESULT create_source_function(parser_ctx_t*,parameter_t*,source_elements_t*,scope_chain_t*, + const WCHAR*,DWORD,DispatchEx**); typedef struct { VARTYPE vt; @@ -277,6 +278,8 @@ typedef struct _function_declaration_t { const WCHAR *identifier; parameter_t *parameter_list; source_elements_t *source_elements; + const WCHAR *src_str; + DWORD src_len; struct _function_declaration_t *next; } function_declaration_t; @@ -293,6 +296,8 @@ typedef struct { const WCHAR *identifier; parameter_t *parameter_list; source_elements_t *source_elements; + const WCHAR *src_str; + DWORD src_len; } function_expression_t; typedef struct { diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 7d39ad05893..c0ba1e2c864 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -31,6 +31,8 @@ typedef struct { parameter_t *parameters; scope_chain_t *scope_chain; parser_ctx_t *parser; + const WCHAR *src_str; + DWORD src_len; DWORD length; } FunctionInstance; @@ -226,6 +228,23 @@ static HRESULT invoke_value_proc(FunctionInstance *function, LCID lcid, WORD fla return hres; } +static HRESULT function_to_string(FunctionInstance *function, BSTR *ret) +{ + BSTR str; + + if(function->value_proc) { + FIXME("Builtin functions not implemented\n"); + return E_NOTIMPL; + } + + str = SysAllocStringLen(function->src_str, function->src_len); + if(!str) + return E_OUTOFMEMORY; + + *ret = str; + return S_OK; +} + static HRESULT Function_length(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) { @@ -249,8 +268,30 @@ static HRESULT Function_length(DispatchEx *dispex, LCID lcid, WORD flags, DISPPA static HRESULT Function_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp) { - FIXME("\n"); - return E_NOTIMPL; + FunctionInstance *function; + BSTR str; + HRESULT hres; + + TRACE("\n"); + + if(!is_class(dispex, JSCLASS_FUNCTION)) { + FIXME("throw TypeError\n"); + return E_FAIL; + } + + function = (FunctionInstance*)dispex; + + hres = function_to_string(function, &str); + if(FAILED(hres)) + return hres; + + if(retv) { + V_VT(retv) = VT_BSTR; + V_BSTR(retv) = str; + }else { + SysFreeString(str); + } + return S_OK; } static HRESULT Function_toLocaleString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp, @@ -438,7 +479,7 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, } HRESULT create_source_function(parser_ctx_t *ctx, parameter_t *parameters, source_elements_t *source, - scope_chain_t *scope_chain, DispatchEx **ret) + scope_chain_t *scope_chain, const WCHAR *src_str, DWORD src_len, DispatchEx **ret) { FunctionInstance *function; DispatchEx *prototype; @@ -470,6 +511,9 @@ HRESULT create_source_function(parser_ctx_t *ctx, parameter_t *parameters, sourc length++; function->length = length; + function->src_str = src_str; + function->src_len = src_len; + *ret = &function->dispex; return S_OK; } diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 7c7def07468..373066155d5 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -621,7 +621,7 @@ static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptPars return hres; } - hres = create_source_function(parser_ctx, NULL, parser_ctx->source, NULL, &dispex); + hres = create_source_function(parser_ctx, NULL, parser_ctx->source, NULL, NULL, 0, &dispex); parser_release(parser_ctx); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/lex.c b/dlls/jscript/lex.c index ba801547862..4ad9fe50d93 100644 --- a/dlls/jscript/lex.c +++ b/dlls/jscript/lex.c @@ -101,7 +101,7 @@ static int lex_error(parser_ctx_t *ctx, HRESULT hres) return -1; } -static int check_keyword(parser_ctx_t *ctx, const WCHAR *word) +static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval) { const WCHAR *p1 = ctx->ptr; const WCHAR *p2 = word; @@ -116,6 +116,7 @@ static int check_keyword(parser_ctx_t *ctx, const WCHAR *word) if(*p2 || (p1 < ctx->end && isalnumW(*p1))) return 1; + *lval = ctx->ptr; ctx->ptr = p1; return 0; } @@ -145,14 +146,14 @@ static int hex_to_int(WCHAR c) return -1; } -static int check_keywords(parser_ctx_t *ctx) +static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval) { int min = 0, max = sizeof(keywords)/sizeof(keywords[0])-1, r, i; while(min <= max) { i = (min+max)/2; - r = check_keyword(ctx, keywords[i].word); + r = check_keyword(ctx, keywords[i].word, lval); if(!r) return keywords[i].token; @@ -468,7 +469,7 @@ int parser_lex(void *lval, parser_ctx_t *ctx) }while(skip_comment(ctx)); if(isalphaW(*ctx->ptr)) { - ret = check_keywords(ctx); + ret = check_keywords(ctx, lval); if(ret) return ret; @@ -480,7 +481,6 @@ int parser_lex(void *lval, parser_ctx_t *ctx) switch(*ctx->ptr) { case '{': - case '}': case '(': case ')': case '[': @@ -492,6 +492,10 @@ int parser_lex(void *lval, parser_ctx_t *ctx) case ':': return *ctx->ptr++; + case '}': + *(const WCHAR**)lval = ctx->ptr++; + return '}'; + case '.': if(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) return parse_double_literal(ctx, 0, lval); diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index c7c6fb48e15..96ca9e552d1 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -120,7 +120,8 @@ typedef struct _parameter_list_t { static parameter_list_t *new_parameter_list(parser_ctx_t*,const WCHAR*); static parameter_list_t *parameter_list_add(parser_ctx_t*,parameter_list_t*,const WCHAR*); -static expression_t *new_function_expression(parser_ctx_t*,const WCHAR*,parameter_list_t*,source_elements_t*); +static expression_t *new_function_expression(parser_ctx_t*,const WCHAR*,parameter_list_t*, + source_elements_t*,const WCHAR*,DWORD); static expression_t *new_binary_expression(parser_ctx_t*,expression_type_t,expression_t*,expression_t*); static expression_t *new_unary_expression(parser_ctx_t*,expression_type_t,expression_t*); static expression_t *new_conditional_expression(parser_ctx_t*,expression_t*,expression_t*,expression_t*); @@ -134,7 +135,8 @@ static expression_t *new_literal_expression(parser_ctx_t*,literal_t*); static expression_t *new_array_literal_expression(parser_ctx_t*,element_list_t*,int); static expression_t *new_prop_and_value_expression(parser_ctx_t*,property_list_t*); -static function_declaration_t *new_function_declaration(parser_ctx_t*,const WCHAR*,parameter_list_t*,source_elements_t*); +static function_declaration_t *new_function_declaration(parser_ctx_t*,const WCHAR*,parameter_list_t*, + source_elements_t*,const WCHAR*,DWORD); static source_elements_t *new_source_elements(parser_ctx_t*); static source_elements_t *source_elements_add_statement(source_elements_t*,statement_t*); static source_elements_t *source_elements_add_function(source_elements_t*,function_declaration_t*); @@ -146,6 +148,7 @@ static source_elements_t *source_elements_add_function(source_elements_t*,functi %union { int ival; + const WCHAR *srcptr; LPCWSTR wstr; literal_t *literal; struct _argument_list_t *argument_list; @@ -166,10 +169,12 @@ static source_elements_t *source_elements_add_function(source_elements_t*,functi } /* keywords */ -%token kBREAK kCASE kCATCH kCONTINUE kDEFAULT kDELETE kDO kELSE kIF kFINALLY kFOR kFUNCTION kIN +%token kBREAK kCASE kCATCH kCONTINUE kDEFAULT kDELETE kDO kELSE kIF kFINALLY kFOR kIN %token kINSTANCEOF kNEW kNULL kUNDEFINED kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE kTRY kTYPEOF kVAR kVOID kWHILE kWITH %token tANDAND tOROR tINC tDEC +%token kFUNCTION '}' + /* tokens */ %token tIdentifier %token tAssignOper tEqOper tShiftOper tRelOper @@ -257,12 +262,12 @@ SourceElements /* ECMA-262 3rd Edition 13 */ FunctionDeclaration : kFUNCTION tIdentifier '(' FormalParameterList_opt ')' '{' FunctionBody '}' - { $$ = new_function_declaration(ctx, $2, $4, $7); } + { $$ = new_function_declaration(ctx, $2, $4, $7, $1, $8-$1+1); } /* ECMA-262 3rd Edition 13 */ FunctionExpression : kFUNCTION Identifier_opt '(' FormalParameterList_opt ')' '{' FunctionBody '}' - { $$ = new_function_expression(ctx, $2, $4, $7); } + { $$ = new_function_expression(ctx, $2, $4, $7, $1, $8-$1+1); } /* ECMA-262 3rd Edition 13 */ FunctionBody @@ -1247,7 +1252,7 @@ static parameter_list_t *parameter_list_add(parser_ctx_t *ctx, parameter_list_t } static expression_t *new_function_expression(parser_ctx_t *ctx, const WCHAR *identifier, - parameter_list_t *parameter_list, source_elements_t *source_elements) + parameter_list_t *parameter_list, source_elements_t *source_elements, const WCHAR *src_str, DWORD src_len) { function_expression_t *ret = parser_alloc(ctx, sizeof(function_expression_t)); @@ -1255,6 +1260,8 @@ static expression_t *new_function_expression(parser_ctx_t *ctx, const WCHAR *ide ret->identifier = identifier; ret->parameter_list = parameter_list ? parameter_list->head : NULL; ret->source_elements = source_elements; + ret->src_str = src_str; + ret->src_len = src_len; return &ret->expr; } @@ -1444,13 +1451,15 @@ static expression_t *new_literal_expression(parser_ctx_t *ctx, literal_t *litera } static function_declaration_t *new_function_declaration(parser_ctx_t *ctx, const WCHAR *identifier, - parameter_list_t *parameter_list, source_elements_t *source_elements) + parameter_list_t *parameter_list, source_elements_t *source_elements, const WCHAR *src_str, DWORD src_len) { function_declaration_t *ret = parser_alloc(ctx, sizeof(function_declaration_t)); ret->identifier = identifier; ret->parameter_list = parameter_list ? parameter_list->head : NULL; ret->source_elements = source_elements; + ret->src_str = src_str; + ret->src_len = src_len; ret->next = NULL; return ret; diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index d590308b5d7..40842414cc4 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -315,4 +315,18 @@ ok(tmp === 2, "Math.pow(2, 2) = " + tmp); tmp = Math.pow(2, 2, 3); ok(tmp === 4, "Math.pow(2, 2, 3) = " + tmp); +var func = function (a) { + var a = 1; + if(a) return; + }.toString(); +ok(func.toString() === "function (a) {\n var a = 1;\n if(a) return;\n }", + "func.toString() = " + func.toString()); + +function testFuncToString(x,y) { + return x+y; +} + +ok(testFuncToString.toString() === "function testFuncToString(x,y) {\n return x+y;\n}", + "testFuncToString.toString() = " + testFuncToString.toString()); + reportSuccess();