From d57a0e0e4e36508cc06f9230a16c3008bf3ef9a9 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Tue, 4 Feb 2025 18:58:54 +0300 Subject: [PATCH 1/6] second plugin for sts Signed-off-by: Alexander Gorshenev --- arkoala-arkts/arkui/src/sts/arkui.sts | 94 ++++++++++++++----- .../plugins/src/builder-lambda-transformer.ts | 32 ++++--- arkoala-arkts/libarkts/src/arkts-api/types.ts | 2 + .../src/arkts-api/utilities/public.ts | 2 +- arkoala-arkts/libarkts/src/es2panda.ts | 4 +- arkoala-arkts/libarkts/src/utils.ts | 9 ++ arkoala-arkts/user/arktsconfig-pure-sts.json | 4 + arkoala-arkts/user/src/sts/hello.sts | 10 +- 8 files changed, 109 insertions(+), 48 deletions(-) diff --git a/arkoala-arkts/arkui/src/sts/arkui.sts b/arkoala-arkts/arkui/src/sts/arkui.sts index e076a0079..c2f4cb7ea 100644 --- a/arkoala-arkts/arkui/src/sts/arkui.sts +++ b/arkoala-arkts/arkui/src/sts/arkui.sts @@ -26,7 +26,7 @@ export class StructBase { } static instantiateImpl, OptionsS>( - builder: (instance: S)=>S, + builder: (instance: S)=>S, factory: () => S, options: OptionsS ) { @@ -37,54 +37,96 @@ export class StructBase { export enum Color { White, -Red + Red } -export interface ColumnOptions {} -export class ArkColumnComponent {} +export interface CommonAttributes { + onClick(callback: () => void) +} +export interface ColumnOptions { + space: number +} +export interface ColumnAttributes extends CommonAttributes {} // An attempt to put down a component export class Column { + @BuilderLambda("instantiateImpl") static $_instantiate( - factory: () => Column, - options?: ColumnOptions, - content?: () => void - ): ArkColumnComponent { - instance = factory() + factory: () => Column, + options: ColumnOptions, + content: () => void + ): ColumnAttributes { + const instance = factory() content() - return instance + return (null as unknown as TextAttributes) } + + static instantiateImpl( + style: (instance: ColumnAttributes) => void, + factory: () => Column, + options: ColumnOptions, + content: () => void + ): void { + const instance = factory() + content() + } + } + export interface ButtonOptions {} -export class ArkButtonComponent {} +export interface ButtonAttributes extends CommonAttributes {} // An attempt to put down a component export class Button { + @BuilderLambda("instantiateImpl") static $_instantiate( - factory: () => Button, - options?: ButtonOptions, - content?: () => void - ): ArkButtonComponent { - instance = factory() - content() - return instance + factory: () => Button, + options?: ButtonOptions|string, + //content?: () => void + ): ButtonAttributes { + const instance = factory() + //content() + return (null as unknown as TextAttributes) + } + + static instantiateImpl( + style: (instance: ButtonAttributes) => void, + factory: () => Button, + options?: ButtonOptions|string, + //content?: () => void + ): void { + const instance = factory() + //content() } } export interface TextOptions {} -export class ArkTextComponent {} +export interface TextAttributes extends CommonAttributes { + fontColor(color: Color) +} // An attempt to put down a component export class Text { static $_instantiate( - factory: () => Text, - options?: TextOptions, - content?: () => void - ): ArkTextComponent { - instance = factory() - content() - return instance + factory: () => Text, + options?: TextOptions|string, + //content?: () => void + ): TextAttributes { + const instance = factory() + // content() + return (null as unknown as TextAttributes) + } + + @BuilderLambda("instantiateImpl") + static instantiateImpl( + style: (instance: TextAttributes) => void, + factory: () => Text, + options?: TextOptions|string, + //content?: () => void + ): void { + const instance = factory() + // content() } } diff --git a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts index c2cc52f6b..b7f760ec3 100644 --- a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts +++ b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts @@ -61,7 +61,22 @@ function getLambdaArg(lambdaBody: arkts.AstNode): arkts.ArrowFunctionExpression ) } -function builderLambdaFunctionName(node: arkts.CallExpression): undefined | string { +function builderLambdaArgumentName(annotation: arkts.AnnotationUsageIr): string | undefined { + if (!arkts.isIdentifier(annotation.expr)) { + return undefined + } + if (annotation.expr.name !== "BuilderLambda") { + return undefined + } + if (!annotation.properties[0].value || + !arkts.isStringLiteral(annotation.properties[0].value) + ) { + return undefined + } + return annotation.properties[0].value.str +} + +function builderLambdaFunctionName(node: arkts.CallExpression): string | undefined { let decl: arkts.AstNode|undefined = undefined if (arkts.isIdentifier(node.expression)) { decl = arkts.getDecl(node.expression) @@ -77,6 +92,7 @@ function builderLambdaFunctionName(node: arkts.CallExpression): undefined | stri if (decl === undefined) { return undefined } + // TODO: why? We need to support functions. if (!arkts.isMethodDefinition(decl)) { return undefined } @@ -87,19 +103,7 @@ function builderLambdaFunctionName(node: arkts.CallExpression): undefined | stri } // TODO: check all annotations const annotation = declAnnotations[0] - if (!arkts.isIdentifier(annotation.expr)) { - return undefined - } - if (annotation.expr.name !== "BuilderLambda") { - return undefined - } - if (!annotation.properties[0].value || - !arkts.isStringLiteral(annotation.properties[0].value) - ) { - return undefined - } - - return annotation.properties[0].value.str + return builderLambdaArgumentName(annotation) } function builderLambdaReplace(leaf: arkts.CallExpression): arkts.Identifier|arkts.MemberExpression|undefined { diff --git a/arkoala-arkts/libarkts/src/arkts-api/types.ts b/arkoala-arkts/libarkts/src/arkts-api/types.ts index a9bf80f46..da7f25b20 100644 --- a/arkoala-arkts/libarkts/src/arkts-api/types.ts +++ b/arkoala-arkts/libarkts/src/arkts-api/types.ts @@ -151,6 +151,7 @@ export class CallExpression extends AstNode { super(peer) this.expression = unpackNonNullableNode(global.generatedEs2panda._CallExpressionCallee(global.context, this.peer)) this.arguments = unpackNodeArray(global.generatedEs2panda._CallExpressionArguments(global.context, this.peer)) + this.signature = unpackNonNullableNode(global.generatedEs2panda._CallExpressionSignature(global.context, this.peer)) } static create( @@ -172,6 +173,7 @@ export class CallExpression extends AstNode { } readonly expression: AstNode // Expression + readonly signature: AstNode // Expression readonly arguments: readonly AstNode[] } diff --git a/arkoala-arkts/libarkts/src/arkts-api/utilities/public.ts b/arkoala-arkts/libarkts/src/arkts-api/utilities/public.ts index 2d8ba52e9..ec5c19bfa 100644 --- a/arkoala-arkts/libarkts/src/arkts-api/utilities/public.ts +++ b/arkoala-arkts/libarkts/src/arkts-api/utilities/public.ts @@ -55,7 +55,7 @@ export function rebindSubtree(node: AstNode): void { export function getDecl(node: AstNode): AstNode | undefined { let decl: KNativePointer = node.peer - + decl = global.es2panda._AstNodeVariableConst(global.context, decl) if (decl === nullptr) { return undefined diff --git a/arkoala-arkts/libarkts/src/es2panda.ts b/arkoala-arkts/libarkts/src/es2panda.ts index 23d5a91f3..10c09d75b 100644 --- a/arkoala-arkts/libarkts/src/es2panda.ts +++ b/arkoala-arkts/libarkts/src/es2panda.ts @@ -17,7 +17,7 @@ import * as fs from "node:fs" import * as path from "node:path" import { global } from "./arkts-api/static/global" import { Command } from "commander" -import { isNumber, throwError, withWarning } from "./utils" +import { isNumber, throwError, withWarning, filterSource } from "./utils" import { Es2pandaContextState } from "./generated/Es2pandaEnums" import { AstNode, Config, Context, EtsScript, proceedToState } from "./arkts-api" @@ -72,7 +72,7 @@ function insertPlugin(pluginsByState: Map(value: T, message: string): T { export function isNumber(value: any): value is number { return typeof value === `number` } + +// TODO: the lowerings insert %% and other special symbols +// into names of temporary variables. +// Until we keep feeding ast dumps back to the parser +// this function is needed. +export function filterSource(text: string): string { + return text.replaceAll(/%/g, "_") +} + diff --git a/arkoala-arkts/user/arktsconfig-pure-sts.json b/arkoala-arkts/user/arktsconfig-pure-sts.json index 18c1a88e0..0c239888d 100644 --- a/arkoala-arkts/user/arktsconfig-pure-sts.json +++ b/arkoala-arkts/user/arktsconfig-pure-sts.json @@ -18,6 +18,10 @@ { "transform": "@koalaui/libarkts/plugins/parsed-stage-plugin", "stage": "parsed" + }, + { + "transform": "../libarkts/examples/build/src/example-checked-transformer.js", + "stage": "checked" } ] }, diff --git a/arkoala-arkts/user/src/sts/hello.sts b/arkoala-arkts/user/src/sts/hello.sts index 009e71808..51914f16b 100644 --- a/arkoala-arkts/user/src/sts/hello.sts +++ b/arkoala-arkts/user/src/sts/hello.sts @@ -4,21 +4,21 @@ import { Button } from "@ohos.arkui.Button" import { Component, State, Entry } from "@ohos.arkui" import { Color } from "@ohos.arkui.Color" + @Entry @Component struct MyStateSample { @State color: Color = Color.White build() { - Column({} as ColumnOptions) { -/* - Text("") {} + Column({space: 20} as ColumnOptions, () => { + Text("Hello World!") .fontColor(this.color) Button('change') .onClick(() => { this.color = Color.Red }) -*/ - } + + }) } } -- Gitee From 85e0a9ef0302a2d64f71123d16c6b61f836d23b5 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Wed, 5 Feb 2025 16:47:29 +0300 Subject: [PATCH 2/6] tmo Signed-off-by: Alexander Gorshenev --- arkoala-arkts/arkui/src/sts/arkui.sts | 4 +- .../plugins/src/builder-lambda-transformer.ts | 105 ++++++++++++++---- arkoala-arkts/libarkts/src/arkts-api/types.ts | 2 - 3 files changed, 85 insertions(+), 26 deletions(-) diff --git a/arkoala-arkts/arkui/src/sts/arkui.sts b/arkoala-arkts/arkui/src/sts/arkui.sts index c2f4cb7ea..38b37da69 100644 --- a/arkoala-arkts/arkui/src/sts/arkui.sts +++ b/arkoala-arkts/arkui/src/sts/arkui.sts @@ -79,6 +79,7 @@ export interface ButtonAttributes extends CommonAttributes {} // An attempt to put down a component export class Button { + // TODO: the second argument will be gone after hte plugin is improved @BuilderLambda("instantiateImpl") static $_instantiate( factory: () => Button, @@ -108,6 +109,7 @@ export interface TextAttributes extends CommonAttributes { // An attempt to put down a component export class Text { + @BuilderLambda("instantiateImpl") static $_instantiate( factory: () => Text, options?: TextOptions|string, @@ -118,7 +120,7 @@ export class Text { return (null as unknown as TextAttributes) } - @BuilderLambda("instantiateImpl") + // TODO: the second argument will be gone after hte plugin is improved static instantiateImpl( style: (instance: TextAttributes) => void, factory: () => Text, diff --git a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts index b7f760ec3..d6ef36db5 100644 --- a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts +++ b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts @@ -18,7 +18,7 @@ import { AbstractVisitor } from "./AbstractVisitor"; const builderLambdaInstanceName = "instance" -function getLambdaArg(lambdaBody: arkts.AstNode): arkts.ArrowFunctionExpression { +function getLambdaArg(lambdaBody: arkts.AstNode, typeName: string|undefined): arkts.ArrowFunctionExpression { const body = arkts.factory.createBlock( [ arkts.factory.createReturnStatement( @@ -31,11 +31,11 @@ function getLambdaArg(lambdaBody: arkts.AstNode): arkts.ArrowFunctionExpression arkts.factory.createIdentifier( builderLambdaInstanceName, // TODO: it should be the return type of the function annotated with the @BuilderLambda - arkts.factory.createTypeReference( - arkts.factory.createIdentifier( - 'MyComponent' - ) - ) + typeName ? arkts.factory.createTypeReference( + arkts.factory.createIdentifier( + typeName + ) + ) : undefined, ), undefined ) @@ -61,13 +61,17 @@ function getLambdaArg(lambdaBody: arkts.AstNode): arkts.ArrowFunctionExpression ) } -function builderLambdaArgumentName(annotation: arkts.AnnotationUsageIr): string | undefined { +function isBuilderLambdaAnnotation(annotation: arkts.AnnotationUsageIr): boolean { if (!arkts.isIdentifier(annotation.expr)) { - return undefined - } - if (annotation.expr.name !== "BuilderLambda") { - return undefined + return false } + console.log("YES, isBuilderLambdaAnnotation ") + return annotation.expr.name !== "BuilderLambda" +} + +function builderLambdaArgumentName(annotation: arkts.AnnotationUsageIr): string | undefined { + if (!isBuilderLambdaAnnotation(annotation)) return undefined + if (!annotation.properties[0].value || !arkts.isStringLiteral(annotation.properties[0].value) ) { @@ -75,17 +79,27 @@ function builderLambdaArgumentName(annotation: arkts.AnnotationUsageIr): string } return annotation.properties[0].value.str } +/* +function builderLambdaTypeName(annotation: arkts.AnnotationUsageIr): string | undefined { + if (!isBuilderLambdaAnnotation(annotation)) return undefined -function builderLambdaFunctionName(node: arkts.CallExpression): string | undefined { + if (!annotation.properties[1].value || + !arkts.isStringLiteral(annotation.properties[1].value) + ) { + return undefined + } + return annotation.properties[1].value.str +} +*/ +function findBuilderLambdaAnnotation(node: arkts.CallExpression): arkts.AnnotationUsageIr|undefined { + console.log("findBuilderLambdaAnnotation") let decl: arkts.AstNode|undefined = undefined if (arkts.isIdentifier(node.expression)) { decl = arkts.getDecl(node.expression) } else if (arkts.isMemberExpression(node.expression)) { // TODO: getDecl doesn't work for members. // decl = arkts.getDecl(node.expression) - if (arkts.isIdentifier(node.expression.property) && node.expression.property.name == "$_instantiate") { - return `instantiateImpl` - } + return undefined } else { return undefined } @@ -101,17 +115,61 @@ function builderLambdaFunctionName(node: arkts.CallExpression): string | undefin if (declAnnotations.length === 0) { return undefined } - // TODO: check all annotations - const annotation = declAnnotations[0] + + console.log("filtering") + return declAnnotations.find(it => isBuilderLambdaAnnotation(it)) +} + + +function builderLambdaFunctionName(node: arkts.CallExpression): string | undefined { + console.log("builderLambdaFunctionName") + + // TODO: remove this special handling when getDecl is capable. + if (arkts.isMemberExpression(node.expression)) { + if (arkts.isIdentifier(node.expression.property) && node.expression.property.name == "$_instantiate") { + return `instantiateImpl` + } + } + + const annotation = findBuilderLambdaAnnotation(node) + if (!annotation) return undefined return builderLambdaArgumentName(annotation) } +function builderLambdaTypeName(node: arkts.CallExpression): string | undefined { + console.log("builderLambdaTypeName") + // TODO: remove this special handling when getDecl is capable. + // this is the only way to know the type + if (arkts.isMemberExpression(node.expression)) { + console.log("A", node.expression.dumpSrc()) + console.log("A0", node.expression) + console.log("A1", node.expression.object.dumpSrc()) + console.log("A2", node.expression.object) + if (arkts.isIdentifier(node.expression.object)) { + console.log("B") + return node.expression.object.name + } + } + + const annotation = findBuilderLambdaAnnotation(node) + if (!annotation) return undefined + if (arkts.isIdentifier(node.expression)) { + return builderLambdaArgumentName(annotation) + } + + return undefined +} + + +function callIsGoodForBuilderLambda(leaf: arkts.CallExpression): boolean { + const node = leaf.expression + return arkts.isIdentifier(node) || arkts.isMemberExpression(node) +} + function builderLambdaReplace(leaf: arkts.CallExpression): arkts.Identifier|arkts.MemberExpression|undefined { + if (!callIsGoodForBuilderLambda(leaf)) return undefined const node = leaf.expression - if (!arkts.isIdentifier(node) && - !arkts.isMemberExpression(node)) { - return undefined - } + const funcName = builderLambdaFunctionName(leaf) if (funcName === undefined) { return undefined @@ -136,7 +194,6 @@ function builderLambdaReplace(leaf: arkts.CallExpression): arkts.Identifier|arkt return undefined } - export class BuilderLambdaTransformer extends AbstractVisitor { visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) @@ -195,7 +252,9 @@ export class BuilderLambdaTransformer extends AbstractVisitor { ) }) - const lambdaArg = getLambdaArg(lambdaBody) + const typeName = builderLambdaTypeName(leaf) + console.log("typeNmae:", typeName) + const lambdaArg = getLambdaArg(lambdaBody, typeName) return arkts.factory.updateCallExpression( node, diff --git a/arkoala-arkts/libarkts/src/arkts-api/types.ts b/arkoala-arkts/libarkts/src/arkts-api/types.ts index da7f25b20..a9bf80f46 100644 --- a/arkoala-arkts/libarkts/src/arkts-api/types.ts +++ b/arkoala-arkts/libarkts/src/arkts-api/types.ts @@ -151,7 +151,6 @@ export class CallExpression extends AstNode { super(peer) this.expression = unpackNonNullableNode(global.generatedEs2panda._CallExpressionCallee(global.context, this.peer)) this.arguments = unpackNodeArray(global.generatedEs2panda._CallExpressionArguments(global.context, this.peer)) - this.signature = unpackNonNullableNode(global.generatedEs2panda._CallExpressionSignature(global.context, this.peer)) } static create( @@ -173,7 +172,6 @@ export class CallExpression extends AstNode { } readonly expression: AstNode // Expression - readonly signature: AstNode // Expression readonly arguments: readonly AstNode[] } -- Gitee From 95ff552e115db3e368ba003333255aa07b5cc736 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Wed, 5 Feb 2025 19:10:16 +0300 Subject: [PATCH 3/6] more Signed-off-by: Alexander Gorshenev --- arkoala-arkts/arkui/arktsconfig-pure-sts.json | 31 +++++++++++++++ arkoala-arkts/arkui/package.json | 3 +- arkoala-arkts/arkui/src/sts/arkui.sts | 39 +++++++++++-------- .../plugins/src/builder-lambda-transformer.ts | 7 +++- arkoala-arkts/user/arktsconfig-pure-sts.json | 2 +- arkoala-arkts/user/src/sts/hello.sts | 12 +++--- 6 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 arkoala-arkts/arkui/arktsconfig-pure-sts.json diff --git a/arkoala-arkts/arkui/arktsconfig-pure-sts.json b/arkoala-arkts/arkui/arktsconfig-pure-sts.json new file mode 100644 index 000000000..a7d4239b7 --- /dev/null +++ b/arkoala-arkts/arkui/arktsconfig-pure-sts.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "package": "@ohos.example", + "outDir": "build/sts/abc", + "baseUrl": ".", + "paths": { + "@ohos.arkui": ["../arkui/src/sts/arkui.sts"], + "@ohos.arkui.Button": ["../arkui/src/sts/arkui.sts"], + "@ohos.arkui.Column": ["../arkui/src/sts/arkui.sts"], + "@ohos.arkui.Color": ["../arkui/src/sts/arkui.sts"], + "@ohos.arkui.Text": ["../arkui/src/sts/arkui.sts"] + }, + "plugins": [ + { + "transform": "@koalaui/libarkts/plugins/printer-plugin", + "stage": "parsed" + }, + { + "transform": "@koalaui/libarkts/plugins/parsed-stage-plugin", + "stage": "parsed" + }, + { + "transform": "@koalaui/libarkts/plugins/checked-stage-plugin", + "stage": "checked" + } + ] + }, + "include": [ + "./src/ets/hello.sts" + ] +} diff --git a/arkoala-arkts/arkui/package.json b/arkoala-arkts/arkui/package.json index 60d32802b..1207eab98 100644 --- a/arkoala-arkts/arkui/package.json +++ b/arkoala-arkts/arkui/package.json @@ -9,6 +9,7 @@ "clean:arkui-no-common": "npm run clean", "build:arkui-no-common:inc": "npm run unmemoize && fast-arktsc --input-files ./arktsconfig-unmemoized.json --output-dir ./build --compiler ../../incremental/tools/panda/arkts/arktsc --link-name arkui-no-common && ninja ${NINJA_OPTIONS} -f build/build.ninja", "build:arkui-no-common": "npm run unmemoize && fast-arktsc --input-files ./arktsconfig-unmemoized.json --output-dir ./build --compiler ../../incremental/tools/panda/arkts/arktsc --link-name arkui-no-common && ninja ${NINJA_OPTIONS} -f build/build.ninja", - "unmemoize": "ets-tsc -b ./tsconfig-unmemoize.json && cp -r ./src/generated/arkts ./build/unmemoized/src/generated" + "unmemoize": "ets-tsc -b ./tsconfig-unmemoize.json && cp -r ./src/generated/arkts ./build/unmemoized/src/generated", + "build:arkui:pure-sts": "../../incremental/tools/panda/arkts/arktsc-capi --file src/sts/arkui.sts --arktsconfig arktsconfig-pure-sts.json --output build/sts/abc/arkui.abc --dump-plugin-ast" } } diff --git a/arkoala-arkts/arkui/src/sts/arkui.sts b/arkoala-arkts/arkui/src/sts/arkui.sts index 38b37da69..89bbf3acb 100644 --- a/arkoala-arkts/arkui/src/sts/arkui.sts +++ b/arkoala-arkts/arkui/src/sts/arkui.sts @@ -48,29 +48,34 @@ export interface ColumnOptions { } export interface ColumnAttributes extends CommonAttributes {} +export class ComponentBase implements CommonAttributes { + onClick(callback: () => void) { + console.log("registered Button.onClick()") + return this + } +} + // An attempt to put down a component -export class Column { +export class Column extends ComponentBase implements ColumnAttributes { @BuilderLambda("instantiateImpl") static $_instantiate( factory: () => Column, options: ColumnOptions, content: () => void - ): ColumnAttributes { - const instance = factory() - content() - return (null as unknown as TextAttributes) + ): Column { + throw("This method should only be called through a @BuilderLambda redirect") } static instantiateImpl( - style: (instance: ColumnAttributes) => void, + style: (instance: Column) => Column, factory: () => Column, options: ColumnOptions, content: () => void ): void { + console.log("Column(", options, ")") const instance = factory() content() } - } @@ -78,7 +83,7 @@ export interface ButtonOptions {} export interface ButtonAttributes extends CommonAttributes {} // An attempt to put down a component -export class Button { +export class Button extends ComponentBase implements ButtonAttributes { // TODO: the second argument will be gone after hte plugin is improved @BuilderLambda("instantiateImpl") static $_instantiate( @@ -86,9 +91,7 @@ export class Button { options?: ButtonOptions|string, //content?: () => void ): ButtonAttributes { - const instance = factory() - //content() - return (null as unknown as TextAttributes) + throw("This method should only be called through a @BuilderLambda redirect") } static instantiateImpl( @@ -97,6 +100,7 @@ export class Button { options?: ButtonOptions|string, //content?: () => void ): void { + console.log("Button(", options, ")") const instance = factory() //content() } @@ -104,20 +108,18 @@ export class Button { export interface TextOptions {} export interface TextAttributes extends CommonAttributes { - fontColor(color: Color) + fontColor(color: Color): TextAttributes } // An attempt to put down a component -export class Text { +export class Text extends ComponentBase implements TextAttributes { @BuilderLambda("instantiateImpl") static $_instantiate( factory: () => Text, options?: TextOptions|string, //content?: () => void ): TextAttributes { - const instance = factory() - // content() - return (null as unknown as TextAttributes) + throw("This method should only be called through a @BuilderLambda redirect") } // TODO: the second argument will be gone after hte plugin is improved @@ -130,5 +132,10 @@ export class Text { const instance = factory() // content() } + + fontColor(value: Color): this { + console.log(value) + return this + } } diff --git a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts index d6ef36db5..70777e18e 100644 --- a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts +++ b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts @@ -44,7 +44,12 @@ function getLambdaArg(lambdaBody: arkts.AstNode, typeName: string|undefined): ar [ param ], - undefined + // TODO: it should be the return type of the function annotated with the @BuilderLambda + typeName ? arkts.factory.createTypeReference( + arkts.factory.createIdentifier( + typeName + ) + ) : undefined ) const func = arkts.factory.createScriptFunction( diff --git a/arkoala-arkts/user/arktsconfig-pure-sts.json b/arkoala-arkts/user/arktsconfig-pure-sts.json index 0c239888d..a7d4239b7 100644 --- a/arkoala-arkts/user/arktsconfig-pure-sts.json +++ b/arkoala-arkts/user/arktsconfig-pure-sts.json @@ -20,7 +20,7 @@ "stage": "parsed" }, { - "transform": "../libarkts/examples/build/src/example-checked-transformer.js", + "transform": "@koalaui/libarkts/plugins/checked-stage-plugin", "stage": "checked" } ] diff --git a/arkoala-arkts/user/src/sts/hello.sts b/arkoala-arkts/user/src/sts/hello.sts index 51914f16b..8003dcc1d 100644 --- a/arkoala-arkts/user/src/sts/hello.sts +++ b/arkoala-arkts/user/src/sts/hello.sts @@ -11,12 +11,12 @@ struct MyStateSample { @State color: Color = Color.White build() { Column({space: 20} as ColumnOptions, () => { - Text("Hello World!") - .fontColor(this.color) - Button('change') - .onClick(() => { - this.color = Color.Red - }) + Text("Hello World!") + .fontColor(this.color) + Button('change') + .onClick(() => { + this.color = Color.Red + }) }) } -- Gitee From 26ec57dd77ad30a3cdb92d76ca088109fa0123d2 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Wed, 5 Feb 2025 16:49:54 -0500 Subject: [PATCH 4/6] Made it runnable --- arkoala-arkts/arkui/arktsconfig-pure-sts.json | 29 ++------------ arkoala-arkts/arkui/package.json | 2 +- arkoala-arkts/arkui/src/sts/arkui.sts | 38 +++++++++++------- arkoala-arkts/arkui/src/sts/index.sts | 2 + arkoala-arkts/libarkts/src/es2panda.ts | 5 ++- arkoala-arkts/libarkts/src/utils.ts | 5 ++- arkoala-arkts/user/arktsconfig-pure-sts.json | 6 +-- arkoala-arkts/user/package.json | 3 +- arkoala-arkts/user/src/sts/hello.sts | 39 ++++++++++++------- 9 files changed, 66 insertions(+), 63 deletions(-) create mode 100644 arkoala-arkts/arkui/src/sts/index.sts diff --git a/arkoala-arkts/arkui/arktsconfig-pure-sts.json b/arkoala-arkts/arkui/arktsconfig-pure-sts.json index a7d4239b7..52c609f78 100644 --- a/arkoala-arkts/arkui/arktsconfig-pure-sts.json +++ b/arkoala-arkts/arkui/arktsconfig-pure-sts.json @@ -1,31 +1,10 @@ { "compilerOptions": { - "package": "@ohos.example", + "package": "@ohos.arkui", "outDir": "build/sts/abc", - "baseUrl": ".", - "paths": { - "@ohos.arkui": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Button": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Column": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Color": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Text": ["../arkui/src/sts/arkui.sts"] - }, - "plugins": [ - { - "transform": "@koalaui/libarkts/plugins/printer-plugin", - "stage": "parsed" - }, - { - "transform": "@koalaui/libarkts/plugins/parsed-stage-plugin", - "stage": "parsed" - }, - { - "transform": "@koalaui/libarkts/plugins/checked-stage-plugin", - "stage": "checked" - } - ] + "baseUrl": "./src/sts" }, - "include": [ - "./src/ets/hello.sts" + "files": [ + "./src/sts/arkui.sts" ] } diff --git a/arkoala-arkts/arkui/package.json b/arkoala-arkts/arkui/package.json index 1207eab98..2654aa0db 100644 --- a/arkoala-arkts/arkui/package.json +++ b/arkoala-arkts/arkui/package.json @@ -10,6 +10,6 @@ "build:arkui-no-common:inc": "npm run unmemoize && fast-arktsc --input-files ./arktsconfig-unmemoized.json --output-dir ./build --compiler ../../incremental/tools/panda/arkts/arktsc --link-name arkui-no-common && ninja ${NINJA_OPTIONS} -f build/build.ninja", "build:arkui-no-common": "npm run unmemoize && fast-arktsc --input-files ./arktsconfig-unmemoized.json --output-dir ./build --compiler ../../incremental/tools/panda/arkts/arktsc --link-name arkui-no-common && ninja ${NINJA_OPTIONS} -f build/build.ninja", "unmemoize": "ets-tsc -b ./tsconfig-unmemoize.json && cp -r ./src/generated/arkts ./build/unmemoized/src/generated", - "build:arkui:pure-sts": "../../incremental/tools/panda/arkts/arktsc-capi --file src/sts/arkui.sts --arktsconfig arktsconfig-pure-sts.json --output build/sts/abc/arkui.abc --dump-plugin-ast" + "build:arkui:pure-sts": "../../incremental/tools/panda/arkts/arktsc --arktsconfig arktsconfig-pure-sts.json" } } diff --git a/arkoala-arkts/arkui/src/sts/arkui.sts b/arkoala-arkts/arkui/src/sts/arkui.sts index 89bbf3acb..e71ca8e4c 100644 --- a/arkoala-arkts/arkui/src/sts/arkui.sts +++ b/arkoala-arkts/arkui/src/sts/arkui.sts @@ -15,24 +15,28 @@ export interface CommonMethod { width(value: number) } -export class StructBase { +export abstract class StructBase { @BuilderLambda("instantiateImpl") static $_instantiate, OptionsS> ( factory: () => S, - options: OptionsS + options?: OptionsS, + content?: () => void ): S { - const instance = factory() - return instance + throw new Error("This method should only be called through a @BuilderLambda redirect") } static instantiateImpl, OptionsS>( - builder: (instance: S)=>S, + builder: ((instance: S)=>S)|undefined, factory: () => S, - options: OptionsS + options?: OptionsS, + content?: () => void ) { + console.log("Struct instantiate redirected") const instance = factory() - builder(instance) + if (builder !== undefined) builder(instance) + instance.build() } + abstract build() } export enum Color { @@ -41,7 +45,7 @@ export enum Color { } export interface CommonAttributes { - onClick(callback: () => void) + onClick(callback: () => void): CommonAttributes } export interface ColumnOptions { space: number @@ -49,7 +53,7 @@ export interface ColumnOptions { export interface ColumnAttributes extends CommonAttributes {} export class ComponentBase implements CommonAttributes { - onClick(callback: () => void) { + onClick(callback: () => void): CommonAttributes { console.log("registered Button.onClick()") return this } @@ -63,7 +67,7 @@ export class Column extends ComponentBase implements ColumnAttributes { options: ColumnOptions, content: () => void ): Column { - throw("This method should only be called through a @BuilderLambda redirect") + throw new Error("This method should only be called through a @BuilderLambda redirect") } static instantiateImpl( @@ -72,8 +76,9 @@ export class Column extends ComponentBase implements ColumnAttributes { options: ColumnOptions, content: () => void ): void { - console.log("Column(", options, ")") + console.log("Column({space:", options.space, "})") const instance = factory() + style(instance) content() } } @@ -91,7 +96,7 @@ export class Button extends ComponentBase implements ButtonAttributes { options?: ButtonOptions|string, //content?: () => void ): ButtonAttributes { - throw("This method should only be called through a @BuilderLambda redirect") + throw new Error("This method should only be called through a @BuilderLambda redirect") } static instantiateImpl( @@ -102,7 +107,9 @@ export class Button extends ComponentBase implements ButtonAttributes { ): void { console.log("Button(", options, ")") const instance = factory() + style(instance) //content() + } } @@ -119,7 +126,7 @@ export class Text extends ComponentBase implements TextAttributes { options?: TextOptions|string, //content?: () => void ): TextAttributes { - throw("This method should only be called through a @BuilderLambda redirect") + throw new Error("This method should only be called through a @BuilderLambda redirect") } // TODO: the second argument will be gone after hte plugin is improved @@ -129,8 +136,10 @@ export class Text extends ComponentBase implements TextAttributes { options?: TextOptions|string, //content?: () => void ): void { + console.log("Text(", options, ")") const instance = factory() - // content() + style(instance) + //content() } fontColor(value: Color): this { @@ -138,4 +147,3 @@ export class Text extends ComponentBase implements TextAttributes { return this } } - diff --git a/arkoala-arkts/arkui/src/sts/index.sts b/arkoala-arkts/arkui/src/sts/index.sts new file mode 100644 index 000000000..0cef4eb4d --- /dev/null +++ b/arkoala-arkts/arkui/src/sts/index.sts @@ -0,0 +1,2 @@ +export * from "./arkui" + diff --git a/arkoala-arkts/libarkts/src/es2panda.ts b/arkoala-arkts/libarkts/src/es2panda.ts index 10c09d75b..6dd1435ca 100644 --- a/arkoala-arkts/libarkts/src/es2panda.ts +++ b/arkoala-arkts/libarkts/src/es2panda.ts @@ -57,7 +57,7 @@ function insertPlugin(pluginsByState: Map", "_cctor_") } diff --git a/arkoala-arkts/user/arktsconfig-pure-sts.json b/arkoala-arkts/user/arktsconfig-pure-sts.json index a7d4239b7..c6c229b25 100644 --- a/arkoala-arkts/user/arktsconfig-pure-sts.json +++ b/arkoala-arkts/user/arktsconfig-pure-sts.json @@ -4,11 +4,7 @@ "outDir": "build/sts/abc", "baseUrl": ".", "paths": { - "@ohos.arkui": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Button": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Column": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Color": ["../arkui/src/sts/arkui.sts"], - "@ohos.arkui.Text": ["../arkui/src/sts/arkui.sts"] + "@ohos.arkui": ["../arkui/src/sts"] }, "plugins": [ { diff --git a/arkoala-arkts/user/package.json b/arkoala-arkts/user/package.json index e11160f60..77272971b 100644 --- a/arkoala-arkts/user/package.json +++ b/arkoala-arkts/user/package.json @@ -13,7 +13,8 @@ "unmemoize:all": "npm run unmemoize:runtime && npm run unmemoize:arkui-no-common && npm run unmemoize:arkui-common && npm run unmemoize", "build:user": "npm run unmemoize:all && npm run build:user:inc", "build:user:inc": "fast-arktsc --input-files ./arktsconfig-run-unmemoized.json --output-dir ./build --compiler ../../incremental/tools/panda/arkts/arktsc --link-name user && ninja ${NINJA_OPTIONS} -f build/build.ninja", - "build:user:pure-sts": "../../incremental/tools/panda/arkts/arktsc-capi --file src/sts/hello.sts --arktsconfig arktsconfig-pure-sts.json --output build/sts/abc/hello.abc --dump-plugin-ast", + "build:user:pure-sts": "npm run build:arkui:pure-sts --prefix ../arkui && ../../incremental/tools/panda/arkts/arktsc-capi --file src/sts/hello.sts --arktsconfig arktsconfig-pure-sts.json --output build/sts/abc/hello.abc --dump-plugin-ast", + "run:user:pure-sts": "npm run build:user:pure-sts && ../../incremental/tools/panda/arkts/ark build/sts/abc/hello.abc --ark-boot-files ../arkui/build/sts/abc/src/sts/arkui.abc:build/sts/abc/hello.abc --ark-entry-point @ohos.example.src.sts.hello.ArkUIEntry::run", "pack": "npm run cli-tools:check && cd app && DEVECO_SDK_HOME=../../../arkoala/ohos-sdk/ohos-sdk ../command-line-tools/hvigor/bin/hvigorw --no-daemon --mode module -p product=default -p module=user@default assembleHar", "har-arm32": "npm run build:user && npm run --prefix ../../arkoala/ohos-sdk download && node scripts/build-har.mjs --name user --arch arm32 && npm run pack", "har-arm64": "npm run build:user && npm run --prefix ../../arkoala/ohos-sdk download && node scripts/build-har.mjs --name user --arch arm64 && npm run pack", diff --git a/arkoala-arkts/user/src/sts/hello.sts b/arkoala-arkts/user/src/sts/hello.sts index 8003dcc1d..66627778e 100644 --- a/arkoala-arkts/user/src/sts/hello.sts +++ b/arkoala-arkts/user/src/sts/hello.sts @@ -1,25 +1,38 @@ -import { Text } from "@ohos.arkui.Text" -import { Column, ColumnOptions } from "@ohos.arkui.Column" -import { Button } from "@ohos.arkui.Button" +import { Text } from "@ohos.arkui" +import { Column, ColumnOptions } from "@ohos.arkui" +import { Button } from "@ohos.arkui" import { Component, State, Entry } from "@ohos.arkui" -import { Color } from "@ohos.arkui.Color" - +import { Color } from "@ohos.arkui" @Entry @Component struct MyStateSample { @State color: Color = Color.White build() { - Column({space: 20} as ColumnOptions, () => { - Text("Hello World!") - .fontColor(this.color) - Button('change') - .onClick(() => { - this.color = Color.Red - }) + Column({ space: 20 } as ColumnOptions, () => { + Text("Hello World!") + .fontColor(this.color) + Button('change') + .onClick(() => { + this.color = Color.Red + }) }) } } - +export class ArkUIEntry { + static mandatory: boolean = ArkUIEntry.run() + static run(): boolean { + console.log("About to invoke the struct") + // The proper call fails because of a compiler frontend bug. + // MyStateSample({} as __Options_MyStateSample) + MyStateSample.instantiateImpl( + undefined, + (): MyStateSample => new MyStateSample(), + {} as __Options_MyStateSample, + undefined + ) + return true + } +} -- Gitee From ec08df9c61b45cf69377ac51c12166b3ab7f3038 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Wed, 5 Feb 2025 17:56:08 -0500 Subject: [PATCH 5/6] Added .with(100) to the column --- arkoala-arkts/arkui/src/sts/arkui.sts | 37 ++++++++++----------------- arkoala-arkts/user/src/sts/hello.sts | 2 +- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/arkoala-arkts/arkui/src/sts/arkui.sts b/arkoala-arkts/arkui/src/sts/arkui.sts index e71ca8e4c..06e96582c 100644 --- a/arkoala-arkts/arkui/src/sts/arkui.sts +++ b/arkoala-arkts/arkui/src/sts/arkui.sts @@ -10,11 +10,6 @@ export @interface State {} export @interface memo {} -// Imitation of CommonMethod -export interface CommonMethod { - width(value: number) -} - export abstract class StructBase { @BuilderLambda("instantiateImpl") static $_instantiate, OptionsS> ( @@ -44,23 +39,23 @@ export enum Color { Red } -export interface CommonAttributes { - onClick(callback: () => void): CommonAttributes -} export interface ColumnOptions { space: number } -export interface ColumnAttributes extends CommonAttributes {} -export class ComponentBase implements CommonAttributes { - onClick(callback: () => void): CommonAttributes { +export class CommonMethod { + onClick(callback: () => void): this { console.log("registered Button.onClick()") return this - } + } + width(value: number): this { + console.log(`.width(${value})`) + return this + } } // An attempt to put down a component -export class Column extends ComponentBase implements ColumnAttributes { +export class Column extends CommonMethod { @BuilderLambda("instantiateImpl") static $_instantiate( factory: () => Column, @@ -85,22 +80,21 @@ export class Column extends ComponentBase implements ColumnAttributes { export interface ButtonOptions {} -export interface ButtonAttributes extends CommonAttributes {} // An attempt to put down a component -export class Button extends ComponentBase implements ButtonAttributes { +export class Button extends CommonMethod { // TODO: the second argument will be gone after hte plugin is improved @BuilderLambda("instantiateImpl") static $_instantiate( factory: () => Button, options?: ButtonOptions|string, //content?: () => void - ): ButtonAttributes { + ): Button { throw new Error("This method should only be called through a @BuilderLambda redirect") } static instantiateImpl( - style: (instance: ButtonAttributes) => void, + style: (instance: Button) => Button, factory: () => Button, options?: ButtonOptions|string, //content?: () => void @@ -114,24 +108,21 @@ export class Button extends ComponentBase implements ButtonAttributes { } export interface TextOptions {} -export interface TextAttributes extends CommonAttributes { - fontColor(color: Color): TextAttributes -} // An attempt to put down a component -export class Text extends ComponentBase implements TextAttributes { +export class Text extends CommonMethod { @BuilderLambda("instantiateImpl") static $_instantiate( factory: () => Text, options?: TextOptions|string, //content?: () => void - ): TextAttributes { + ): Text { throw new Error("This method should only be called through a @BuilderLambda redirect") } // TODO: the second argument will be gone after hte plugin is improved static instantiateImpl( - style: (instance: TextAttributes) => void, + style: (instance: Text) => Text, factory: () => Text, options?: TextOptions|string, //content?: () => void diff --git a/arkoala-arkts/user/src/sts/hello.sts b/arkoala-arkts/user/src/sts/hello.sts index 66627778e..6a41db84c 100644 --- a/arkoala-arkts/user/src/sts/hello.sts +++ b/arkoala-arkts/user/src/sts/hello.sts @@ -17,7 +17,7 @@ struct MyStateSample { this.color = Color.Red }) - }) + }).width(100) } } -- Gitee From ef91d396dafe5f3ec8ffc101e36aea0836350341 Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Wed, 5 Feb 2025 18:09:47 -0500 Subject: [PATCH 6/6] more --- arkoala-arkts/libarkts/plugins/input/main.sts | 1 + .../plugins/src/builder-lambda-transformer.ts | 14 ++------------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/arkoala-arkts/libarkts/plugins/input/main.sts b/arkoala-arkts/libarkts/plugins/input/main.sts index ef366ef8b..bff61711a 100644 --- a/arkoala-arkts/libarkts/plugins/input/main.sts +++ b/arkoala-arkts/libarkts/plugins/input/main.sts @@ -18,6 +18,7 @@ struct MyComponent { } width(value: number): MyComponent { return this } + build() {} } diff --git a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts index 70777e18e..6be93bccd 100644 --- a/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts +++ b/arkoala-arkts/libarkts/plugins/src/builder-lambda-transformer.ts @@ -70,7 +70,6 @@ function isBuilderLambdaAnnotation(annotation: arkts.AnnotationUsageIr): boolean if (!arkts.isIdentifier(annotation.expr)) { return false } - console.log("YES, isBuilderLambdaAnnotation ") return annotation.expr.name !== "BuilderLambda" } @@ -97,7 +96,7 @@ function builderLambdaTypeName(annotation: arkts.AnnotationUsageIr): string | un } */ function findBuilderLambdaAnnotation(node: arkts.CallExpression): arkts.AnnotationUsageIr|undefined { - console.log("findBuilderLambdaAnnotation") + let decl: arkts.AstNode|undefined = undefined if (arkts.isIdentifier(node.expression)) { decl = arkts.getDecl(node.expression) @@ -121,14 +120,11 @@ function findBuilderLambdaAnnotation(node: arkts.CallExpression): arkts.Annotati return undefined } - console.log("filtering") return declAnnotations.find(it => isBuilderLambdaAnnotation(it)) } function builderLambdaFunctionName(node: arkts.CallExpression): string | undefined { - console.log("builderLambdaFunctionName") - // TODO: remove this special handling when getDecl is capable. if (arkts.isMemberExpression(node.expression)) { if (arkts.isIdentifier(node.expression.property) && node.expression.property.name == "$_instantiate") { @@ -142,16 +138,11 @@ function builderLambdaFunctionName(node: arkts.CallExpression): string | undefin } function builderLambdaTypeName(node: arkts.CallExpression): string | undefined { - console.log("builderLambdaTypeName") + // TODO: remove this special handling when getDecl is capable. // this is the only way to know the type if (arkts.isMemberExpression(node.expression)) { - console.log("A", node.expression.dumpSrc()) - console.log("A0", node.expression) - console.log("A1", node.expression.object.dumpSrc()) - console.log("A2", node.expression.object) if (arkts.isIdentifier(node.expression.object)) { - console.log("B") return node.expression.object.name } } @@ -258,7 +249,6 @@ export class BuilderLambdaTransformer extends AbstractVisitor { }) const typeName = builderLambdaTypeName(leaf) - console.log("typeNmae:", typeName) const lambdaArg = getLambdaArg(lambdaBody, typeName) return arkts.factory.updateCallExpression( -- Gitee