diff --git a/test/harness/sth.js b/test/harness/sth.js index 7ae7d20780..9053ea6427 100644 --- a/test/harness/sth.js +++ b/test/harness/sth.js @@ -1,14 +1,14 @@ -/// Copyright (c) 2009 Microsoft Corporation -/// +/// Copyright (c) 2009 Microsoft Corporation +/// /// Redistribution and use in source and binary forms, with or without modification, are permitted provided -/// that the following conditions are met: +/// that the following conditions are met: /// * Redistributions of source code must retain the above copyright notice, this list of conditions and -/// the following disclaimer. -/// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and -/// the following disclaimer in the documentation and/or other materials provided with the distribution. +/// the following disclaimer. +/// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +/// the following disclaimer in the documentation and/or other materials provided with the distribution. /// * Neither the name of Microsoft nor the names of its contributors may be used to /// endorse or promote products derived from this software without specific prior written permission. -/// +/// /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR /// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS /// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE @@ -16,7 +16,7 @@ /// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS /// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, /// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //Do not cache any JSON files - see https://bugs.ecmascript.org/show_bug.cgi?id=87 @@ -52,7 +52,7 @@ function BrowserRunner() { if(currentTest.error instanceof SputnikError) { currentTest.error = currentTest.message; } else { - currentTest.error = currentTest.error.name + ": " + currentTest.error.message + currentTest.error = currentTest.error.name + ": " + currentTest.error.message; } } @@ -94,7 +94,7 @@ function BrowserRunner() { // Set up some globals. win.testRun = testRun; win.testFinished = testFinished; - + //TODO: these should be moved to sta.js win.SputnikError = SputnikError; win.$ERROR = $ERROR; @@ -112,59 +112,59 @@ function BrowserRunner() { $.ajax({ async: false, url: 'resources/scripts/global/' + include, - success: function(s) { scriptCache[include] = s } - }) + success: function(s) { scriptCache[include] = s; } + }); } // Finally, write the required script to the window. doc.writeln(""); } } - + //Write out all of our helper functions doc.writeln(""); - - - + + + //--Scenario 1: we're dealing with a global scope test case if (GlobalScopeTests[id]!==undefined) { win.iframeError = undefined; win.onerror = undefined; win.onErrorHack = undefined; var testDescrip = GlobalScopeTests[id]; - + //Add an error handler doc.writeln(""); //Parse and execute the code doc.writeln(""); - + //validation if (testDescrip.negative!==undefined) { //An exception is expected if (win.onErrorHack===undefined) { //Hack for browsers not supporting window.onerror WRT early parse errors - testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', + testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 'pass', 'Not parsable'); } else if (win.iframeError===undefined) { //no exception was thrown - testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', + testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 'fail', 'No Exception Thrown'); } else if(! (new RegExp(testDescrip.negative, "i").test(win.iframeError))) { //wrong type of exception thrown - testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', + testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 'fail', 'Wrong Type of Exception Thrown'); } else { - testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', + testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 'pass', undefined); } } else if (win.iframeError!==undefined) { //Exception was not expected to be thrown - testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', + testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 'fail', 'Unexpected Exception'); } else { - testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', + testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 'pass', undefined); - } + } } //--Scenario 2: we're dealing with a normal positive(?) test case else { - + // Write ES5Harness.registerTest and fnGlobalObject, which returns the global object, and the testFinished call. doc.writeln(""); doc.close(); - } + }; } /* Loads tests from the sections specified in testcaseslist.json. @@ -219,9 +219,9 @@ function TestLoader() { $.ajax({url: group.path, dataType: 'json', success: function(data) { group.tests = data.testsCollection.tests; loader.getNextTest(); - }, + }, error: function (XMLHttpRequest, textStatus, errorThrown) { - //alert(XMLHttpRequest); + //alert(XMLHttpRequest); } }); @@ -238,13 +238,13 @@ function TestLoader() { loader.version = data.version; loader.date = data.date; - loader.totalTests = data.numTests; + loader.totalTests = data.numTests; for (var i = 0; i < testSuite.length; i++) { testGroups[i] = { path: testSuite[i], tests: [] - } + }; } loader.onInitialized(loader.totalTests, loader.version, loader.date); getNextXML(); @@ -271,13 +271,13 @@ function TestLoader() { // We're done. loader.onTestsExhausted(); } - } + }; /* Start over at the beginning */ this.reset = function() { currentTestIndex = 0; testGroupIndex = 0; - } + }; } /* Controls test generation and running, and sends results to the presenter. */ @@ -294,22 +294,22 @@ function Controller() { if(state === 'running') setTimeout(loader.getNextTest, 10); - } + }; loader.onInitialized = function(totalTests, version, date) { presenter.setVersion(version); presenter.setDate(date); presenter.setTotalTests(totalTests); - } + }; loader.onLoadingNextSection = function(path) { presenter.updateStatus("Loading: " + path); - } + }; loader.onTestReady = function(id, test) { presenter.updateStatus("Executing Test: " + id); runner.run(id, test); - } + }; loader.onTestsExhausted = function() { state = 'stopped'; @@ -317,27 +317,27 @@ function Controller() { elapsed = elapsed/(1000*60); //minutes elapsed = elapsed.toFixed(1); presenter.finished(elapsed); - } + }; this.start = function() { state = 'running'; startTime = new Date(); loader.getNextTest(); presenter.started(); - } - + }; + this.pause = function() { elapsed += new Date() - startTime; state = 'paused'; presenter.paused(); - } + }; this.reset = function() { startTime = new Date(); elapsed = 0; loader.reset(); presenter.reset(); - } + }; this.toggle = function() { if(state === 'running') { @@ -345,16 +345,16 @@ function Controller() { } else { controller.start(); } - } + }; } -var controller = new Controller() +var controller = new Controller(); /* Helper function which shows if we're in the 'debug' mode of the Test262 site. - This mode is only useful for debugging issues with the test harness and + This mode is only useful for debugging issues with the test harness and website. */ function isSiteDebugMode() { - var str=window.location.href.substring(window.location.href.indexOf("?")+1) + var str=window.location.href.substring(window.location.href.indexOf("?")+1); if(str.indexOf("sitedebug") > -1) { return true; } @@ -385,7 +385,7 @@ $(function () { $(this).attr('targetDiv', '.content-browsers'); } - //Attaching the click event to the header tab that shows the respective div of header + //Attaching the click event to the header tab that shows the respective div of header $(this).click(function () { var target = $(this).attr('targetDiv'); $('#contentContainer > div:visible').hide(); diff --git a/tools/SputnikConverter/ES5TestCase.cs b/tools/SputnikConverter/ES5TestCase.cs index db39133a74..bbe4ba0463 100644 --- a/tools/SputnikConverter/ES5TestCase.cs +++ b/tools/SputnikConverter/ES5TestCase.cs @@ -139,7 +139,7 @@ namespace Microsoft.Sputnik.Interop.ParserEngine } FileStream fs = new FileStream(destination.Remove(destination.LastIndexOf("\\")) + globalScopeFileName, FileMode.Create, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); - sw.Write("this.GlobalScopeTests = this.GlobalScopeTests || new Array();\n"); + sw.Write("this.GlobalScopeTests = this.GlobalScopeTests || {};\n"); sw.Flush(); sw.Close(); fs.Close(); diff --git a/tools/converter/convert.js b/tools/converter/convert.js index 7ec555e57c..c7be73ffdb 100644 --- a/tools/converter/convert.js +++ b/tools/converter/convert.js @@ -8,6 +8,10 @@ var t262 = global.t262; var platform = t262.platform; var regExp = platform.regExp; + var toRelPathStr = platform.toRelPathStr; + var toPathStr = platform.toPathStr; + var toRelPath = platform.toRelPath; + var toPath = platform.toPath; var headerPattern = /(?:(?:\/\/.*)?\s*\n)*/; var captureCommentPattern = /\/\*\*?((?:\s|\S)*?)\*\/\s*\n/; @@ -27,8 +31,9 @@ /\}\s*\)/, ')', /\s*;?(?:\s|\n)*$/); - var captureFuncBodyPattern = - regExp(/^function(?:\s+\w*)?\(\s*\)\s*\{/, + // Matches a named function. Captures both the name and the body. + var captureFuncNameBodyPattern = + regExp(/^function\s+(\w*)\(\s*\)\s*\{/, '(', anyPattern, ')', /;?/, blanksPattern, /\}$/); @@ -80,8 +85,10 @@ propTexts.forEach(function(propText) { var propName = propText.match(/^\w+/)[0]; var propVal = propText.substring(propName.length); - var propMatch = /^:?([^;]*);?\s*$/.exec(propVal); - if (propMatch) { propVal = propMatch[1]; } + // strip optional initial colon or final semicolon. + // The initial colon is only stripped if it comes immediately + // after the identifier with no intervening whitespace. + propVal = propVal.replace(/^:\s*/, '').replace(/;\s*$/, ''); propVal = stripStars(propVal); if (propName in envelope.testRecord) { throw new Error('duplicate: ' + propName); @@ -106,27 +113,49 @@ } /** - * Given a function, return the source for an expression that, when - * evaluated in the environment the function assumes, will behave - * the same as calling that function in that environment. + * Given a function that indicates success by returning a truthy + * value, return the source for a Program that, when evaluated in + * the environment the function assumes, will behave the same as + * calling that function in that environment and asserting the + * truthiness of the result. + * + *

