diff --git a/arkoala-arkts/libarkts/native/src/bridges.cc b/arkoala-arkts/libarkts/native/src/bridges.cc index 01162cef2a79d8b03d3507c1bbd67fd6c59e5126..f7571ea5fc3c19edc0cee928d6afc7b61922da85 100644 --- a/arkoala-arkts/libarkts/native/src/bridges.cc +++ b/arkoala-arkts/libarkts/native/src/bridges.cc @@ -221,3 +221,11 @@ static KNativePointer impl_ExternalSourcePrograms(KNativePointer instance) return new std::vector(programs, programs + program_len); } KOALA_INTEROP_1(ExternalSourcePrograms, KNativePointer, KNativePointer); + +static void impl_ProgramSetSource(KNativePointer contextPtr, KNativePointer instance, KStringPtr& source, KStringPtr& sourceFile, KStringPtr& sourceDir) +{ + auto _context = reinterpret_cast(contextPtr); + auto _instance = reinterpret_cast(instance); + return GetImpl()->ProgramSetSource(_context, _instance, getStringCopy(source), getStringCopy(sourceFile), getStringCopy(sourceDir)); +} +KOALA_INTEROP_V5(ProgramSetSource, KNativePointer, KNativePointer, KStringPtr, KStringPtr, KStringPtr) \ No newline at end of file diff --git a/arkoala-arkts/libarkts/src/Es2pandaNativeModule.ts b/arkoala-arkts/libarkts/src/Es2pandaNativeModule.ts index 37f1ae75b79056dc0d83ebf8716bbaf5dc9d4a19..1c9ea02b46a9bf407c30ad0e13392235217358b9 100644 --- a/arkoala-arkts/libarkts/src/Es2pandaNativeModule.ts +++ b/arkoala-arkts/libarkts/src/Es2pandaNativeModule.ts @@ -603,6 +603,10 @@ export class Es2pandaNativeModule { _ExternalSourcePrograms(instance: KNativePointer): KNativePointer { throw new Error("Not implemented"); } + + _ProgramSetSource(context: KNativePointer, program: KNativePointer, src: string, srcFile: string, srcDir: string): void { + throw new Error("Not implemented"); + } } export function initEs2panda(): Es2pandaNativeModule { diff --git a/arkoala-arkts/libarkts/src/arkts-api/peers/Program.ts b/arkoala-arkts/libarkts/src/arkts-api/peers/Program.ts index 52fe134f0211e596edeb29da6028a0cb485f4b8a..788768f557f72112c710b6619b5970c29fc322a8 100644 --- a/arkoala-arkts/libarkts/src/arkts-api/peers/Program.ts +++ b/arkoala-arkts/libarkts/src/arkts-api/peers/Program.ts @@ -15,7 +15,7 @@ import { ArktsObject } from "./ArktsObject" import { global } from "../static/global" -import { acceptNativeObjectArrayResult, unpackString } from "../utilities/private" +import { acceptNativeObjectArrayResult, passString, unpackString } from "../utilities/private" import { KNativePointer } from "@koalaui/interop" import { EtsScript } from "../types" @@ -28,6 +28,10 @@ export class Program extends ArktsObject { return new EtsScript(global.es2panda._ProgramAst(global.context, this.peer)); } + setSource(src: string, srcFile: string, srcDir: string) { + global.es2panda._ProgramSetSource(global.context, this.peer, passString(src), passString(srcFile), passString(srcDir)); + } + get externalSources(): ExternalSource[] { return acceptNativeObjectArrayResult( global.es2panda._ProgramExternalSources(global.context, this.peer), diff --git a/arkoala-arkts/libarkts/src/es2panda.ts b/arkoala-arkts/libarkts/src/es2panda.ts index 84b065d4780c95781284536632020185ace16336..3c1b2521f7d0a053fe16fcb3e1d0b4ac479ad38d 100644 --- a/arkoala-arkts/libarkts/src/es2panda.ts +++ b/arkoala-arkts/libarkts/src/es2panda.ts @@ -19,7 +19,7 @@ import { global } from "./arkts-api/static/global" import { Command } from "commander" import { isNumber, throwError, withWarning, filterSource } from "./utils" import { Es2pandaContextState } from "./generated/Es2pandaEnums" -import { AstNode, Config, Context, EtsScript, proceedToState } from "./arkts-api" +import { AstNode, Config, Context, EtsScript, passString, proceedToState } from "./arkts-api" function parseCommandLineArgs() { const commander = new Command() @@ -50,7 +50,18 @@ function parseCommandLineArgs() { return { filePath, configPath, outputPath, dumpAst, restartStages } } -function insertPlugin(plugin: (ast: AstNode) => void, state: Es2pandaContextState, dumpAst: boolean): AstNode { +interface UserExternalOptions { + include?: string[] +} + +type Plugin = { + transform: (node: AstNode) => AstNode, + externalOptions: UserExternalOptions, +} + +let updatedAstSrc: string + +function insertPlugin(plugin: Plugin, state: Es2pandaContextState, dumpAst: boolean): AstNode { proceedToState(state) const script = EtsScript.fromContext() if (script === undefined) { @@ -62,7 +73,22 @@ function insertPlugin(plugin: (ast: AstNode) => void, state: Es2pandaContextStat console.log(filterSource(script.dumpSrc())) } - const transform = plugin + const transform = plugin.transform + const include = plugin.externalOptions.include + if (include) { + global.compilerContext.program.externalSources.forEach((it) => { + const itName = it.getName() + if (include.findIndex(inc => inc == itName) != -1) { + console.log("BEFORE:") + console.log(it.programs[0].astNode.dumpSrc()) + transform?.(it.programs[0].astNode) + updatedAstSrc = filterSource(it.programs[0].astNode.dumpSrc()) + console.log("AFTER:") + console.log(it.programs[0].astNode.dumpSrc()) + } + }) + } + transform?.(script) if (dumpAst) { @@ -74,14 +100,34 @@ function insertPlugin(plugin: (ast: AstNode) => void, state: Es2pandaContextStat return script } -function restartCompilerUptoState(state: Es2pandaContextState, restart: boolean) { +function restartCompilerUptoState(state: Es2pandaContextState, restart: boolean, manual?: boolean) { const ast = EtsScript.fromContext() if (restart) { console.log("restarting") + const srcText = filterSource(ast.dumpSrc()) global.es2panda._DestroyContext(global.context) global.compilerContext = Context.createFromString(srcText) + + if (manual) { + proceedToState(Es2pandaContextState.ES2PANDA_STATE_PARSED) + console.log("MANUAL") + console.log(updatedAstSrc) + global.compilerContext.program.externalSources.forEach((it) => { + const itName = it.getName() + if (itName == "@koalaui/runtime.stub") { + global.es2panda._ProgramSetSource( + global.context, + it.programs[0].peer, + passString(updatedAstSrc), + passString("stub.sts"), + passString(".") + ) + global.es2panda._ProceedToState(global.context, Es2pandaContextState.ES2PANDA_STATE_PARSED) + } + }) + } } console.log("proceeeding to", Es2pandaContextState[state]) proceedToState(state) @@ -92,7 +138,7 @@ function invokeWithPlugins( configPath: string, filePath: string, outputPath: string, - pluginsByState: Map void)[]>, + pluginsByState: Map, dumpAst: boolean, restart: boolean ): void { @@ -121,7 +167,7 @@ function invokeWithPlugins( console.log("PLUGINS: ", pluginsByState.size, pluginsByState) - if (pluginsByState.size == 0 ) { + if (pluginsByState.size == 0) { proceedToState(Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) return } @@ -140,24 +186,30 @@ function invokeWithPlugins( insertPlugin(plugin, Es2pandaContextState.ES2PANDA_STATE_CHECKED, dumpAst) }) - restartCompilerUptoState(Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED, restart) + restartCompilerUptoState(Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED, restart, true) } function setAllParents(ast: AstNode) { global.es2panda._AstNodeUpdateAll(global.context, ast.peer) } -function loadPlugin(configDir: string, jsonPlugin: any) { +function loadPlugin(configDir: string, jsonPlugin: any): Plugin { const pluginPath = jsonPlugin.transform ?? throwError(`arktsconfig plugins objects should specify transform`) /** TODO: read and pass plugin options */ const plugin = (pluginPath.startsWith(".") || pluginPath.startsWith("/")) ? path.resolve(configDir, pluginPath) : pluginPath const pluginFunction: (config?: any) => any = require(plugin).default(jsonPlugin) - return pluginFunction + if (jsonPlugin.include) { + jsonPlugin.include = jsonPlugin.include.map((it: string) => { + it = ConfigHelper.resolveInclude(it) + return it + }) + } + return { transform: pluginFunction, externalOptions: jsonPlugin } } -function selectPlugins(configDir: string, plugins: any[], stage: string): ((arg: AstNode) => AstNode)[] | undefined { +function selectPlugins(configDir: string, plugins: any[], stage: string): Plugin[] | undefined { const selected = plugins .filter(it => (it.stage == stage)) .map(it => loadPlugin(configDir, it)) @@ -172,7 +224,7 @@ function stateName(value: Es2pandaContextState): string { } function readAndSortPlugins(configDir: string, plugins: any[]) { - const pluginsByState = new Map void)[]>() + const pluginsByState = new Map() Object.values(Es2pandaContextState) .filter(isNumber) @@ -187,9 +239,22 @@ function readAndSortPlugins(configDir: string, plugins: any[]) { return pluginsByState } +class ConfigHelper { + static configPath: string + static arktsconfig: any + + static resolveInclude(include: string) { + const pkg = ConfigHelper.arktsconfig.compilerOptions.package ?? "" + const dirPart = path.normalize(path.dirname(include)).replaceAll('/', '.') + return [pkg, '.', dirPart != '.' ? dirPart : '', path.basename(include, path.extname(include)).replaceAll('/', '.')].join('') + } +} + export function main() { const { filePath, configPath, outputPath, dumpAst, restartStages } = parseCommandLineArgs() const arktsconfig = JSON.parse(fs.readFileSync(configPath).toString()) + ConfigHelper.configPath = configPath + ConfigHelper.arktsconfig = arktsconfig const configDir = path.dirname(configPath) const compilerOptions = arktsconfig.compilerOptions ?? throwError(`arktsconfig should specify compilerOptions`) const plugins = compilerOptions.plugins ?? [] diff --git a/arkoala-arkts/memo-plugin/demo/arktsconfig.json b/arkoala-arkts/memo-plugin/demo/arktsconfig.json index 1bbcbffbc12594ee2728b27dd8adcf3a7773b0ce..9694fc750cf944df6361bd1ca7be01da7a9c8643 100644 --- a/arkoala-arkts/memo-plugin/demo/arktsconfig.json +++ b/arkoala-arkts/memo-plugin/demo/arktsconfig.json @@ -15,7 +15,8 @@ }, { "transform": "..", - "stage": "checked" + "stage": "checked", + "include": ["./stub.sts"] } ] }, diff --git a/arkoala-arkts/memo-plugin/demo/stub.sts b/arkoala-arkts/memo-plugin/demo/stub.sts index e444446f64cb815255aa51557b27f87961bc80c0..faa636259c8c8c67c39114cdf3132f0628593d1c 100644 --- a/arkoala-arkts/memo-plugin/demo/stub.sts +++ b/arkoala-arkts/memo-plugin/demo/stub.sts @@ -1,4 +1,3 @@ import { memo, __memo_context_type, __memo_id_type } from "@koalaui/runtime" -@memo export declare function memo_foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, s: String): void -@memo export declare function memo_foo(s: String): void +@memo export function memo_foo(s: String): void { console.log("no declare because we are not visiting such nodes") }