aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMark Miller <erights@gmail.com>2011-09-07 21:42:49 -0700
committerMark Miller <erights@gmail.com>2011-09-07 21:42:49 -0700
commitca417c93dc8c4d97b08284dd3c763e6389a7f2c1 (patch)
treeefa3b6f76532c1755a6118f82e8a288adc83492e /tools
parent57c450002dc284c080aaae61839323c72440e65e (diff)
Now generating the format David Fugate and I agreed on this
morning. The rewrite of "function testcase()..." now puts the assertTrue at the bottom. Preconditions, names, and ids are removed. And the path in the file is ignored, and is instead set accurately according to where the file is found.
Diffstat (limited to 'tools')
-rw-r--r--tools/SputnikConverter/ES5TestCase.cs2
-rw-r--r--tools/converter/convert.js203
-rw-r--r--tools/converter/v8PosixPlatform.js118
3 files changed, 220 insertions, 103 deletions
diff --git a/tools/SputnikConverter/ES5TestCase.cs b/tools/SputnikConverter/ES5TestCase.cs
index db39133a7..bbe4ba046 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 7ec555e57..c7be73ffd 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.
+ *
+ * <p>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
+ * <code>assertTrue</code> function which throws an indication of
+ * test failure iff given a falsy argument.
+ *
+ * <p>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 cfnbMatch = captureFuncNameBodyPattern.exec(funcSrc);
+ if (!cfnbMatch) {
+ throw new Error('Could not recognize: "' + funcSrc + '"');
+ }
+ var name = cfnbMatch[1].trim();
+ var body = cfnbMatch[2].trim();
- var cebMatch = captureExprBodyPattern.exec(body);
- if (cebMatch) { return '(' + cebMatch[1].trim() + ')'; }
+ // Look for special cases
- var cpMatch = capturePredicatePattern.exec(body);
- if (cpMatch) { return '(' + cpMatch[1].trim() + ')'; }
+ var cebMatch = captureExprBodyPattern.exec(body);
+ if (cebMatch) {
+ return 'assertTrue(' + cebMatch[1].trim() + ');';
+ }
- } else {
- // signal an error?
+ var cpMatch = capturePredicatePattern.exec(body);
+ if (cpMatch) {
+ return 'assertTrue(' + cpMatch[1].trim() + ');';
}
- return '(' + funcSrc + ').call(this)';
+
+ // 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 069deb59c..f9b01645d 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.
*
- * <p>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.
+ * <p>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.
*
* <p>Not platform dependent, so does not really belong in this
* file.
@@ -96,22 +101,38 @@
}
/**
+ * 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.
+ *
+ * <p>See toRelPathStr.
+ */
+ function toRelPath(relPathStr) {
+ return validatePath(relPathStr.split('/'));
+ }
+ platform.toRelPath = toRelPath;
/**
* Converts a pathStr to a path.
*
- * See toPathStr.
+ * <p>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 //////////////////////