diff --git a/arkoala-arkts/libarkts/arktsconfig.json b/arkoala-arkts/libarkts/arktsconfig.json index 85a85ddde40103afb756f39d533a8352f2f30a85..ca68d7458acaab32eb71474c5a5375512c8a8d55 100644 --- a/arkoala-arkts/libarkts/arktsconfig.json +++ b/arkoala-arkts/libarkts/arktsconfig.json @@ -2,14 +2,6 @@ "compilerOptions": { "outDir": "./abc", "baseUrl": ".", - "paths": { - "std": [ - "../../incremental/tools/panda/node_modules/@panda/sdk/ets/stdlib/std" - ], - "escompat": [ - "../../incremental/tools/panda/node_modules/@panda/sdk/ets/stdlib/escompat" - ] - }, "plugins": [ { "transform": "./examples/build/src/example-parsed-transformer.js", diff --git a/arkoala-arkts/libarkts/examples/src/builder-lambda-transformer.ts b/arkoala-arkts/libarkts/examples/src/builder-lambda-transformer.ts index 82db906e669591564fb608054e7dbd9f5ef202ba..c5de79be8fae8d85b84e3dfd326f4bb61288273f 100644 --- a/arkoala-arkts/libarkts/examples/src/builder-lambda-transformer.ts +++ b/arkoala-arkts/libarkts/examples/src/builder-lambda-transformer.ts @@ -30,11 +30,13 @@ function getLambdaArg(lambdaBody: arkts.Node): arkts.ArrowFunctionExpression { const param = arkts.factory.createParameterDeclaration( arkts.factory.createIdentifier( builderLambdaInstanceName, - arkts.factory.createTypeReference( - arkts.factory.createIdentifier( - 'string' - ) - ) + undefined + // TODO: it should be the return type of the function annotated with the @BuilderLambda + // arkts.factory.createTypeReference( + // arkts.factory.createIdentifier( + // 'MyComponent' + // ) + // ) ), undefined ) diff --git a/arkoala-arkts/libarkts/package.json b/arkoala-arkts/libarkts/package.json index 76258d7299c6327a9f1e6e52e27e2125144de2ae..92f587c9def219c06426cc61439f6ad9745ab9c8 100644 --- a/arkoala-arkts/libarkts/package.json +++ b/arkoala-arkts/libarkts/package.json @@ -21,7 +21,7 @@ "compile:src": "npx memo-tsc -p ./tsconfig.json", "compile": "npm run compile:native && npm run compile:src", "compile:plugin": "npx memo-tsc -p examples/tsconfig.json", - "run:js": "PANDA_SDK_PATH=../../incremental/tools/panda/node_modules/@panda/sdk node . --file ./examples/input/main.sts --arktsconfig ./arktsconfig.json", + "run:js": "PANDA_SDK_PATH=../../incremental/tools/panda/node_modules/@panda/sdk node . --file ./examples/input/main.sts --arktsconfig ./arktsconfig.json --output ./build/abc/main.abc --dump-plugin-ast", "run": "npm run compile && npm run compile:plugin && npm run run:js", "mocha": "PANDA_SDK_PATH=../../incremental/tools/panda/node_modules/@panda/sdk TS_NODE_PROJECT=./test/tsconfig.json mocha -r tsconfig-paths/register --reporter-option maxDiffSize=0", "test": "npm run compile:native && npm run mocha", diff --git a/arkoala-arkts/libarkts/src/es2panda.ts b/arkoala-arkts/libarkts/src/es2panda.ts index f6809f9728e04959a61cc2e6df3e1cbbcc37e3c1..57ed1f57bf353a0c2efdbb28ff610fcdfffa5e90 100644 --- a/arkoala-arkts/libarkts/src/es2panda.ts +++ b/arkoala-arkts/libarkts/src/es2panda.ts @@ -3,17 +3,23 @@ import * as path from "node:path" import * as arkts from "./arkts-api" import global from "./arkts-api/static/global" import { Command } from "commander" -import { throwError } from "./utils" +import { throwError, withWarning } from "./utils" function parseCommandLineArgs() { const commander = new Command() .option('--file, ', 'Path to file to be compiled') .option('--arktsconfig, ', 'Path to arkts configuration file') + .option('--ets-module', 'Do nothing, legacy compatibility') + .option('--output, ', 'The name of result file') + .option('--dump-plugin-ast', 'Dump ast before and after each plugin') .parse(process.argv) .opts() + const restOptions = commander.args + const filePath = path.resolve(commander.file) const configPath = path.resolve(commander.arktsconfig) + const outputPath = path.resolve(commander.output) if (!fs.existsSync(filePath)) { throw new Error(`File path doesn't exist: ${filePath}`) } @@ -21,57 +27,84 @@ function parseCommandLineArgs() { throw new Error(`Arktsconfig path doesn't exist: ${configPath}`) } - return { filePath, configPath } + const dumpAst = !!commander.dumpPluginAst + + return { filePath, configPath, outputPath, dumpAst } } -function insertPlugin(state: arkts.Es2pandaContextState): arkts.Node { +function insertPlugin(pluginsByState: Map void>, state: arkts.Es2pandaContextState, dumpAst: boolean): arkts.Node { arkts.proceedToState(state) const script = arkts.unpackNode(arkts.getAstFromContext()) if (script === undefined) { throwError(`Failed to receive ast from es2panda`) } - console.log(`BEFORE ${stateName(state)}:`) - console.log(script.dumpSrc()) + if (dumpAst) { + console.log(`BEFORE ${stateName(state)}:`) + console.log(script.dumpSrc()) + } const transform = pluginsByState.get(state) transform?.(script) - console.log(`AFTER ${stateName(state)}:`) - console.log(script.dumpSrc()) + if (dumpAst) { + console.log(`AFTER ${stateName(state)}:`) + console.log(script.dumpSrc()) + } return script } -function invokePlugins(configPath: string, filePath: string ): void { +function restartCompilerUptoState(ast: arkts.Node, state: arkts.Es2pandaContextState) { + const srcText = ast.dumpSrc() + global.es2panda._DestroyContext(global.context) + // TODO: disentangle EstScript.create and states, please + const afterParsedScript = arkts.EtsScript.create( + srcText, + state + ) +} + +const defaultPandaSdk = "../../../incremental/tools/panda/node_modules/@panda/sdk" +function invokeWithPlugins(configPath: string, filePath: string, outputPath: string, pluginsByState: Map void>, dumpAst: boolean ): void { const source = fs.readFileSync(filePath).toString() + const sdk = process.env.PANDA_SDK_PATH ?? withWarning( + defaultPandaSdk, + `PANDA_SDK_PATH not set, assuming ${defaultPandaSdk}` + ) + const stdlib = `${sdk}/ets/stdlib` global.config = arkts.createConfig([ '_', '--arktsconfig', configPath, - filePath + filePath, + // Always assume this option unconditionally + '--extension', + 'sts', + '--stdlib', + stdlib, + '--output', + outputPath ]) global.context = arkts.createContextFromString(global.config, source, filePath) - // ComponentTransformer - const parsedTransform = insertPlugin(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED) - const afterParsedSrc = parsedTransform.dumpSrc() + console.log("PLUGINS: ", pluginsByState.size, pluginsByState) - global.es2panda._DestroyContext(global.context) - const afterParsedScript = arkts.EtsScript.create( - afterParsedSrc, - arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED - ) + if (pluginsByState.size == 0 ) { + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) + return + } + + // ComponentTransformer + const parsedTransform = insertPlugin(pluginsByState, arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, dumpAst) + // TODO: Normally we need just to proceede to a given state, + // but the compiler crashes now, so we restart + restartCompilerUptoState(parsedTransform, arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) // BuilderLambdaTransformer - const checkedTransform = insertPlugin(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) - const afterCheckedSrc = checkedTransform.dumpSrc() + const checkedTransform = insertPlugin(pluginsByState, arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, dumpAst) + restartCompilerUptoState(checkedTransform, arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) - global.es2panda._DestroyContext(global.context) - const afterCheckedScript = arkts.EtsScript.create( - afterParsedSrc, - arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED - ) } function loadPlugin(configDir: string, jsonPlugin: any) { @@ -81,39 +114,50 @@ function loadPlugin(configDir: string, jsonPlugin: any) { return require(path.resolve(configDir, plugin)).default() } -function selectPlugins(configDir: string, plugins: any[], stage: string) { - return (ast: arkts.Node) => plugins +function selectPlugins(configDir: string, plugins: any[], stage: string): ((arg: arkts.Node) => arkts.Node)|undefined { + const selected = plugins .filter(it => (it.stage == stage)) .map(it => loadPlugin(configDir, it)) - .reduce( + if (selected.length == 0) { + return undefined + } else { + return (ast: arkts.Node) => selected.reduce( (it, transform) => transform(it), ast ) + } } -const pluginsByState = new Map void>() function stateName(value: arkts.Es2pandaContextState): string { return arkts.Es2pandaContextState[value].substring("ES2PANDA_STATE_".length) } -export function main() { - const { filePath, configPath } = parseCommandLineArgs() - const arktsconfig = JSON.parse(fs.readFileSync(configPath).toString()) - const configDir = path.dirname(configPath) - const compilerOptions = arktsconfig.compilerOptions ?? throwError(`arktsconfig should specify compilerOptions`) - const plugins = compilerOptions.plugins ?? throwError(`arktsconfig compilerOptions should specify plugins`) +function readAndSortPlugins(configDir: string, plugins: any[]) { + const pluginsByState = new Map void>() Object.values(arkts.Es2pandaContextState) .filter(it => typeof it == "number") // enum values are numbers and strings together - .forEach(it => - pluginsByState.set( + .forEach(it => { + const selected = selectPlugins(configDir, plugins, stateName(it as number).toLowerCase()) + if (selected) pluginsByState.set( it as number, - selectPlugins(configDir, plugins, stateName(it as number).toLowerCase() + selected ) - ) - ) + }) + + return pluginsByState +} + +export function main() { + const { filePath, configPath, outputPath, dumpAst } = parseCommandLineArgs() + const arktsconfig = JSON.parse(fs.readFileSync(configPath).toString()) + const configDir = path.dirname(configPath) + const compilerOptions = arktsconfig.compilerOptions ?? throwError(`arktsconfig should specify compilerOptions`) + const plugins = compilerOptions.plugins ?? [] + + const pluginsByState = readAndSortPlugins(configDir, plugins) - invokePlugins(configPath, filePath) + invokeWithPlugins(configPath, filePath, outputPath, pluginsByState, dumpAst) } main() diff --git a/arkoala-arkts/libarkts/src/utils.ts b/arkoala-arkts/libarkts/src/utils.ts index 7bb42d13fee0a28721b2aaa5f12d962d782f43cf..eef3d501f5327118d7c2702312de2db84b28e59d 100644 --- a/arkoala-arkts/libarkts/src/utils.ts +++ b/arkoala-arkts/libarkts/src/utils.ts @@ -16,3 +16,8 @@ export function throwError(error: string): never { throw new Error(error) } + +export function withWarning(value: T, message: string): T { + console.warn(message) + return value +} \ No newline at end of file diff --git a/arkoala-arkts/libarkts/test/test-util.ts b/arkoala-arkts/libarkts/test/test-util.ts index 10b12ed93353446190643988ae200d654cce814d..434713a001da17732c2d027d57dba9bd2ac03fa3 100644 --- a/arkoala-arkts/libarkts/test/test-util.ts +++ b/arkoala-arkts/libarkts/test/test-util.ts @@ -136,7 +136,7 @@ export function cleanGenerated(): void { export function fileToAbc(path: string, isModule?: boolean): void { const file = pth.basename(path).split('.')[0] - execSync(`../../incremental/tools/panda/node_modules/@panda/sdk/linux_host_tools/bin/es2panda ${path} --arktsconfig ./arktsconfig.json ${isModule ? '--ets-module' : ''}`) + execSync(`../../../incremental/tools/panda/node_modules/@panda/sdk/linux_host_tools/bin/es2panda ${path} --arktsconfig ./arktsconfig.json ${isModule ? '--ets-module' : ''}`) execSync('mkdir -p ./generated') execSync(`mv ./${file}.abc ./generated/${file}.abc`) } diff --git a/incremental/compat/package.json b/incremental/compat/package.json index 0ca606077be2272026b2e87e9084a13c292a8069..40737e3e00bb7026b76a78e9b9af5980d8770d9f 100644 --- a/incremental/compat/package.json +++ b/incremental/compat/package.json @@ -26,7 +26,9 @@ "compile:ohos": "memo-tsc -b ./tsconfig-ohos.json", "compile:all": "npm run compile && npm run compile:ohos", "build:compat": "npm run build:compat:inc", - "build:compat:inc": "fast-arktsc --input-files ./arktsconfig.json --output-dir ./build --compiler ../tools/panda/arkts/arktsc --link-name compat && ninja ${NINJA_OPTIONS} -f build/build.ninja" + "build:compat:inc": "fast-arktsc --input-files ./arktsconfig.json --output-dir ./build --compiler ../tools/panda/arkts/arktsc --link-name compat && ninja ${NINJA_OPTIONS} -f build/build.ninja", + "build:compat:inc:capi": "fast-arktsc --input-files ./arktsconfig.json --output-dir ./build --compiler ../tools/panda/arkts/arktsc-capi --file-option --link-name compat && ninja ${NINJA_OPTIONS} -f build/build.ninja" + }, "keywords": [], "dependencies": { diff --git a/incremental/package.json b/incremental/package.json index 2c712e0fce682f3456472c16304388d852129cec..f698a4de54b07e078849fb94cd06d4b91413c8e0 100644 --- a/incremental/package.json +++ b/incremental/package.json @@ -24,13 +24,13 @@ "compile": "npm run compile -w ./compat && npm run compile -w ./common && npm run compile -w ./runtime && npm run compile -w ./demo-playground && npm run compile -w ./compiler-plugin" }, "dependencies": { + "@koalaui/fast-arktsc": "next", + "@koalaui/memo-tsc": "4.9.5", "circular-dependency-plugin": "^5.2.2", "copy-webpack-plugin": "^12.0.2", "source-map-loader": "^5.0.0", "ts-loader": "^9.5.1", "webpack": "^5.93.0", - "webpack-cli": "^5.1.4", - "@koalaui/memo-tsc": "4.9.5", - "@koalaui/fast-arktsc": "next" + "webpack-cli": "^5.1.4" } } diff --git a/incremental/tools/panda/arkts/arktsc-capi b/incremental/tools/panda/arkts/arktsc-capi new file mode 100755 index 0000000000000000000000000000000000000000..bc801943f7498781731463d3282b325fe1f7ce16 --- /dev/null +++ b/incremental/tools/panda/arkts/arktsc-capi @@ -0,0 +1,18 @@ +#!/bin/bash + +# Copyright (c) 2022-2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SCRIPT_DIR=`dirname "${BASH_SOURCE[0]}"` +PANDA_SDK_PATH=$SCRIPT_DIR/../node_modules/@panda/sdk node $SCRIPT_DIR/../../../../arkoala-arkts/libarkts/build/src/es2panda.js "$@" --dump-plugin-ast +