1From 2dda1e012ab4d0a8f64101c8e06e94a8591421bd Mon Sep 17 00:00:00 2001 2Date: Mon, 27 Feb 2023 11:30:18 +0800 3Subject: [PATCH] eshost 4 5--- 6 lib/Agent.js | 1 + 7 lib/ConsoleAgent.js | 53 +++++++++++++++------------ 8 lib/agents/panda.js | 88 +++++++++++++++++++++++++++++++++++++++++++++ 9 lib/dependencies.js | 6 ++-- 10 runtimes/panda.js | 44 +++++++++++++++++++++++ 11 5 files changed, 166 insertions(+), 26 deletions(-) 12 create mode 100644 lib/agents/panda.js 13 create mode 100644 runtimes/panda.js 14 15diff --git a/lib/Agent.js b/lib/Agent.js 16index edcdf0e..7e655c5 100644 17--- a/lib/Agent.js 18+++ b/lib/Agent.js 19@@ -7,6 +7,7 @@ class Agent { 20 this.args = options.hostArguments || []; 21 this.transform = options.transform || (x => x); 22 this.out = options.out || ''; 23+ this.test262Dir = options.test262Dir; 24 25 if (typeof this.args === 'string') { 26 this.args = this.args.includes(' ') ? 27diff --git a/lib/ConsoleAgent.js b/lib/ConsoleAgent.js 28index 947c1db..3bf41a0 100644 29--- a/lib/ConsoleAgent.js 30+++ b/lib/ConsoleAgent.js 31@@ -19,7 +19,7 @@ const { 32 const cpSym = Symbol.for('cp'); 33 const tpSym = Symbol.for('tp'); 34 35-function generateTempFileName() { 36+function generateTempFileName(file) { 37 const now = Date.now(); 38 return `f-${now}-${process.pid}-${(Math.random() * 0x100000000 + 1).toString(36)}.js`; 39 } 40@@ -47,9 +47,28 @@ class ConsoleAgent extends Agent { 41 } 42 } 43 44+ genTempFileName(code){ 45+ let file = code.file; 46+ let scenario = code.scenario === 'strict mode' ? '' : code.scenario; 47+ let tmps = file.split(this.test262Dir); 48+ let tempFile = path.join(this.out, tmps[1]); 49+ tempFile = tempFile.substring(0, tempFile.indexOf('.js')); 50+ let fileBase = path.basename(tempFile); 51+ if (tempFile.indexOf("/dynamic-import/") != -1 || tempFile.indexOf("\\dynamic-import\\") != -1) { 52+ tempFile = path.join(tempFile, "/", fileBase); 53+ } 54+ tempFile = path.normalize( 55+ `${tempFile}${scenario}.js` 56+ ); 57+ return tempFile; 58+ } 59+ 60 evalScript(code, options = {}) { 61- let tempfile = path.join(this[tpSym], generateTempFileName()); 62- let temppath = this[tpSym]; 63+ let fileBase = path.basename(code.file); 64+ let originalFilePath = code.file.split(fileBase)[0]; 65+ let tempFile = this.genTempFileName(code); 66+ let outputFilePath = path.basename(tempFile); 67+ let depTempPath = tempFile.substring(0, tempFile.indexOf(outputFilePath)); 68 69 let isExpectingRawSource = false; 70 let hasDependencies = false; 71@@ -57,11 +76,6 @@ class ConsoleAgent extends Agent { 72 const sources = []; 73 const dependencies = []; 74 75- if (this.out) { 76- tempfile = tempfile.replace(temppath, this.out); 77- temppath = this.out; 78- } 79- 80 // When evalScript is called with a test262-stream test record: 81 if (typeof code === 'object' && code.contents) { 82 let {attrs, contents, file} = code; 83@@ -84,13 +98,6 @@ class ConsoleAgent extends Agent { 84 hasDependencies = false; 85 } 86 87- if (options.module || attrs.flags.module || 88- hasModuleSpecifier(contents)) { 89- // When testing module or dynamic import code that imports itself, 90- // we must copy the test file with its actual name. 91- tempfile = path.join(temppath, sourcebase); 92- } 93- 94 // The test record in "code" is no longer needed and 95 // all further operations expect the "code" argument to be 96 // a string, make that true for back-compat. 97@@ -112,7 +119,7 @@ class ConsoleAgent extends Agent { 98 // raw source code. 99 // - The file name of the test being executed, but within 100 // the os's temporary file directory 101- sources.push([ tempfile, code ]); 102+ sources.push([ tempFile, code ]); 103 104 // If any dependencies were discovered, there will be 105 if (hasDependencies) { 106@@ -123,23 +130,24 @@ class ConsoleAgent extends Agent { 107 // 3. Push the dependency and source into the sources to be written. 108 // 109 dependencies.forEach(file => { 110- let absname = path.join(temppath, file); 111- let depsource = rawSource.get(path.basename(file)); 112+ let absName = path.join(depTempPath, file); 113+ let depFile = path.join(originalFilePath, file); 114+ let depSource = rawSource.get(depFile); 115 116 // Sometimes a test file might want to import itself, 117 // which is a valid exercise of the import semantics. 118 // Here we avoid adding the test file more than once. 119- if (absname !== tempfile) { 120+ if (absName !== tempFile) { 121 sources.push([ 122- absname, 123- depsource 124+ absName, 125+ depSource 126 ]); 127 } 128 }); 129 } 130 131 this[cpSym] = writeSources(sources) 132- .then(() => this.createChildProcess([tempfile])); 133+ .then(() => this.createChildProcess([tempFile])); 134 135 return this[cpSym].then(child => { 136 let stdout = ''; 137@@ -161,7 +169,6 @@ class ConsoleAgent extends Agent { 138 sources.forEach(({0: file}) => fs.unlink(file, () => { /* ignore */ })); 139 140 const result = this.normalizeResult({ stderr, stdout }); 141- 142 result.error = this.parseError(result.stderr); 143 144 return result; 145diff --git a/lib/agents/panda.js b/lib/agents/panda.js 146new file mode 100644 147index 0000000..ab22b47 148--- /dev/null 149+++ b/lib/agents/panda.js 150@@ -0,0 +1,88 @@ 151+'use strict'; 152+ 153+const fs = require('fs'); 154+const runtimePath = require('../runtime-path'); 155+const ConsoleAgent = require('../ConsoleAgent'); 156+ 157+const errorRe = /[(](\d+),(\d+)[)]: (.*)/; 158+const errorRe1 = /^(\w+): (.*)$/m; 159+// const errorRe2 = /^(?:(\w+): (.*))|(?:(\w+))$/m; 160+const errorRe2 = /(\w+): (\w+): (.*)$/m; 161+ 162+function parseSyntaxError(syntaxErrorMessage) { 163+ const matches = syntaxErrorMessage.match(); 164+ if (matches && matches.length) { 165+ return { 166+ message: matches[3], 167+ lineNumber: Number(matches[1]), 168+ columnNumber: Number(matches[2]) 169+ }; 170+ } 171+ return null; 172+} 173+ 174+class PandaAgent extends ConsoleAgent{ 175+ constructor(options) { 176+ super(options); 177+ } 178+ 179+ createChildProcess(args) { 180+ let js_file = args[0] 181+ args = [] 182+ args.unshift(`--js-file=${js_file}`) 183+ return super.createChildProcess(args); 184+ } 185+ 186+ evalScript(code, options = {}) { 187+ return super.evalScript(code, options); 188+ } 189+ 190+ parseError(str) { 191+ let match = str.match(errorRe1); 192+ if (match) { 193+ return { 194+ name: match[1], 195+ message: match[2], 196+ stack: [], 197+ }; 198+ } else { 199+ // Syntax errors don't have nice error messages... 200+ let error = null; 201+ let errors = str.match(/[(](\d+),(\d+)[)]: (.*)/gm); 202+ 203+ if (errors && errors.length) { 204+ error = { 205+ name: 'SyntaxError', 206+ message: errors[0], 207+ stack: [] 208+ }; 209+ 210+ const stack = parseSyntaxError(errors[0]); 211+ 212+ if (stack) { 213+ error.stack.push(stack); 214+ error.message = stack.message; 215+ } 216+ } 217+ 218+ if (error) { 219+ return error; 220+ } 221+ 222+ // Last chance... 223+ errors = str.match(errorRe2); 224+ if (errors && errors.length >3) { 225+ return { 226+ name: errors[2], 227+ message: errors[0], 228+ stack: [], 229+ }; 230+ } 231+ } 232+ 233+ return null; 234+ } 235+} 236+ 237+PandaAgent.runtime = fs.readFileSync(runtimePath.for('panda'), 'utf8'); 238+module.exports = PandaAgent; 239\ No newline at end of file 240diff --git a/lib/dependencies.js b/lib/dependencies.js 241index 00de9a4..3de6002 100644 242--- a/lib/dependencies.js 243+++ b/lib/dependencies.js 244@@ -46,12 +46,12 @@ function getDependencies(file, accum = []) { 245 let basename = path.basename(file); 246 let contents = ''; 247 248- if (rawSourceCache.has(basename)) { 249- contents = rawSourceCache.get(basename); 250+ if (rawSourceCache.has(file)) { 251+ contents = rawSourceCache.get(file); 252 } else { 253 try { 254 contents = fs.readFileSync(file, 'utf8'); 255- rawSourceCache.set(basename, contents); 256+ rawSourceCache.set(file, contents); 257 } catch (error) { 258 accum.splice(accum.indexOf(basename), 1); 259 } 260diff --git a/runtimes/panda.js b/runtimes/panda.js 261new file mode 100644 262index 0000000..0acbd09 263--- /dev/null 264+++ b/runtimes/panda.js 265@@ -0,0 +1,44 @@ 266+if (!globalThis.$262) { 267+ globalThis.$262 = { 268+ global: globalThis, 269+ evalScript(code) { 270+ try { 271+ global.evalScript(code); 272+ return { type: 'normal', value: undefined }; 273+ } catch (e) { 274+ return { type: 'throw', value: e }; 275+ } 276+ }, 277+ gc() { 278+ throw new Test262Error('gc() not yet supported.'); 279+ }, 280+ getGlobal(name) { 281+ return global[name]; 282+ }, 283+ setGlobal(name, value) { 284+ global[name] = value; 285+ }, 286+ agent: (function() { 287+ function thrower() { 288+ throw new Test262Error('agent.* not yet supported.'); 289+ }; 290+ return { 291+ start: thrower, 292+ broadcast: thrower, 293+ getReport: thrower, 294+ sleep: thrower, 295+ monotonicNow: thrower, 296+ }; 297+ })(), 298+ }; 299+} 300+ 301+$262.IsHTMLDDA = function() {}; 302+$262.destroy = function() {}; 303+$262.getGlobal = function(name) { 304+ return this.global[name]; 305+}; 306+$262.setGlobal = function(name, value) { 307+ this.global[name] = value; 308+}; 309+$262.source = $SOURCE; 310-- 3112.34.1 312 313