feat:更改配置项
This commit is contained in:
@@ -21,7 +21,7 @@ function getConfigForEnv(env) {
|
||||
case 'test':
|
||||
return { url: 'https://test-service.001code.cn', disabledev: false };
|
||||
case 'prod':
|
||||
return { url: 'https://service.001code.cn', disabledev: true };
|
||||
return { url: 'https://service.001code.com', disabledev: true };
|
||||
case 'start':
|
||||
default:
|
||||
return { url: 'http://127.0.0.1:8000', disabledev: false };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Regression tests for variable scopes in the editor interpreter.
|
||||
// Regression tests for variable scopes and return control flow in the editor interpreter.
|
||||
// Run: node scripts/test-cpp-regressions.cjs
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
@@ -15,7 +15,7 @@ const compiled = babel.transformSync(source, {
|
||||
const silentConsole = {log() {}, warn() {}, error() {}};
|
||||
const context = {exports: {}, require, setTimeout, console: silentConsole, window: {}};
|
||||
vm.runInNewContext(compiled, context, {filename: parserPath});
|
||||
const {CppCodeExecutor, validateCppSyntax} = context.exports;
|
||||
const {CppCodeExecutor, validateCppSyntax, createCppExecutor} = context.exports;
|
||||
const main = body => `int main() {\n${body}\n}`;
|
||||
// Complete program from the first email screenshot; the second repeats this issue.
|
||||
const customerEmailCode = `void test() {
|
||||
@@ -44,15 +44,30 @@ async function run(code, expected, configure) {
|
||||
if (configure) configure(executor, context.window);
|
||||
const validation = await validateCppSyntax(code);
|
||||
assert.strictEqual(validation.isValid, true, JSON.stringify(validation.errors));
|
||||
await executor.run();
|
||||
const exitCode = await executor.run();
|
||||
if (Object.prototype.hasOwnProperty.call(expected, 'exitCode')) assert.strictEqual(exitCode, expected.exitCode);
|
||||
if (expected.moves) assert.deepStrictEqual(moves, expected.moves);
|
||||
if (expected.turns) assert.deepStrictEqual(turns, expected.turns);
|
||||
assert.strictEqual(executor.variables, executor.globalVariables, 'scope must unwind after execution');
|
||||
assert.strictEqual(executor.callStack.length, 0);
|
||||
assert.strictEqual(executor.currentExecutionContext, null);
|
||||
assert.strictEqual(executor.isRunning, false);
|
||||
return executor;
|
||||
}
|
||||
|
||||
const cases = [
|
||||
['screenshot: main return 1 is a normal exit', main('playerMove(4);\nreturn 1;'), {moves: [4], exitCode: 1}],
|
||||
['return 1 skips remaining main statements', main('return 1;\nplayerMove(9);'), {moves: [], exitCode: 1}],
|
||||
['return 0 also stops main early', main('return 0;\nplayerMove(9);'), {moves: [], exitCode: 0}],
|
||||
['negative exit code', main('return -1;'), {moves: [], exitCode: -1}],
|
||||
['parenthesized return expression', main('int status = 2;\nreturn (status + 1);'), {moves: [], exitCode: 3}],
|
||||
['main fallthrough returns zero', main('playerMove(1);'), {moves: [1], exitCode: 0}],
|
||||
['return from for loop exits main', main('for (int i = 0; i < 3; i++) {\nplayerMove(i);\nreturn 1;\n}\nplayerMove(9);'), {moves: [0], exitCode: 1}],
|
||||
['return zero inside loop is not ignored', main('for (int i = 0; i < 3; i++) {\nreturn 0;\n}\nplayerMove(9);'), {moves: [], exitCode: 0}],
|
||||
['return through while and if exits main', main('while (true) {\nif (true) {\nreturn 2;\n}\nplayerMove(9);\n}\nplayerMove(8);'), {moves: [], exitCode: 2}],
|
||||
['function return 0 skips only its own remaining statements', 'int f() {\nreturn 0;\nplayerMove(9);\n}\n' + main('f();\nplayerMove(1);\nreturn 1;'), {moves: [1], exitCode: 1}],
|
||||
['function return inside loop resumes caller', 'int f() {\nfor (int i = 0; i < 3; i++) {\nreturn 1;\n}\nplayerMove(9);\n}\n' + main('f();\nplayerMove(1);'), {moves: [1], exitCode: 0}],
|
||||
['identifier starting with return is not a return statement', main('int returnValue = 1;\nreturnValue = 2;\nplayerMove(returnValue);\nreturn 0;'), {moves: [2], exitCode: 0}],
|
||||
['customer email complete program (screenshots 1 and 2)', customerEmailCode, {moves: [0], turns: [-1]}],
|
||||
['nested loops', main('for (int i = 0; i < 2; i++) {\nfor (int i = 0; i < 2; i++) {\n}\nplayerMove(i);\n}'), {moves: [0, 1]}],
|
||||
['loop initializer restores shadowed value', main('int i = 9;\nfor (int i = 0; i < 2; i++) {\n}\nplayerMove(i);'), {moves: [9]}],
|
||||
@@ -104,5 +119,21 @@ const cases = [
|
||||
console.log(`PASS scope cleanup on ${stop ? 'stop' : 'error'}`);
|
||||
}
|
||||
|
||||
console.log(`${cases.length + 4} regression checks passed`);
|
||||
const highlighted = [];
|
||||
context.window = {isScriptRunOver: false, setHighlightedLine: line => highlighted.push(line)};
|
||||
const manager = createCppExecutor();
|
||||
for (const status of [1, 0]) {
|
||||
assert.strictEqual(await manager.execute(main(`return ${status};`)), status);
|
||||
assert.strictEqual(manager.currentExecutor, null);
|
||||
assert.strictEqual(highlighted[highlighted.length - 1], null);
|
||||
}
|
||||
console.log('PASS editor executor manager resolves nonzero exit and can run again');
|
||||
|
||||
context.window.cppGameAPI = {playerMove: async () => {throw new Error('RETURN_INTERRUPT');}};
|
||||
await assert.rejects(manager.execute('void f() {\nplayerMove(1);\n}\n' + main('f();')), /RETURN_INTERRUPT/);
|
||||
assert.strictEqual(manager.currentExecutor, null);
|
||||
assert.strictEqual(highlighted[highlighted.length - 1], null);
|
||||
console.log('PASS real game errors are not mistaken for a return signal');
|
||||
|
||||
console.log(`${cases.length + 6} regression checks passed`);
|
||||
})().catch(error => {console.error(error); process.exitCode = 1;});
|
||||
|
||||
@@ -548,6 +548,14 @@ class CppVariableScope extends Map {
|
||||
}
|
||||
}
|
||||
|
||||
// return 是跨越循环/条件块的控制信号,只在所属函数边界消费。
|
||||
// 使用独立类型,避免吞掉恰好带有相同消息的真实运行错误。
|
||||
class CppReturnSignal {
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
export class CppCodeExecutor {
|
||||
constructor(code, setHighlightedLine) {
|
||||
this.code = code;
|
||||
@@ -566,7 +574,7 @@ export class CppCodeExecutor {
|
||||
try {
|
||||
this.isRunning = true;
|
||||
this.parseCode();
|
||||
await this.withVariableScope(() => this.executeMain(), this.globalVariables);
|
||||
return await this.withVariableScope(() => this.executeMain(), this.globalVariables);
|
||||
} catch (error) {
|
||||
console.error('C++执行错误:', error);
|
||||
throw error;
|
||||
@@ -814,12 +822,26 @@ export class CppCodeExecutor {
|
||||
|
||||
while (i < lines.length) {
|
||||
const line = lines[i].trim();
|
||||
if (!line || line.startsWith('//') || line === '{' || line === '}' || line === 'return 0;' ||
|
||||
if (!line || line.startsWith('//') || line === '{' || line === '}' ||
|
||||
line.match(/^\s*}\s*else\s*\{\s*$/) || line.startsWith('else')) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// return 不能标记成 continue,否则循环会直接跳过它。
|
||||
if (/^return\b/.test(line)) {
|
||||
statements.push({
|
||||
type: 'control',
|
||||
subtype: 'return',
|
||||
content: line,
|
||||
lineNumber: isMainFunction ? this.getActualLineNumber(i) : i + 1,
|
||||
originalContent: line,
|
||||
contextPath: isMainFunction ? 'main' : 'function'
|
||||
});
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否是自定义函数调用(包括带括号的实参,如 f((n + 1));)
|
||||
const customCall = this.parseCustomFunctionCall(line);
|
||||
if (customCall) {
|
||||
@@ -848,8 +870,8 @@ export class CppCodeExecutor {
|
||||
statements.push(whileLoop);
|
||||
i = whileLoop.endIndex;
|
||||
} else {
|
||||
// 检查是否是break或continue或return语句
|
||||
if (line === 'break;' || line === 'continue;' || line.startsWith('return')) {
|
||||
// 检查是否是break或continue语句
|
||||
if (line === 'break;' || line === 'continue;') {
|
||||
statements.push({
|
||||
type: 'control',
|
||||
subtype: line === 'break;' ? 'break' : 'continue',
|
||||
@@ -1327,10 +1349,17 @@ export class CppCodeExecutor {
|
||||
}
|
||||
|
||||
async executeMain() {
|
||||
try {
|
||||
for (const statement of this.statements) {
|
||||
if (this.shouldStop()) break;
|
||||
await this.executeStatement(statement);
|
||||
}
|
||||
} catch (signal) {
|
||||
if (!(signal instanceof CppReturnSignal)) throw signal;
|
||||
return signal.value;
|
||||
}
|
||||
// main 正常执行到末尾,相当于 return 0。
|
||||
return 0;
|
||||
}
|
||||
|
||||
async executeStatement(statement) {
|
||||
@@ -1361,8 +1390,11 @@ export class CppCodeExecutor {
|
||||
await this.executeFunctionCall(statement);
|
||||
break;
|
||||
case 'control':
|
||||
if (statement.content.startsWith('return')) {
|
||||
throw new Error('RETURN_INTERRUPT');
|
||||
if (statement.subtype === 'return') {
|
||||
const match = statement.content.match(/^return\b([\s\S]*?);(?:\s*\/\/.*)?$/);
|
||||
if (!match) throw new Error(`无法解析return语句: ${statement.content}`);
|
||||
const expression = match[1].trim();
|
||||
throw new CppReturnSignal(expression ? this.evaluateExpression(expression) : undefined);
|
||||
}
|
||||
// break和continue在各自的循环中处理,这里只记录
|
||||
debugLog(`🔄 控制语句: ${statement.subtype}`);
|
||||
@@ -1887,7 +1919,8 @@ export class CppCodeExecutor {
|
||||
await this.executeStatement(adjustedStatement);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.message !== 'RETURN_INTERRUPT') throw e;
|
||||
if (!(e instanceof CppReturnSignal)) throw e;
|
||||
return e.value;
|
||||
}
|
||||
|
||||
console.log(`✅ 函数${functionName}执行完成`);
|
||||
@@ -2719,7 +2752,7 @@ export const createCppExecutor = () => {
|
||||
const executor = new CppCodeExecutor(code, window.setHighlightedLine);
|
||||
this.currentExecutor = executor;
|
||||
try {
|
||||
await executor.run();
|
||||
return await executor.run();
|
||||
} finally {
|
||||
this.currentExecutor = null;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// config.js
|
||||
|
||||
// const CONFIG = {
|
||||
// DataServerBaseUrl: "https://service.001code.cn", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.cn", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.cn",
|
||||
// // DataServerBaseUrl: "https://service.001code.cn",
|
||||
// // DataServerBaseUrl: "https://service.001code.cn",
|
||||
// // DataServerBaseUrl: "https://service.001code.cn",
|
||||
// DataServerBaseUrl: "https://service.001code.com", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.com", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.com",
|
||||
// // DataServerBaseUrl: "https://service.001code.com",
|
||||
// // DataServerBaseUrl: "https://service.001code.com",
|
||||
// // DataServerBaseUrl: "https://service.001code.com",
|
||||
// version : "2025010301",
|
||||
// unitycdndir : 'https://oss-rpwqy.jjwlcdn.com/001_code_unity_res_20250826',
|
||||
// unitycdnbuilddir : 'https://oss-rpwqy.jjwlcdn.com/001_code_unity_res_20250826/Build',
|
||||
@@ -78,12 +78,12 @@
|
||||
|
||||
|
||||
// const CONFIG = {
|
||||
// // DataServerBaseUrl: "https://service.001code.cn", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.cn", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.cn",
|
||||
// DataServerBaseUrl: "https://service.001code.cn",
|
||||
// // DataServerBaseUrl: "https://service.001code.cn",
|
||||
// // DataServerBaseUrl: "https://service.001code.cn",
|
||||
// // DataServerBaseUrl: "https://service.001code.com", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.com", // 在这里定义服务器地址
|
||||
// // DataServerBaseUrl: "https://service.001code.com",
|
||||
// DataServerBaseUrl: "https://service.001code.com",
|
||||
// // DataServerBaseUrl: "https://service.001code.com",
|
||||
// // DataServerBaseUrl: "https://service.001code.com",
|
||||
// version : "2025011001",
|
||||
// unitycdndir : 'https://oss-rpwqy.jjwlcdn.com/001_code_unity_res_20250826',
|
||||
// unitycdnbuilddir : 'https://oss-rpwqy.jjwlcdn.com/001_code_unity_res_20250826/Build',
|
||||
@@ -157,12 +157,12 @@
|
||||
|
||||
|
||||
const CONFIG = {
|
||||
// DataServerBaseUrl: "https://service.001code.cn", // 在这里定义服务器地址
|
||||
// DataServerBaseUrl: "https://service.001code.cn", // 在这里定义服务器地址
|
||||
// DataServerBaseUrl: "https://service.001code.cn",
|
||||
DataServerBaseUrl: "https://service.001code.cn",
|
||||
// DataServerBaseUrl: "https://service.001code.cn",
|
||||
// DataServerBaseUrl: "https://service.001code.cn",
|
||||
// DataServerBaseUrl: "https://service.001code.com", // 在这里定义服务器地址
|
||||
// DataServerBaseUrl: "https://service.001code.com", // 在这里定义服务器地址
|
||||
// DataServerBaseUrl: "https://service.001code.com",
|
||||
DataServerBaseUrl: "https://service.001code.com",
|
||||
// DataServerBaseUrl: "https://service.001code.com",
|
||||
// DataServerBaseUrl: "https://service.001code.com",
|
||||
|
||||
version: "2026071701",
|
||||
/** OSS 真实地址(生产环境浏览器直连) */
|
||||
|
||||
Reference in New Issue
Block a user