Programs do not conveniently return any value, even their + * completion value, so Programs in canonical test262 style instead + * indicate success simply by completing normally, i.e., without + * throwing anything. The convertion assumes a one argument + * assertTrue function which throws an indication of + * test failure iff given a falsy argument. + * + *

Unless it specifies otherwise, the Program source may be + * executed strict and/or non-strict, and it may be exeuted within + * the try block of a try/catch or try/catch finally, i.e., as a + * Block rather than as a Program. */ - function expressionize(func) { + function functionToProgramSrc(func) { var funcSrc = '' + func; - var cfbMatch = captureFuncBodyPattern.exec(funcSrc); - if (cfbMatch) { - // Look for special cases - var body = cfbMatch[1].trim(); - - var cebMatch = captureExprBodyPattern.exec(body); - if (cebMatch) { return '(' + cebMatch[1].trim() + ')'; } - - var cpMatch = capturePredicatePattern.exec(body); - if (cpMatch) { return '(' + cpMatch[1].trim() + ')'; } - - } else { - // signal an error? + var cfnbMatch = captureFuncNameBodyPattern.exec(funcSrc); + if (!cfnbMatch) { + throw new Error('Could not recognize: "' + funcSrc + '"'); } - return '(' + funcSrc + ').call(this)'; + var name = cfnbMatch[1].trim(); + var body = cfnbMatch[2].trim(); + + // Look for special cases + + var cebMatch = captureExprBodyPattern.exec(body); + if (cebMatch) { + return 'assertTrue(' + cebMatch[1].trim() + ');'; + } + + var cpMatch = capturePredicatePattern.exec(body); + if (cpMatch) { + return 'assertTrue(' + cpMatch[1].trim() + ');'; + } + + // General case + + return funcSrc + '\n' + + 'assertTrue(' + name + '.call(this));'; } /** @@ -158,27 +187,25 @@ 'forceNonStrict'); if (testRecords.length !== 1) { - // We plan to lift this restriction in order to support test + // We may lift this restriction in order to support test // generators. throw new Error('not singleton: ' + name); } var testRecord = testRecords[0]; if (typeof testRecord.test === 'function') { - testRecord.test = envelope.rest + - 'assertTrue(' + expressionize(testRecord.test) + ');\n'; + testRecord.test = envelope.rest + '\n' + + functionToProgramSrc(testRecord.test); } - if (typeof testRecord.precondition === 'function') { - var precondition = expressionize(testRecord.precondition); - if (precondition === '(true)') { - delete testRecord.precondition; - } else { - testRecord.precondition = precondition; - } + if ('precondition' in testRecord) { + // Only ietestcenter tests currently have preconditions, and they + // plan to drop them. So canonical test262 style omits + // them. + delete testRecord.precondition; } return testRecord; - }; + } /** * Normalizes the properties of testRecord to be the canonical @@ -186,11 +213,6 @@ * runners. */ function normalizeProps(testRecord) { - if (!testRecord.id && testRecord.name) { - testRecord.id = testRecord.name; - delete testRecord.name; - } - if (!('strict_only' in testRecord) && testRecord.strict === 1) { testRecord.strict_only = ''; delete testRecord.strict; @@ -206,6 +228,8 @@ } } + // Note that testRecord.negative is falsy whether negative is + // absent or empty. if (!testRecord.negative && 'errortype' in testRecord) { testRecord.negative = testRecord.errortype; delete testRecord.errortype; @@ -219,19 +243,22 @@ testRecord.comment = testRecord.assertion; delete testRecord.assertion; } - }; + } t262.normalizeProps = normalizeProps; /** * Parses the source of a test262 test case file into a normalized * JSON test record. */ - function parseTestRecord(path, name) { - var nextPath = path.concat([name]); + function parseTestRecord(inBase, relPath, name) { + var nextRelPath = relPath.concat([name]); + var nextPath = inBase.concat(nextRelPath); var src = platform.read(nextPath); var testRecord; - if (!src) { throw new Error('no src: ' + nextPath.join('/')); } + if (!src) { + throw new Error('no src: ' + toPathStr(nextPath)); + } var envelope = parseTestEnvelope(src, name); if (envelope.registerExpr) { @@ -242,16 +269,19 @@ testRecord.test = envelope.rest; } } + delete testRecord.id; + delete testRecord.name; + testRecord.path = toRelPathStr(nextRelPath); testRecord.header = envelope.header; testRecord.comment = envelope.comment; normalizeProps(testRecord); return testRecord; - }; + } t262.parseTestRecord = parseTestRecord; // The known ones will be rendered first, and in this order. - var KNOWN_PROPS = ['id', 'section', 'path', 'description', + var KNOWN_PROPS = ['section', 'path', 'description', 'strict_only', 'negative']; /** @@ -283,30 +313,31 @@ result += ' * ' + testRecord.comment.replace(/\n/g, '\n * ') + '\n *\n'; } delete testRecord.comment; - KNOWN_PROPS.concat(['precondition']).forEach(addProp); + KNOWN_PROPS.forEach(addProp); Object.keys(testRecord).forEach(addProp); result += ' */\n\n' + test; return result; - }; + } t262.formatTestRecord = formatTestRecord; /** * Reads the test case at pathStr and returns the source of that * test case converted to canonical test262 style. */ - function convertTest(pathStr) { - var path = platform.toPath(pathStr); - var name = path.pop(); - var testRecord = parseTestRecord(path, name); + function convertTest(inBaseStr, relPathStr) { + var inBase = toPath(inBaseStr); + var relPath = platform.toRelPath(relPathStr); + var name = relPath.pop(); + var testRecord = parseTestRecord(inBase, relPath, name); var result = formatTestRecord(testRecord); return result; - }; + } t262.convertTest = convertTest; var SRC_DIRS = [ ['test', 'suite', 'other'], - ['test', 'suite', 'sputnik', 'Conformance'], - ['test', 'suite', 'ietestcenter'] + ['test', 'suite', 'ietestcenter'], + ['test', 'suite', 'sputnik', 'Conformance'] ]; var CONV_DIR = ['test', 'suite', 'converted']; @@ -315,6 +346,8 @@ var ME_PATH = platform.CONVERTER_PATH.concat('convert.js'); + var writeSpawnFailures = []; + /** * Convert all the testcases found at inBase+relDir to test cases * in canonical test262 style, to be stored at corresponding @@ -329,27 +362,43 @@ if (platform.isDirectory(inBase.concat(nextRelPath))) { convertAll(inBase, outBase, nextRelPath); } else if (/\.js$/.test(name)) { - var inFilePath = inPath.concat([name]); var outFilePath = outPath.concat([name]); - platform.writeSpawn( - [ME_PATH], - 't262.convertTest("' + platform.toPathStr(inFilePath) + '")', - void 0, - outFilePath); + try { + platform.writeSpawn( + [ME_PATH], + 't262.convertTest("' + toPathStr(inBase) + + '", "' + toRelPathStr(nextRelPath) + '")', + void 0, + outFilePath); + } catch (err) { + writeSpawnFailures.push({ + error: err, + relPath: relPath + }); + } } }); - }; + } t262.convertAll = convertAll; /** * Do all the conversions (from sputnik style, ietestcenter style, * or other to canonical test262 style) matching relPath. */ - function convert(opt_relPath) { + function convert(opt_relPathStr) { + var relPath = opt_relPathStr ? toRelPath(opt_relPathStr) : []; + writeSpawnFailures = []; SRC_DIRS.forEach(function(srcDir) { - convertAll(srcDir, CONV_DIR, opt_relPath || []); + convertAll(srcDir, CONV_DIR, relPath); }); - }; + if (writeSpawnFailures.length >= 1) { + print('********* failures **********'); + writeSpawnFailures.forEach(function(failure) { + print(failure.error + ': ' + toRelPathStr(failure.relPath)); + }); + throw writeSpawnFailures[0].error; + } + } t262.convert = convert; /** @@ -359,7 +408,7 @@ * runner. */ function buildSection(pathStr) { - var path = platform.toPath(pathStr); + var path = toPath(pathStr); if (!platform.isDirectory(path)) { throw new Error('not dir: ' + path); } var jsFiles = platform.ls(path).filter(function(name) { @@ -382,7 +431,7 @@ tests: testRecords } }; - }; + } t262.buildSection = buildSection; /** @@ -403,14 +452,21 @@ if (hasJS) { var name = relPath[relPath.length -1] + '.json'; var outFilePath = outBase.concat([name]); - platform.writeSpawn( - [ME_PATH], - 't262.asJSONTxt(t262.buildSection("' + - platform.toPathStr(inPath) + '"))', - void 0, - outFilePath); + try { + platform.writeSpawn( + [ME_PATH], + 't262.asJSONTxt(t262.buildSection("' + + toPathStr(inPath) + '"))', + void 0, + outFilePath); + } catch (err) { + writeSpawnFailures.push({ + error: err, + path: relPath + }); + } } - }; + } t262.buildAll = buildAll; /** @@ -421,12 +477,13 @@ * files. Once we switch over to converted as the maintained * sources, we should change this. */ - function buildWebSite(opt_relPath) { + function buildWebSite(opt_relPathStr) { + var relPath = opt_relPathStr ? toRelPath(opt_relPathStr) : []; SRC_DIRS.forEach(function(srcDir) { - buildAll(srcDir, OUT_DIR, opt_relPath || []); + buildAll(srcDir, OUT_DIR, relPath); }); -// buildAll(CONV_DIR, OUT_DIR, opt_relPath || []); - }; +// buildAll(CONV_DIR, OUT_DIR, relPath); + } t262.buildWebSite = buildWebSite; })(this); diff --git a/tools/converter/v8PosixPlatform.js b/tools/converter/v8PosixPlatform.js index 069deb59c1..f9b01645d8 100644 --- a/tools/converter/v8PosixPlatform.js +++ b/tools/converter/v8PosixPlatform.js @@ -34,11 +34,16 @@ /** * Appends a bunch of RegExps together into a single RegExp, * solving both the RegExp-one-liner problem and the doubled - * backslash problem when composing literal string. + * backslash problem when composing literal strings. * - *

The arguments can be any mixture of RegExps and strings. The - * strings are added as is without escaping -- BEWARE. If - * arguments[0] is a RegExp, we use its flag on the resuting RegExp. + *

The arguments can be any mixture of RegExps and strings. By + * expressing the portions that should be well formed regexps as + * regexps, we catch well-formedness errors within such a portion + * separately. The strings are added as is without escaping -- + * BEWARE. By not escaping the strings, we can use them to + * represent the individually unbalanced fragments, like capturing + * parens, around other regexps. If arguments[0] is a RegExp, we + * use its flags on the resuting RegExp. * *

Not platform dependent, so does not really belong in this * file. @@ -95,23 +100,39 @@ return path; } + /** + * Converts a relPath to a relPathStr. + * + * A relPath is an array of filenames relative to some base onto + * which it will be concatenated before use. + */ + function toRelPathStr(relPath) { + validatePath(relPath); + return relPath.join('/'); + } + platform.toRelPathStr = toRelPathStr; + /** * Converts a path to a pathStr. * * A path is an array of filenames relative to TEST262_ROOT. A * pathStr is a (possibly fully qualified string) for referring to - * that string on the current platform, according to the operations + * that file on the current platform, according to the operations * in this *Platform.js file. */ function toPathStr(path) { validatePath(path); return TEST262_ROOT.concat(path).join('/'); - }; + } platform.toPathStr = toPathStr; /** * Returns the text found at path, with newlines normalized and * any initial BOM (Unicode Byte Order Mark) removed. + * + * Note: Don't simply revise this (without renamings) to follow the + * general pattern of also defining a local 'read' function, as it + * will mask the v8 shell's read function, which we use. */ platform.read = function(path) { var text = read(toPathStr(path)). @@ -153,12 +174,12 @@ * @returns If there is a target, then the null string. Otherwise, * the string result of evaluating opt_exprSrc. */ - platform.writeSpawn = function(scriptPaths, - opt_exprSrc, - opt_args, - opt_targetPath, - opt_spawn_required, - opt_forceNonStrict) { + function writeSpawn(scriptPaths, + opt_exprSrc, + opt_args, + opt_targetPath, + opt_spawn_required, + opt_forceNonStrict) { if (opt_exprSrc && !opt_targetPath && !opt_spawn_required) { var str = '(function(/*var_args*/) {'; if (opt_forceNonStrict !== 'forceNonStrict') { @@ -182,8 +203,21 @@ } if (VERBOSE || DRY_RUN) { print(cmd); } if (DRY_RUN) { return ''; } - return os.system('bash', ['-c', cmd]); - }; + try { + return os.system('bash', ['-c', cmd]); + } catch (err) { + if (opt_targetPath) { + // The error we catch is almost certainly less interesting + // than the one unfortunately written to the target file. + var message = 'failed: ' + cmd + '\n' + + platform.read(opt_targetPath); + os.system('rm', [toPathStr(opt_targetPath)]); + throw new Error(message); + } + throw err; + } + } + platform.writeSpawn = writeSpawn; ////////////////// Only needed for building ///////////////////// @@ -193,7 +227,7 @@ * On platforms (like SES) where this can be a safely confining * evaluation, it should be. The implementation here is not safe. */ - platform.evalExprIn = function(exprSrc, env, opt_forceNonStrict) { + function evalExprIn(exprSrc, env, opt_forceNonStrict) { var varNames = Object.getOwnPropertyNames(env); var str = '(function(' + varNames.join(',') + ') {'; if (opt_forceNonStrict !== 'forceNonStrict') { @@ -203,12 +237,23 @@ return (1,eval)(str).apply(void 0, varNames.map(function(varName) { return env[varName]; })); - }; + } + platform.evalExprIn = evalExprIn; + + /** + * Converts a relPathStr to a relPath. + * + *

See toRelPathStr. + */ + function toRelPath(relPathStr) { + return validatePath(relPathStr.split('/')); + } + platform.toRelPath = toRelPath; /** * Converts a pathStr to a path. * - * See toPathStr. + *

See toPathStr. */ function toPath(pathStr) { if (pathStr[0] === '/') { @@ -225,24 +270,38 @@ /** * Does path name a directory? */ - platform.isDirectory = function(path) { - var fileOut = os.system('file', [toPathStr(path)]); - var fileMatch = fileOut.match(/:\s*([^:]*)\s*$/); - if (!fileMatch) { return null; } - var fileType = fileMatch[1].trim(); - return fileType === 'directory'; - }; + function isDirectory(path) { +// var fileOut = os.system('file', [toPathStr(path)]); +// var fileMatch = fileOut.match(/:\s*([^:]*)\s*$/); +// if (!fileMatch) { return null; } +// var fileType = fileMatch[1].trim(); +// return fileType === 'directory'; + try { + os.system('test', ['-d', toPathStr(path)]); + return true; + } catch (x) { + return false; + } + } + platform.isDirectory = isDirectory; /** * A list of the filenames found in path, which must name a * directory. */ - platform.ls = function(path) { + function ls(path) { var pathStr = toPathStr(path); - var lines = os.system('ls', [pathStr]).trim(); + if (!isDirectory(path)) { return []; } + var lines; + try { + lines = os.system('ls', [pathStr]).trim(); + } catch (err) { + throw err; + } if (lines === '') { return []; } return lines.split('\n'); - }; + } + platform.ls = ls; /** * Emits the jsonRecord serialized as JSON, either compactly or @@ -257,7 +316,7 @@ } global.t262.asJSONTxt = platform.asJSONTxt = asJSONTxt; - platform.mkdir = function(path) { + function mkdir(path) { var pathStr = toPathStr(path); if (DRY_RUN) { print('mkdir ' + pathStr); @@ -269,7 +328,8 @@ print('***could not mkdir: ' + pathStr); throw err; } - }; + } + platform.mkdir = mkdir; ////////////////// Only needed for running //////////////////////