jscript: Added Function.toString implementation.
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index 5337b24..bc0b525 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -367,7 +367,8 @@
         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 @@
 
     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 3f7fda8..beabc9b 100644
--- a/dlls/jscript/engine.h
+++ b/dlls/jscript/engine.h
@@ -98,7 +98,8 @@
 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 @@
     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 @@
     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 7d39ad0..c0ba1e2 100644
--- a/dlls/jscript/function.c
+++ b/dlls/jscript/function.c
@@ -31,6 +31,8 @@
     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 @@
     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_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_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 @@
         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 7c7def0..3730661 100644
--- a/dlls/jscript/jscript.c
+++ b/dlls/jscript/jscript.c
@@ -621,7 +621,7 @@
         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 ba80154..4ad9fe5 100644
--- a/dlls/jscript/lex.c
+++ b/dlls/jscript/lex.c
@@ -101,7 +101,7 @@
     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 @@
     if(*p2 || (p1 < ctx->end && isalnumW(*p1)))
         return 1;
 
+    *lval = ctx->ptr;
     ctx->ptr = p1;
     return 0;
 }
@@ -145,14 +146,14 @@
     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 @@
     }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 @@
 
     switch(*ctx->ptr) {
     case '{':
-    case '}':
     case '(':
     case ')':
     case '[':
@@ -492,6 +492,10 @@
     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 c7c6fb4..96ca9e5 100644
--- a/dlls/jscript/parser.y
+++ b/dlls/jscript/parser.y
@@ -120,7 +120,8 @@
 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_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 @@
 
 %union {
     int                     ival;
+    const WCHAR             *srcptr;
     LPCWSTR                 wstr;
     literal_t               *literal;
     struct _argument_list_t *argument_list;
@@ -166,10 +169,12 @@
 }
 
 /* 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 <srcptr> kFUNCTION '}'
+
 /* tokens */
 %token <identifier> tIdentifier
 %token <ival> tAssignOper tEqOper tShiftOper tRelOper
@@ -257,12 +262,12 @@
 /* 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 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 @@
     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 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 d590308..4084241 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -315,4 +315,18 @@
 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();