diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index ee3e766ffc..70dcc16527 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -62,6 +62,12 @@ JSClass global_class = { void ErrorReporter(JSContext* UNUSED(cx), const char* message, JSErrorReport* report) { + // XXX Ugly hack: we want to compile code with 'use strict' and with JSOPTION_STRICT, + // but the latter causes the former to be reported as a useless expression, so + // ignore that specific warning here + if (report->flags == 5 && report->lineno == 0 && report->errorNumber == 163) + return; + std::stringstream msg; bool isWarning = JSREPORT_IS_WARNING(report->flags); msg << (isWarning ? "JavaScript warning: " : "JavaScript error: "); @@ -152,19 +158,6 @@ ScriptInterface_impl::~ScriptInterface_impl() } } -static JSBool LoadScript(JSContext* cx, const jschar* chars, uintN length, const char* filename, jsval* rval) -{ - JSFunction* func = JS_CompileUCFunction(cx, NULL, NULL, 0, NULL, chars, length, filename, 1); - if (!func) - return JS_FALSE; - JS_AddRoot(cx, &func); // TODO: do we need to root this? - *rval = OBJECT_TO_JSVAL((JSObject*)func); - jsval scriptRval; - JSBool ok = JS_CallFunction(cx, NULL, func, 0, NULL, &scriptRval); - JS_RemoveRoot(cx, &func); - return ok; -} - void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs) { JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); @@ -434,10 +427,22 @@ bool ScriptInterface::SetPrototype(jsval obj, jsval proto) bool ScriptInterface::LoadScript(const std::wstring& filename, const std::wstring& code) { std::string fnAscii(filename.begin(), filename.end()); - utf16string codeUtf16(code.begin(), code.end()); - jsval rval; - JSBool ok = ::LoadScript(m->m_cx, reinterpret_cast (codeUtf16.c_str()), (uintN)(codeUtf16.length()), - fnAscii.c_str(), &rval); + + // Compile the code in strict mode, to encourage better coding practices and + // to possibly help SpiderMonkey with optimisations + std::wstring codeStrict = L"\"use strict\";\n" + code; + utf16string codeUtf16(codeStrict.begin(), codeStrict.end()); + uintN lineNo = 0; // put the automatic 'use strict' on line 0, so the real code starts at line 1 + + JSFunction* func = JS_CompileUCFunction(m->m_cx, NULL, NULL, 0, NULL, reinterpret_cast (codeUtf16.c_str()), (uintN)(codeUtf16.length()), fnAscii.c_str(), lineNo); + if (!func) + return false; + + JS_AddRoot(m->m_cx, &func); // TODO: do we need to root this? + jsval scriptRval; + JSBool ok = JS_CallFunction(m->m_cx, NULL, func, 0, NULL, &scriptRval); + JS_RemoveRoot(m->m_cx, &func); + return ok ? true : false; } diff --git a/source/scriptinterface/tests/test_ScriptInterface.h b/source/scriptinterface/tests/test_ScriptInterface.h new file mode 100644 index 0000000000..b7f5c23e4f --- /dev/null +++ b/source/scriptinterface/tests/test_ScriptInterface.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2010 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "lib/self_test.h" + +#include "scriptinterface/ScriptInterface.h" + +#include "ps/CLogger.h" + +class TestScriptInterface : public CxxTest::TestSuite +{ +public: + void test_loadscript_basic() + { + ScriptInterface script("Test"); + TestLogger logger; + TS_ASSERT(script.LoadScript(L"test.js", L"var x = 1+1;")); + TS_ASSERT_WSTR_NOT_CONTAINS(logger.GetOutput(), L"JavaScript error"); + TS_ASSERT_WSTR_NOT_CONTAINS(logger.GetOutput(), L"JavaScript warning"); + } + + void test_loadscript_error() + { + ScriptInterface script("Test"); + TestLogger logger; + TS_ASSERT(!script.LoadScript(L"test.js", L"1+")); + TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"JavaScript error: test.js line 1\nSyntaxError: syntax error"); + } + + void test_loadscript_strict_warning() + { + ScriptInterface script("Test"); + TestLogger logger; + TS_ASSERT(script.LoadScript(L"test.js", L"1+1;")); + TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"JavaScript warning: test.js line 1\nuseless expression"); + } + + void test_loadscript_strict_error() + { + ScriptInterface script("Test"); + TestLogger logger; + TS_ASSERT(!script.LoadScript(L"test.js", L"with(1){}")); + TS_ASSERT_WSTR_CONTAINS(logger.GetOutput(), L"JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements"); + } +};