From d06bae88b9983977e8e4d380c0b2a1e8b053b6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 16 Jan 2025 19:17:53 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=A4=84=E7=90=86=E7=BC=A9?= =?UTF-8?q?=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ecaCompiler/compiler.ts | 19 ++++--- src/ecaCompiler/fillConfig.ts | 4 +- src/ecaCompiler/formatter.ts | 99 ++++++++++++++++++++++++++--------- src/ecaCompiler/index.ts | 10 ++-- src/ecaCompiler/process.ts | 48 ++++++++--------- 5 files changed, 118 insertions(+), 62 deletions(-) diff --git a/src/ecaCompiler/compiler.ts b/src/ecaCompiler/compiler.ts index e044405..b1f1a7c 100644 --- a/src/ecaCompiler/compiler.ts +++ b/src/ecaCompiler/compiler.ts @@ -278,12 +278,19 @@ export class Trigger { conditions: Exp[] = []; actions: Action[] = []; variables: Variable[] = []; - constructor(public eca: ECA, private json: any) { + constructor(public eca: ECA, private json: any, isClosure = false) { this.name = json.trigger_name as string; this.groupID = json.group_id as number; - if (!json.enabled || !json.valid || !json.call_enabled) { - this.enabled = false; - return; + if (isClosure) { + if (!json.call_enabled || !json.valid) { + this.enabled = false; + return; + } + } else { + if (!json.enabled || !json.valid) { + this.enabled = false; + return; + } } if (json.event) { for (let event of json.event as any[]) { @@ -342,7 +349,7 @@ export class Function { constructor(private eca: ECA, private json: any) { this.name = json.func_name as string; this.id = json.func_id as string; - if (!json.enabled) { + if (!json.call_enabled || !json.valid) { this.enabled = false; return; } @@ -393,7 +400,7 @@ export class ECA { constructor(private json: y3.json.JObject, public group?: ECAGroup) { if (y3.is.object(json.sub_trigger)) { for (let [id, closure] of Object.entries(json.sub_trigger as Record)) { - this.closures[id] = new Trigger(this, closure); + this.closures[id] = new Trigger(this, closure, true); } } if (json.is_func) { diff --git a/src/ecaCompiler/fillConfig.ts b/src/ecaCompiler/fillConfig.ts index 83b4c31..e37431c 100644 --- a/src/ecaCompiler/fillConfig.ts +++ b/src/ecaCompiler/fillConfig.ts @@ -333,12 +333,12 @@ export async function fillStatic(formatter: Formatter) { let result = ''; result += `if ${filters ?? 'false'} then\n`; if (thens !== undefined && thens !== '') { - result += formatter.increaseTab(thens); + result += thens; result += '\n'; } if (elses !== undefined && elses !== '') { result += 'else\n'; - result += formatter.increaseTab(elses); + result += elses; result += '\n'; } result += 'end'; diff --git a/src/ecaCompiler/formatter.ts b/src/ecaCompiler/formatter.ts index caa5f54..b8b43f8 100644 --- a/src/ecaCompiler/formatter.ts +++ b/src/ecaCompiler/formatter.ts @@ -179,27 +179,9 @@ class RuleHandler { optionalGaurd = undefined; } }; - this.alignIndent(buf); return buf.join(''); } - // 对齐缩进 - private alignIndent(buf: string[]) { - for (let i = 0; i < buf.length; i++) { - let line = buf[i]; - // 检查此行是以 `\n ` 结尾 - let match = line.match(/\n([ \t]+)$/); - if (match) { - let indent = match[1]; - // 将下一行中所有的换行符后面都添加相同的缩进 - let nextLine = buf[i + 1]; - if (nextLine) { - buf[i + 1] = nextLine.replaceAll('\n', '\n' + indent); - } - } - } - } - private clearLastEmptyLine(buf: string[]) { for (let i = buf.length - 1; i >= 0; i--) { if (buf[i].match(/^[ ]*$/)) { @@ -324,7 +306,7 @@ export class Formatter { results.push('}'); - return results.join('\n') + '\n\n'; + return results.join('\n') + '\n'; } private makeGroupVariablePart(trg: Trigger | Function): string { @@ -408,7 +390,7 @@ export class Formatter { result += this.makeLocalVariableDefine(trg) ?? ''; if (trg.events.length === 1) { result += `${eventTarget}:event(${trg.events[0].make(this)}, function(_, params)\n`; - result += this.increaseTab(this.makeBody(trg)); + result += this.makeBody(trg); result += `\nend)`; } else { if (trg.events.length > 1) { @@ -422,7 +404,7 @@ export class Formatter { result += `---@param params ${types.join('|')}\n`; } result += `local function action(_, params)\n`; - result += this.increaseTab(this.makeBody(trg)); + result += this.makeBody(trg); result += `\nend\n\n`; for (let event of trg.events) { result += `${eventTarget}:event(${event.make(this)}, action)\n`; @@ -441,7 +423,7 @@ export class Formatter { result += this.makeLocalVariableDefine(func) ?? ''; const params = func.params.map((param) => y3.lua.getValidName(param.name)).join(', '); result += `Func[${y3.lua.encode(func.name)}] = function (${params})\n`; - result += this.increaseTab(this.makeBody(func)); + result += this.makeBody(func); result += `\nend`; return result; } @@ -467,10 +449,6 @@ export class Formatter { return this.funcNameRecord[id]; } - public increaseTab(content: string, tab: string = ' '): string { - return content.split('\n').map((line) => tab + line).join('\n'); - } - private ensureEndWithNL(content: string): string { return content.endsWith('\n') ? content : content + '\n'; } @@ -480,7 +458,76 @@ export class Formatter { return content.replace(/\n/g, '\r\n'); } + static increaseIndent = new Set(['else', 'function', 'then', 'do', 'repeat', 'elseif', '[', '{', '(']); + static decreaseIndent = new Set(['end', 'until', ']', '}', ')']); + + private getIncreseDelta(line: string): [number, number] { + if (line.startsWith('--')) { + return [0, 0]; + } + let current = 0; + let next = 0; + const wordAndSymbolRegex = /\w+|[^\s\w]/g; + let hasOther = false; + // 遍历每个完整的单词和单个的符号 + let match; + while ((match = wordAndSymbolRegex.exec(line)) !== null) { + let wordOrSymbol = match[0]; + if (Formatter.increaseIndent.has(wordOrSymbol)) { + next++; + } else if (Formatter.decreaseIndent.has(wordOrSymbol)) { + if (hasOther) { + next--; + } else { + current--; + } + } else { + hasOther = true; + } + } + return [current, next]; + } + + private formatIdent(content: string) { + let lines = content.split('\n'); + let level = 0; + let levels: number[] = []; + + function 整理缩进(current: number) { + let lastLevel = levels[levels.length - 1] ?? 0; + if (current === lastLevel) { + return; + } else if (current > lastLevel) { + levels.push(current); + return; + } else { + levels.pop(); + 整理缩进(current); + return; + } + } + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + line = line.trimStart(); + + if (line !== '') { + let [current, next] = this.getIncreseDelta(line); + level += current; + 整理缩进(level); + line = ' '.repeat(levels.length) + line; + level += next; + 整理缩进(level); + } + + lines[i] = line; + } + + return lines.join('\n'); + } + public asFileContent(content: string): string { + content = this.formatIdent(content); content = this.ensureEndWithNL(content); content = this.ensureNLisCRLF(content); return content; diff --git a/src/ecaCompiler/index.ts b/src/ecaCompiler/index.ts index 8e89ba8..e6c1218 100644 --- a/src/ecaCompiler/index.ts +++ b/src/ecaCompiler/index.ts @@ -15,7 +15,7 @@ class ProgressHandle implements Progress { constructor(private token: vscode.CancellationToken, private report: (increment: number, message: string) => void) { } makeMessage() { - const curStr = this.cur.toString().padStart(this.max.toString().length, '0'); + const curStr = this.cur.toFixed().padStart(this.max.toString().length, '0'); return `(${curStr}/${this.max})${this.msg}`; } @@ -24,11 +24,12 @@ class ProgressHandle implements Progress { this.report(0, this.makeMessage()); } - total(value: number) { - this.max = value; + total(value: number = 1) { + this.max += value; + this.report(0, this.makeMessage()); } - update(value = 1) { + async update(value = 1) { this.cur += value; if (this.max === 0) { return; @@ -40,6 +41,7 @@ class ProgressHandle implements Progress { const increment = percent - this.lastPercent; this.lastPercent = percent; this.report(increment, this.makeMessage()); + await new Promise(resolve => setImmediate(resolve)); } isCanceled() { diff --git a/src/ecaCompiler/process.ts b/src/ecaCompiler/process.ts index 5870bd1..a821bb5 100644 --- a/src/ecaCompiler/process.ts +++ b/src/ecaCompiler/process.ts @@ -5,8 +5,8 @@ import * as vscode from 'vscode'; export interface Progress { message: (message: string) => void, - total: (total: number) => void, - update: (value?: number) => void, + total: (total?: number) => void, + update: (value?: number) => Promise, isCanceled: () => boolean, } @@ -38,24 +38,19 @@ export class Process { constructor(private inMap: y3.Map, private outMap: y3.Map, private formatter: Formatter, private progress?: Progress) { } public async fullCompile() { - let total = 0; this.progress?.message('搜索触发器文件...'); y3.log.info('【编译ECA】搜索触发器文件...'); let searchedTriggers = await this.scanTriggers(y3.uri(this.inMap.uri, this.inTriggerDir)); - total += searchedTriggers.length; this.progress?.message('搜索函数文件...'); y3.log.info('【编译ECA】搜索函数文件...'); let searchedFunctions = await this.scanTriggers(y3.uri(this.inMap.uri, this.inFunctionDir)); - total += searchedFunctions.length; this.progress?.message('搜索物编触发器文件...'); y3.log.info('【编译ECA】搜索物编触发器文件...'); let searchedObjects = await this.scanObjects(this.inMap.uri); - total += searchedObjects.length; - - this.progress?.total(total * 3 + 1); + this.progress?.total(1); await this.compileGlobalVariables(); let compileResults: CompileResult[] = []; @@ -66,8 +61,8 @@ export class Process { } this.progress?.message(`触发器: ${searchedTriggers[i].fileName}`); y3.log.info(`【编译ECA】正在解析触发器文件(${i + 1}/${searchedTriggers.length}): ${searchedTriggers[i].fileName}`); - this.progress?.update(); - let compileResult = await this.compileOneTrigger(searchedTriggers[i]); + await this.progress?.update(0.2); + let compileResult = this.compileOneTrigger(searchedTriggers[i]); if (compileResult) { compileResults.push(compileResult); } @@ -79,14 +74,16 @@ export class Process { } this.progress?.message(`函数: ${searchedFunctions[i].fileName}`); y3.log.info(`【编译ECA】正在解析函数文件(${i + 1}/${searchedFunctions.length}): ${searchedFunctions[i].fileName}`); - this.progress?.update(); - let compileResult = await this.compileOneFunction(searchedFunctions[i]); + await this.progress?.update(0.2); + let compileResult = this.compileOneFunction(searchedFunctions[i]); if (compileResult) { compileResults.push(compileResult); - let main = compileResult.eca.main; - if ('id' in main) { - this.formatter.setFuncName(main.id, main.name); + if ('main' in compileResult.eca) { + let main = compileResult.eca.main; + if ('id' in main) { + this.formatter.setFuncName(main.id, main.name); + } } } } @@ -97,8 +94,8 @@ export class Process { } this.progress?.message(`物编触发器: ${searchedObjects[i].fileName}`); y3.log.info(`【编译ECA】正在解析物编触发器文件(${i + 1}/${searchedObjects.length}): ${searchedObjects[i].fileName}`); - this.progress?.update(); - let compileResult = await this.compileOneObject(searchedObjects[i]); + await this.progress?.update(0.2); + let compileResult = this.compileOneObject(searchedObjects[i]); if (compileResult) { compileResults.push(compileResult); } @@ -110,8 +107,8 @@ export class Process { } let result = compileResults[i]; this.progress?.message(`生成: ${result.fileName}`); - y3.log.info(`【编译ECA】正在生成代码(${i + 1}/${compileResults.length}): ${result.fileName}`); - this.progress?.update(); + y3.log.debug(`【编译ECA】正在生成代码(${i + 1}/${compileResults.length}): ${result.fileName}`); + await this.progress?.update(0.2); try { let content = result.eca.make(this.formatter); this.includeFiles.push(result.includeName); @@ -153,6 +150,7 @@ export class Process { content: file.string, uri, }); + this.progress?.total(); } y3.log.info(`【编译ECA】读取${results.length}个json文件`); @@ -205,12 +203,13 @@ export class Process { uri, objectType: nameCN, }); + this.progress?.total(); } } return results; } - public async compileOneTrigger(searched: SearchResult): Promise { + public compileOneTrigger(searched: SearchResult): CompileResult | undefined { try { let eca = this.compiler.compileECA(searched.content); @@ -230,7 +229,7 @@ export class Process { } } - public async compileOneFunction(searched: SearchResult) { + public compileOneFunction(searched: SearchResult): CompileResult | undefined { try { let eca = this.compiler.compileECA(searched.content); @@ -250,7 +249,7 @@ export class Process { } } - public async compileOneObject(searched: SearchResult) { + public compileOneObject(searched: SearchResult): CompileResult | undefined { try { let eca = this.compiler.compileObject(searched.content, searched.objectType!); @@ -280,6 +279,7 @@ export class Process { return; } + await this.progress?.update(0.4); const includeName = [this.outBasseDir, '全局变量.lua'].join('/'); this.includeFiles.push(includeName); this.write(includeName, content); @@ -335,13 +335,13 @@ export class Process { let file = await y3.fs.readFile(uri); if (file?.string === content) { y3.log.debug(`【编译ECA】跳过相同的文件:${includeName}`); - this.progress?.update(); + await this.progress?.update(0.6); continue; } this.progress?.message(`正在写入硬盘:${includeName}`); y3.log.debug(`【编译ECA】写入文件:${includeName}`); await y3.fs.writeFile(uri, content); - this.progress?.update(); + await this.progress?.update(0.6); } if (removeTask.length > 0) {