diff --git a/ets1.2/.gitignore b/ets1.2/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..652516b5cda354c0bc01679f7fb9cc2d33f3f6ee --- /dev/null +++ b/ets1.2/.gitignore @@ -0,0 +1,40 @@ +**/node_modules +build +build-m3* +arkoala-arkts/arkui/build-recheck +dist +arkoala/tools/peer-generator/arkoala +**/package-lock.json +.vscode +**.code-workspace +.idea +**/target +**/cjpm.lock +**/CallsiteKey.o +interface_sdk-js +.ninja_log +**/.hvigor +**/js_output +**/command-line-tools +**/libs +**/lib +!incremental/tools/ets-tsc/lib +**/*.abc +cachegrind.out.* +perf.data* +/ui2abc/memo-plugin-ng/tests/out +*.tsbuildinfo +ui2abc/libarkts/lib +ui2abc/memo-plugin-ng/lib +ui2abc/ui-plugins-ng/lib +incremetal-cj/runtime/callsitekey +.rollup.cache +tsconfig.tsbuildinfo +*.meta.json +.cache +incremental/benchmarks/memo-benchmark/ets +koala_mirror +koala_tools +out +sdk +koala_build.log diff --git a/ets1.2/build-common/package.json b/ets1.2/build-common/package.json new file mode 100644 index 0000000000000000000000000000000000000000..e90180ccdac35dd08ab155e8e0f808b008ca4d59 --- /dev/null +++ b/ets1.2/build-common/package.json @@ -0,0 +1,11 @@ +{ + "name": "@koalaui/build-common", + "version": "1.7.10+devel", + "description": "", + "files": [ + "tsconfig.json" + ], + "scripts": { + "compile:release": "" + } +} \ No newline at end of file diff --git a/ets1.2/build-common/tsconfig.json b/ets1.2/build-common/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..02ca836732ea922edcb061e64008364e67b8f1e9 --- /dev/null +++ b/ets1.2/build-common/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "ESNext", + "lib": ["ESNext", "ESNext.WeakRef"], + "moduleResolution": "node", + "composite": true, + "incremental": true, + "declarationMap": true, + "sourceMap": true, + "declaration": true, + "noEmitOnError": true, + "strict": true, + "skipLibCheck": true, + "removeComments": false + } +} diff --git a/ets1.2/common/empty.js b/ets1.2/common/empty.js new file mode 100644 index 0000000000000000000000000000000000000000..ac57d1240ec618f291f4624f135240eb8c6bde18 --- /dev/null +++ b/ets1.2/common/empty.js @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2022-2023 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. + */ + diff --git a/ets1.2/common/package.json b/ets1.2/common/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1f2687d5cdd32a052ac04f2dc8d75a62f971ad87 --- /dev/null +++ b/ets1.2/common/package.json @@ -0,0 +1,45 @@ +{ + "name": "@koalaui/common", + "version": "1.7.10+devel", + "description": "", + "main": "build/lib/src/index.js", + "types": "./index.d.ts", + "files": [ + "build/lib/**/*.js", + "build/lib/**/*.d.ts", + "src/**/*" + ], + "exports": { + ".": "./build/lib/src/index.js" + }, + "typesVersions": { + "*": { + "*": [ + "build/lib/src/*", + "build/lib/typescript/*" + ] + } + }, + "scripts": { + "compile": "ets-tsc -b .", + "compile:release": "ets-tsc -b .", + "clean": "rimraf build", + "test": "mocha", + "test:coverage": "nyc mocha", + "build": "node ../../ui2abc/fast-arktsc --config ./ui2abcconfig.json --compiler ../tools/panda/arkts/ui2abc --link-name ./build/common.abc --simultaneous && PANDA_SDK_PATH=${PANDA_SDK_PATH:=../tools/panda/node_modules/@panda/sdk} ninja ${NINJA_OPTIONS} -f build/abc/build.ninja" + }, + "keywords": [], + "dependencies": { + "@koalaui/compat": "1.7.10+devel" + }, + "devDependencies": { + "@ohos/hypium": "1.0.6", + "@types/mocha": "^9.1.0", + "@typescript-eslint/eslint-plugin": "^5.20.0", + "@typescript-eslint/parser": "^5.20.0", + "eslint": "^8.13.0", + "eslint-plugin-unused-imports": "^2.0.0", + "mocha": "^9.2.2", + "source-map-support": "^0.5.21" + } +} \ No newline at end of file diff --git a/ets1.2/common/src/Finalization.ts b/ets1.2/common/src/Finalization.ts new file mode 100644 index 0000000000000000000000000000000000000000..c2056c2571f135e4dc65fea7efeb81b53a95d01e --- /dev/null +++ b/ets1.2/common/src/Finalization.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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. + */ + +import { + finalizerRegister as finalizerRegisterCompat, + finalizerUnregister as finalizerUnregisterCompat, + Thunk, +} from '@koalaui/compat'; + +export { Thunk } from '@koalaui/compat'; + +export function finalizerRegister(target: object, thunk: Thunk) { + finalizerRegisterCompat(target, thunk); +} + +export function finalizerRegisterWithCleaner(target: object, cleaner: () => void) { + finalizerRegisterCompat(target, new CleanerThunk(cleaner)); +} + +export function finalizerUnregister(target: object) { + finalizerUnregisterCompat(target); +} + +class CleanerThunk implements Thunk { + private cleaner: () => void; + constructor(cleaner: () => void) { + this.cleaner = cleaner; + } + clean() { + this.cleaner(); + } +} diff --git a/ets1.2/common/src/index.ts b/ets1.2/common/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a5de09250fc760d448fb9c077909244c63a68de --- /dev/null +++ b/ets1.2/common/src/index.ts @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +export { + int8, + uint8, + int32, + int32toFloat32, + int32toFloat64, + int32to64, + uint32, + int64, + int64toFloat32, + int64toFloat64, + int64to32, + uint64, + float32, + float32to64, + float32toInt32, + float32toInt64, + float64, + float64to32, + float64toInt32, + float64toInt64, + asArray, + asFloat64, + Array_from_set, + AtomicRef, + CustomTextDecoder, + CustomTextEncoder, + className, + lcClassName, + functionOverValue, + Observed, + Observable, + ObservableClass, + ClassMetadata, + ObservableHandler, + observableProxy, + observableProxyArray, + TrackableProperties, + trackableProperties, + isFunction, + propDeepCopy, + refEqual, + int8Array, + errorAsString, + unsafeCast, + WorkerLocalValue, + scheduleCoroutine, + memoryStats, + launchJob, +} from '@koalaui/compat'; +export { clamp, lerp, modulo, parseNumber, isFiniteNumber, getDistancePx } from './math'; +export { hashCodeFromString } from './stringUtils'; +export * from './Finalization'; +export { SHA1Hash, createSha1 } from './sha1'; +export { UniqueId } from './uniqueId'; +export * from './koalaKey'; diff --git a/ets1.2/common/src/koalaKey.ts b/ets1.2/common/src/koalaKey.ts new file mode 100644 index 0000000000000000000000000000000000000000..a529f81bdbbd94beaf231211f74cbdb1b1fd0efa --- /dev/null +++ b/ets1.2/common/src/koalaKey.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import { int32 } from '@koalaui/compat'; + +export type KoalaCallsiteKey = int32; + +export class KoalaCallsiteKeys { + static readonly empty: KoalaCallsiteKey = 0; + + static combine(key1: KoalaCallsiteKey, key2: KoalaCallsiteKey): KoalaCallsiteKey { + return key1 + key2; + } + + static asString(key: KoalaCallsiteKey): string { + return key.toString(16); + } +} diff --git a/ets1.2/common/src/math.ts b/ets1.2/common/src/math.ts new file mode 100644 index 0000000000000000000000000000000000000000..52c39a60b09ad6b05ca1d2d54d62255ea00d7134 --- /dev/null +++ b/ets1.2/common/src/math.ts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import { asFloat64, float64 } from '@koalaui/compat'; + +/** + * Computes the linear interpolation between `source` and `target` based on `weight`. + * + * @param weight - interpolation factor in the range [0..1] + * @param source - a value corresponding to weight 0 + * @param target - a value corresponding to weight 1 + * @returns interpolated value + */ +export function lerp(weight: float64, source: float64, target: float64): float64 { + return source * (1.0 - weight) + target * weight; +} + +/** + * Clamps a {@link value} within the specified range. + * + * @param value - a value to clamp + * @param min - the lower boundary of the range + * @param max - the upper boundary of the range + * @returns `min` if `value` is less than `min`, + * `max` if `value` is greater than `max`, + * `value` otherwise + */ +export function clamp(value: float64, min: float64, max: float64): float64 { + return value <= min ? min : value >= max ? max : value; +} + +/** + * Calculates the difference between the argument and + * the largest (closest to positive infinity) integer value + * that is less than or equal to the argument. + * + * @param value a floating-point value to process + * @returns a floor modulus of the given value in the range [0..1) + */ +export function modulo(value: float64): float64 { + // The casts below are needed since floor returns double in ArkTS + const modulo: float64 = value - Math.floor(value); + return modulo < 1.0 ? modulo : 0.0; +} + +/** + * @param str a string to parse + * @param name a name for error message + * @param verify whether to verify parsing validity + * @returns a floating-point number + * @throws Error if `str` cannot be parsed + */ +export function parseNumber(str: string, name: string = 'number', verify: boolean = false): float64 { + if (str != '') { + // do not parse empty string to 0 + // ArkTS does not support NaN, isNaN, parseFloat + const value = asFloat64(str); + if (verify) { + const reverseStr = value.toString(); + if (reverseStr !== undefined && reverseStr?.length == str.length && reverseStr == str) { + return value; + } + } else { + return value; + } + } + throw new Error(`cannot parse ${name}: "${str}"`); +} + +/** + * An ArkTS-compliant replacement for {@link isFinite}. + */ +export function isFiniteNumber(number: float64): boolean { + // With Node.js: + // isFiniteNumber(Number.NEGATIVE_INFINITY) == false + // isFiniteNumber(Number.POSITIVE_INFINITY) == false + // isFiniteNumber(NaN) == false + return number >= Number.MIN_SAFE_INTEGER && number <= Number.MAX_SAFE_INTEGER; +} + +export function getDistancePx(startX: float64, startY: float64, endX: float64, endY: float64): float64 { + const cathetA = Math.abs(endX - startX); + const cathetB = Math.abs(endY - startY); + return Math.sqrt(cathetA * cathetA + cathetB * cathetB) as float64; +} diff --git a/ets1.2/common/src/sha1.ts b/ets1.2/common/src/sha1.ts new file mode 100644 index 0000000000000000000000000000000000000000..569d0831450e534cdaf84f0ac3e76acc37fe9903 --- /dev/null +++ b/ets1.2/common/src/sha1.ts @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import { CustomTextDecoder, float64toInt32, int64to32 } from '@koalaui/compat'; +import { int32 } from '@koalaui/compat'; + +const K = [0x5a827999 | 0, 0x6ed9eba1 | 0, 0x8f1bbcdc | 0, 0xca62c1d6 | 0]; + +const inputBytes = 64; +const inputWords = inputBytes / 4; +const highIndex = inputWords - 2; +const lowIndex = inputWords - 1; +const workWords = 80; +const allocBytes = 80; +const allocWords = allocBytes / 4; +const allocTotal = allocBytes * 100; + +export function createSha1(): SHA1Hash { + return new SHA1Hash(); +} + +export class SHA1Hash { + private A = 0x67452301 | 0; + private B = 0xefcdab89 | 0; + private C = 0x98badcfe | 0; + private D = 0x10325476 | 0; + private E = 0xc3d2e1f0 | 0; + private readonly _byte: Uint8Array; + private readonly _word: Int32Array; + private _size = 0; + private _sp = 0; // surrogate pair + + constructor() { + if (!sharedBuffer || sharedOffset >= allocTotal) { + sharedBuffer = new ArrayBuffer(allocTotal); + sharedOffset = 0; + } + + this._byte = new Uint8Array(sharedBuffer, sharedOffset, allocBytes); + this._word = new Int32Array(sharedBuffer, sharedOffset, allocWords); + sharedOffset += allocBytes; + } + + updateString(data: string, encoding?: string): SHA1Hash { + return this._utf8(data); + } + updateInt32(data: int32): SHA1Hash { + const buffer = new Int32Array(1); + buffer[0] = data; + return this.update(buffer); + } + + update(data: Int32Array | Float32Array | Uint32Array | Uint8Array): SHA1Hash { + if (data == null) { + throw new TypeError('SHA1Hash expected non-null data: '); + } + + let byteOffset: int32 = 0; + let length: int32 = 0; + let buffer: ArrayBufferLike | undefined = undefined; + + // Improve: an attempt to wrie this in a generic form causes + // es2panda to segfault. + let BYTES_PER_ELEMENT = 4; + if (data instanceof Int32Array) { + byteOffset = float64toInt32(data.byteOffset); + length = float64toInt32(data.byteLength); + buffer = data.buffer; + } else if (data instanceof Uint32Array) { + byteOffset = float64toInt32(data.byteOffset); + length = float64toInt32(data.byteLength); + buffer = data.buffer; + } else if (data instanceof Float32Array) { + byteOffset = float64toInt32(data.byteOffset); + length = float64toInt32(data.byteLength); + buffer = data.buffer; + } else if (data instanceof Uint8Array) { + byteOffset = float64toInt32(data.byteOffset); + length = float64toInt32(data.byteLength); + buffer = data.buffer; + BYTES_PER_ELEMENT = 1; + } + + let blocks: int32 = (length / inputBytes) | 0; + let offset: int32 = 0; + + // longer than 1 block + if (blocks != 0 && !(byteOffset & 3) && !(this._size % inputBytes)) { + const block = new Int32Array(buffer!, byteOffset, blocks * inputWords); + while (blocks--) { + this._int32(block, offset >> 2); + offset += inputBytes; + } + this._size += offset; + } + + // data: TypedArray | DataView + if (BYTES_PER_ELEMENT != 1 && buffer != undefined) { + const rest = new Uint8Array(buffer, byteOffset + offset, length - offset); + return this._uint8(rest); + } + + // no more bytes + if (offset == length) return this; + + return this._uint8(new Uint8Array(buffer!), offset); + } + + private _uint8(data: Uint8Array, offset?: int32): SHA1Hash { + const _byte = this._byte; + const _word = this._word; + const length = data.length; + offset = (offset ?? 0) | 0; + + while (offset < length) { + const start = this._size % inputBytes; + let index = start; + + while (offset < length && index < inputBytes) { + _byte[index++] = data[offset++]; + } + + if (index >= inputBytes) { + this._int32(_word); + } + + this._size += index - start; + } + + return this; + } + + private _utf8(text: string): SHA1Hash { + const _byte = this._byte; + const _word = this._word; + const length = text.length; + let surrogate = this._sp; + + for (let offset = 0; offset < length; ) { + const start = this._size % inputBytes; + let index = start; + + while (offset < length && index < inputBytes) { + let code = float64toInt32(text.charCodeAt(offset++)) | 0; + if (code < 0x80) { + // ASCII characters + _byte[index++] = code; + } else if (code < 0x800) { + // 2 bytes + _byte[index++] = 0xc0 | (code >>> 6); + _byte[index++] = 0x80 | (code & 0x3f); + } else if (code < 0xd800 || code > 0xdfff) { + // 3 bytes + _byte[index++] = 0xe0 | (code >>> 12); + _byte[index++] = 0x80 | ((code >>> 6) & 0x3f); + _byte[index++] = 0x80 | (code & 0x3f); + } else if (surrogate) { + // 4 bytes - surrogate pair + code = ((surrogate & 0x3ff) << 10) + (code & 0x3ff) + 0x10000; + _byte[index++] = 0xf0 | (code >>> 18); + _byte[index++] = 0x80 | ((code >>> 12) & 0x3f); + _byte[index++] = 0x80 | ((code >>> 6) & 0x3f); + _byte[index++] = 0x80 | (code & 0x3f); + surrogate = 0; + } else { + surrogate = int64to32(code); + } + } + + if (index >= inputBytes) { + this._int32(_word); + _word[0] = _word[inputWords]; + } + + this._size += index - start; + } + + this._sp = surrogate; + return this; + } + + private _int32(data: Int32Array, offset?: int32): void { + let A = this.A; + let B = this.B; + let C = this.C; + let D = this.D; + let E = this.E; + let i = 0; + offset = (offset ?? 0) | 0; + + while (i < inputWords) { + W[i++] = swap32(float64toInt32(data[offset!++])); + } + + for (i = inputWords; i < workWords; i++) { + W[i] = rotate1(float64toInt32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16])); + } + + for (i = 0; i < workWords; i++) { + const S = (i / 20) | 0; + const T = float64toInt32((rotate5(A) + ft(S, B, C, D) + E + W[i] + K[S]) | 0); + E = D; + D = C; + C = rotate30(B); + B = A; + A = T; + } + + this.A = (A + this.A) | 0; + this.B = (B + this.B) | 0; + this.C = (C + this.C) | 0; + this.D = (D + this.D) | 0; + this.E = (E + this.E) | 0; + } + + // digest(): Uint8Array + // digest(encoding: string): string + digest(encoding?: string): Uint8Array | string { + const _byte = this._byte; + const _word = this._word; + let i = this._size % inputBytes | 0; + _byte[i++] = 0x80; + + // pad 0 for current word + while (i & 3) { + _byte[i++] = 0; + } + i >>= 2; + + if (i > highIndex) { + while (i < inputWords) { + _word[i++] = 0; + } + i = 0; + this._int32(_word); + } + + // pad 0 for rest words + while (i < inputWords) { + _word[i++] = 0; + } + + // input size + const bits64: int32 = this._size * 8; + const low32: int32 = float64toInt32((bits64 & 0xffffffff) >>> 0); + const high32: int32 = float64toInt32((bits64 - low32) / 0x100000000); + if (high32) _word[highIndex] = swap32(high32); + if (low32) _word[lowIndex] = swap32(low32); + + this._int32(_word); + + return encoding === 'hex' ? this._hex() : this._bin(); + } + + private _hex(): string { + let A = this.A; + let B = this.B; + let C = this.C; + let D = this.D; + let E = this.E; + + return hex32Str(A, B, C, D, E); + } + + private _bin(): Uint8Array { + let A = this.A; + let B = this.B; + let C = this.C; + let D = this.D; + let E = this.E; + const _byte = this._byte; + const _word = this._word; + + _word[0] = swap32(A); + _word[1] = swap32(B); + _word[2] = swap32(C); + _word[3] = swap32(D); + _word[4] = swap32(E); + + return _byte.slice(0, 20); + } +} + +type NS = (num: int32) => string; +type NN = (num: int32) => int32; + +const W = new Int32Array(workWords); + +let sharedBuffer: ArrayBuffer; +let sharedOffset: int32 = 0; + +const swapLE: NN = (c: int32): int32 => + ((c << 24) & 0xff000000) | ((c << 8) & 0xff0000) | ((c >> 8) & 0xff00) | ((c >> 24) & 0xff); +const swapBE: NN = (c: int32): int32 => c; +const swap32: NN = isBE() ? swapBE : swapLE; +const rotate1: NN = (num: int32): int32 => (num << 1) | (num >>> 31); +const rotate5: NN = (num: int32): int32 => (num << 5) | (num >>> 27); +const rotate30: NN = (num: int32): int32 => (num << 30) | (num >>> 2); + +function isBE(): boolean { + let a16 = new Uint16Array(1); + a16[0] = 0xfeff; + let a8 = new Uint8Array(a16.buffer); + return a8[0] == 0xfe; // BOM +} + +function ft(s: int32, b: int32, c: int32, d: int32) { + if (s == 0) return (b & c) | (~b & d); + if (s == 2) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +const hex32Decoder = new CustomTextDecoder(); +const hex32DecodeBuffer = new Uint8Array(40); +function hex32Str(A: int32, B: int32, C: int32, D: int32, E: int32): string { + writeIntAsHexUTF8(A, hex32DecodeBuffer, 0); + writeIntAsHexUTF8(B, hex32DecodeBuffer, 8); + writeIntAsHexUTF8(C, hex32DecodeBuffer, 16); + writeIntAsHexUTF8(D, hex32DecodeBuffer, 24); + writeIntAsHexUTF8(E, hex32DecodeBuffer, 32); + return hex32Decoder.decode(hex32DecodeBuffer); +} + +function writeIntAsHexUTF8(value: int32, buffer: Uint8Array, byteOffset: int32) { + buffer[byteOffset++] = nibbleToHexCode((value >> 28) & 0xf); + buffer[byteOffset++] = nibbleToHexCode((value >> 24) & 0xf); + buffer[byteOffset++] = nibbleToHexCode((value >> 20) & 0xf); + buffer[byteOffset++] = nibbleToHexCode((value >> 16) & 0xf); + buffer[byteOffset++] = nibbleToHexCode((value >> 12) & 0xf); + buffer[byteOffset++] = nibbleToHexCode((value >> 8) & 0xf); + buffer[byteOffset++] = nibbleToHexCode((value >> 4) & 0xf); + buffer[byteOffset++] = nibbleToHexCode((value >> 0) & 0xf); +} + +function nibbleToHexCode(nibble: int32) { + return nibble > 9 ? nibble + 87 : nibble + 48; +} diff --git a/ets1.2/common/src/stringUtils.ts b/ets1.2/common/src/stringUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4a5853f5c572da8b52f9a80a7a3157b67b137e1 --- /dev/null +++ b/ets1.2/common/src/stringUtils.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { float64toInt32, int32, int64to32 } from '@koalaui/compat'; + +/** + * Computes a hash code from the string {@link value}. + */ +export function hashCodeFromString(value: string): int32 { + let hash = 5381; + for (let i = 0; i < value.length; i++) { + hash = int64to32((hash * 33) ^ float64toInt32(value.charCodeAt(i))); + } + return hash; +} diff --git a/ets1.2/common/src/uniqueId.ts b/ets1.2/common/src/uniqueId.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5511e6588107218717c409a3a7cb4be5063541d --- /dev/null +++ b/ets1.2/common/src/uniqueId.ts @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import { float64toInt32, int32 } from '@koalaui/compat'; +import { createSha1 } from './sha1'; + +export class UniqueId { + private sha = createSha1(); + + public addString(data: string): UniqueId { + this.sha.updateString(data); + return this; + } + + public addI32(data: int32): UniqueId { + this.sha.updateInt32(data); + return this; + } + + public addF32Array(data: Float32Array): UniqueId { + this.sha.update(data); + return this; + } + + public addI32Array(data: Int32Array): UniqueId { + this.sha.update(data); + return this; + } + + public addU32Array(data: Uint32Array): UniqueId { + this.sha.update(data); + return this; + } + + public addU8Array(data: Uint8Array): UniqueId { + this.sha.update(data); + return this; + } + + public addPtr(data: Uint32Array | number): UniqueId { + if (data instanceof Uint32Array) { + return this.addU32Array(data); + } + return this.addI32(float64toInt32(data)); + } + + public compute(): string { + return this.sha.digest('hex') as string; + } +} diff --git a/ets1.2/common/tsconfig.json b/ets1.2/common/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..443ddd555f10cccdf26ec4a7c46345652c18b6ca --- /dev/null +++ b/ets1.2/common/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@koalaui/build-common/tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "build/lib", + "module": "CommonJS", + "paths": { + "@koalaui/compat": ["../compat/typescript"] + } + }, + "include": ["./src/**/*"], + "exclude": ["./src/ohos"], + "references": [ + {"path": "../compat"} + ] +} diff --git a/ets1.2/common/ui2abcconfig.json b/ets1.2/common/ui2abcconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..dcacec76b99a9d7f60c6f2f3a3b18c1a87480bea --- /dev/null +++ b/ets1.2/common/ui2abcconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "package": "@koalaui/common", + "outDir": "build/abc", + "baseUrl": "./src", + "paths": { + "@koalaui/compat": ["../../compat/src/arkts"] + } + }, + "include": ["src/**/*.ts"], + "references": [ + { "path": "../compat" } + ] +} diff --git a/ets1.2/compat/package.json b/ets1.2/compat/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3afa14ef6ffd9cbb012dba95262125947561b8f8 --- /dev/null +++ b/ets1.2/compat/package.json @@ -0,0 +1,39 @@ +{ + "name": "@koalaui/compat", + "version": "1.7.10+devel", + "description": "", + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "files": [ + "build/src/**/*.js", + "build/src/**/*.d.ts", + "src/**/*" + ], + "imports": { + "#platform": { + "ark": "./build/src/ohos/index.js", + "ios": "./build/src/typescript/index.js", + "browser": "./build/src/typescript/index.js", + "node": "./build/src/typescript/index.js", + "default": "./build/src/typescript/index.js" + } + }, + "exports": { + ".": "./build/src/index.js" + }, + "scripts": { + "clean": "rimraf build dist", + "compile": "ets-tsc -b .", + "compile:release": "ets-tsc -b .", + "build": "node ../../ui2abc/fast-arktsc --config ./ui2abcconfig.json --compiler ../tools/panda/arkts/ui2abc --link-name ./build/compat.abc --simultaneous && PANDA_SDK_PATH=${PANDA_SDK_PATH:=../tools/panda/node_modules/@panda/sdk} ninja ${NINJA_OPTIONS} -f build/abc/build.ninja" + }, + "keywords": [], + "dependencies": {}, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.20.0", + "@typescript-eslint/parser": "^5.20.0", + "eslint": "^8.13.0", + "eslint-plugin-unused-imports": "^2.0.0", + "source-map-support": "^0.5.21" + } +} \ No newline at end of file diff --git a/ets1.2/compat/src/arkts/array.ts b/ets1.2/compat/src/arkts/array.ts new file mode 100644 index 0000000000000000000000000000000000000000..843ad018de48d2a046beb4915fe74bedcf84e105 --- /dev/null +++ b/ets1.2/compat/src/arkts/array.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import { float64, int32, int8 } from './types'; + +// Improve: this can be a performance disaster +// just wait for the library to provide the proper functionality. +export function asArray(value: T[]): Array { + return Array.of(...value); +} + +// Improve: this can be a performance disaster +// just wait for the library to provide the proper functionality. +export function Array_from_set(set: Set): Array { + const array = new Array(); // to avoid creation of undefined content + const values = set.values(); + for (let it = values.next(); it.done != true; it = values.next()) { + array.push(it.value as T); + } + return array; +} + +// Improve: this can be a performance disaster +// just wait for the library to provide the proper functionality. +export function Array_from_int32(data: Int32Array): number[] { + const result: number[] = []; + for (let i: int32 = 0; i < data.length; i++) { + result[i] = data.at(i) as number; + } + return result; +} + +// Improve: this can be a performance disaster +// just wait for the library to provide the proper functionality. +export function Array_from_number(data: float64[]): Array { + const result = new Array(data.length); + for (let i: int32 = 0; i < data.length; i++) { + result[i] = data[i]; + } + return result; +} + +export function int8Array(size: int32): FixedArray { + // Adding () breaks the array creation + // prettier-ignore + const array: FixedArray = new int8[size]; + return array; +} diff --git a/ets1.2/compat/src/arkts/atomic.ts b/ets1.2/compat/src/arkts/atomic.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3418ecbb06f877168cd0013c9886fa842f6a1b6 --- /dev/null +++ b/ets1.2/compat/src/arkts/atomic.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * A reference that may be updated atomically. + */ +export class AtomicRef { + value: Value; + + /** + * Creates a new reference object with the given initial value. + * @param value - the new value + */ + constructor(value: Value) { + this.value = value; + } + + /** + * Atomically sets the reference value to the given value and returns the previous one. + * @param value - the new value + * @returns the previous value + */ + getAndSet(value: Value): Value { + // Improve: replace with the implementation from ArkTS language when it is ready + const result = this.value; + this.value = value; + return result; + } +} diff --git a/ets1.2/compat/src/arkts/finalization.ts b/ets1.2/compat/src/arkts/finalization.ts new file mode 100644 index 0000000000000000000000000000000000000000..7648b12d39421507c2e143464d4ce40be4a35fd9 --- /dev/null +++ b/ets1.2/compat/src/arkts/finalization.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 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. + */ + +export interface Thunk { + clean(): void; +} + +const registry = new FinalizationRegistry((thunk: Thunk) => { + thunk.clean(); +}); + +export function finalizerRegister(target: Object, thunk: Object) { + registry.register(target, thunk as Thunk); +} + +export function finalizerUnregister(target: Object) { + registry.unregister(target); +} diff --git a/ets1.2/compat/src/arkts/index.ts b/ets1.2/compat/src/arkts/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f12c977dd562486615a1f2edf04145ec8cde835b --- /dev/null +++ b/ets1.2/compat/src/arkts/index.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +export * from './array'; +export * from './atomic'; +export * from './primitive'; +export * from './finalization'; +export * from './performance'; +export * from './prop-deep-copy'; +export * from './observable'; +export * from './reflection'; +export * from './strings'; +export * from './ts-reflection'; +export * from './types'; +export * from './utils'; diff --git a/ets1.2/compat/src/arkts/observable.ts b/ets1.2/compat/src/arkts/observable.ts new file mode 100644 index 0000000000000000000000000000000000000000..88f6be9444ea648c67360f785c31d75959798d09 --- /dev/null +++ b/ets1.2/compat/src/arkts/observable.ts @@ -0,0 +1,1281 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +export function getObservableTarget(proxy0: Object): Object { + try { + // do not use proxy for own observables + if (proxy0 instanceof ObservableArray + || proxy0 instanceof ObservableDate + || proxy0 instanceof ObservableMap + || proxy0 instanceof ObservableSet ) { + return proxy0 + } + return (proxy.Proxy.tryGetTarget(proxy0) as Object|undefined|null) ?? proxy0 + } catch (error) { + return proxy0 + } +} + +/** + * Data class decorator that makes all child fields trackable. + */ +export function Observed() { + throw new Error("TypeScript class decorators are not supported yet") +} + +/** @internal */ +export interface Observable { + /** + * It is called when the observable value is accessed. + * @param propertyName - Optional name of the accessed property. + * Should be provided when tracking individual properties. + * */ + onAccess(propertyName?: string): void + /** + * It is called when the observable value is modified. + * @param propertyName - Optional name of the modified property. + * Should be provided when tracking individual properties. + * */ + onModify(propertyName?: string): void +} + +/** @internal */ +export class ObservableHandler implements Observable { + private static handlers: WeakMap | undefined = undefined + + private parents = new Set() + private children = new Map() + + private readonly observables = new Set() + private _modified = false + + readonly observed: boolean + constructor(parent?: ObservableHandler, observed: boolean = false) { + this.observed = observed + if (parent) this.addParent(parent) + } + + onAccess(propertyName?: string): void { + if (this.observables.size > 0) { + const it = this.observables.keys() + while (true) { + const result = it.next() + if (result.done) break + result.value?.onAccess(propertyName) + } + } + } + + onModify(propertyName?: string): void { + const set = new Set() + this.collect(true, set) + set.forEach((handler: ObservableHandler) => { + handler._modified = true + if (handler.observables.size > 0) { + const it = handler.observables.keys() + while (true) { + const result = it.next() + if (result.done) break + result.value?.onModify(propertyName) + } + } + }) + } + + static dropModified(value: Value): boolean { + const handler = ObservableHandler.findIfObject(value) + if (handler === undefined) return false + const result = handler._modified + handler._modified = false + return result + } + + /** Adds the specified `observable` to the handler corresponding to the given `value`. */ + static attach(value: Value, observable: Observable): void { + const handler = ObservableHandler.findIfObject(value) + if (handler) handler.observables.add(observable) + } + + /** Deletes the specified `observable` from the handler corresponding to the given `value`. */ + static detach(value: Value, observable: Observable): void { + const handler = ObservableHandler.findIfObject(value) + if (handler) handler.observables.delete(observable) + } + + /** @returns the handler corresponding to the given `value` if it was installed */ + private static findIfObject(value: Value): ObservableHandler | undefined { + const handlers = ObservableHandler.handlers + return handlers !== undefined && value instanceof Object ? handlers.get(getObservableTarget(value as Object)) : undefined + } + + /** + * @param value - any non-null object including arrays + * @returns an observable handler or `undefined` if it is not installed + */ + static find(value: Object): ObservableHandler | undefined { + const handlers = ObservableHandler.handlers + return handlers ? handlers.get(getObservableTarget(value)) : undefined + } + + /** + * @param value - any non-null object including arrays + * @param observable - a handler to install on this object + * @throws an error if observable handler cannot be installed + */ + static installOn(value: Object, observable?: ObservableHandler): void { + let handlers = ObservableHandler.handlers + if (handlers === undefined) { + handlers = new WeakMap() + ObservableHandler.handlers = handlers + } + observable + ? handlers.set(getObservableTarget(value), observable) + : handlers.delete(getObservableTarget(value)) + } + + addParent(parent: ObservableHandler) { + const count = parent.children.get(this) ?? 0 + parent.children.set(this, count + 1) + this.parents.add(parent) + } + + hasChild(child: ObservableHandler): boolean { + return this.children.has(child) + } + + removeParent(parent: ObservableHandler) { + const count = parent.children.get(this) ?? 0 + if (count > 1) { + parent.children.set(this, count - 1) + } + else if (count == 1) { + parent.children.delete(this) + this.parents.delete(parent) + } + } + + removeChild(value: Value) { + const child = ObservableHandler.findIfObject(value) + if (child) child.removeParent(this) + } + + private collect(all: boolean, guards: Set) { + if (guards.has(this)) return guards // already collected + guards.add(this) // handler is already guarded + this.parents.forEach((handler: ObservableHandler) => { handler.collect(all, guards) }) + if (all) this.children.forEach((_count: number, handler: ObservableHandler) => { handler.collect(all, guards) }) + return guards + } + + static contains(observable: ObservableHandler, guards?: Set) { + if (observable.observed) return true + if (guards === undefined) guards = new Set() // create if needed + else if (guards!.has(observable)) return false // already checked + guards.add(observable) // handler is already guarded + for (const it of observable.parents.keys()) { + if (ObservableHandler.contains(it, guards)) return true + } + return false + } +} + +/** @internal */ +export function observableProxyArray(...value: Value[]): Array { + return observableProxy(Array.of(...value)) +} + +/** @internal */ +export function observableProxy(value: Value, parent?: ObservableHandler, observed?: boolean, strict: boolean = true): Value { + if (value instanceof ObservableHandler) return value as Value // do not proxy a marker itself + if (value == null || !(value instanceof Object)) return value as Value // only non-null object can be observable + const observable = ObservableHandler.find(value as Object) + if (observable) { + if (parent) { + if (strict) observable.addParent(parent) + if (observed === undefined) observed = ObservableHandler.contains(parent) + } + if (observed) { + if (value instanceof Array) { + for (let index = 0; index < value.length; index++) { + value[index] = observableProxy(value[index], observable, observed, false) + } + } else { + // Improve: proxy fields of the given object + } + } + return value as Value + } + if (value instanceof Array) { + return ObservableArray(value, parent, observed) as Value + } else if (value instanceof Map) { + return ObservableMap(value, parent, observed) as Value + } else if (value instanceof Set) { + return ObservableSet(value, parent, observed) as Value + } else if (value instanceof Date) { + return ObservableDate(value, parent, observed) as Value + } + + // Improve: Fatal error on using proxy with generic types + // see: panda issue #26492 + + const valueType = Type.of(value) + if (valueType instanceof ClassType && !(value instanceof BaseEnum)) { + const isObservable = isObservedV1Class(value as Object) + if (!hasTrackableProperties(value as Object) && !isObservable) { + return value as Value + } + if (valueType.hasEmptyConstructor()) { + const result = proxy.Proxy.create(value as Object, new CustomProxyHandler(isObservable)) as Value + ObservableHandler.installOn(result as Object, new ObservableHandler(parent)) + return result + } else { + throw new Error(`Class '${valueType.getName()}' must contain a default constructor`) + } + } + return value as Value +} + +class CustomProxyHandler extends proxy.DefaultProxyHandler { + private readonly isObservable: boolean + + constructor(isObservable: boolean) { + super(); + this.isObservable = isObservable + } + + override get(target: T, name: string): Any { + const value = super.get(target, name) + const targetHandler = ObservableHandler.find(target) + if (targetHandler && this.isObservable) { + const valueHandler = ObservableHandler.find(value as Object) + if (valueHandler && !targetHandler.hasChild(valueHandler)) { + valueHandler.addParent(targetHandler) + } + } + targetHandler?.onAccess(name) + return value + } + + override set(target: T, name: string, value: Any): boolean { + const observable = ObservableHandler.find(target) + if (observable) { + observable.onModify(name) + observable.removeChild(super.get(target, name)) + value = observableProxy(value, observable, ObservableHandler.contains(observable)) + } + const result = super.set(target, name, value) + observable?.onModify(name) + return result + } +} + +function proxyChildrenOnly(array: T[], parent: ObservableHandler, observed?: boolean) { + for (let i = 0; i < array.length; i++) { + if (observed === undefined) observed = ObservableHandler.contains(parent) + array[i] = observableProxy(array[i], parent, observed) + } +} + +class ObservableArray extends Array { + static $_invoke(array: Array, parent?: ObservableHandler, observed?: boolean): Array { + return new ObservableArray(array, parent, observed); + } + + constructor(array: Array, parent?: ObservableHandler, observed?: boolean) { + super(array.length) + const handler = new ObservableHandler(parent) + for (let i = 0; i < array.length; i++) { + if (observed === undefined) observed = ObservableHandler.contains(handler) + super.$_set(i, observableProxy(array[i], handler, observed)) + } + ObservableHandler.installOn(this, handler) + } + + private get handler(): ObservableHandler | undefined { + return ObservableHandler.find(this) + } + + override get length(): int { + this.handler?.onAccess() + return super.length + } + + override set length(length: int) { + super.length = length + this.handler?.onModify() + } + + override at(index: int): T | undefined { + this.handler?.onAccess() + return super.at(index) + } + + override $_get(index: int): T { + this.handler?.onAccess() + return super.$_get(index) + } + + override $_set(index: int, value: T): void { + const handler = this.handler + if (handler) { + handler.removeChild(super.$_get(index)) + value = observableProxy(value, handler) + } + super.$_set(index, value) + handler?.onModify() + } + + override copyWithin(target: int, start: int, end: int): this { + super.copyWithin(target, start, end) + this.handler?.onModify() + return this + } + + override fill(value: T, start: int, end: int): this { + const handler = this.handler + if (handler) { + value = observableProxy(value, handler) + } + super.fill(value, start, end) + handler?.onModify() + return this + } + + override pop(): T | undefined { + const handler = this.handler + const result = super.pop() + handler?.onModify() + if (result) { + handler?.removeChild(result) + } + return result + } + + override pushArray(...items: T[]): number { + const handler = this.handler + if (handler) { + proxyChildrenOnly(items, handler) + } + const result = super.pushArray(...items) + handler?.onModify() + return result + } + + override pushOne(value: T): number { + const handler = this.handler + if (handler) { + value = observableProxy(value, handler) + } + const result = super.pushOne(value) + handler?.onModify() + return result + } + + override pushECMA(...items: T[]): number { + const handler = this.handler + if (handler) { + proxyChildrenOnly(items, handler) + } + const result = super.pushECMA(...items) + handler?.onModify() + return result + } + + override reverse(): this { + super.reverse() + this.handler?.onModify() + return this + } + + override shift(): T | undefined { + const handler = this.handler + const result = super.shift() + if (result) handler?.removeChild(result) + handler?.onModify() + return result + } + + override sort(comparator?: (a: T, b: T) => number): this { + super.sort(comparator) + this.handler?.onModify() + return this + } + + override splice(index: int, count: int, ...items: T[]): Array { + const handler = this.handler + if (handler) { + proxyChildrenOnly(items, handler) + const result = super.splice(index, count, ...items) + for (let i = 0; i < result.length; i++) { + handler.removeChild(result[i]) + } + handler.onModify() + return result + } + return super.splice(index, count, ...items) + } + + override unshift(...items: T[]): number { + const handler = this.handler + if (handler) { + proxyChildrenOnly(items, handler) + } + const result = super.unshift(...items) + handler?.onModify() + return result + } + + override keys(): IterableIterator { + this.handler?.onAccess() + return super.keys() + } + + // === methods with uncompatible implementation === + + override filter(predicate: (value: T, index: number, array: Array) => boolean): Array { + this.handler?.onAccess() + return super.filter(predicate) + } + + override flat(depth: int): Array { + this.handler?.onAccess() + return super.flat(depth) + } + + override flatMap(fn: (v: T, k: number, arr: Array) => U): Array { + this.handler?.onAccess() + return super.flatMap(fn) + } + + // === methods common among all arrays === + + override concat(...items: FixedArray>): Array { + this.handler?.onAccess() + return super.concat(...items) + } + + override find(predicate: (value: T, index: number, array: Array) => boolean): T | undefined { + this.handler?.onAccess() + return super.find(predicate) + } + + override findIndex(predicate: (value: T, index: number, array: Array) => boolean): number { + this.handler?.onAccess() + return super.findIndex(predicate) + } + + override findLast(predicate: (elem: T, index: number, array: Array) => boolean): T | undefined { + this.handler?.onAccess() + return super.findLast(predicate) + } + + override every(predicate: (value: T, index: number, array: Array) => boolean): boolean { + this.handler?.onAccess() + return super.every(predicate) + } + + override some(predicate: (value: T, index: number, array: Array) => boolean): boolean { + this.handler?.onAccess() + return super.some(predicate) + } + + override findLastIndex(predicate: (element: T, index: number, array: Array) => boolean): number { + this.handler?.onAccess() + return super.findLastIndex(predicate) + } + + override reduce(callbackfn: (previousValue: T, currentValue: T, index: number, array: Array) => T): T { + this.handler?.onAccess() + return super.reduce(callbackfn) + } + + override reduce(callbackfn: (previousValue: U, currentValue: T, index: number, array: Array) => U, initialValue: U): U { + this.handler?.onAccess() + return super.reduce(callbackfn, initialValue) + } + + override reduceRight(callbackfn: (previousValue: T, currentValue: T, index: number, array: Array) => T): T { + this.handler?.onAccess() + return super.reduceRight(callbackfn) + } + + override reduceRight(callbackfn: (previousValue: U, currentValue: T, index: number, array: Array) => U, initialValue: U): U { + this.handler?.onAccess() + return super.reduceRight(callbackfn, initialValue) + } + + override forEach(callbackfn: (value: T, index: number, array: Array) => void): void { + this.handler?.onAccess() + super.forEach(callbackfn) + } + + override slice(start: int, end: int): Array { + this.handler?.onAccess() + return super.slice(start, end) + } + + override lastIndexOf(searchElement: T, fromIndex?: int): int { + this.handler?.onAccess() + return super.lastIndexOf(searchElement, fromIndex) + } + + override join(sep?: String): string { + this.handler?.onAccess() + return super.join(sep) + } + + override toLocaleString(): string { + this.handler?.onAccess() + return super.toLocaleString() + } + + override toSpliced(start: int, delete: int, ...items: FixedArray): Array { + this.handler?.onAccess() + return super.toSpliced(start, delete, ...items) + } + + override includes(val: T, fromIndex?: Number): boolean { + this.handler?.onAccess() + return super.includes(val, fromIndex) + } + + override indexOf(val: T, fromIndex?: int): int { + this.handler?.onAccess() + return super.indexOf(val, fromIndex) + } + + override toSorted(): Array { + this.handler?.onAccess() + return super.toSorted() + } + + override toSorted(comparator: (a: T, b: T) => number): Array { + this.handler?.onAccess() + return super.toSorted(comparator) + } + + override toReversed(): Array { + this.handler?.onAccess() + return super.toReversed() + } + + override with(index: int, value: T): Array { + this.handler?.onAccess() + return super.with(index, value) + } + + override values(): IterableIterator { + this.handler?.onAccess() + return super.values() + } + + override entries(): IterableIterator<[number, T]> { + this.handler?.onAccess() + return super.entries() + } + + override map(callbackfn: (value: T, index: number, array: Array) => U): Array { + this.handler?.onAccess() + return super.map(callbackfn) + } +} + +class ObservableMap extends Map { + static $_invoke(data: Map, parent?: ObservableHandler, observed?: boolean): Map { + return new ObservableMap(data, parent, observed); + } + + constructor(data: Map, parent?: ObservableHandler, observed?: boolean) { + super() + const handler = new ObservableHandler(parent) + for (let item: [T, V] of data.entries()) { + if (observed === undefined) observed = ObservableHandler.contains(handler) + super.set(item[0], observableProxy(item[1], handler, observed)) + } + ObservableHandler.installOn(this, handler) + } + + private get handler(): ObservableHandler | undefined { + return ObservableHandler.find(this) + } + + override get size(): int { + this.handler?.onAccess() + return super.size + } + + override has(key: T): boolean { + this.handler?.onAccess() + return super.has(key) + } + + override get(key: T): V | undefined { + this.handler?.onAccess() + return super.get(key) + } + + override set(key: T, value: V): this { + const handler = this.handler + if (handler) { + const prev = super.get(key) + if (prev) handler.removeChild(prev) + value = observableProxy(value, handler) + } + super.set(key, value) + handler?.onModify() + return this + } + + override delete(key: T): boolean { + const handler = this.handler + if (handler) { + const value = super.get(key) + if (value) handler.removeChild(value) + } + const result = super.delete(key) + handler?.onModify() + return result + } + + override clear() { + const handler = this.handler + if (handler) { + for (let value of super.values()) { + handler!.removeChild(value) + } + } + super.clear() + handler?.onModify() + } + + override keys(): IterableIterator { + this.handler?.onAccess() + return super.keys() + } + + override values(): IterableIterator { + this.handler?.onAccess() + return super.values() + } + + override $_iterator(): IterableIterator<[T, V]> { + this.handler?.onAccess() + return super.$_iterator() + } + + override entries(): IterableIterator<[T, V]> { + this.handler?.onAccess() + return super.entries() + } + + override forEach(callbackfn: (value: V, key: T, map: Map) => void) { + this.handler?.onAccess() + super.forEach(callbackfn) + } + + override toString(): string { + this.handler?.onAccess() + return super.toString() + } +} + +class ObservableSet extends Set { + private readonly elements: Map + + static $_invoke(data: Set, parent?: ObservableHandler, observed?: boolean): Set { + return new ObservableSet(data, parent, observed); + } + + constructor(data: Set, parent?: ObservableHandler, observed?: boolean) { + this.elements = new Map() + const handler = new ObservableHandler(parent) + for (let item of data.values()) { + if (observed === undefined) observed = ObservableHandler.contains(handler) + this.elements.set(item, observableProxy(item, handler, observed)) + } + ObservableHandler.installOn(this, handler) + } + + private get handler(): ObservableHandler | undefined { + return ObservableHandler.find(this) + } + + override toString(): string { + return new Set(this.elements.keys()).toString() + } + + override get size(): int { + this.handler?.onAccess() + return this.elements.size + } + + override has(value: T): boolean { + this.handler?.onAccess() + return this.elements.has(value) + } + + override add(value: T): this { + const handler = this.handler + let observable = value + let modified = !this.elements.has(value) + if (handler) { + const prev = this.elements.get(value) + if (prev) handler.removeChild(prev) + observable = observableProxy(value) + } + this.elements.set(value, observable) + if (modified) handler?.onModify() + return this + } + + override delete(value: T): boolean { + const handler = this.handler + if (handler) { + const prev = this.elements.get(value) + if (prev) handler.removeChild(prev) + } + const result = this.elements.delete(value) + handler?.onModify() + return result + } + + override clear() { + const handler = this.handler + if (handler) { + for (let value of this.elements.values()) { + handler!.removeChild(value) + } + } + this.elements.clear() + handler?.onModify() + } + + override keys(): IterableIterator { + return this.values() + } + + override values(): IterableIterator { + this.handler?.onAccess() + return this.elements.values() + } + + override $_iterator(): IterableIterator { + return this.values() + } + + override entries(): IterableIterator<[T, T]> { + this.handler?.onAccess() + return new MappingIterator(this.elements.values(), (item) => [item, item]) + } + + override forEach(callbackfn: (value: T, key: T, set: Set) => void) { + this.handler?.onAccess() + const it = this.elements.values() + while (true) { + const item = it.next() + if (item.done) return + callbackfn(item.value as T, item.value as T, this) + } + } +} + +class MappingIterator implements IterableIterator { + private it: IterableIterator + private mapper: (value: T) => V + + constructor(it: IterableIterator, fn: (value: T) => V) { + this.it = it + this.mapper = fn + } + + override next(): IteratorResult { + const item = this.it.next() + if (item.done) return new IteratorResult() + return new IteratorResult(this.mapper(item.value as T)) + } + + override $_iterator(): IterableIterator { + return this + } +} + +class ObservableDate extends Date { + static $_invoke(value: Date, parent?: ObservableHandler, observed?: boolean): Date { + return new ObservableDate(value, parent, observed); + } + + constructor(value: Date, parent?: ObservableHandler, observed?: boolean) { + super(value) + const handler = new ObservableHandler(parent) + ObservableHandler.installOn(this, handler) + } + + private get handler(): ObservableHandler | undefined { + return ObservableHandler.find(this) + } + + override isDateValid(): boolean { + this.handler?.onAccess() + return super.isDateValid() + } + + override valueOf(): number { + this.handler?.onAccess() + return super.valueOf() + } + + override toLocaleTimeString(): string { + this.handler?.onAccess() + return super.toLocaleTimeString() + } + + override toLocaleString(): string { + this.handler?.onAccess() + return super.toLocaleString() + } + + override toLocaleDateString(): string { + this.handler?.onAccess() + return super.toLocaleDateString() + } + + override toISOString(): string { + this.handler?.onAccess() + return super.toISOString() + } + + override toTimeString(): string { + this.handler?.onAccess() + return super.toTimeString() + } + + override toDateString(): string { + this.handler?.onAccess() + return super.toDateString() + } + + override toString(): string { + this.handler?.onAccess() + return super.toString() + } + + override toUTCString(): string { + this.handler?.onAccess() + return super.toUTCString() + } + + override getDate(): number { + this.handler?.onAccess() + return super.getDate() + } + + override setDate(value: byte) { + super.setDate(value) + this.handler?.onModify() + } + + override setDate(value: number): number { + const result = super.setDate(value) + this.handler?.onModify() + return result + } + + override getUTCDate(): number { + this.handler?.onAccess() + return super.getUTCDate() + } + + override setUTCDate(value: byte) { + super.setUTCDate(value) + this.handler?.onModify() + } + + override setUTCDate(value: number): number { + const result = super.setUTCDate(value) + this.handler?.onModify() + return result + } + + override getDay(): number { + this.handler?.onAccess() + return super.getDay() + } + + override setDay(value: byte) { + super.setDay(value) + this.handler?.onModify() + } + + override getUTCDay(): number { + this.handler?.onAccess() + return super.getUTCDay() + } + + override setUTCDay(value: byte) { + super.setUTCDay(value) + this.handler?.onModify() + } + + override setUTCDay(value: number): number { + const result = super.setUTCDay(value) + this.handler?.onModify() + return result + } + + override getMonth(): number { + this.handler?.onAccess() + return super.getMonth() + } + + override setMonth(value: int) { + super.setMonth(value) + this.handler?.onModify() + } + + override setMonth(value: number, date?: number): number { + const result = super.setMonth(value, date) + this.handler?.onModify() + return result + } + + override getUTCMonth(): number { + this.handler?.onAccess() + return super.getUTCMonth() + } + + override setUTCMonth(value: int) { + super.setUTCMonth(value) + this.handler?.onModify() + } + + override setUTCMonth(value: number, date?: number): number { + const result = super.setUTCMonth(value, date) + this.handler?.onModify() + return result + } + + override getYear(): int { + this.handler?.onAccess() + return super.getYear() + } + + override setYear(value: int) { + super.setYear(value) + this.handler?.onModify() + } + + override setYear(value: number) { + super.setYear(value) + this.handler?.onModify() + } + + override getFullYear(): number { + this.handler?.onAccess() + return super.getFullYear() + } + + override setFullYear(value: number, month?: number, date?: number): number { + const result = super.setFullYear(value, month, date) + this.handler?.onModify() + return result + } + + override setFullYear(value: int) { + super.setFullYear(value) + this.handler?.onModify() + } + + override getUTCFullYear(): number { + this.handler?.onAccess() + return super.getUTCFullYear() + } + + override setUTCFullYear(value: number, month?: number, date?: number): number { + const result = super.setUTCFullYear(value, month, date) + this.handler?.onModify() + return result + } + + override setUTCFullYear(value: int) { + super.setUTCFullYear(value) + this.handler?.onModify() + } + + override getTime(): number { + this.handler?.onAccess() + return super.getTime() + } + + override setTime(value: long) { + super.setTime(value) + this.handler?.onModify() + } + + override setTime(value: number): number { + const result = super.setTime(value) + this.handler?.onModify() + return result + } + + override getHours(): number { + this.handler?.onAccess() + return super.getHours() + } + + override setHours(value: number, min?: number, sec?: number, ms?: number): number { + const result = super.setHours(value, min, sec, ms) + this.handler?.onModify() + return result + } + + override setHours(value: byte) { + super.setHours(value) + this.handler?.onModify() + } + + override getUTCHours(): number { + this.handler?.onAccess() + return super.getUTCHours() + } + + override setUTCHours(value: number, min?: number, sec?: number, ms?: number): number { + const result = super.setUTCHours(value, min, sec, ms) + this.handler?.onModify() + return result + } + + override setUTCHours(value: byte) { + super.setUTCHours(value) + this.handler?.onModify() + } + + override getMilliseconds(): number { + this.handler?.onAccess() + return super.getMilliseconds() + } + + override setMilliseconds(value: short) { + super.setMilliseconds(value) + this.handler?.onModify() + } + + override setMilliseconds(value: number): number { + const result = super.setMilliseconds(value) + this.handler?.onModify() + return result + } + + override getUTCMilliseconds(): number { + this.handler?.onAccess() + return super.getUTCMilliseconds() + } + + override setUTCMilliseconds(value: short) { + super.setUTCMilliseconds(value) + this.handler?.onModify() + } + + override setUTCMilliseconds(value: number): number { + const result = super.setUTCMilliseconds(value) + this.handler?.onModify() + return result + } + + override getSeconds(): number { + this.handler?.onAccess() + return super.getSeconds() + } + + override setSeconds(value: byte) { + super.setSeconds(value) + this.handler?.onModify() + } + + override setSeconds(value: number, ms?: number): number { + const result = super.setSeconds(value, ms) + this.handler?.onModify() + return result + } + + override getUTCSeconds(): number { + this.handler?.onAccess() + return super.getUTCSeconds() + } + + override setUTCSeconds(value: byte) { + super.setUTCSeconds(value) + this.handler?.onModify() + } + + override setUTCSeconds(value: number, ms?: number): number { + const result = super.setUTCSeconds(value, ms) + this.handler?.onModify() + return result + } + + override getMinutes(): number { + this.handler?.onAccess() + return super.getMinutes() + } + + override setMinutes(value: byte) { + super.setMinutes(value) + this.handler?.onModify() + } + + override setMinutes(value: number, sec?: Number, ms?: number): number { + const result = super.setMinutes(value, sec, ms) + this.handler?.onModify() + return result + } + + override getUTCMinutes(): number { + this.handler?.onAccess() + return super.getUTCMinutes() + } + + override setUTCMinutes(value: byte) { + super.setUTCMinutes(value) + this.handler?.onModify() + } + + override setUTCMinutes(value: number, sec?: Number, ms?: number): number { + const result = super.setUTCMinutes(value, sec, ms) + this.handler?.onModify() + return result + } +} + +function getClassMetadata(value: T): ClassMetadata | undefined { + return value instanceof ObservableClass ? value.getClassMetadata() : undefined +} + +function isObservedV1Class(value: Object): boolean { + return getClassMetadata(value)?.isObservedV1(value) ?? false +} + +function hasTrackableProperties(value: Object): boolean { + return getClassMetadata(value)?.hasTrackableProperties() ?? false +} + +/** + * Interface for getting the observability status of a class + */ +export interface ObservableClass { + getClassMetadata(): ClassMetadata | undefined +} + +/** + * Interface for checking the observed properties of a class + */ +export interface TrackableProperties { + isTrackable(propertyName: string): boolean +} + +/** + * If value is a class, then returns a list of trackable properties + * @param value + */ +export function trackableProperties(value: T): TrackableProperties | undefined { + return getClassMetadata(value) +} + +export class ClassMetadata implements TrackableProperties { + private readonly parent: ClassMetadata | undefined + private readonly markAsObservedV1: boolean + private readonly markAsObservedV2: boolean + private readonly targetClass: Class + private static readonly metadataPropName = "__classMetadata" + + /** + * Class property names marked with the @Track or @Trace decorator + * @private + */ + private readonly trackableProperties: ReadonlySet | undefined + + /** + * Contains fields marked with the @Type decorator. + * The key of the map is the property name and the value is the typename of the corresponding field. + * @private + */ + private readonly typedProperties: ReadonlyMap | undefined + + constructor(parent: ClassMetadata | undefined, + markAsObservedV1: boolean, + markAsObservedV2: boolean, + trackable: string[] | undefined, + typed: [string, string][] | undefined) { + const target = Class.ofCaller() + if (target == undefined) { + throw new Error("ClassMetadata must be created in the class context") + } + this.targetClass = target! + this.parent = parent + this.markAsObservedV1 = markAsObservedV1 + this.markAsObservedV2 = markAsObservedV2 + if (trackable) { + this.trackableProperties = new Set(trackable) + } + if (typed) { + this.typedProperties = new Map(typed) + } + } + + isObservedV1(value: Object): boolean { + return this.markAsObservedV1 && Class.of(value) == this.targetClass + } + + isObservedV2(value: Object): boolean { + return this.markAsObservedV2 && Class.of(value) == this.targetClass + } + + isTrackable(propertyName: string): boolean { + return (this.trackableProperties?.has(propertyName) || this.parent?.isTrackable(propertyName)) ?? false + } + + hasTrackableProperties(): boolean { + if (this.trackableProperties) { + return this.trackableProperties!.size > 0 + } + return this.parent?.hasTrackableProperties() ?? false + } + + getTypenameTypeDecorator(propertyName: string): string | undefined { + if (this.typedProperties) { + return this.typedProperties?.get(propertyName) + } + if (this.parent) { + return this.parent!.getTypenameTypeDecorator(propertyName) + } + return undefined + } + + static findClassMetadata(type: Type): ClassMetadata | undefined { + if (type instanceof ClassType) { + const fieldsNum = type.getFieldsNum() + for (let i = 0; i < fieldsNum; i++) { + const field = type.getField(i) + if (field.isStatic() && field.getName() == ClassMetadata.metadataPropName) { + const meta = field.getStaticValue() + if (meta != undefined && meta instanceof ClassMetadata) { + return meta + } + break + } + } + } + return undefined + } +} diff --git a/ets1.2/compat/src/arkts/performance.ts b/ets1.2/compat/src/arkts/performance.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b7c1c4dbe10ae6323949240e248bbb0c85fbcbf --- /dev/null +++ b/ets1.2/compat/src/arkts/performance.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +/** + * @returns the number of milliseconds elapsed since midnight, + * January 1, 1970 Universal Coordinated Time (UTC). + */ +export function timeNow(): number { + return Date.now(); +} + +/** + * @param fractionDigits - number of digits after the decimal point [0 - 20] + * @returns a string representing a number in fixed-point notation + */ +export function numberToFixed(value: number, fractionDigits: number): string { + return new Number(value).toFixed(fractionDigits); +} diff --git a/ets1.2/compat/src/arkts/primitive.ts b/ets1.2/compat/src/arkts/primitive.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2555e3d3c157591ada284d7c53eedf651b20beb --- /dev/null +++ b/ets1.2/compat/src/arkts/primitive.ts @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024-2025 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. + */ +import { float32, float64, int32, int64 } from './types'; + +export function float32to64(value: float32): float64 { + return Float.toDouble(value); +} +export function float32toInt32(value: float32): int32 { + return Float.toInt(value); +} +export function float32toInt64(value: float32): int64 { + return Float.toLong(value); +} + +export function float64to32(value: float64): float32 { + return Double.toFloat(value); +} +export function float64toInt32(value: float64): int32 { + return Double.toInt(value); +} +export function float64toInt64(value: float64): int64 { + return Double.toLong(value); +} + +export function int32toFloat32(value: int32): float32 { + return Int.toFloat(value); +} +export function int32toFloat64(value: int32): float64 { + return Int.toDouble(value); +} +export function int32to64(value: int32): int64 { + return Int.toLong(value); +} + +export function int64toFloat32(value: int64): float32 { + return Long.toFloat(value); +} +export function int64toFloat64(value: int64): float64 { + return Long.toDouble(value); +} +export function int64to32(value: int64): int32 { + return Long.toInt(value); +} + +export function asFloat64(value: string): float64 { + return new Number(value).valueOf(); +} diff --git a/ets1.2/compat/src/arkts/prop-deep-copy.ts b/ets1.2/compat/src/arkts/prop-deep-copy.ts new file mode 100644 index 0000000000000000000000000000000000000000..53aa5e2d0d132ad923e75f5d162044e4fa796ef3 --- /dev/null +++ b/ets1.2/compat/src/arkts/prop-deep-copy.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/* + When decorating variables of complex types, + @Prop makes a deep copy, during which all types, + except primitive types, Map, Set, Date, and Array, will be lost. + */ +import { getObservableTarget } from './observable.ts'; + +export function propDeepCopy(sourceObject: T): T { + // at the moment of intergation deepcopy from the stdlib requires a default constructor + // but default constructor is not available for ObservableDate, so we + // add a special case for Date (a parent for ObservableDate) + if (sourceObject instanceof Date) { + const copy: Date = new Date(sourceObject.valueOf()); + return copy as T; + } + return deepcopy(getObservableTarget(sourceObject as Object) as T) as T; +} diff --git a/ets1.2/compat/src/arkts/reflection.ts b/ets1.2/compat/src/arkts/reflection.ts new file mode 100644 index 0000000000000000000000000000000000000000..9768e144ff1124643b20496d1e0c83b07cf7569b --- /dev/null +++ b/ets1.2/compat/src/arkts/reflection.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022-2023 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. + */ +import { className } from './ts-reflection'; + +export function lcClassName(object: Object) { + return className(object).toLowerCase(); +} diff --git a/ets1.2/compat/src/arkts/strings.ts b/ets1.2/compat/src/arkts/strings.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d1d21f5fa641aac0c1a070da1404caa53694e57 --- /dev/null +++ b/ets1.2/compat/src/arkts/strings.ts @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { int32, uint8 } from './types'; +import { Array_from_int32 } from './array'; + +interface SystemTextEncoder { + encode(input?: string): Uint8Array; + encodeInto(src: string, dest: Uint8Array): void; +} + +interface WithStreamOption { + stream: Boolean | undefined; +} + +interface SystemTextDecoder { + decode(input: ArrayBuffer | null | undefined | Uint8Array, options: WithStreamOption | undefined): string; +} + +export class CustomTextEncoder { + static readonly HeaderLen: int32 = Int32Array.BYTES_PER_ELEMENT; + + constructor(encoder: SystemTextEncoder | undefined = undefined) { + this.encoder = encoder; + } + + private readonly encoder: SystemTextEncoder | undefined; + + public static stringLength(input: string): int32 { + let length = 0; + for (let i = 0; i < input.length; i++) { + length++; + let cp = input.codePointAt(i)!; + if (cp >= 0x10000) { + i++; + } + } + return length; + } + + encodedLength(input: string): int32 { + let length = 0; + for (let i = 0; i < input.length; i++) { + let cp = input.codePointAt(i)!; + if (cp < 0x80) { + length += 1; + } else if (cp < 0x800) { + length += 2; + } else if (cp < 0x10000) { + length += 3; + } else { + length += 4; + i++; + } + } + return length; + } + + private addLength(array: Uint8Array, offset: int32, length: int32 | number): void { + const len = length.toInt(); + array.set(offset, len & 0xff); + array.set(offset + 1, (len >> 8) & 0xff); + array.set(offset + 2, (len >> 16) & 0xff); + array.set(offset + 3, (len >> 24) & 0xff); + } + + static getHeaderLength(array: Uint8Array, offset: int32 = 0): int32 { + return ( + array.at(offset)!.toInt() | + array.at((offset + 1) << 8)!.toInt() | + array.at((offset + 2) << 16)!.toInt() | + array.at((offset + 3) << 24)!.toInt() + ); + } + + // Produces array of bytes with encoded string headed by 4 bytes (little endian) size information: + // [s0][s1][s2][s3] [c_0] ... [c_size-1] + encode(input: string | undefined, addLength: boolean = true): Uint8Array { + let headerLen = addLength ? CustomTextEncoder.HeaderLen : 0; + let result: Uint8Array; + if (!input) { + result = new Uint8Array(headerLen); + } else if (this.encoder !== undefined) { + result = this.encoder!.encode('s'.repeat(headerLen) + input); + } else { + let length = this.encodedLength(input); + result = new Uint8Array(length + headerLen); + this.encodeInto(input, result, headerLen); + } + if (addLength) { + this.addLength(result, 0, (result.length - headerLen).toInt()); + } + return result; + } + + // Produces encoded array of strings with size information. + encodeArray(strings: Array): Uint8Array { + let totalBytes = CustomTextEncoder.HeaderLen; + let lengths = new Int32Array(strings.length); + for (let i = 0; i < lengths.length; i++) { + let len = this.encodedLength(strings[i]); + lengths[i] = len; + totalBytes += len + CustomTextEncoder.HeaderLen; + } + let array = new Uint8Array(totalBytes); + let position = 0; + this.addLength(array, position, lengths.length.toInt()); + position += CustomTextEncoder.HeaderLen; + for (let i = 0; i < lengths.length; i++) { + this.addLength(array, position, lengths[i].toInt()); + position += CustomTextEncoder.HeaderLen; + this.encodeInto(strings[i], array, position); + position += lengths[i]; + } + return array; + } + + encodeInto(input: string, result: Uint8Array, position: int32): Uint8Array { + if (this.encoder !== undefined) { + this.encoder!.encodeInto(input, result.subarray(position, result.length)); + return result; + } + let index = position; + for (let stringPosition = 0; stringPosition < input.length; stringPosition++) { + let cp = input.codePointAt(stringPosition)!; + if (cp < 0x80) { + result[index++] = cp | 0; + } else if (cp < 0x800) { + result[index++] = (cp >> 6) | 0xc0; + result[index++] = (cp & 0x3f) | 0x80; + } else if (cp < 0x10000) { + result[index++] = (cp >> 12) | 0xe0; + result[index++] = ((cp >> 6) & 0x3f) | 0x80; + result[index++] = (cp & 0x3f) | 0x80; + } else { + result[index++] = (cp >> 18) | 0xf0; + result[index++] = ((cp >> 12) & 0x3f) | 0x80; + result[index++] = ((cp >> 6) & 0x3f) | 0x80; + result[index++] = (cp & 0x3f) | 0x80; + stringPosition++; + } + } + result[index] = 0; + return result; + } +} + +export class CustomTextDecoder { + static cpArrayMaxSize = 128; + constructor(decoder: SystemTextDecoder | undefined = undefined) { + this.decoder = decoder; + } + + private readonly decoder: SystemTextDecoder | undefined; + + decode(input: Uint8Array): string { + if (this.decoder !== undefined) { + return this.decoder!.decode(input, undefined); + } + + const cpSize = Math.min(CustomTextDecoder.cpArrayMaxSize, input.length); + let codePoints = new Int32Array(cpSize); + let cpIndex = 0; + let index = 0; + let result = ''; + while (index < input.length) { + let elem = input[index].toByte(); + let lead = elem & 0xff; + let count = 0; + let value = 0; + if (lead < 0x80) { + count = 1; + value = elem; + } else if (lead >> 5 == 0x6) { + value = (((elem << 6) & 0x7ff) + (input[index + 1] & 0x3f)).toInt(); + count = 2; + } else if (lead >> 4 == 0xe) { + value = ( + ((elem << 12) & 0xffff) + + ((input[index + 1] << 6) & 0xfff) + + (input[index + 2] & 0x3f) + ).toInt(); + count = 3; + } else if (lead >> 3 == 0x1e) { + value = ( + ((elem << 18) & 0x1fffff) + + ((input[index + 1] << 12) & 0x3ffff) + + ((input[index + 2] << 6) & 0xfff) + + (input[index + 3] & 0x3f) + ).toInt(); + count = 4; + } + codePoints[cpIndex++] = value; + if (cpIndex == cpSize) { + cpIndex = 0; + //result += String.fromCodePoint(...codePoints) + result += String.fromCodePoint(...Array_from_int32(codePoints)); + } + index += count; + } + if (cpIndex > 0) { + result += String.fromCodePoint(...Array_from_int32(codePoints.slice(0, cpIndex))); + } + return result; + } +} diff --git a/ets1.2/compat/src/arkts/ts-reflection.ts b/ets1.2/compat/src/arkts/ts-reflection.ts new file mode 100644 index 0000000000000000000000000000000000000000..90744e2732f8734f9b853d618be61f6a2c8f2b8e --- /dev/null +++ b/ets1.2/compat/src/arkts/ts-reflection.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ + +export function className(object?: Object): string { + return object ? (Type.of(object) as ClassType).getName() : 'null'; +} + +export function isFunction(object?: Object): boolean { + return Type.of(object) instanceof FunctionType; +} + +// Improve: This is an very ad hoc function, +// but I could not find in ArkTS stdlib enough functionality +// for a more generic way. +export function functionOverValue(value: Value | (() => Value)): boolean { + return Type.of(value) instanceof FunctionType; +} + +// Somehow es2panda only allows === on reference types. +export function refEqual(a: Value, b: Value): boolean { + return a == b; +} + +export function isNotPrimitive(value: Object): boolean { + return !Type.of(value).isPrimitive(); +} diff --git a/ets1.2/compat/src/arkts/types.ts b/ets1.2/compat/src/arkts/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..8bb86313d5abdc21d02af732aa4543a0ce522e20 --- /dev/null +++ b/ets1.2/compat/src/arkts/types.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +export type uint8 = byte; +export type int8 = byte; +export type unt16 = short; +export type int16 = short; +export type int32 = int; +export type uint32 = int; +export type int64 = long; +export type uint64 = long; +export type float32 = float; +export type float64 = double; diff --git a/ets1.2/compat/src/arkts/utils.ts b/ets1.2/compat/src/arkts/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..0dd2550bbbe947cc73203e138165acd13bf2ad69 --- /dev/null +++ b/ets1.2/compat/src/arkts/utils.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024-2025 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. + */ + +export function errorAsString(error: Any): string { + if (error instanceof Error) { + const stack = error.stack; + return stack ? error.toString() + '\n' + stack : error.toString(); + } + return JSON.stringify(error); +} + +export function unsafeCast(value: Object): T { + return value as T; +} + +export function scheduleCoroutine(): void { + Coroutine.Schedule(); +} + +export function memoryStats(): string { + return `used ${GC.getUsedHeapSize()} free ${GC.getFreeHeapSize()}`; +} + +export function launchJob(task: () => void): Promise { + return taskpool.execute(task); +} + +export type WorkerLocalValue = WorkerLocal; diff --git a/ets1.2/compat/src/index.ts b/ets1.2/compat/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..83ad0450ee446f522e9e31b840751f5c39c1415b --- /dev/null +++ b/ets1.2/compat/src/index.ts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +export { + asArray, + Array_from_set, + Array_from_int32, + Array_from_number, + AtomicRef, + asFloat64, + Thunk, + finalizerRegister, + finalizerUnregister, + timeNow, + numberToFixed, + Observed, + Observable, + ObservableHandler, + ObservableClass, + TrackableProperties, + trackableProperties, + ClassMetadata, + observableProxy, + observableProxyArray, + propDeepCopy, + lcClassName, + CustomTextEncoder, + CustomTextDecoder, + className, + isFunction, + functionOverValue, + refEqual, + isNotPrimitive, + uint8, + int8, + int16, + int32, + int32toFloat32, + int32toFloat64, + int32to64, + uint32, + int64, + int64toFloat32, + int64toFloat64, + int64to32, + uint64, + float32, + float32to64, + float32toInt32, + float32toInt64, + float64, + float64to32, + float64toInt32, + float64toInt64, + int8Array, + errorAsString, + unsafeCast, + WorkerLocalValue, + scheduleCoroutine, + memoryStats, + launchJob, +} from '#platform'; diff --git a/ets1.2/compat/src/ohos/index.ts b/ets1.2/compat/src/ohos/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4bf6e7fc8d9c82a36b041bbcd5d0dc90c1598e23 --- /dev/null +++ b/ets1.2/compat/src/ohos/index.ts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +export { + asArray, + Array_from_set, + Array_from_int32, + Array_from_number, + AtomicRef, + asFloat64, + Thunk, + finalizerRegister, + finalizerUnregister, + Observed, + Observable, + ObservableHandler, + observableProxy, + ObservableClass, + TrackableProperties, + trackableProperties, + ClassMetadata, + observableProxyArray, + propDeepCopy, + lcClassName, + CustomTextEncoder, + CustomTextDecoder, + className, + isFunction, + functionOverValue, + refEqual, + isNotPrimitive, + uint8, + int8, + int16, + int32, + int32toFloat32, + int32toFloat64, + int32to64, + uint32, + int64, + int64toFloat32, + int64toFloat64, + int64to32, + uint64, + float32, + float32to64, + float32toInt32, + float32toInt64, + float64, + float64to32, + float64toInt32, + float64toInt64, + int8Array, + errorAsString, + unsafeCast, + WorkerLocalValue, + scheduleCoroutine, + memoryStats, + launchJob, +} from '../typescript'; + +export { timeNow, numberToFixed } from './performance'; diff --git a/ets1.2/compat/src/ohos/performance.ts b/ets1.2/compat/src/ohos/performance.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b7c1c4dbe10ae6323949240e248bbb0c85fbcbf --- /dev/null +++ b/ets1.2/compat/src/ohos/performance.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +/** + * @returns the number of milliseconds elapsed since midnight, + * January 1, 1970 Universal Coordinated Time (UTC). + */ +export function timeNow(): number { + return Date.now(); +} + +/** + * @param fractionDigits - number of digits after the decimal point [0 - 20] + * @returns a string representing a number in fixed-point notation + */ +export function numberToFixed(value: number, fractionDigits: number): string { + return new Number(value).toFixed(fractionDigits); +} diff --git a/ets1.2/compat/src/typescript/Types.d.ts b/ets1.2/compat/src/typescript/Types.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4b3ef111fcdd44850f0f397637fed5eea188440 --- /dev/null +++ b/ets1.2/compat/src/typescript/Types.d.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +type int = number; +type long = number; +type float = number; +type double = number; diff --git a/ets1.2/compat/src/typescript/array.ts b/ets1.2/compat/src/typescript/array.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d87e05b0923f9db489afb396b82939e3b481454 --- /dev/null +++ b/ets1.2/compat/src/typescript/array.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +import { float64, int32, int8 } from './types'; + +export function asArray(value: T[]): Array { + return value; +} + +export function Array_from_set(set: Set): Array { + return Array.from(set); +} + +export function Array_from_int32(data: Int32Array): int32[] { + return Array.from(data); +} + +export function Array_from_number(data: float64[]): Array { + return data; +} + +export function int8Array(size: int32): int8[] { + return []; +} diff --git a/ets1.2/compat/src/typescript/atomic.ts b/ets1.2/compat/src/typescript/atomic.ts new file mode 100644 index 0000000000000000000000000000000000000000..6164e189ce7210c8d93f2ef08280ae41cc694bff --- /dev/null +++ b/ets1.2/compat/src/typescript/atomic.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/** + * A reference that may be updated atomically. + */ +export class AtomicRef { + value: Value; + + /** + * Creates a new reference object with the given initial value. + * @param value - the new value + */ + constructor(value: Value) { + this.value = value; + } + + /** + * Atomically sets the reference value to the given value and returns the previous one. + * @param value - the new value + * @returns the previous value + */ + getAndSet(value: Value): Value { + const result = this.value; + this.value = value; + return result; + } +} diff --git a/ets1.2/compat/src/typescript/finalization.ts b/ets1.2/compat/src/typescript/finalization.ts new file mode 100644 index 0000000000000000000000000000000000000000..34d7e8a00ffa053354f1dde8703cf2b4fc5579ec --- /dev/null +++ b/ets1.2/compat/src/typescript/finalization.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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. + */ + +export interface Thunk { + clean(): void; +} + +interface FinalizationRegistry { + register(target: object, value: any, token?: object): void; + unregister(token: object): void; +} + +interface FinalizationRegistryConstructor { + readonly prototype: FinalizationRegistry; + new (callback: (value: any) => void): FinalizationRegistry; +} + +declare const FinalizationRegistry: FinalizationRegistryConstructor; + +const registry = new FinalizationRegistry((thunk: Thunk) => { + thunk.clean(); +}); + +export function finalizerRegister(target: object, thunk: object) { + registry.register(target, thunk); +} + +export function finalizerUnregister(target: object) { + registry.unregister(target); +} diff --git a/ets1.2/compat/src/typescript/index.ts b/ets1.2/compat/src/typescript/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..71ecbdad7c9473ab95e99347f8d8b738498afa83 --- /dev/null +++ b/ets1.2/compat/src/typescript/index.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +export * from './array'; +export * from './atomic'; +export * from './primitive'; +export * from './finalization'; +export * from './observable'; +export * from './performance'; +export * from './prop-deep-copy'; +export * from './reflection'; +export * from './strings'; +export * from './ts-reflection'; +export * from './types'; +export * from './utils'; diff --git a/ets1.2/compat/src/typescript/observable.ts b/ets1.2/compat/src/typescript/observable.ts new file mode 100644 index 0000000000000000000000000000000000000000..affbf61f10f81b476d73eaa237b31520173b14b5 --- /dev/null +++ b/ets1.2/compat/src/typescript/observable.ts @@ -0,0 +1,643 @@ +/* + * 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. + */ + +const OBSERVABLE_TARGET = '__proxy_observable_target__'; + +export function getObservableTarget(proxy: Object): Object { + return getPropertyValue(OBSERVABLE_TARGET, proxy) ?? proxy; +} + +function getPropertyValue(name: string, object: any): any { + return object[name]; +} + +/** + * Data class decorator that makes all child fields trackable. + */ +export function Observed(constructorFunction: Function) { + constructorFunction.prototype[OBSERVED] = true; +} + +const OBSERVED = '__ObservedByArkUI__'; +function isObserved(value: any): boolean { + return value[OBSERVED] === true; +} + +/** @internal */ +export interface Observable { + /** It is called when the observable value is accessed. */ + onAccess(): void; + /** It is called when the observable value is modified. */ + onModify(): void; +} + +/** @internal */ +export class ObservableHandler implements Observable { + private static handlers: WeakMap | undefined = undefined; + + private parents = new Set(); + private children = new Map(); + + private readonly observables = new Set(); + private _modified = false; + + readonly observed: boolean; + constructor(parent?: ObservableHandler, observed: boolean = false) { + this.observed = observed; + if (parent) this.addParent(parent); + } + + onAccess(): void { + if (this.observables.size > 0) { + const it = this.observables.keys(); + while (true) { + const result = it.next(); + if (result.done) break; + result.value?.onAccess(); + } + } + } + + onModify(): void { + const set = new Set(); + this.collect(true, set); + set.forEach((handler: ObservableHandler) => { + handler._modified = true; + if (handler.observables.size > 0) { + const it = handler.observables.keys(); + while (true) { + const result = it.next(); + if (result.done) break; + result.value?.onModify(); + } + } + }); + } + + static dropModified(value: Value): boolean { + const handler = ObservableHandler.findIfObject(value); + if (handler === undefined) return false; + const result = handler._modified; + handler._modified = false; + return result; + } + + /** Adds the specified `observable` to the handler corresponding to the given `value`. */ + static attach(value: Value, observable: Observable): void { + const handler = ObservableHandler.findIfObject(value); + if (handler) handler.observables.add(observable); + } + + /** Deletes the specified `observable` from the handler corresponding to the given `value`. */ + static detach(value: Value, observable: Observable): void { + const handler = ObservableHandler.findIfObject(value); + if (handler) handler.observables.delete(observable); + } + + /** @returns the handler corresponding to the given `value` if it was installed */ + private static findIfObject(value: Value): ObservableHandler | undefined { + const handlers = ObservableHandler.handlers; + return handlers !== undefined && value instanceof Object + ? handlers.get(getObservableTarget(value as Object)) + : undefined; + } + + /** + * @param value - any non-null object including arrays + * @returns an observable handler or `undefined` if it is not installed + */ + static find(value: Object): ObservableHandler | undefined { + const handlers = ObservableHandler.handlers; + return handlers ? handlers.get(getObservableTarget(value)) : undefined; + } + + /** + * @param value - any non-null object including arrays + * @param observable - a handler to install on this object + * @throws an error if observable handler cannot be installed + */ + static installOn(value: Object, observable?: ObservableHandler): void { + let handlers = ObservableHandler.handlers; + if (handlers === undefined) { + handlers = new WeakMap(); + ObservableHandler.handlers = handlers; + } + observable ? handlers.set(getObservableTarget(value), observable) : handlers.delete(getObservableTarget(value)); + } + + addParent(parent: ObservableHandler) { + const count = parent.children.get(this) ?? 0; + parent.children.set(this, count + 1); + this.parents.add(parent); + } + + removeParent(parent: ObservableHandler) { + const count = parent.children.get(this) ?? 0; + if (count > 1) { + parent.children.set(this, count - 1); + } else if (count == 1) { + parent.children.delete(this); + this.parents.delete(parent); + } + } + + removeChild(value: Value) { + const child = ObservableHandler.findIfObject(value); + if (child) child.removeParent(this); + } + + private collect(all: boolean, guards = new Set()) { + if (guards.has(this)) return guards; // already collected + guards.add(this); // handler is already guarded + this.parents.forEach((handler) => handler.collect(all, guards)); + if (all) this.children.forEach((_count, handler) => handler.collect(all, guards)); + return guards; + } + + static contains(observable: ObservableHandler, guards?: Set) { + if (observable.observed) return true; + if (guards === undefined) + guards = new Set(); // create if needed + else if (guards.has(observable)) return false; // already checked + guards.add(observable); // handler is already guarded + for (const it of observable.parents.keys()) { + if (ObservableHandler.contains(it, guards)) return true; + } + return false; + } +} + +/** @internal */ +export function observableProxyArray(...value: Value[]): Array { + return observableProxy(value); +} + +/** @internal */ +export function observableProxy( + value: Value, + parent?: ObservableHandler, + observed?: boolean, + strict = true +): Value { + if (value instanceof ObservableHandler) return value; // do not proxy a marker itself + if (value === null || !(value instanceof Object)) return value; // only non-null object can be observable + const observable = ObservableHandler.find(value); + if (observable) { + if (parent) { + if (strict) observable.addParent(parent); + if (observed === undefined) observed = ObservableHandler.contains(parent); + } + if (observed) { + if (Array.isArray(value)) { + for (let index = 0; index < value.length; index++) { + value[index] = observableProxy(value[index], observable, observed, false); + } + } else { + proxyFields(value, false, observable); + } + } + return value; + } + if (Array.isArray(value)) { + const handler = new ObservableHandler(parent); + const array = proxyChildrenOnly(value, handler, observed); + copyWithinObservable(array); + fillObservable(array); + popObservable(array); + pushObservable(array); + reverseObservable(array); + shiftObservable(array); + sortObservable(array); + spliceObservable(array); + unshiftObservable(array); + return proxyObject(array, handler); + } + if (value instanceof Date) { + const valueAsAny = value as any; + const handler = new ObservableHandler(parent); + const setMethods = new Set([ + 'setFullYear', + 'setMonth', + 'setDate', + 'setHours', + 'setMinutes', + 'setSeconds', + 'setMilliseconds', + 'setTime', + 'setUTCFullYear', + 'setUTCMonth', + 'setUTCDate', + 'setUTCHours', + 'setUTCMinutes', + 'setUTCSeconds', + 'setUTCMilliseconds', + ]); + setMethods.forEach((method: string) => { + const originalMethod = method + 'Original'; + if (valueAsAny[originalMethod] !== undefined) { + return; + } + valueAsAny[originalMethod] = valueAsAny[method]; + valueAsAny[method] = function (...args: any[]) { + ObservableHandler.find(this)?.onModify(); + return this[originalMethod](...args); + }; + }); + return proxyObject(value, handler); + } + if (value instanceof Map) { + const handler = new ObservableHandler(parent); + const data = proxyMapValues(value, handler, observed); + setObservable(data); + deleteObservable(data); + clearObservable(data); + return proxyMapOrSet(data, handler); + } + if (value instanceof Set) { + const handler = new ObservableHandler(parent); + const data = proxySetValues(value, handler, observed); + addObservable(data); + deleteObservable(data); + clearObservable(data); + return proxyMapOrSet(data, handler); + } + const handler = new ObservableHandler(parent, isObserved(value)); + if (handler.observed || observed) proxyFields(value, true, handler); + return proxyObject(value, handler); +} + +function proxyObject(value: any, observable: ObservableHandler) { + ObservableHandler.installOn(value, observable); + return new Proxy(value, { + get(target, property, receiver) { + if (property == OBSERVABLE_TARGET) return target; + const value: any = Reflect.get(target, property, receiver); + ObservableHandler.find(target)?.onAccess(); + return typeof value == 'function' ? value.bind(target) : value; + }, + set(target, property, value, receiver) { + const old = Reflect.get(target, property, receiver); + if (value === old) return true; + const observable = ObservableHandler.find(target); + if (observable) { + observable.onModify(); + observable.removeChild(old); + const observed = ObservableHandler.contains(observable); + if (observed || Array.isArray(target)) { + value = observableProxy(value, observable, observed); + } + } + return Reflect.set(target, property, value, receiver); + }, + deleteProperty(target, property) { + ObservableHandler.find(target)?.onModify(); + delete target[property]; + return true; + }, + }); +} + +function proxyFields(value: any, strict: boolean, parent?: ObservableHandler) { + for (const name of Object.getOwnPropertyNames(value)) { + const descriptor = Object.getOwnPropertyDescriptor(value, name); + if (descriptor?.writable) value[name] = observableProxy(value[name], parent, true, strict); + } +} + +function proxyChildrenOnly(array: any[], parent: ObservableHandler, observed?: boolean): any[] { + if (observed === undefined) observed = ObservableHandler.contains(parent); + return array.map((it) => observableProxy(it, parent, observed)); +} + +function copyWithinObservable(array: any) { + if (array.copyWithinOriginal === undefined) { + array.copyWithinOriginal = array.copyWithin; + array.copyWithin = function (this, target: number, start: number, end?: number) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + return this.copyWithinOriginal(target, start, end); + }; + } +} + +function fillObservable(array: any) { + if (array.fillOriginal === undefined) { + array.fillOriginal = array.fill; + array.fill = function (this, value: any, start?: number, end?: number) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + if (observable) value = observableProxy(value, observable); + return this.fillOriginal(value, start, end); + }; + } +} + +function popObservable(array: any) { + if (array.popOriginal === undefined) { + array.popOriginal = array.pop; + array.pop = function (...args: any[]) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + const result = this.popOriginal(...args); + if (observable) observable.removeChild(result); + return result; + }; + } +} + +function pushObservable(array: any) { + if (array.pushOriginal === undefined) { + array.pushOriginal = array.push; + array.push = function (this, ...args: any[]) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + if (observable) args = proxyChildrenOnly(args, observable); + return this.pushOriginal(...args); + }; + } +} + +function reverseObservable(array: any) { + if (array.reverseOriginal === undefined) { + array.reverseOriginal = array.reverse; + array.reverse = function (this) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + return this.reverseOriginal(); + }; + } +} + +function shiftObservable(array: any) { + if (array.shiftOriginal === undefined) { + array.shiftOriginal = array.shift; + array.shift = function (this, ...args: any[]) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + const result = this.shiftOriginal(...args); + if (observable) observable.removeChild(result); + return result; + }; + } +} + +function sortObservable(array: any) { + if (array.sortOriginal === undefined) { + array.sortOriginal = array.sort; + array.sort = function (this, compareFn?: (a: any, b: any) => number) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + return this.sortOriginal(compareFn); + }; + } +} + +function spliceObservable(array: any) { + if (array.spliceOriginal === undefined) { + array.spliceOriginal = array.splice; + array.splice = function (this, start: number, deleteCount: number, ...items: any[]) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + if (observable) items = proxyChildrenOnly(items, observable); + if (deleteCount === undefined) deleteCount = array.length; + const result = this.spliceOriginal(start, deleteCount, ...items); + if (observable && Array.isArray(result)) { + result.forEach((it) => observable.removeChild(it)); + } + return result; + }; + } +} + +function unshiftObservable(array: any) { + if (array.unshiftOriginal === undefined) { + array.unshiftOriginal = array.unshift; + array.unshift = function (this, ...items: any[]) { + const observable = ObservableHandler.find(this); + observable?.onModify(); + if (observable) items = proxyChildrenOnly(items, observable); + return this.unshiftOriginal(...items); + }; + } +} + +function proxyMapValues(data: Map, parent: ObservableHandler, observed?: boolean): Map { + if (observed === undefined) observed = ObservableHandler.contains(parent); + const result = new Map(); + for (const [key, value] of data.entries()) { + result.set(key, observableProxy(value, parent, observed)); + } + return result; +} + +function proxySetValues(data: Set, parent: ObservableHandler, observed?: boolean): Set { + // Improve: check if necessary to replace items of the set with observed objects as + // for complex objects add() function won't find original object inside the set of proxies + /* + if (observed === undefined) observed = ObservableHandler.contains(parent) + const result = new Set() + for (const value of data.values()) { + result.add(observableProxy(value, parent, observed)) + } + return result + */ + return data; +} + +function proxyMapOrSet(value: any, observable: ObservableHandler) { + ObservableHandler.installOn(value, observable); + return new Proxy(value, { + get(target, property, receiver) { + if (property == OBSERVABLE_TARGET) return target; + if (property == 'size') { + ObservableHandler.find(target)?.onAccess(); + return target.size; + } + const value: any = Reflect.get(target, property, receiver); + ObservableHandler.find(target)?.onAccess(); + return typeof value == 'function' ? value.bind(target) : value; + }, + }); +} + +function addObservable(data: any) { + if (data.addOriginal === undefined) { + data.addOriginal = data.add; + data.add = function (this, value: any) { + const observable = ObservableHandler.find(this); + if (observable && !this.has(value)) { + observable.onModify(); + // Improve: check if necessary to replace items of the set with observed objects as + // for complex objects add() function won't find original object inside the set of proxies + // value = observableProxy(value, observable) + } + return this.addOriginal(value); + }; + } +} + +function setObservable(data: any) { + if (data.setOriginal === undefined) { + data.setOriginal = data.set; + data.set = function (this, key: any, value: any) { + const observable = ObservableHandler.find(this); + if (observable) { + observable.onModify(); + observable.removeChild(this.get(key)); + value = observableProxy(value, observable); + } + return this.setOriginal(key, value); + }; + } +} + +function deleteObservable(data: any) { + if (data.deleteOriginal === undefined) { + data.deleteOriginal = data.delete; + data.delete = function (this, key: any) { + const observable = ObservableHandler.find(this); + if (observable) { + observable.onModify(); + if (this instanceof Map) { + observable.removeChild(this.get(key)); + } else if (this instanceof Set) { + observable.removeChild(key); + } + } + return this.deleteOriginal(key); + }; + } +} + +function clearObservable(data: any) { + if (data.clearOriginal === undefined) { + data.clearOriginal = data.clear; + data.clear = function (this) { + const observable = ObservableHandler.find(this); + if (observable) { + observable.onModify(); + Array.from(this.values()).forEach((it) => observable.removeChild(it)); + } + return this.clearOriginal(); + }; + } +} + +function getClassMetadata(value: any): ClassMetadata | undefined { + if (value !== undefined && typeof value.getClassMetadata === 'function') { + return (value as ObservableClass).getClassMetadata(); + } + return undefined; +} + +/** + * Interface for getting the observability status of a class + */ +export interface ObservableClass { + getClassMetadata(): ClassMetadata | undefined; +} + +/** + * Interface for checking the observed properties of a class + */ +export interface TrackableProperties { + isTrackable(propertyName: string): boolean; +} + +/** + * If value is a class, then returns a list of trackable properties + * @param value + */ +export function trackableProperties(value: T): TrackableProperties | undefined { + return getClassMetadata(value); +} + +export class ClassMetadata implements TrackableProperties { + private readonly parent: ClassMetadata | undefined; + private readonly markAsObservedV1: boolean; + private readonly markAsObservedV2: boolean; + private static readonly metadataPropName = '__classMetadata'; + + /** + * Class property names marked with the @Track or @Trace decorator + * @private + */ + private readonly trackableProperties: ReadonlySet | undefined; + + /** + * Contains fields marked with the @Type decorator. + * The key of the map is the property name and the value is the typename of the corresponding field. + * @private + */ + private readonly typedProperties: ReadonlyMap | undefined; + + constructor( + parent: ClassMetadata | undefined, + markAsObservedV1: boolean, + markAsObservedV2: boolean, + trackable: string[] | undefined, + typed: [string, string][] | undefined + ) { + this.parent = parent; + this.markAsObservedV1 = markAsObservedV1; + this.markAsObservedV2 = markAsObservedV2; + if (trackable) { + this.trackableProperties = new Set(trackable); + } + if (typed) { + this.typedProperties = new Map(typed); + } + } + + isObservedV1(value: Object): boolean { + return this.markAsObservedV1; + } + + isObservedV2(value: Object): boolean { + return this.markAsObservedV2; + } + + isTrackable(propertyName: string): boolean { + return (this.trackableProperties?.has(propertyName) || this.parent?.isTrackable(propertyName)) ?? false; + } + + hasTrackableProperties(): boolean { + if (this.trackableProperties) { + return this.trackableProperties!.size > 0; + } + return this.parent?.hasTrackableProperties() ?? false; + } + + getTypenameTypeDecorator(propertyName: string): string | undefined { + if (this.typedProperties) { + return this.typedProperties?.get(propertyName); + } + if (this.parent) { + return this.parent!.getTypenameTypeDecorator(propertyName); + } + return undefined; + } + + private static findClassMetadata(type: any): ClassMetadata | undefined { + let prototype = Object.getPrototypeOf(type); + while (prototype) { + if (prototype.hasOwnProperty(ClassMetadata.metadataPropName) && prototype.__classMetadata !== undefined) { + return prototype.__classMetadata; + } + prototype = Object.getPrototypeOf(prototype); + } + return undefined; + } +} diff --git a/ets1.2/compat/src/typescript/performance.ts b/ets1.2/compat/src/typescript/performance.ts new file mode 100644 index 0000000000000000000000000000000000000000..64ee6a7528409ade10a0613844e3dc783e341700 --- /dev/null +++ b/ets1.2/compat/src/typescript/performance.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +/** + * @returns the number of milliseconds elapsed since midnight, + * January 1, 1970 Universal Coordinated Time (UTC). + */ +export function timeNow(): number { + return performance.now(); +} + +/** + * @param fractionDigits - number of digits after the decimal point [0 - 20] + * @returns a string representing a number in fixed-point notation + */ +export function numberToFixed(value: number, fractionDigits: number): string { + return value.toFixed(fractionDigits); +} diff --git a/ets1.2/compat/src/typescript/primitive.ts b/ets1.2/compat/src/typescript/primitive.ts new file mode 100644 index 0000000000000000000000000000000000000000..e561639da15d1183bcf4223a59a7696e07b00f41 --- /dev/null +++ b/ets1.2/compat/src/typescript/primitive.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import { float32, float64, int32, int64 } from './types'; + +export function float32to64(value: float32): float64 { + return value; // toDouble() +} +export function float32toInt32(value: float32): int32 { + return value | 0; // toInt() +} +export function float32toInt64(value: float32): int64 { + return Math.trunc(value); // toLong() +} + +export function float64to32(value: float64): float32 { + return value; // toFloat() +} +export function float64toInt32(value: float64): int32 { + return value | 0; // toInt() +} +export function float64toInt64(value: float64): int64 { + return Math.trunc(value); // toLong() +} + +export function int32toFloat32(value: int32): float32 { + return value; // toFloat() +} +export function int32toFloat64(value: int32): float64 { + return value; // toDouble() +} +export function int32to64(value: int32): int64 { + return Math.trunc(value); // toLong() +} + +export function int64toFloat32(value: int64): float32 { + return value; // toFloat() +} +export function int64toFloat64(value: int64): float64 { + return value; // toDouble() +} +export function int64to32(value: int64): int32 { + return value | 0; // toInt() +} + +export function asFloat64(value: string): float64 { + return Number(value); +} diff --git a/ets1.2/compat/src/typescript/prop-deep-copy.ts b/ets1.2/compat/src/typescript/prop-deep-copy.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d92bfb82178a0767f271141fe5e8bc7227d13aa --- /dev/null +++ b/ets1.2/compat/src/typescript/prop-deep-copy.ts @@ -0,0 +1,94 @@ +/* + * 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. + */ + +import { getObservableTarget } from './observable'; + +/* + When decorating variables of complex types, + @Prop makes a deep copy, during which all types, + except primitive types, Map, Set, Date, and Array, will be lost. + */ + +export function propDeepCopy(sourceObject: T): T { + if (!sourceObject || typeof sourceObject !== 'object') { + return sourceObject; + } + + const copiedObjects = new Map(); + return recursiveDeepCopy(sourceObject) as T; + + function recursiveDeepCopy(sourceObject: Object): Object { + if (!sourceObject || typeof sourceObject !== 'object') { + return sourceObject; + } + + const storedObject = copiedObjects.get(sourceObject); + if (storedObject !== undefined) { + return storedObject; + } + + const copy: any = copyDeepTrackable(sourceObject); + + const objectToCopyFrom = getObservableTarget(sourceObject); + Object.keys(objectToCopyFrom).forEach((key) => { + const property = objectToCopyFrom[key as keyof Object]; + + if (typeof property === 'function') { + Reflect.set(copy, key, property); + copy[key] = copy[key].bind(copy); + return; + } + Reflect.set(copy, key, recursiveDeepCopy(property)); + }); + + return copy; + } + + function copyDeepTrackable(sourceObject: T): T { + if (sourceObject instanceof Set) { + const copy = new Set(); + Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)); + copiedObjects.set(sourceObject, copy); + for (const setKey of sourceObject.keys()) { + copy.add(recursiveDeepCopy(setKey)); + } + return copy as T; + } + if (sourceObject instanceof Map) { + const copy = new Map(); + Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)); + copiedObjects.set(sourceObject, copy); + for (const mapKey of sourceObject.keys()) { + copy.set(mapKey, recursiveDeepCopy(sourceObject.get(mapKey))); + } + return copy as T; + } + if (sourceObject instanceof Date) { + const copy = new Date(); + copy.setTime(sourceObject.getTime()); + Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)); + copiedObjects.set(sourceObject, copy); + return copy as T; + } + if (sourceObject instanceof Object) { + const copy = Array.isArray(sourceObject) ? [] : {}; + Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)); + copiedObjects.set(sourceObject, copy); + return copy as T; + } + + return sourceObject; + } +} diff --git a/ets1.2/compat/src/typescript/reflection.ts b/ets1.2/compat/src/typescript/reflection.ts new file mode 100644 index 0000000000000000000000000000000000000000..9768e144ff1124643b20496d1e0c83b07cf7569b --- /dev/null +++ b/ets1.2/compat/src/typescript/reflection.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022-2023 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. + */ +import { className } from './ts-reflection'; + +export function lcClassName(object: Object) { + return className(object).toLowerCase(); +} diff --git a/ets1.2/compat/src/typescript/strings.ts b/ets1.2/compat/src/typescript/strings.ts new file mode 100644 index 0000000000000000000000000000000000000000..264154f995859e0a073f69f2b327eb43572dff06 --- /dev/null +++ b/ets1.2/compat/src/typescript/strings.ts @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { int32 } from './types'; + +interface SystemTextEncoder { + encode(input?: string): Uint8Array; + encodeInto(src: string, dest: Uint8Array): void; +} + +interface WithStreamOption { + stream?: boolean | undefined; +} + +interface SystemTextDecoder { + decode(input?: ArrayBuffer | null, options?: WithStreamOption): string; +} + +export class CustomTextEncoder { + static readonly HeaderLen: int32 = Int32Array.BYTES_PER_ELEMENT; + + constructor( + encoder: SystemTextEncoder | undefined = typeof TextEncoder != 'undefined' ? new TextEncoder() : undefined + ) { + this.encoder = encoder; + } + + private readonly encoder: SystemTextEncoder | undefined; + + public static stringLength(input: string): int32 { + let length = 0; + for (let i = 0; i < input.length; i++) { + length++; + let cp = input.codePointAt(i)!; + if (cp >= 0x10000) { + i++; + } + } + return length; + } + + encodedLength(input: string): int32 { + let length = 0; + for (let i = 0; i < input.length; i++) { + let cp = input.codePointAt(i)!; + if (cp < 0x80) { + length += 1; + } else if (cp < 0x800) { + length += 2; + } else if (cp < 0x10000) { + length += 3; + } else { + length += 4; + i++; + } + } + return length; + } + + private addLength(array: Uint8Array, offset: int32, len: int32): void { + array[offset] = len & 0xff; + array[offset + 1] = (len >> 8) & 0xff; + array[offset + 2] = (len >> 16) & 0xff; + array[offset + 3] = (len >> 24) & 0xff; + } + + static getHeaderLength(array: Uint8Array, offset: int32 = 0): int32 { + return array[offset] | (array[offset + 1] << 8) | (array[offset + 2] << 16) | (array[offset + 3] << 24); + } + + // Produces array of bytes with encoded string headed by 4 bytes (little endian) size information: + // [s0][s1][s2][s3] [c_0] ... [c_size-1] + encode(input: string | undefined, addLength: boolean = true): Uint8Array { + let headerLen = addLength ? CustomTextEncoder.HeaderLen : 0; + let result: Uint8Array; + if (!input) { + result = new Uint8Array(headerLen); + } else if (this.encoder !== undefined) { + result = this.encoder!.encode('s'.repeat(headerLen) + input); + } else { + let length = this.encodedLength(input); + result = new Uint8Array(length + headerLen); + this.encodeInto(input, result, headerLen); + } + if (addLength) { + this.addLength(result, 0, result.length - headerLen); + } + return result; + } + + // Produces encoded array of strings with size information. + encodeArray(strings: Array): Uint8Array { + let totalBytes = CustomTextEncoder.HeaderLen; + let lengths = new Int32Array(strings.length); + for (let i = 0; i < lengths.length; i++) { + let len = this.encodedLength(strings[i]); + lengths[i] = len; + totalBytes += len + CustomTextEncoder.HeaderLen; + } + let array = new Uint8Array(totalBytes); + let position = 0; + this.addLength(array, position, lengths.length); + position += CustomTextEncoder.HeaderLen; + for (let i = 0; i < lengths.length; i++) { + this.addLength(array, position, lengths[i]); + position += CustomTextEncoder.HeaderLen; + this.encodeInto(strings[i], array, position); + position += lengths[i]; + } + return array; + } + + encodeInto(input: string, result: Uint8Array, position: int32): Uint8Array { + if (this.encoder !== undefined) { + this.encoder!.encodeInto(input, result.subarray(position, result.length)); + return result; + } + let index = position; + for (let stringPosition = 0; stringPosition < input.length; stringPosition++) { + let cp = input.codePointAt(stringPosition)!; + if (cp < 0x80) { + result[index++] = cp | 0; + } else if (cp < 0x800) { + result[index++] = (cp >> 6) | 0xc0; + result[index++] = (cp & 0x3f) | 0x80; + } else if (cp < 0x10000) { + result[index++] = (cp >> 12) | 0xe0; + result[index++] = ((cp >> 6) & 0x3f) | 0x80; + result[index++] = (cp & 0x3f) | 0x80; + } else { + result[index++] = (cp >> 18) | 0xf0; + result[index++] = ((cp >> 12) & 0x3f) | 0x80; + result[index++] = ((cp >> 6) & 0x3f) | 0x80; + result[index++] = (cp & 0x3f) | 0x80; + stringPosition++; + } + } + result[index] = 0; + return result; + } +} + +export class CustomTextDecoder { + static cpArrayMaxSize = 128; + constructor( + decoder: SystemTextDecoder | undefined = typeof TextDecoder != 'undefined' ? new TextDecoder() : undefined + ) { + this.decoder = decoder; + } + + private readonly decoder: SystemTextDecoder | undefined; + + decode(input: Uint8Array): string { + if (this.decoder !== undefined) { + return this.decoder!.decode(input); + } + const cpSize = Math.min(CustomTextDecoder.cpArrayMaxSize, input.length); + let codePoints = new Int32Array(cpSize); + let cpIndex = 0; + let index = 0; + let result = ''; + while (index < input.length) { + let elem = input[index]; + let lead = elem & 0xff; + let count = 0; + let value = 0; + if (lead < 0x80) { + count = 1; + value = elem; + } else if (lead >> 5 == 0x6) { + value = ((elem << 6) & 0x7ff) + (input[index + 1] & 0x3f); + count = 2; + } else if (lead >> 4 == 0xe) { + value = ((elem << 12) & 0xffff) + ((input[index + 1] << 6) & 0xfff) + (input[index + 2] & 0x3f); + count = 3; + } else if (lead >> 3 == 0x1e) { + value = + ((elem << 18) & 0x1fffff) + + ((input[index + 1] << 12) & 0x3ffff) + + ((input[index + 2] << 6) & 0xfff) + + (input[index + 3] & 0x3f); + count = 4; + } + codePoints[cpIndex++] = value; + if (cpIndex == cpSize) { + cpIndex = 0; + result += String.fromCodePoint(...codePoints); + } + index += count; + } + if (cpIndex > 0) { + result += String.fromCodePoint(...codePoints.slice(0, cpIndex)); + } + return result; + } +} diff --git a/ets1.2/compat/src/typescript/ts-reflection.ts b/ets1.2/compat/src/typescript/ts-reflection.ts new file mode 100644 index 0000000000000000000000000000000000000000..68d76e32e6cf66fc8ed0a46dd470c169b9a5a871 --- /dev/null +++ b/ets1.2/compat/src/typescript/ts-reflection.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ + +export function className(object?: Object): string { + return object?.constructor.name ?? ''; +} + +export function isFunction(object?: Object): boolean { + return typeof object === 'function'; +} + +// Improve: this is to match arkts counterpart +export function functionOverValue(value: Value | (() => Value)): boolean { + return typeof value === 'function'; +} + +export function refEqual(a: Value, b: Value): boolean { + return a === b; +} + +export function isNotPrimitive(value: Object): boolean { + return true; +} diff --git a/ets1.2/compat/src/typescript/types.ts b/ets1.2/compat/src/typescript/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ca487641c4b1e461de0fa209ee4dec0bd53bf41 --- /dev/null +++ b/ets1.2/compat/src/typescript/types.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +/// +export type uint8 = int; +export type int8 = int; +export type int16 = int; +export type int32 = int; +export type uint32 = int; +export type int64 = long; +export type uint64 = long; +export type float32 = float; +export type float64 = double; + +export {}; +declare global { + export interface Number { + toByte(): int; + toShort(): int; + toInt(): int; + toLong(): long; + toFloat(): float; + toDouble(): double; + } +} +Number.prototype.toByte = function () { + return this as Number | 0 as number; +}; + +Number.prototype.toShort = function () { + return this as Number | 0 as number; +}; + +Number.prototype.toInt = function () { + return this as Number | 0 as number; +}; + +Number.prototype.toLong = function () { + return this as Number | 0 as number; +}; + +Number.prototype.toFloat = function () { + return this as number; +}; + +Number.prototype.toDouble = function () { + return this as number; +}; diff --git a/ets1.2/compat/src/typescript/utils.ts b/ets1.2/compat/src/typescript/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..4574ef04d42a166addda9d92903d18a37caeeaf3 --- /dev/null +++ b/ets1.2/compat/src/typescript/utils.ts @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024-2025 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. + */ + +import { AtomicRef } from './atomic'; + +export function errorAsString(error: any): string { + if (error instanceof Error) { + return error.stack ?? error.toString(); + } + return JSON.stringify(error); +} + +export function unsafeCast(value: unknown): T { + return value as unknown as T; +} + +export function scheduleCoroutine(): void {} + +export function memoryStats(): string { + return `none`; +} + +export function launchJob(task: () => void): Promise { + return new Promise((resolve, reject) => { + try { + task(); + resolve(undefined); + } catch (error) { + reject(error); + } + }); +} + +export class WorkerLocalValue { + private ref?: AtomicRef; + + /** + * @param init - a factory function to provide initial worker-local value if needed + */ + constructor(private init?: () => T) {} + + /** + * @returns the worker-local value for current worker + * @throws `Error` when value not initialized and no `init` function provided + */ + get(): T { + const ref = this.ref; + if (ref) return ref.value; + const init = this.init; + if (!init) throw new Error('WorkerLocalValue not initialized: call set() first or provide init() function.'); + const value = init(); + this.ref = new AtomicRef(value); + return value; + } + + /** + * Updates the worker-local value for current worker. + * @param value - new value to store + */ + set(value: T) { + const ref = this.ref; + if (ref) { + ref.value = value; + } else { + this.ref = new AtomicRef(value); + } + } + + /** + * Deletes the worker-local value for current worker. + */ + delete() { + this.ref = undefined; + } +} diff --git a/ets1.2/compat/tsconfig.json b/ets1.2/compat/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..595bc28a0a80e17714720a214ec119cb15774206 --- /dev/null +++ b/ets1.2/compat/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@koalaui/build-common/tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": ".", + "outDir": "build/", + "module": "CommonJS", + "paths": { + "#platform": ["./src/typescript"] + } + }, + "include": ["./src/index.ts", "./src/typescript/**/*"] +} diff --git a/ets1.2/compat/ui2abcconfig.json b/ets1.2/compat/ui2abcconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..fcb140e0b5d235f8337b881d9c3763f10e618a33 --- /dev/null +++ b/ets1.2/compat/ui2abcconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "package": "@koalaui/compat", + "outDir": "build/abc", + "rootDir": "./src/arkts", + "baseUrl": "./src/arkts", + "paths": { + "#platform": ["./"], + "@koalaui/compat": ["../"] + } + }, + "include": ["src/arkts/**/*.ts"] +} diff --git a/ets1.2/gn/command/npm_util.py b/ets1.2/gn/command/npm_util.py new file mode 100755 index 0000000000000000000000000000000000000000..c6b6809cfa12b8dcbdcbe03f3bbfd69eb9a3b507 --- /dev/null +++ b/ets1.2/gn/command/npm_util.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2025 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. + +import argparse +import shutil +import subprocess +import os +import sys + +NPM_REPO = "https://repo.huaweicloud.com/repository/npm/" + +parser = argparse.ArgumentParser(description="npm command parser") +parser.add_argument("--project-path", help="project directory in koala repo") +parser.add_argument("--node-path", help="nodejs path") +parser.add_argument("--arklink-path", help="ark-link path") +parser.add_argument("--es2panda-path", help="es2panda path") +parser.add_argument("--stdlib-path", help="stdlib path") +parser.add_argument("--target-out-path", help="out directory of built target") +parser.add_argument("--built-file-path", help="result of building") +parser.add_argument("--install", action="store_true", help="request npm install") +parser.add_argument("--install-path", help="path to install in") +parser.add_argument("--run-tasks", nargs='+', help="npm run tasks") + +args = parser.parse_args() + +project_path = args.project_path +koala_log = os.path.join(project_path, "koala_build.log") + +if args.node_path is None: + print("Error: --node-path is expected") + sys.exit(1) + +os.environ["PATH"] = f"{args.node_path}:{os.environ['PATH']}" + +if args.es2panda_path: + os.environ["ES2PANDA_PATH"] = args.es2panda_path +if args.arklink_path: + os.environ["ARKLINK_PATH"] = args.arklink_path +if args.stdlib_path: + os.environ["ETS_STDLIB_PATH"] = args.stdlib_path + +os.environ["PANDA_SDK_PATH"] = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../ui2abc/build/sdk") + +def run(npm_args, dir = None): + os.chdir(dir or project_path) + + if os.environ.get("KOALA_LOG_STDOUT"): + subprocess.run(["npm"] + npm_args, env=os.environ, text=True, check=True, stderr=subprocess.STDOUT) + return + + result = subprocess.run(["npm"] + npm_args, capture_output=True, env=os.environ, text=True) + with open(koala_log, "a+") as f: + f.write(f"npm args: {npm_args}; project: {project_path}:\n" + result.stdout) + if result.returncode != 0: + f.write(f"npm args: {npm_args}; project: {project_path}:\n" + result.stderr) + print(open(koala_log, "r").read()) + raise Exception("npm failed") + f.close() + +def install(dir = None): + run(["install", "--registry", NPM_REPO, "--verbose"], dir or project_path) + +def copy_target(): + if not os.path.exists(args.built_file_path): + print(f"Error: Built file not found at {args.built_file_path}") + sys.exit(1) + shutil.copy(args.built_file_path, args.target_out_path) + +def main(): + if args.install: + install(args.install_path) + if args.run_tasks: + for task in args.run_tasks: + run(["run", task]) + if args.target_out_path and args.built_file_path: + copy_target() + +if __name__ == '__main__': + main() diff --git a/ets1.2/gn/config/BUILD.gn b/ets1.2/gn/config/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b798729a84ddb23c282a7ef3bba288e74952285e --- /dev/null +++ b/ets1.2/gn/config/BUILD.gn @@ -0,0 +1,33 @@ +# Copyright (c) 2025 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. + +config("compiler_defaults") { + if (current_os == "linux") { + cflags = [ + "-fPIC", + "-pthread", + ] + cflags_cc = [ + "-std=c++17", + ] + } +} + +config("executable_ldconfig") { + if (!is_mac) { + ldflags = [ + "-Wl,-rpath=\$ORIGIN/", + "-Wl,-rpath-link=", + ] + } +} \ No newline at end of file diff --git a/ets1.2/gn/config/BUILDCONFIG.gn b/ets1.2/gn/config/BUILDCONFIG.gn new file mode 100644 index 0000000000000000000000000000000000000000..4497405f205c87f27230df7936f4777b4a289a61 --- /dev/null +++ b/ets1.2/gn/config/BUILDCONFIG.gn @@ -0,0 +1,59 @@ +# Copyright (c) 2025 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. + +if (target_os == "") { + target_os = host_os +} +if (target_cpu == "") { + target_cpu = host_cpu +} +if (current_cpu == "") { + current_cpu = target_cpu +} +if (current_os == "") { + current_os = target_os +} + +_shared_binary_target_configs = [ "//gn/config:compiler_defaults" ] +set_defaults("executable") { + configs = _shared_binary_target_configs + configs += [ "//gn/config:executable_ldconfig" ] +} +set_defaults("static_library") { + configs = _shared_binary_target_configs +} +set_defaults("shared_library") { + configs = _shared_binary_target_configs +} +set_defaults("source_set") { + configs = _shared_binary_target_configs +} +set_default_toolchain("//gn/toolchain:clang") + +koala_mr = { + root_path = "//." + scripts_path = "$root_path/gn/script" + imports_prefix = "$root_path/gn/import" + ui2abc_path = "$root_path/ui2abc" + libarkts_path = "$ui2abc_path/libarkts" + incremental_path = "$root_path/incremental" + panda_sdk_path = "$incremental_path/tools/panda/node_modules/@panda/sdk" + es2panda_path = "$panda_sdk_path/ohos_arm64/include/tools/es2panda" + interop_path = "$root_path/interop" + is_rri = true +} + +host_toolchain = "//gn/toolchain:clang" + +is_linux = host_os == "linux" && current_os == "linux" && target_os == "linux" +is_mac = host_os == "mac" && current_os == "mac" && target_os == "mac" \ No newline at end of file diff --git a/ets1.2/gn/import/npm.gni b/ets1.2/gn/import/npm.gni new file mode 100644 index 0000000000000000000000000000000000000000..0a60c64e95c9ef787b386524d90b4bc783fe9dd6 --- /dev/null +++ b/ets1.2/gn/import/npm.gni @@ -0,0 +1,82 @@ +# Copyright (c) 2025 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. + +if (!defined(koala_mr)) { + # OHOS build tree workaround + import("../../../koala_integration.gni") +} + +template("npm_cmd") { + if (!defined(invoker.panda_sdk_path)) { + invoker.panda_sdk_path = rebase_path(koala_mr.panda_sdk_path) + } + action("$target_name") { + script = "${koala_mr.scripts_path}/npm.py" + if (!defined(invoker.outputs)) { + outputs = [ + "$target_out_dir/$target_name" + ] + } else { + outputs = invoker.outputs + } + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.inputs)) { + inputs = invoker.inputs + } + if (defined(invoker.external_deps)) { + external_deps = invoker.external_deps + } + + args = [ + "--project-path", invoker.project_path + ] + if (defined(invoker.panda_sdk_path)) { + args += [ "--panda-sdk-path", invoker.panda_sdk_path ] + } + if (defined(invoker.koala_node_path)) { + args += [ "--node-path", invoker.koala_node_path ] + } + if (defined(invoker.target_out_path)) { + args += [ "--target-out-path", invoker.target_out_path ] + } + if (defined(invoker.built_file_path)) { + args += [ "--built-file-path", invoker.built_file_path ] + } + if (defined(invoker.install) && invoker.install) { + args += [ "--install" ] + } + if (defined(invoker.install_path)) { + args += [ "--install-path", invoker.install_path ] + } + if (defined(invoker.run_tasks)) { + args += [ "--run-tasks" ] + invoker.run_tasks + } + } +} + +template("npm_install") { + forward_variables_from(invoker, "*") + npm_cmd(target_name) { + if (!defined(sources)) { + sources = [ + "$project_path/package.json" + ] + } + install = true + } +} \ No newline at end of file diff --git a/ets1.2/gn/npm_util.gni b/ets1.2/gn/npm_util.gni new file mode 100644 index 0000000000000000000000000000000000000000..bf1f906cd36a03192b2931e51ecc5d6504678f08 --- /dev/null +++ b/ets1.2/gn/npm_util.gni @@ -0,0 +1,63 @@ +# Copyright (c) 2025 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. + +import("//build/config/components/ets_frontend/ets2abc_config.gni") + +node_version = "v16.20.2" +host_arch = "${host_os}-${host_cpu}" + +template("npm_cmd") { + action("$target_name") { + script = "//foundation/arkui/ace_engine/frameworks/bridge/arkts_frontend/koala_mirror/gn/command/npm_util.py" + outputs = invoker.outputs + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.inputs)) { + inputs = invoker.inputs + } + if (defined(invoker.external_deps)) { + external_deps = invoker.external_deps + } + args = [ + "--node-path", rebase_path("//prebuilts/build-tools/common/nodejs/node-${node_version}-${host_arch}/bin"), + "--arklink-path", rebase_path("${static_linker_build_path}"), + "--es2panda-path", rebase_path("${ets2abc_build_path}"), + "--stdlib-path", rebase_path("//arkcompiler/runtime_core/static_core/plugins/ets/stdlib"), + "--project-path", invoker.project_path + ] + if (defined(invoker.target_out_path)) { + args += [ "--target-out-path", invoker.target_out_path ] + } + if (defined(invoker.built_file_path)) { + args += [ "--built-file-path", invoker.built_file_path ] + } + if (defined(invoker.install) && invoker.install) { + args += [ "--install" ] + } + if (defined(invoker.install_path)) { + args += [ "--install-path", invoker.install_path ] + } + if (defined(invoker.run_tasks)) { + args += [ "--run-tasks" ] + invoker.run_tasks + } + } +} + +template("npm_install") { + assert(current_toolchain == host_toolchain, "must be executed with host_toolchain") + forward_variables_from(invoker, "*") + npm_cmd(target_name) { + install = true + } +} \ No newline at end of file diff --git a/ets1.2/gn/script/npm.py b/ets1.2/gn/script/npm.py new file mode 100755 index 0000000000000000000000000000000000000000..09499e0083aca2ec169a68e5ef40d903596dacd3 --- /dev/null +++ b/ets1.2/gn/script/npm.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2025 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. + +import argparse +import shutil +import subprocess +import os +import sys + +NPM_REPO = "https://repo.huaweicloud.com/repository/npm/" + +parser = argparse.ArgumentParser(description="npm command parser") +parser.add_argument("--project-path", help="project directory in koala repo") +parser.add_argument("--node-path", help="nodejs path") +parser.add_argument("--arklink-path", help="ark-link path") +parser.add_argument("--es2panda-path", help="es2panda path") +parser.add_argument("--stdlib-path", help="stdlib path") +parser.add_argument("--target-out-path", help="out directory of built target") +parser.add_argument("--built-file-path", help="result of building") +parser.add_argument("--install", action="store_true", help="request npm install") +parser.add_argument("--install-path", help="path to install in") +parser.add_argument("--run-tasks", nargs='+', help="npm run tasks") +parser.add_argument("--panda-sdk-path", help="panda sdk path") + +args = parser.parse_args() + +project_path = args.project_path +koala_log = os.path.join(project_path, "koala_build.log") + +koala_node_path = args.node_path or (os.path.dirname(shutil.which("node")) if shutil.which("node") else None) +if koala_node_path: + os.environ["PATH"] = f"{koala_node_path}:{os.environ.get('PATH', '')}" +else: + print("Error: Node.js is not found in the system PATH, and --node-path is not provided") + sys.exit(1) + +if args.es2panda_path: + os.environ["ES2PANDA_PATH"] = args.es2panda_path +if args.arklink_path: + os.environ["ARKLINK_PATH"] = args.arklink_path +if args.stdlib_path: + os.environ["ETS_STDLIB_PATH"] = args.stdlib_path +if args.panda_sdk_path: + os.environ["PANDA_SDK_PATH"] = args.panda_sdk_path + +def run(npm_args, dir = None): + os.chdir(dir or project_path) + + if os.environ.get("KOALA_LOG_STDOUT"): + subprocess.run(["npm"] + npm_args, env=os.environ, text=True, check=True, stderr=subprocess.STDOUT) + return + result = subprocess.run(["npm"] + npm_args, capture_output=True, env=os.environ, text=True) + with open(koala_log, "a+") as f: + f.write(f"npm args: {npm_args}; project: {project_path}:\n" + result.stdout) + if result.returncode != 0: + f.write(f"npm args: {npm_args}; project: {project_path}:\n" + result.stderr) + print(open(koala_log, "r").read()) + raise Exception("npm failed") + f.close() + +def install(dir = None): + run(["install", "--registry", NPM_REPO, "--verbose"], dir or project_path) + +def copy_target(): + if not os.path.exists(args.built_file_path): + print(f"Error: Built file not found at {args.built_file_path}") + sys.exit(1) + shutil.copy(args.built_file_path, args.target_out_path) + +def main(): + if args.install: + install(args.install_path) + if args.run_tasks: + for task in args.run_tasks: + run(["run", task]) + if args.target_out_path and args.built_file_path: + copy_target() + +if __name__ == '__main__': + main() diff --git a/ets1.2/gn/toolchain/BUILD.gn b/ets1.2/gn/toolchain/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e5e4c8a5fbab479137e4ec0f6777e4fed5693665 --- /dev/null +++ b/ets1.2/gn/toolchain/BUILD.gn @@ -0,0 +1,85 @@ +# Copyright (c) 2025 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. + +toolchain("clang") { + tool("cc") { + depfile = "{{output}}.d" + command = "clang -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CC {{output}}" + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] + } + tool("cxx") { + depfile = "{{output}}.d" + command = "clang++ -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CXX {{output}}" + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] + } + tool("alink") { + command = "ar rcs {{output}} {{inputs}}" + description = "AR {{target_output_name}}{{output_extension}}" + outputs = + [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ] + default_output_extension = ".a" + output_prefix = "lib" + } + tool("solink") { + soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". + sofile = "{{output_dir}}/$soname" + rspfile = soname + ".rsp" + if (is_mac) { + os_specific_option = "-install_name @executable_path/$sofile" + rspfile_content = "{{inputs}} {{solibs}} {{libs}}" + } else { + os_specific_option = "-Wl,-soname=$soname" + rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}" + } + command = "clang++ -shared {{ldflags}} -o $sofile $os_specific_option @$rspfile" + description = "SOLINK $soname" + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_extension = ".so" + # Use this for {{output_dir}} expansions unless a target manually overrides + # it (in which case {{output_dir}} will be what the target specifies). + default_output_dir = "{{root_out_dir}}" + outputs = [ sofile ] + link_output = sofile + depend_output = sofile + output_prefix = "lib" + } + tool("link") { + outfile = "{{target_output_name}}{{output_extension}}" + rspfile = "$outfile.rsp" + if (is_mac) { + command = "clang++ {{ldflags}} -o $outfile @$rspfile {{solibs}} {{libs}}" + } else { + command = "clang++ {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}" + } + description = "LINK $outfile" + default_output_dir = "{{root_out_dir}}" + rspfile_content = "{{inputs}}" + outputs = [ outfile ] + } + tool("stamp") { + command = "touch {{output}}" + description = "STAMP {{output}}" + } + tool("copy") { + command = "cp -af {{source}} {{output}}" + description = "COPY {{source}} {{output}}" + } +} \ No newline at end of file diff --git a/ets1.2/interop/.clang-format b/ets1.2/interop/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..35740da59029fdf79b010223eca5b755f7e5af06 --- /dev/null +++ b/ets1.2/interop/.clang-format @@ -0,0 +1,107 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakAfterJavaFieldAnnotations: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +ReflowComments: true +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^"(base|core|elements|rendering|adapter|dsl|frameworks|resource|accessibility|bridge)/' + Priority: 3 + - Regex: '<*>' + Priority: 1 + - Regex: '.*' + Priority: 2 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 39 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 80 +PointerAlignment: Left +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/ets1.2/interop/.gitignore b/ets1.2/interop/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..44a0964582ad20972cb3bc522a25f96c04a00484 --- /dev/null +++ b/ets1.2/interop/.gitignore @@ -0,0 +1 @@ +*.ini \ No newline at end of file diff --git a/ets1.2/interop/BUILD.gn b/ets1.2/interop/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c9d60bc5857553d4b3817645a419088c89964b83 --- /dev/null +++ b/ets1.2/interop/BUILD.gn @@ -0,0 +1,57 @@ +# Copyright (c) 2025 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. + +if (!defined(koala_mr)) { + # OHOS build tree workaround + import("../../koala_integration.gni") +} +if (!koala_mr.is_rri) { + import("//build/config/components/ets_frontend/ets2abc_config.gni") + import("//build/ohos.gni") + import("//foundation/arkui/ace_engine/ace_config.gni") +} +import("${koala_mr.imports_prefix}/npm.gni") + +if (current_toolchain == host_toolchain) { + npm_install("interop_install") { + outputs = [ + "$target_out_dir/interop_install" + ] + project_path = rebase_path(".") + } +} + +npm_cmd("interop.abc") { + outputs = [ + "$target_out_dir/interop.abc" + ] + project_path = rebase_path(".") + run_tasks = [ "build" ] + + deps = [ + "${koala_mr.ui2abc_path}:ui2abc" + ] + + if (!koala_mr.is_rri) { + external_deps = [ + ets2abc_build_deps, + static_linker_build_deps + ] + } +} + +group("interop") { + deps = [ + "${koala_mr.interop_path}:interop.abc" + ] +} \ No newline at end of file diff --git a/ets1.2/interop/meson_options.txt b/ets1.2/interop/meson_options.txt new file mode 100644 index 0000000000000000000000000000000000000000..0496ac5b57ad30cdc0f1aba0508d6ded4765b766 --- /dev/null +++ b/ets1.2/interop/meson_options.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2025 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. + +option('vm_kind', type : 'string', value : '', + description : 'VM type') +option('jdk_dir', type : 'string', value : '', + description : 'A path to JDK root') +option('vmloader', type : 'boolean', value : false, + description : 'Whether to build libvmloader.so') +option('vmloader_apis', type : 'string', value : 'ets', + description : 'APIs to use in libvmloader.so') diff --git a/ets1.2/interop/package.json b/ets1.2/interop/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ba1d33e3d28a0bd8fadc70f248f1d1a1c9bc196a --- /dev/null +++ b/ets1.2/interop/package.json @@ -0,0 +1,114 @@ +{ + "name": "@koalaui/interop", + "version": "1.7.10+devel", + "description": "", + "workspaces": [ + "../incremental/build-common", + "../incremental/compat", + "../incremental/common", + "../ui2abc/fast-arktsc" + ], + "files": [ + "build/lib/src/**/*.js", + "build/lib/src/**/*.d.ts", + "src/**/*", + "index.ts" + ], + "main": "./build/lib/src/interop/index.js", + "exports": { + ".": "./build/lib/src/interop/index.js", + "./*.js": "./build/lib/src/interop/*.js", + "./*": "./build/lib/src/interop/*.js" + }, + "imports": { + "#common/wrappers": { + "browser": "./build/lib/src/wasm/wrappers/index.js", + "node": "./build/lib/src/napi/wrappers/index.js" + }, + "#common/wrappers/*": { + "browser": "./build/lib/src/wasm/wrappers/*.js", + "node": "./build/lib/src/napi/wrappers/*.js", + "default": "./build/lib/src/napi/wrappers/*.js" + } + }, + "types": "index.d.ts", + "typesVersions": { + "*": { + "*": [ + "./build/lib/src/interop/*" + ] + } + }, + "scripts": { + "clean": "rimraf dist build types", + "compile": "ets-tsc -b .", + "compile:release": "ets-tsc -b .", + "build": "node ../ui2abc/fast-arktsc --config ./ui2abcconfig.json --compiler ../incremental/tools/panda/arkts/ui2abc --link-name ./build/interop.abc --simultaneous && ninja ${NINJA_OPTIONS} -f build/abc/build.ninja", + "lint": "eslint src test components", + "test:wasm:coverage": "NODE_OPTIONS='--conditions browser --no-experimental-fetch' nyc mocha", + "test:wasm": "NODE_OPTIONS='--conditions browser --no-experimental-fetch' mocha", + "test:node:coverage": "nyc mocha", + "test:node": "mocha", + "test:coverage": "npm run test:node:coverage", + "test": "npm run test:node", + "watch": "ets-tsc -b . --watch", + "prepare:compiler": "test $(node -e \"console.log(process.platform)\") != \"linux\" && npm run --prefix ../arkoala-arkts/ohos-sdk download || npm run install:toolchain --prefix ../arkoala-arkts/tools/compiler", + "prepare:arm64": "npm run prepare:compiler && npm run install:sysroot:arm64 --prefix ../arkoala-arkts/tools/compiler", + "prepare:arm32": "npm run prepare:compiler && npm run install:sysroot:arm32 --prefix ../arkoala-arkts/tools/compiler", + "configure:native-node-host": "meson setup -D vm_kind=node build-node-host", + "compile:native-node-host": "npm run configure:native-node-host && meson compile -C build-node-host && meson install -C build-node-host", + "configure:native-hzvm-host": "meson setup -D vm_kind=hzvm build-hzvm-host", + "compile:native-hzvm-host": "npm run configure:native-hzvm-host && meson compile -C build-hzvm-host && meson install -C build-hzvm-host", + "configure:native-panda-host": "meson setup -D vm_kind=panda build-panda-host", + "compile:native-panda-host": "npm run configure:native-panda-host && meson compile -C build-panda-host && meson install -C build-panda-host", + "configure:native-kotlin-host": "meson setup -D vm_kind=kotlin build-kotlin-host", + "compile:native-kotlin-host": "npm run configure:native-kotlin-host && meson compile -C build-kotlin-host && meson install -C build-kotlin-host", + "configure:native-panda-linux-x64": "node ./scripts/configure.mjs panda-linux-x64", + "compile:native-panda-linux-x64": "npm run configure:native-panda-linux-x64 && meson compile -C build-panda-linux-x64 && meson install -C build-panda-linux-x64", + "configure:native-panda-linux-arm64": "node ./scripts/configure.mjs panda-linux-arm64", + "compile:native-panda-linux-arm64": "npm run configure:native-panda-linux-arm64 && meson compile -C build-panda-linux-arm64 && meson install -C build-panda-linux-arm64", + "configure:native-panda-windows-x64": "node ./scripts/configure.mjs panda-windows-x64", + "compile:native-panda-windows-x64": "npm run configure:native-panda-windows-x64 && meson compile -C build-panda-windows-x64 && meson install -C build-panda-windows-x64", + "configure:native-panda-macos-x64": "node ./scripts/configure.mjs panda-macos-x64", + "compile:native-panda-macos-x64": "npm run configure:native-panda-macos-x64 && meson compile -C build-panda-macos-x64 && meson install -C build-panda-macos-x64", + "configure:native-panda-macos-arm64": "node ./scripts/configure.mjs panda-macos-arm64", + "compile:native-panda-macos-arm64": "npm run configure:native-panda-macos-arm64 && meson compile -C build-panda-macos-arm64 && meson install -C build-panda-macos-arm64", + "configure:native-jvm-host": "meson setup -D vm_kind=jvm build-jvm-host -D vmloader=true -D jdk_dir=$JAVA_HOME", + "compile:native-jvm-host": "npm run configure:native-jvm-host && meson compile -C build-jvm-host && meson install -C build-jvm-host", + "configure:native-hzvm-ohos-arm64": "npm run prepare:arm64 && node ./scripts/configure.mjs hzvm-ohos-arm64", + "compile:native-hzvm-ohos-arm64": "npm run configure:native-hzvm-ohos-arm64 && meson compile -C build-hzvm-ohos-arm64 && meson install -C build-hzvm-ohos-arm64", + "configure:native-hzvm-ohos-arm32": "npm run prepare:arm32 && node ./scripts/configure.mjs hzvm-ohos-arm32", + "compile:native-hzvm-ohos-arm32": "npm run configure:native-hzvm-ohos-arm32 && meson compile -C build-hzvm-ohos-arm32 && meson install -C build-hzvm-ohos-arm32", + "configure:native-hzvm-ohos": "npm run configure:native-hzvm-ohos-arm64", + "compile:native-hzvm-ohos": "npm run compile:native-hzvm-ohos-arm64", + "configure:native-panda-ohos-arm64": "npm run prepare:arm64 && node ./scripts/configure.mjs panda-ohos-arm64", + "compile:native-panda-ohos-arm64": "npm run configure:native-panda-ohos-arm64 && meson compile -C build-panda-ohos-arm64 && meson install -C build-panda-ohos-arm64", + "configure:native-panda-ohos-arm32": "npm run prepare:arm32 && node ./scripts/configure.mjs panda-ohos-arm32", + "compile:native-panda-ohos-arm32": "npm run configure:native-panda-ohos-arm32 && meson compile -C build-panda-ohos-arm32 && meson install -C build-panda-ohos-arm32", + "configure:native-panda-with-node-host": "npm run configure:native-panda-host && meson setup -D vm_kind=node -D vmloader=true build-node-host-vmloader", + "compile:native-panda-with-node-host": "npm run configure:native-panda-with-node-host && npm run compile:native-panda-host && npm run compile:native-panda-host && meson compile -C build-node-host-vmloader && meson install -C build-node-host-vmloader", + "configure:native-panda-with-hzvm-ohos-arm64": "npm run configure:native-panda-ohos-arm64 && node ./scripts/configure.mjs hzvm-ohos-arm64-vmloader", + "compile:native-panda-with-hzvm-ohos-arm64": "npm run configure:native-panda-with-hzvm-ohos-arm64 && npm run compile:native-panda-ohos-arm64 && meson compile -C build-hzvm-ohos-arm64-vmloader && meson install -C build-hzvm-ohos-arm64-vmloader", + "configure:native-panda-with-hzvm-ohos-arm32": "npm run configure:native-panda-ohos-arm32 && node ./scripts/configure.mjs hzvm-ohos-arm32-vmloader", + "compile:native-panda-with-hzvm-ohos-arm32": "npm run configure:native-panda-with-hzvm-ohos-arm32 && npm run compile:native-panda-ohos-arm32 && meson compile -C build-hzvm-ohos-arm32-vmloader && meson install -C build-hzvm-ohos-arm32-vmloader", + "compile:kotlin:cinterop": "cd src/cpp/kotlin && cinterop -def cinterop-interop_native_module.def -pkg cinterop.interop_native_module -compiler-option -I. -o ../../../build/kotlin-interop/cinterop.interop_native_module", + "compile:kotlin:kt": "konanc ./src/kotlin/*.kt -l ./build/kotlin-interop/cinterop.interop_native_module.klib -p library -o ./build/kotlin-interop/interop", + "compile:kotlin:interop": "rm -rf build/kotlin-interop && npm run compile:kotlin:cinterop && npm run compile:kotlin:kt", + "format:src:ts": "npx prettier --config .prettierrc --write \"./src/**/*.ts\"" + }, + "keywords": [], + "dependencies": { + "@types/node": "^18.0.0", + "@koalaui/common": "1.7.10+devel" + }, + "devDependencies": { + "@ohos/hypium": "1.0.6", + "@types/node": "^18.0.0", + "@typescript-eslint/eslint-plugin": "^5.20.0", + "@typescript-eslint/parser": "^5.20.0", + "eslint": "^8.13.0", + "eslint-plugin-unused-imports": "^2.0.0", + "source-map-support": "^0.5.21", + "@koalaui/ets-tsc": "4.9.5-r5" + } +} diff --git a/ets1.2/interop/src/arkts/DeserializerBase.ts b/ets1.2/interop/src/arkts/DeserializerBase.ts new file mode 100644 index 0000000000000000000000000000000000000000..5388affb8487f62b7aaa2df9110bd01b9ac77790 --- /dev/null +++ b/ets1.2/interop/src/arkts/DeserializerBase.ts @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2024-2025 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. + */ + +import { float32, int32, int64 } from "@koalaui/common" +import { pointer, KUint8ArrayPtr, KSerializerBuffer, nullptr } from "./InteropTypes" +import { NativeBuffer } from "./NativeBuffer" +import { InteropNativeModule } from "./InteropNativeModule" +import { Tags, CallbackResource } from "./SerializerBase"; +import { ResourceHolder, Disposable } from "./ResourceManager" + +export class DeserializerBase implements Disposable { + private _position : int64 = 0 + private _buffer: KSerializerBuffer + private readonly _isOwnBuffer: boolean; + private readonly _length: int32 + private readonly _end: int64 + private static customDeserializers: CustomDeserializer | undefined = new DateDeserializer() + + static registerCustomDeserializer(deserializer: CustomDeserializer) { + let current = DeserializerBase.customDeserializers + if (current == undefined) { + DeserializerBase.customDeserializers = deserializer + } else { + while (current!.next != undefined) { + current = current!.next + } + current!.next = deserializer + } + } + + constructor(buffer: KUint8ArrayPtr|KSerializerBuffer, length: int32) { + if (buffer instanceof KUint8ArrayPtr) { + const newBuffer = InteropNativeModule._Malloc(length) + this._isOwnBuffer = true + for (let i = 0; i < length; i++) { + unsafeMemory.writeInt8(newBuffer + i, buffer[i].toByte()) + } + this._buffer = newBuffer + } else { + this._buffer = buffer + } + + const newBuffer = this._buffer; + this._length = length + this._position = newBuffer + this._end = newBuffer + length; + } + + public final dispose() { + if (this._isOwnBuffer) { + InteropNativeModule._Free(this._buffer) + this._buffer = 0 + this._position = 0 + } + } + + final asBuffer(): KSerializerBuffer { + return this._buffer + } + + final currentPosition(): int64 { + return this._position + } + + final resetCurrentPosition(): void { + this._position = this._buffer + } + + final readInt8(): int32 { + const pos = this._position + const newPos = pos + 1 + + if (newPos > this._end) { + throw new Error(`value size(1) is less than remaining buffer length`) + } + + this._position = newPos + return unsafeMemory.readInt8(pos) + } + + final readInt32(): int32 { + const pos = this._position + const newPos = pos + 4 + + if (newPos > this._end) { + throw new Error(`value size(4) is less than remaining buffer length`) + } + + this._position = newPos + return unsafeMemory.readInt32(pos) + } + + final readPointer(): pointer { + const pos = this._position + const newPos = pos + 8 + + if (newPos > this._end) { + throw new Error(`value size(8) is less than remaining buffer length`) + } + + this._position = newPos + return unsafeMemory.readInt64(pos) + } + + final readInt64(): int64 { + const pos = this._position + const newPos = pos + 8 + + if (newPos > this._end) { + throw new Error(`value size(8) is less than remaining buffer length`) + } + + this._position = newPos + return unsafeMemory.readInt64(pos) + } + + final readFloat32(): float32 { + const pos = this._position + const newPos = pos + 4 + + if (newPos > this._end) { + throw new Error(`value size(4) is less than remaining buffer length`) + } + + + this._position = newPos + return unsafeMemory.readFloat32(pos) + } + + final readFloat64(): double { + const pos = this._position + const newPos = pos + 8 + + if (newPos > this._end) { + throw new Error(`value size(8) is less than remaining buffer length`) + } + + + this._position = newPos + return unsafeMemory.readFloat64(pos) + } + + final readBoolean(): boolean { + const pos = this._position + const newPos = pos + 1 + + if (newPos > this._end) { + throw new Error(`value size(1) is less than remaining buffer length`) + } + + + this._position = newPos + const value = unsafeMemory.readInt8(pos); + if (value == Tags.UNDEFINED) + return false; + + return value == 1 + } + + final readCallbackResource(): CallbackResource { + return { + resourceId: this.readInt32(), + hold: this.readPointer(), + release: this.readPointer(), + } + } + + final readString(): string { + const encodedLength = this.readInt32(); + const pos = this._position + const newPos = pos + encodedLength + + if (newPos > this._end) { + throw new Error(`value size(${encodedLength}) is less than remaining buffer length`) + } + + this._position = newPos + // NOTE: skip null-terminated byte + return unsafeMemory.readString(pos, encodedLength - 1) + } + + final readCustomObject(kind: string): object { + let current = DeserializerBase.customDeserializers + while (current) { + if (current!.supports(kind)) { + return current!.deserialize(this, kind) + } + current = current!.next + } + // consume tag + const tag = this.readInt8() + throw Error(`${kind} is not supported`) + } + + final readNumber(): number | undefined { + const pos = this._position + const tag = this.readInt8().toInt() + switch (tag) { + case Tags.UNDEFINED.valueOf(): + return undefined; + case Tags.INT32.valueOf(): + return this.readInt32() + case Tags.FLOAT32.valueOf(): + return this.readFloat32() + default: + throw new Error(`Unknown number tag: ${tag}`) + } + } + + final readObject():object { + const resource = this.readCallbackResource() + return ResourceHolder.instance().get(resource.resourceId) + } + + final readBuffer(): ArrayBuffer { + const resource = this.readCallbackResource() + const data = this.readPointer() + const length = this.readInt64() + InteropNativeModule._CallCallbackResourceHolder(resource.hold, resource.resourceId) + return InteropNativeModule._MaterializeBuffer(data, length, resource.resourceId, resource.hold, resource.release) + } +} + +export abstract class CustomDeserializer { + protected supported: string + protected constructor(supported_: string) { + this.supported = supported_ + } + + supports(kind: string): boolean { + return this.supported.includes(kind) + } + + abstract deserialize(serializer: DeserializerBase, kind: string): object + + next: CustomDeserializer | undefined = undefined +} + +class DateDeserializer extends CustomDeserializer { + constructor() { + super("Date") + } + + deserialize(serializer: DeserializerBase, kind: string): Date { + return new Date(serializer.readString()) + } +} \ No newline at end of file diff --git a/ets1.2/interop/src/arkts/Finalizable.ts b/ets1.2/interop/src/arkts/Finalizable.ts new file mode 100644 index 0000000000000000000000000000000000000000..80a7c5fbb81c328279f45716137db4b2e67e1a97 --- /dev/null +++ b/ets1.2/interop/src/arkts/Finalizable.ts @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025 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. + */ + +import { finalizerRegister, finalizerUnregister, Thunk } from '@koalaui/common'; +import { InteropNativeModule } from './InteropNativeModule'; +import { pointer, nullptr } from './InteropTypes'; + +class NativeThunk implements Thunk { + finalizer: pointer; + obj: pointer; + name: string | undefined; + + constructor(obj: pointer, finalizer: pointer, name?: string) { + this.finalizer = finalizer; + this.obj = obj; + this.name = name; + } + + clean() { + if (this.obj != nullptr) { + this.destroyNative(this.obj, this.finalizer); + } + this.obj = nullptr; + } + + destroyNative(ptr: pointer, finalizer: pointer): void { + InteropNativeModule._InvokeFinalizer(ptr, finalizer); + } +} + +/** + * Class with the custom finalizer, usually used to release a native peer. + * Do not use directly, only via subclasses. + */ +export class Finalizable { + ptr: pointer; + finalizer: pointer; + cleaner: NativeThunk | undefined = undefined; + managed: boolean; + + constructor(ptr: pointer, finalizer: pointer) { + this.init(ptr, finalizer, true); + } + + constructor(ptr: pointer, finalizer: pointer, managed: boolean) { + this.init(ptr, finalizer, managed); + } + + init(ptr: pointer, finalizer: pointer, managed: boolean) { + this.ptr = ptr; + this.finalizer = finalizer; + this.managed = managed; + const handle = undefined; + + if (managed) { + if (this.ptr == nullptr) throw new Error("Can't have nullptr ptr ${}"); + if (this.finalizer == nullptr) throw new Error('Managed finalizer is 0'); + + const thunk = new NativeThunk(ptr, finalizer, handle); + finalizerRegister(this, thunk); + this.cleaner = thunk; + } + } + + close() { + if (this.ptr == nullptr) { + throw new Error(`Closing a closed object: ` + this.toString()); + } else if (this.cleaner == undefined) { + throw new Error(`No thunk assigned to ` + this.toString()); + } else { + finalizerUnregister(this); + this.cleaner!.clean(); + this.cleaner = undefined; + this.ptr = nullptr; + } + } + + release(): pointer { + finalizerUnregister(this); + if (this.cleaner) this.cleaner!.obj = nullptr; + let result = this.ptr; + this.ptr = nullptr; + return result; + } + + resetPeer(pointer: pointer) { + if (this.managed) throw new Error('Can only reset peer for an unmanaged object'); + this.ptr = pointer; + } + + use(body: (value: Finalizable) => R): R { + let result = body(this); + this.close(); + return result; + } +} diff --git a/ets1.2/interop/src/arkts/InteropNativeModule.ts b/ets1.2/interop/src/arkts/InteropNativeModule.ts new file mode 100644 index 0000000000000000000000000000000000000000..53a57ef9756141ecda2e651845c3fb89dcacb04d --- /dev/null +++ b/ets1.2/interop/src/arkts/InteropNativeModule.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 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. +*/ + +import { int32, int64 } from "@koalaui/common"; +import { KPointer, KUint8ArrayPtr, KInt, KSerializerBuffer } from "./InteropTypes"; +import { callCallback } from "./callback" +import { loadNativeModuleLibrary } from "./loadLibraries" + +export class InteropNativeModule { + static { + loadNativeModuleLibrary("InteropNativeModule") + } + static callCallbackFromNative(id: KInt, args: KSerializerBuffer, length: KInt): KInt { + return callCallback(id, args, length) + } + native static _GetGroupedLog(index: int32): KPointer + native static _StartGroupedLog(index: int32): void + native static _StopGroupedLog(index: int32): void + native static _AppendGroupedLog(index: int32, message: string): void + native static _PrintGroupedLog(index: int32): void + native static _GetStringFinalizer(): KPointer + native static _InvokeFinalizer(ptr1: KPointer, ptr2: KPointer): void + native static _IncrementNumber(value: number): number + native static _GetPtrVectorElement(ptr1: KPointer, arg: int32): KPointer + native static _StringLength(ptr1: KPointer): int32 + native static _StringData(ptr1: KPointer, array: KUint8ArrayPtr, arrayLength: int32): void + native static _StringMake(str1: string): KPointer + native static _GetPtrVectorSize(ptr1: KPointer): int32 + @ani.unsafe.Quick + native static _ManagedStringWrite(str1: string, array: KPointer, arrayLength: int32, arg: int32): int32 + native static _NativeLog(str1: string): void + @ani.unsafe.Quick + native static _Utf8ToString(data: KPointer, offset: int32, length: int32): string + native static _StdStringToString(cstring: KPointer): string + @ani.unsafe.Direct + native static _CheckCallbackEvent(buffer: KSerializerBuffer, bufferLength: int32): int32 + native static _HoldCallbackResource(resourceId: int32): void + native static _ReleaseCallbackResource(resourceId: int32): void + native static _CallCallback(apiKind: int32, callbackKind: int32, args: KSerializerBuffer, argsSize: int32): void + native static _CallCallbackSync(apiKind: int32, callbackKind: int32, args: KSerializerBuffer, argsSize: int32): void + native static _CallCallbackResourceHolder(holder: KPointer, resourceId: int32): void + native static _CallCallbackResourceReleaser(releaser: KPointer, resourceId: int32): void + native static _CallbackAwait(pipeline: KPointer): Object + native static _UnblockCallbackWait(pipeline: KPointer): void + + native static _LoadVirtualMachine(arg0: int32, arg1: string, arg2: string, arg3: string): int32 + native static _RunApplication(arg0: int32, arg1: int32): boolean + native static _StartApplication(appUrl: string, appParams: string): KPointer + native static _EmitEvent(eventType: int32, target: int32, arg0: int32, arg1: int32): string + native static _CallForeignVM(context:KPointer, callback: int32, data: KSerializerBuffer, dataLength: int32): int32 + native static _SetForeignVMContext(context: KPointer): void + native static _RestartWith(page: string): void + @ani.unsafe.Direct + native static _ReadByte(data: KPointer, index: int64, length: int64): int32 + @ani.unsafe.Direct + native static _WriteByte(data: KPointer, index: int64, length: int64, value: int32): void + @ani.unsafe.Direct + native static _Malloc(length: int64): KPointer + @ani.unsafe.Direct + native static _GetMallocFinalizer(): KPointer + @ani.unsafe.Direct + native static _Free(data: KPointer): void + @ani.unsafe.Quick + native static _CopyArray(data: KPointer, length: int64, args: KUint8ArrayPtr): void + native static _ReportMemLeaks(): void + native static _MaterializeBuffer(data: KPointer, length: int64, resourceId: int32, hold: KPointer, release: KPointer): ArrayBuffer + native static _GetNativeBufferPointer(data: ArrayBuffer): KPointer +} + diff --git a/ets1.2/interop/src/arkts/InteropTypes.ts b/ets1.2/interop/src/arkts/InteropTypes.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd701ed30f77eecf78e1295ca0f83ecb251f2c32 --- /dev/null +++ b/ets1.2/interop/src/arkts/InteropTypes.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ + +export type NodePointer = pointer; // Improve: move to NativeModule + +export type KStringPtr = string; +export type KStringPtrArray = FixedArray; +export type KUint8ArrayPtr = FixedArray; +export type KInt32ArrayPtr = FixedArray; +export type KFloat32ArrayPtr = FixedArray; +export type KInt = int; +export type KLong = long; +export type KUInt = KInt; +export type KBoolean = int; +export type KFloat = float; +export type KDouble = double; +export type KPointer = long; // look once again +export type pointer = KPointer; +export type KNativePointer = KPointer; +export type KInteropReturnBuffer = FixedArray; +export type KSerializerBuffer = pointer; + +export const nullptr: pointer = 0; diff --git a/ets1.2/interop/src/arkts/MaterializedBase.ts b/ets1.2/interop/src/arkts/MaterializedBase.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e5a69b3da759efe5ea0436a12595b6e27237f48 --- /dev/null +++ b/ets1.2/interop/src/arkts/MaterializedBase.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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. + */ + +import { Finalizable } from './Finalizable'; + +export class MaterializedBaseTag { + static NOP = new MaterializedBaseTag(); + private constructor() {} +} + +export interface MaterializedBase { + getPeer(): Finalizable | undefined; +} diff --git a/ets1.2/interop/src/arkts/NativeBuffer.ts b/ets1.2/interop/src/arkts/NativeBuffer.ts new file mode 100644 index 0000000000000000000000000000000000000000..a6dceba23ff04f82cdbffaad4704570fe023580d --- /dev/null +++ b/ets1.2/interop/src/arkts/NativeBuffer.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 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. + */ + +import { pointer, KSerializerBuffer, nullptr } from './InteropTypes' +import { int32, int64 } from '@koalaui/common' +import { InteropNativeModule } from "./InteropNativeModule" +import { Disposable } from "./ResourceManager" +import { Finalizable } from './Finalizable' + +export final class NativeBuffer { + public data: pointer + public length: int64 + protected finalizable: Finalizable + + constructor(length: int64) { + this(InteropNativeModule._Malloc(length), length, InteropNativeModule._GetMallocFinalizer()) + } + + constructor(data: pointer, length: int64, destroy: pointer) { + this.data = data + this.length = length + this.finalizable = new Finalizable(data, destroy) + } + + public readByte(index:int64): int32 { + return unsafeMemory.readInt8(this.data + index) + } + + public writeByte(index:int64, value: int32): void { + unsafeMemory.writeInt8(this.data + index, value.toByte()) + } +} + +export class KBuffer implements Disposable { + private _buffer: KSerializerBuffer + private readonly _length: int64 + private readonly _owned: boolean + constructor(length: int64) { + this._buffer = InteropNativeModule._Malloc(length) + this._length = length + this._owned = true + } + constructor(buffer: KSerializerBuffer, length: int64) { + this._buffer = buffer + this._length = length + this._owned = false + } + + dispose(): void { + if (this._owned && this._buffer != nullptr) { + InteropNativeModule._Free(this._buffer) + this._buffer = nullptr + } + } + + public get buffer(): KSerializerBuffer { + return this._buffer + } + + public get length(): int64 { + return this._length + } + + public get(index: int64): byte { + return unsafeMemory.readInt8(this._buffer + index) + } + public set(index: int64, value: byte): void { + unsafeMemory.writeInt8(this._buffer + index, value) + } +} \ No newline at end of file diff --git a/ets1.2/interop/src/arkts/ResourceManager.ts b/ets1.2/interop/src/arkts/ResourceManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..39fb006a6c677d5aae3541342d24b36b316b90e7 --- /dev/null +++ b/ets1.2/interop/src/arkts/ResourceManager.ts @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { int32, float64toInt32 } from '@koalaui/common'; + +export type ResourceId = int32; + +interface ResourceInfo { + resource: object; + holdersCount: int32; +} + +export interface Disposable { + dispose(): void; +} + +export class ResourceHolder { + private static nextResourceId: ResourceId = 100; + private resources: Map = new Map(); + private static _instance: ResourceHolder | undefined = undefined; + private static disposables = new Array(); + private static disposablesSize = 0; + + static instance(): ResourceHolder { + if (ResourceHolder._instance == undefined) { + ResourceHolder._instance = new ResourceHolder(); + } + return ResourceHolder._instance!; + } + + public hold(resourceId: ResourceId) { + if (!this.resources.has(resourceId)) throw new Error(`Resource ${resourceId} does not exists, can not hold`); + this.resources.get(resourceId)!.holdersCount++; + } + + public release(resourceId: ResourceId) { + if (!this.resources.has(resourceId)) throw new Error(`Resource ${resourceId} does not exists, can not release`); + const resource = this.resources.get(resourceId)!; + resource.holdersCount--; + if (resource.holdersCount <= 0) this.resources.delete(resourceId); + } + + public registerAndHold(resource: object): ResourceId { + const resourceId = ResourceHolder.nextResourceId++; + this.resources.set(resourceId, { + resource: resource, + holdersCount: 1, + }); + return resourceId; + } + + public get(resourceId: ResourceId): object { + if (!this.resources.has(resourceId)) throw new Error(`Resource ${resourceId} does not exists`); + return this.resources.get(resourceId)!.resource; + } + + public has(resourceId: ResourceId): boolean { + return this.resources.has(resourceId); + } + + static register(resource: Disposable) { + if (ResourceHolder.disposablesSize < ResourceHolder.disposables.length) { + ResourceHolder.disposables[ResourceHolder.disposablesSize] = resource; + } else { + ResourceHolder.disposables.push(resource); + } + ResourceHolder.disposablesSize++; + } + + static unregister(resource: Disposable) { + const index = float64toInt32(ResourceHolder.disposables.indexOf(resource)); + if (index !== -1 && index < ResourceHolder.disposablesSize) { + if (index !== ResourceHolder.disposablesSize - 1) { + ResourceHolder.disposables[index] = ResourceHolder.disposables[ResourceHolder.disposablesSize - 1]; + } + ResourceHolder.disposablesSize--; + } + } + + static disposeAll() { + for (let i = 0; i < ResourceHolder.disposablesSize; ++i) { + ResourceHolder.disposables[i].dispose(); + } + ResourceHolder.disposablesSize = 0; + } + + static compactDisposables() { + ResourceHolder.disposables = ResourceHolder.disposables.slice(0, ResourceHolder.disposablesSize); + } +} diff --git a/ets1.2/interop/src/arkts/SerializerBase.ts b/ets1.2/interop/src/arkts/SerializerBase.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae500b0756307195afa49dd946ac380992e02c96 --- /dev/null +++ b/ets1.2/interop/src/arkts/SerializerBase.ts @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2024-2025 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. + */ +import { float32, int32, int64 } from "@koalaui/common" +import { pointer, nullptr, KSerializerBuffer } from "./InteropTypes" +import { ResourceId, ResourceHolder, Disposable } from "./ResourceManager" +import { NativeBuffer } from "./NativeBuffer" +import { InteropNativeModule } from "./InteropNativeModule" +import { MaterializedBase } from "./MaterializedBase" + +/** + * Value representing possible JS runtime object type. + * Must be synced with "enum RuntimeType" in C++. + */ +export final class RuntimeType { + static readonly UNEXPECTED = -1 + static readonly NUMBER = 1 + static readonly STRING = 2 + static readonly OBJECT = 3 + static readonly BOOLEAN = 4 + static readonly UNDEFINED = 5 + static readonly BIGINT = 6 + static readonly FUNCTION = 7 + static readonly SYMBOL = 8 + static readonly MATERIALIZED = 9 +} + +export function registerCallback(value: object): int32 { + throw new Error("Should no longer be used") +} + +/** + * Value representing object type in serialized data. + * Must be synced with "enum Tags" in C++. + */ +export enum Tags { + UNDEFINED = 101, + INT32 = 102, + FLOAT32 = 103, + STRING = 104, + LENGTH = 105, + RESOURCE = 106, + OBJECT = 107, +} + +const VALUE_TRUE: number = 1 +const VALUE_FALSE: number = 0 + +export function toPeerPtr(value: object): pointer { + if (value instanceof MaterializedBase) { + const peer = (value as MaterializedBase).getPeer() + return peer ? peer.ptr : nullptr + } else { + throw new Error("Value is not a MaterializedBase instance") + } +} + +export interface CallbackResource { + resourceId: int32 + hold: pointer + release: pointer +} + +/* Serialization extension point */ +export abstract class CustomSerializer { + protected supported: Array + constructor(supported: Array) { + this.supported = supported + } + supports(kind: string): boolean { return this.supported.includes(kind) } + abstract serialize(serializer: SerializerBase, value: object, kind: string): void + next: CustomSerializer | undefined = undefined +} + +class DateSerializer extends CustomSerializer { + constructor() { + super(new Array("Date")) + } + + serialize(serializer: SerializerBase, value: object, kind: string): void { + serializer.writeString((value as Date).toISOString()) + } +} +SerializerBase.registerCustomSerializer(new DateSerializer()) + +export class SerializerBase implements Disposable { + private _position: int64 = 0 + private _buffer: KSerializerBuffer + private _length: int32 + private _last: int64 + + private static pool: SerializerBase[] = [ + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + ] + private static poolTop = 0 + + static hold(): SerializerBase { + if (SerializerBase.poolTop === SerializerBase.pool.length) { + throw new Error("Pool empty! Release one of taken serializers") + } + return SerializerBase.pool[SerializerBase.poolTop++] + } + + private static customSerializers: CustomSerializer | undefined = new DateSerializer() + static registerCustomSerializer(serializer: CustomSerializer) { + if (SerializerBase.customSerializers == undefined) { + SerializerBase.customSerializers = serializer + } else { + let current = SerializerBase.customSerializers + while (current!.next != undefined) { + current = current!.next + } + current!.next = serializer + } + } + + constructor() { + let length = 96 + this._buffer = InteropNativeModule._Malloc(length.toLong()) + this._length = length + this._position = this._buffer + this._last = this._buffer + length - 1; + } + + public release() { + this.releaseResources() + this._position = this._buffer + if (this !== SerializerBase.pool[SerializerBase.poolTop - 1]) { + throw new Error("Serializers should be release in LIFO order") + } + SerializerBase.poolTop-- + } + public final dispose() { + InteropNativeModule._Free(this._buffer) + this._buffer = nullptr + } + + final asBuffer(): KSerializerBuffer { + return this._buffer + } + final length(): int32 { + return (this._position - this._buffer).toInt() + } + + final toArray(): byte[] { + const len = this.length() + let result = new byte[len] + for (let i = 0; i < len; i++) { + result[i] = unsafeMemory.readInt8(this._buffer + i) + } + return result + } + + private final updateCapacity(value: int32) { + let buffSize = this._length + const minSize = buffSize + value + const resizedSize = Math.max(minSize, Math.round(3 * buffSize / 2)).toInt() + if (value <= 0 || resizedSize <= 0) { + throw new Error(`bug: value(${value}) resizedSize(${resizedSize}) is illegal`) + } + let resizedBuffer = InteropNativeModule._Malloc(resizedSize) + let oldBuffer = this._buffer + let offset = this._position - oldBuffer; + for (let i = 0; i < offset; i++) { + let val = unsafeMemory.readInt8(oldBuffer + i); + unsafeMemory.writeInt8(resizedBuffer + i, val) + } + this._buffer = resizedBuffer + this._position = this._position - oldBuffer + resizedBuffer + this._length = resizedSize + this._last = resizedBuffer + resizedSize - 1; + InteropNativeModule._Free(oldBuffer) + } + + private heldResources: Array = new Array() + private heldResourcesCount: int32 = 0 + private final addHeldResource(resourceId: ResourceId) { + if (this.heldResourcesCount == this.heldResources.length) + this.heldResources.push(resourceId) + else + this.heldResources[this.heldResourcesCount] = resourceId + this.heldResourcesCount++ + } + final holdAndWriteCallback(callback: object, hold: pointer = 0, release: pointer = 0, call: pointer = 0, callSync: pointer = 0): ResourceId { + const resourceId = ResourceHolder.instance().registerAndHold(callback) + this.addHeldResource(resourceId) + this.writeInt32(resourceId) + this.writePointer(hold) + this.writePointer(release) + this.writePointer(call) + this.writePointer(callSync) + return resourceId + } + final holdAndWriteCallbackForPromiseVoid(hold: pointer = 0, release: pointer = 0, call: pointer = 0): [Promise, ResourceId] { + let resourceId: ResourceId = 0 + const promise = new Promise((resolve: (value: PromiseLike) => void, reject: (err: Error) => void) => { + const callback = (err?: string[] | undefined) => { + if (err !== undefined) + reject(new Error(err!.join(';'))) + else + resolve(Promise.resolve()) + } + resourceId = this.holdAndWriteCallback(callback, hold, release, call) + }) + return [promise, resourceId] + } + final holdAndWriteCallbackForPromise(hold: pointer = 0, release: pointer = 0, call: pointer = 0): [Promise, ResourceId] { + let resourceId: ResourceId = 0 + const promise = new Promise((resolve: (value: T | PromiseLike) => void, reject: (err: Error) => void) => { + const callback = (value?: T | undefined, err?: string[] | undefined) => { + if (err !== undefined) + reject(new Error(err!.join(';'))) + else + resolve(value!) + } + resourceId = this.holdAndWriteCallback(callback, hold, release, call) + }) + return [promise, resourceId] + } + final holdAndWriteObject(obj: object, hold: pointer = 0, release: pointer = 0): ResourceId { + const resourceId = ResourceHolder.instance().registerAndHold(obj) + this.addHeldResource(resourceId) + this.writeInt32(resourceId) + this.writePointer(hold) + this.writePointer(release) + return resourceId + } + final writeCallbackResource(resource: CallbackResource) { + this.writeInt32(resource.resourceId) + this.writePointer(resource.hold) + this.writePointer(resource.release) + } + final writeResource(resource: object) { + const resourceId = ResourceHolder.instance().registerAndHold(resource) + this.addHeldResource(resourceId) + this.writeInt32(resourceId) + } + private final releaseResources() { + if (this.heldResourcesCount == 0) return + for (let i = 0; i < this.heldResourcesCount; i++) { + InteropNativeModule._ReleaseCallbackResource(this.heldResources[i]) + } + this.heldResourcesCount = 0 + } + final writeCustomObject(kind: string, value: object) { + let current = SerializerBase.customSerializers + while (current) { + if (current!.supports(kind)) { + current!.serialize(this, value, kind) + return + } + current = current!.next + } + this.writeInt8(Tags.UNDEFINED.valueOf()) + } + final writeTag(tag: int32): void { + this.writeInt8(tag) + } + final writeNumber(value: number | undefined) { + if (value == undefined) { + this.writeTag(Tags.UNDEFINED) + return + } + if (Number.isInteger(value)) { + this.writeTag(Tags.INT32) + this.writeInt32(value.toInt()) + } else { + this.writeInt8(Tags.FLOAT32) + this.writeFloat32(value.toFloat()) + } + } + + final writeInt8(value: int32) { + let pos = this._position + let newPos = pos + 1 + if (newPos > this._last) { + this.updateCapacity(1) + pos = this._position + newPos = pos + 1 + } + + unsafeMemory.writeInt8(pos, value.toByte()) + this._position = newPos + } + + final writeInt32(value: int32) { + let pos = this._position + let newPos = pos + 4 + if (newPos > this._last) { + this.updateCapacity(4) + pos = this._position + newPos = pos + 4 + } + unsafeMemory.writeInt32(pos, value) + this._position = newPos + } + final writeInt64(value: int64) { + let pos = this._position + let newPos = pos + 8 + if (newPos > this._last) { + this.updateCapacity(8) + pos = this._position + newPos = pos + 8 + } + unsafeMemory.writeInt64(pos, value) + this._position = newPos + } + final writeFloat32(value: float32) { + let pos = this._position + let newPos = pos + 4 + if (newPos > this._last) { + this.updateCapacity(4) + pos = this._position + newPos = pos + 4 + } + unsafeMemory.writeFloat32(pos, value) + this._position = newPos + } + final writeFloat64(value: double) { + let pos = this._position + let newPos = pos + 8 + if (newPos > this._last) { + this.updateCapacity(8) + pos = this._position + newPos = pos + 8 + } + unsafeMemory.writeFloat64(pos, value) + this._position = newPos + } + final writePointer(value: pointer) { + this.writeInt64(value) + } + final writeBoolean(value: boolean | undefined) { + let pos = this._position + let newPos = pos + 1 + if (newPos > this._last) { + this.updateCapacity(1) + pos = this._position + newPos = pos + 1 + } + this._position = newPos + + if (value == undefined) + unsafeMemory.writeInt8(pos, Tags.UNDEFINED); + else if (value == true) + unsafeMemory.writeInt8(pos, VALUE_TRUE.toByte()); + else if (value == false) + unsafeMemory.writeInt8(pos, VALUE_FALSE.toByte()); + } + final writeString(value: string) { + const encodedLength = unsafeMemory.getStringSizeInBytes(value) + + let pos = this._position + if (pos + encodedLength + 5 > this._last) { + this.updateCapacity(encodedLength + 5) + pos = this._position + } + + if (encodedLength > 0) + unsafeMemory.writeString(pos + 4, value) + // NOTE: add \0 for supporting C char* reading from buffer for utf8-strings, + // need check native part fot utf16 cases and probably change this solution. + unsafeMemory.writeInt8(pos + encodedLength + 4, 0) + unsafeMemory.writeInt32(pos, encodedLength + 1) + this._position = pos + encodedLength + 4 + 1 + } + final writeBuffer(value: ArrayBuffer) { + this.holdAndWriteObject(value) + const ptr = InteropNativeModule._GetNativeBufferPointer(value) + this.writePointer(ptr) + this.writeInt64(value.byteLength) + } +} diff --git a/ets1.2/interop/src/arkts/callback.ts b/ets1.2/interop/src/arkts/callback.ts new file mode 100644 index 0000000000000000000000000000000000000000..e90460a019058e77a398e72e03f8a7a3bd7746b4 --- /dev/null +++ b/ets1.2/interop/src/arkts/callback.ts @@ -0,0 +1,89 @@ +/* + * 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. + */ + +import { KUint8ArrayPtr, KSerializerBuffer } from './InteropTypes'; +import { int32 } from '@koalaui/common'; + +export type CallbackType = (args: KSerializerBuffer, length: int32) => int32; + +class CallbackRecord { + public readonly callback: CallbackType; + public readonly autoDisposable: boolean; + + constructor(callback: CallbackType, autoDisposable: boolean) { + this.callback = callback; + this.autoDisposable = autoDisposable; + } +} + +class CallbackRegistry { + static INSTANCE = new CallbackRegistry(); + + private callbacks = new Map(); + private id = 1024; + + constructor() { + this.callbacks.set( + 0, + new CallbackRecord((args: KSerializerBuffer, length: int32): int32 => { + console.log(`Callback 0 called with args = ${args} and length = ${length}`); + throw new Error(`Null callback called`); + }, false) + ); + } + + wrap(callback: CallbackType, autoDisposable: boolean): int32 { + const id = this.id++; + this.callbacks.set(id, new CallbackRecord(callback, autoDisposable)); + return id; + } + + wrapSystem(id: int32, callback: CallbackType, autoDisposable: boolean): int32 { + this.callbacks.set(id, new CallbackRecord(callback, autoDisposable)); + return id; + } + + call(id: int32, args: KSerializerBuffer, length: int32): int32 { + const record = this.callbacks.get(id); + if (!record) { + console.log(`Callback ${id} is not known`); + throw new Error(`Disposed or unwrapped callback called (id = ${id})`); + } + if (record.autoDisposable) { + this.dispose(id); + } + return record.callback(args, length); + } + + dispose(id: int32) { + this.callbacks.delete(id); + } +} + +export function wrapCallback(callback: CallbackType, autoDisposable: boolean = true): int32 { + return CallbackRegistry.INSTANCE.wrap(callback, autoDisposable); +} + +export function wrapSystemCallback(id: int32, callback: CallbackType): int32 { + return CallbackRegistry.INSTANCE.wrapSystem(id, callback, false); +} + +export function disposeCallback(id: int32) { + CallbackRegistry.INSTANCE.dispose(id); +} + +export function callCallback(id: int32, args: KSerializerBuffer, length: int32): int32 { + return CallbackRegistry.INSTANCE.call(id, args, length); +} diff --git a/ets1.2/interop/src/arkts/events.ts b/ets1.2/interop/src/arkts/events.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6b3eddc3e292e843a149cac82467f3a1b6b7d8f --- /dev/null +++ b/ets1.2/interop/src/arkts/events.ts @@ -0,0 +1,92 @@ +/* + * 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. + */ + +import { int32 } from '@koalaui/common'; +import { DeserializerBase } from './DeserializerBase'; +import { InteropNativeModule } from './InteropNativeModule'; +import { ResourceHolder } from '../arkts/ResourceManager'; +import { KSerializerBuffer } from './InteropTypes'; +import { wrapSystemCallback } from './callback'; +import { KBuffer } from './NativeBuffer'; + +const API_KIND_MAX = 100; +const apiEventHandlers = new Array(API_KIND_MAX).fill(undefined); +export type EventHandler = (deserializer: DeserializerBase) => void; +export function registerApiEventHandler(apiKind: int32, handler: EventHandler) { + if (apiKind < 0 || apiKind > API_KIND_MAX) { + throw new Error(`Maximum api kind is ${API_KIND_MAX}, received ${apiKind}`); + } + if (apiEventHandlers[apiKind] !== undefined) { + throw new Error(`Callback caller for api kind ${apiKind} already was set`); + } + apiEventHandlers[apiKind] = handler; +} +export function handleApiEvent(apiKind: int32, deserializer: DeserializerBase) { + if (apiKind < 0 || apiKind > API_KIND_MAX) { + throw new Error(`Maximum api kind is ${API_KIND_MAX}, received ${apiKind}`); + } + if (apiEventHandlers[apiKind] === undefined) { + throw new Error(`Callback caller for api kind ${apiKind} was not set`); + } + apiEventHandlers[apiKind]!(deserializer); +} +export function wrapSystemApiHandlerCallback() { + wrapSystemCallback(1, (buffer: KSerializerBuffer, len: int32) => { + const deserializer = new DeserializerBase(buffer, len); + const apiKind = deserializer.readInt32(); + handleApiEvent(apiKind, deserializer); + return 0; + }); +} +export function checkEvents(): void { + while (checkSingleEvent()) {} +} + +enum CallbackEventKind { + Event_CallCallback = 0, + Event_HoldManagedResource = 1, + Event_ReleaseManagedResource = 2, +} + +const bufferSize = 8 * 1024; +const buffer = new KBuffer(bufferSize); +const deserializer = new DeserializerBase(buffer.buffer, bufferSize); +function checkSingleEvent(): boolean { + deserializer.resetCurrentPosition(); + let result = InteropNativeModule._CheckCallbackEvent(buffer.buffer, bufferSize); + if (result == 0) return false; + + const eventKind = deserializer.readInt32() as CallbackEventKind; + switch (eventKind) { + case CallbackEventKind.Event_CallCallback: { + const apiKind = deserializer.readInt32(); + handleApiEvent(apiKind, deserializer); + return true; + } + case CallbackEventKind.Event_HoldManagedResource: { + const resourceId = deserializer.readInt32() + ResourceHolder.instance().hold(resourceId) + return true; + } + case CallbackEventKind.Event_ReleaseManagedResource: { + const resourceId = deserializer.readInt32() + ResourceHolder.instance().release(resourceId) + return true; + } + default: { + throw new Error(`Unknown callback event kind ${eventKind}`) + } + } +} diff --git a/ets1.2/interop/src/arkts/index.ts b/ets1.2/interop/src/arkts/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4d0bb4001cba09c85399df5ae89d2653683d43cd --- /dev/null +++ b/ets1.2/interop/src/arkts/index.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +export * from './InteropTypes'; +export * from './callback'; +export * from './ResourceManager'; +export * from './NativeBuffer'; +export * from './InteropNativeModule'; +export * from './SerializerBase'; +export * from './DeserializerBase'; +export * from './Finalizable'; +export * from './loadLibraries'; +export * from './MaterializedBase'; +export * from './events'; diff --git a/ets1.2/interop/src/arkts/loadLibraries.ts b/ets1.2/interop/src/arkts/loadLibraries.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa9b2f8e75bf99e506763dfcffcda4d26133cc98 --- /dev/null +++ b/ets1.2/interop/src/arkts/loadLibraries.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 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. + */ + +const nativeModuleLibraries: Map = new Map(); + +export function loadNativeLibrary(library: string) { + console.log(`[loadLibraries] Loading ${library} [${library}]`); + loadLibrary(library); +} + +export function registerNativeModuleLibraryName(nativeModule: string, libraryName: string) { + console.log(`[loadLibraries] Registered ${libraryName} as ${nativeModule}`); + nativeModuleLibraries.set(nativeModule, libraryName); +} + +export function loadNativeModuleLibrary(nativeModule: string) { + console.log(`[loadLibraries] Loading ${nativeModule} [${nativeModuleLibraries.get(nativeModule) ?? nativeModule}]`); + loadLibrary(nativeModuleLibraries.get(nativeModule) ?? nativeModule); +} diff --git a/ets1.2/interop/src/cpp/DeserializerBase.h b/ets1.2/interop/src/cpp/DeserializerBase.h new file mode 100644 index 0000000000000000000000000000000000000000..3c0119355df13bb542fa3990a8c269c5b0c280b8 --- /dev/null +++ b/ets1.2/interop/src/cpp/DeserializerBase.h @@ -0,0 +1,618 @@ +/* + * Copyright (c) 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. + */ +#ifndef _DESERIALIZER_BASE_H_ +#define _DESERIALIZER_BASE_H_ + +#include +#include +#include +#include +#include + +#include "interop-logging.h" +#include "interop-types.h" +#include "interop-utils.h" +#include "koala-types.h" + +void holdManagedCallbackResource(InteropInt32); +void releaseManagedCallbackResource(InteropInt32); + +#ifdef __arm__ +#define KOALA_NO_UNALIGNED_ACCESS 1 +#endif + +inline const char* tagName(InteropTag tag) +{ + switch (tag) { + case InteropTag::INTEROP_TAG_UNDEFINED: + return "UNDEFINED"; + case InteropTag::INTEROP_TAG_INT32: + return "INT32"; + case InteropTag::INTEROP_TAG_FLOAT32: + return "FLOAT32"; + case InteropTag::INTEROP_TAG_LENGTH: + return "LENGTH"; + case InteropTag::INTEROP_TAG_RESOURCE: + return "RESOURCE"; + case InteropTag::INTEROP_TAG_STRING: + return "STRING"; + case InteropTag::INTEROP_TAG_OBJECT: + return "OBJECT"; + } + INTEROP_FATAL("Fatal error"); +} + +inline const char* tagNameExact(InteropTag tag) +{ + switch (tag) { + case InteropTag::INTEROP_TAG_UNDEFINED: + return "INTEROP_TAG_UNDEFINED"; + case InteropTag::INTEROP_TAG_INT32: + return "INTEROP_TAG_INT32"; + case InteropTag::INTEROP_TAG_FLOAT32: + return "INTEROP_TAG_FLOAT32"; + case InteropTag::INTEROP_TAG_LENGTH: + return "INTEROP_TAG_LENGTH"; + case InteropTag::INTEROP_TAG_RESOURCE: + return "INTEROP_TAG_RESOURCE"; + case InteropTag::INTEROP_TAG_STRING: + return "INTEROP_TAG_STRING"; + case InteropTag::INTEROP_TAG_OBJECT: + return "INTEROP_TAG_OBJECT"; + } + INTEROP_FATAL("Fatal error"); +} + +inline InteropFunction makeArkFunctionFromId(InteropInt32 id) +{ + InteropFunction result; + result.id = id; + return result; +} + +template +inline void convertor(T value) = delete; + +// Improve: restore full printing! +template +inline void WriteToString(std::string* result, T value) = delete; + +template<> +inline void WriteToString(std::string* result, const InteropEmpty& value) +{ + result->append("{"); + result->append(".dummy=" + std::to_string(value.dummy)); + result->append("}"); +} + +struct Error { + std::string message; + Error(const std::string& message) : message(message) {} +}; + +template<> +inline void WriteToString(std::string* result, InteropTag value) +{ + result->append(".tag="); + result->append(tagName(value)); +} + +template<> +inline void WriteToString(std::string* result, InteropNativePointer value) +{ + result->append("0x" + std::to_string((uint64_t)value)); +} + +template<> +inline void WriteToString(std::string* result, const InteropNativePointer* value) +{ + result->append("0x" + std::to_string((uint64_t)(*value))); +} + +template<> +inline void WriteToString(std::string* result, InteropNodeHandle value) +{ + result->append("0x" + std::to_string((uint64_t)value)); +} + +template<> +inline void WriteToString(std::string* result, InteropFunction value) +{ + result->append("{"); + result->append(".id=" + std::to_string(value.id)); + result->append("}"); +} + +template<> +inline void WriteToString(std::string* result, const InteropFunction* value) +{ + result->append("{"); + result->append(".id=" + std::to_string(value->id)); + result->append("}"); +} + +template<> +inline void WriteToString(std::string* result, const InteropMaterialized* value) +{ + char hex[20]; + interop_snprintf(hex, sizeof(hex), "0x%llx", (long long)value->ptr); + result->append("\""); + result->append("Materialized "); + result->append(hex); + result->append("\""); +} + +// Improve: generate! +template<> +inline void WriteToString(std::string* result, const InteropCallbackResource* value) +{ + result->append("{"); + result->append(".resourceId=" + std::to_string(value->resourceId)); + result->append(", .hold=0"); + result->append(", .release=0"); + result->append("}"); +} + +class DeserializerBase; + +template<> +inline void WriteToString(std::string* result, InteropUndefined value) +{ + result->append("{}"); +} +template<> +inline void WriteToString(std::string* result, const InteropUndefined* value) +{ + result->append("{}"); +} +template<> +inline void WriteToString(std::string* result, InteropVoid value) +{ + result->append("{}"); +} +template<> +inline void WriteToString(std::string* result, const InteropVoid* value) +{ + result->append("{}"); +} +template<> +inline void WriteToString(std::string* result, const InteropCustomObject* value) +{ + if (strcmp(value->kind, "NativeErrorFunction") == 0) { + result->append("() => {} /* Improve: Function*/"); + return; + } + result->append("{"); + result->append(".kind=\""); + result->append(value->kind); + result->append("\"}"); +} +template<> +inline void WriteToString(std::string* result, const InteropObject* value) +{ + result->append("{"); + result->append(".resource="); + WriteToString(result, &(value->resource)); + result->append("}"); +} +template<> +inline void WriteToString(std::string* result, const InteropObject value) +{ + WriteToString(result, &value); +} + +struct CustomDeserializer { + virtual ~CustomDeserializer() {} + virtual bool supports(const std::string& kind) + { + return false; + } + virtual InteropCustomObject deserialize(DeserializerBase* deserializer, const std::string& kind) + { + InteropCustomObject result; + interop_strcpy(result.kind, sizeof(result.kind), "error"); + return result; + } + CustomDeserializer* next = nullptr; +}; + +class DeserializerBase { +protected: + uint8_t* data; + int32_t length; + int32_t position; + std::vector toClean; + + static CustomDeserializer* customDeserializers; + +public: + DeserializerBase(KSerializerBuffer data, int32_t length) + : data(reinterpret_cast(data)), length(length), position(0) + {} + + DeserializerBase(uint8_t* data, int32_t length) : data(data), length(length), position(0) {} + + ~DeserializerBase() + { + for (auto data : toClean) { + free(data); + } + } + + static void registerCustomDeserializer(CustomDeserializer* deserializer) + { + if (DeserializerBase::customDeserializers == nullptr) { + DeserializerBase::customDeserializers = deserializer; + } else { + auto* current = DeserializerBase::customDeserializers; + while (current->next != nullptr) + current = current->next; + current->next = deserializer; + } + } + + template + void resizeArray(T* array, int32_t length) + { + void* value = nullptr; + if (length > 0) { + value = malloc(length * sizeof(E)); + if (!value) { + INTEROP_FATAL("Cannot allocate memory"); + } + interop_memset(value, length * sizeof(E), 0, length * sizeof(E)); + toClean.push_back(value); + } + array->length = length; + array->array = reinterpret_cast(value); + } + + template + void resizeMap(T* map, int32_t length) + { + void* keys = nullptr; + void* values = nullptr; + if (length > 0) { + keys = malloc(length * sizeof(K)); + if (!keys) { + INTEROP_FATAL("Cannot allocate memory"); + } + interop_memset(keys, length * sizeof(K), 0, length * sizeof(K)); + toClean.push_back(keys); + + values = malloc(length * sizeof(V)); + if (!values) { + INTEROP_FATAL("Cannot allocate memory"); + } + interop_memset(values, length * sizeof(V), 0, length * sizeof(V)); + toClean.push_back(values); + } + map->size = length; + map->keys = reinterpret_cast(keys); + map->values = reinterpret_cast(values); + } + + int32_t currentPosition() const + { + return this->position; + } + + void check(int32_t count) + { + if (position + count > length) { + INTEROP_FATAL("Incorrect serialized data, check for %d, buffer %d position %d\n", count, length, position); + } + } + + InteropCustomObject readCustomObject(std::string kind) + { + auto* current = DeserializerBase::customDeserializers; + while (current) { + if (current->supports(kind)) + return current->deserialize(this, kind); + current = current->next; + } + LOGE("Unsupported custom deserialization for %s\n", kind.c_str()); + auto tag = readTag(); + if (tag == INTEROP_TAG_UNDEFINED) + LOGE("Undefined interop tag"); + // Skip undefined tag!. + InteropCustomObject result; + interop_strcpy(result.kind, sizeof(result.kind), "Error"); + interop_strcat(result.kind, sizeof(result.kind), kind.c_str()); + return result; + } + + InteropCallbackResource readCallbackResource() + { + InteropCallbackResource result = {}; + result.resourceId = readInt32(); + result.hold = reinterpret_cast( + readPointerOrDefault(reinterpret_cast(holdManagedCallbackResource))); + result.release = reinterpret_cast( + readPointerOrDefault(reinterpret_cast(releaseManagedCallbackResource))); + return result; + } + + InteropObject readObject() + { + InteropObject obj; + obj.resource = readCallbackResource(); + return obj; + } + + int8_t readInt8() + { + check(1); + int8_t value = *(data + position); + position += 1; + return value; + } + InteropTag readTag() + { + return (InteropTag)readInt8(); + } + InteropBoolean readBoolean() + { + check(1); + int8_t value = *(data + position); + position += 1; + return value; + } + InteropInt32 readInt32() + { + check(sizeof(InteropInt32)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + InteropInt32 value; + interop_memcpy(&value, sizeof(InteropInt32), data + position, sizeof(InteropInt32)); +#else + auto value = *(InteropInt32*)(data + position); +#endif + position += sizeof(InteropInt32); + return value; + } + InteropInt64 readInt64() + { + check(sizeof(InteropInt64)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + InteropInt64 value; + interop_memcpy(&value, sizeof(InteropInt64), data + position, sizeof(InteropInt64)); +#else + auto value = *(InteropInt64*)(data + position); +#endif + position += sizeof(InteropInt64); + return value; + } + InteropUInt64 readUInt64() + { + check(sizeof(InteropUInt64)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + InteropInt64 value; + interop_memcpy(&value, sizeof(InteropUInt64), data + position, sizeof(InteropUInt64)); +#else + auto value = *(InteropUInt64*)(data + position); +#endif + position += sizeof(InteropUInt64); + return value; + } + InteropFloat32 readFloat32() + { + check(sizeof(InteropFloat32)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + InteropFloat32 value; + interop_memcpy(&value, sizeof(InteropFloat32), data + position, sizeof(InteropFloat32)); +#else + auto value = *(InteropFloat32*)(data + position); +#endif + position += sizeof(InteropFloat32); + return value; + } + InteropFloat64 readFloat64() + { + check(sizeof(InteropFloat64)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + InteropFloat64 value; + interop_memcpy(&value, sizeof(InteropFloat64), data + position, sizeof(InteropFloat64)); +#else + auto value = *(InteropFloat64*)(data + position); +#endif + position += sizeof(InteropFloat64); + return value; + } + InteropNativePointer readPointer() + { + check(sizeof(InteropInt64)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + InteropInt64 value = 0; + interop_memcpy(&value, sizeof(InteropInt64), data + position, sizeof(InteropInt64)); +#else + InteropInt64 value = *(int64_t*)(data + position); +#endif + position += sizeof(InteropInt64); + return reinterpret_cast(static_cast(value)); + } + InteropNativePointer readPointerOrDefault(InteropNativePointer defaultValue) + { + const InteropNativePointer value = this->readPointer(); + return value ? value : defaultValue; + } + InteropNumber readNumber() + { + check(sizeof(int8_t) + sizeof(int32_t)); + InteropNumber result; + result.tag = readTag(); + if (result.tag == InteropTag::INTEROP_TAG_INT32) { + result.i32 = readInt32(); + } else if (result.tag == InteropTag::INTEROP_TAG_FLOAT32) { + result.f32 = readFloat32(); + } else { + INTEROP_FATAL("Fatal error"); + } + return result; + } + InteropBuffer readBuffer() + { + InteropCallbackResource resource = readCallbackResource(); + InteropNativePointer data = readPointer(); + InteropInt64 length = readInt64(); + return InteropBuffer { resource, (void*)data, length }; + } + + InteropString readString() + { + InteropString result; + InteropInt32 length = readInt32(); + check(length); + // We refer to string data in-place. + result.chars = (const char*)(data + position); + result.length = length - 1; + this->position += length; + return result; + } + + InteropFunction readFunction() + { + InteropFunction result; + result.id = readInt32(); + return result; + } + + InteropMaterialized readMaterialized() + { + InteropMaterialized result; + result.ptr = readPointer(); + return result; + } + + InteropUndefined readUndefined() + { + return InteropUndefined(); + } +}; +template<> +inline void WriteToString(std::string* result, InteropBoolean value) +{ + result->append(value ? "true" : "false"); +} +template<> +inline void WriteToString(std::string* result, InteropInt32 value) +{ + result->append(std::to_string(value)); +} +template<> +inline void WriteToString(std::string* result, const InteropInt32* value) +{ + result->append(std::to_string(*value)); +} +template<> +inline void WriteToString(std::string* result, InteropUInt64 value) +{ + result->append(std::to_string(value)); +} +template<> +inline void WriteToString(std::string* result, InteropInt64 value) +{ + result->append(std::to_string(value)); +} +template<> +inline void WriteToString(std::string* result, InteropUInt32 value) +{ + result->append(std::to_string(value)); +} +template<> +inline void WriteToString(std::string* result, InteropFloat32 value) +{ +#if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED < 130300L)) + // to_chars() is not available on older macOS. + char buf[20]; + interop_snprintf(buf, sizeof buf, "%f", value); + result->append(buf); +#else + std::string storage; + constexpr auto BUF_SIZE{20}; + static_assert(BUF_SIZE >= std::numeric_limits::max_digits10, "O-ou!"); + storage.resize(BUF_SIZE); + // We use to_chars() to avoid locale issues. + auto rc = std::to_chars(storage.data(), storage.data() + storage.size(), value); + storage.resize(rc.ptr - storage.data()); + result->append(storage); +#endif +} +template<> +inline void WriteToString(std::string* result, InteropFloat64 value) +{ +#if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED < 130300L)) + // to_chars() is not available on older macOS. + char buf[20]; + interop_snprintf(buf, sizeof buf, "%f", value); + result->append(buf); +#else + std::string storage; + constexpr auto BUF_SIZE{20}; + static_assert(BUF_SIZE >= std::numeric_limits::max_digits10, "O-ou!"); + storage.resize(BUF_SIZE); + // We use to_chars() to avoid locale issues. + auto rc = std::to_chars(storage.data(), storage.data() + storage.size(), value); + storage.resize(rc.ptr - storage.data()); + result->append(storage); +#endif +} +template<> +inline void WriteToString(std::string* result, const InteropBuffer* value) +{ + result->append("{.data=nullptr, .length="); + result->append(std::to_string(value->length)); + result->append("}"); +} +template<> +inline void WriteToString(std::string* result, InteropBuffer value) +{ + result->append("{.data=nullptr, .length="); + result->append(std::to_string(value.length)); + result->append("}"); +} +template<> +inline void WriteToString(std::string* result, const InteropString* value) +{ + result->append("{"); + if (value->chars) { + result->append(".chars=\""); + result->append(value->chars); + result->append("\""); + } else { + result->append(".chars=\"\""); + } + result->append(", .length="); + WriteToString(result, value->length); + result->append("}"); +} + +template<> +inline void WriteToString(std::string* result, const InteropNumber* value) +{ + result->append("{.tag=" + std::to_string(value->tag) + ", "); + + if (value->tag == INTEROP_TAG_FLOAT32) { + std::string valueString; + result->append(".f32="); + WriteToString(result, value->f32); + } else { + result->append(".i32=" + std::to_string(value->i32)); + } + + result->append("}"); +} + +#endif // _DESERIALIZER_BASE_H_ diff --git a/ets1.2/interop/src/cpp/SerializerBase.h b/ets1.2/interop/src/cpp/SerializerBase.h new file mode 100644 index 0000000000000000000000000000000000000000..52e2c942ecd4b08f3aee2d78e5a8009b1d05abb8 --- /dev/null +++ b/ets1.2/interop/src/cpp/SerializerBase.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _SERIALIZER_BASE_H +#define _SERIALIZER_BASE_H + +#include +#include +#include +#include +#include +#include +#include + +#include "callback-resource.h" +#include "interop-logging.h" +#include "interop-types.h" +#include "interop-utils.h" +#include "koala-types.h" + +#ifdef __arm__ +#define KOALA_NO_UNALIGNED_ACCESS 1 +#endif + +template +inline InteropRuntimeType runtimeType(const T &value) = delete; + +template <> +inline InteropRuntimeType runtimeType(const InteropCustomObject &value) { + return INTEROP_RUNTIME_OBJECT; +} + +template <> +inline InteropRuntimeType runtimeType(const InteropMaterialized &value) { + return INTEROP_RUNTIME_OBJECT; +} +template <> inline InteropRuntimeType runtimeType(const InteropObject &value) { + return INTEROP_RUNTIME_OBJECT; +} + +class SerializerBase { +private: + uint8_t *data; + uint32_t dataLength; + uint32_t position; + bool ownData; + CallbackResourceHolder *resourceHolder; + void resize(uint32_t newLength) { + ASSERT(ownData); + ASSERT(newLength > dataLength); + auto *newData = reinterpret_cast(malloc(newLength)); + if (!newData) { + INTEROP_FATAL("Cannot allocate memory"); + } + interop_memcpy(newData, newLength, data, position); + free(data); + data = newData; + dataLength = newLength; + } + +public: + SerializerBase(CallbackResourceHolder *resourceHolder = nullptr) + : position(0), ownData(true), resourceHolder(resourceHolder) { + constexpr auto DEFAULT_INITIAL_DATA_SIZE{256}; + this->dataLength = DEFAULT_INITIAL_DATA_SIZE; + this->data = reinterpret_cast(malloc(this->dataLength)); + if (!this->data) { + INTEROP_FATAL("Cannot allocate memory"); + } + } + + SerializerBase(uint8_t *data, uint32_t dataLength, + CallbackResourceHolder *resourceHolder = nullptr) + : data(data), dataLength(dataLength), position(0), ownData(false), + resourceHolder(resourceHolder) {} + + SerializerBase(KSerializerBuffer data, uint32_t dataLength, + CallbackResourceHolder *resourceHolder = nullptr) + : data(reinterpret_cast(data)), dataLength(dataLength), + position(0), ownData(false), resourceHolder(resourceHolder) {} + + virtual ~SerializerBase() { + if (ownData) { + free(data); + } + } + + SerializerBase(const SerializerBase &) = delete; + SerializerBase &operator=(const SerializerBase &) = delete; + + void *release() { + ownData = false; + return data; + } + int length() { return position; } + + inline void check(int more) { + if (position + more > dataLength) { + if (ownData) { + constexpr auto NUM_2{2}; + constexpr auto NUM_3{3}; + resize((position + more) * NUM_3 / NUM_2 + NUM_2); + } else { + INTEROP_FATAL("Buffer overrun: %d > %d\n", position + more, dataLength); + } + } + } + + void writeInt8(InteropInt8 value) { + check(1); + *(reinterpret_cast(data + position)) = value; + position += sizeof(value); + } + + void writeInt32(InteropInt32 value) { + check(sizeof(value)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + interop_memcpy(data + position, dataLength, &value, sizeof(value)); +#else + *(reinterpret_cast(data + position)) = value; +#endif + position += sizeof(value); + } + + void writeInt64(InteropInt64 value) { + check(sizeof(value)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + interop_memcpy(data + position, dataLength, &value, sizeof(value)); +#else + *(reinterpret_cast(data + position)) = value; +#endif + position += sizeof(value); + } + + void writeUInt64(InteropUInt64 value) { + check(sizeof(value)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + interop_memcpy(data + position, dataLength, &value, sizeof(value)); +#else + *(reinterpret_cast(data + position)) = value; +#endif + position += sizeof(value); + } + + void writeFloat32(InteropFloat32 value) { + check(sizeof(value)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + interop_memcpy(data + position, dataLength, &value, sizeof(value)); +#else + *(reinterpret_cast(data + position)) = value; +#endif + position += sizeof(value); + } + + void writeFloat64(InteropFloat64 value) { + check(sizeof(value)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + interop_memcpy(data + position, dataLength, &value, sizeof(value)); +#else + *(reinterpret_cast(data + position)) = value; +#endif + position += sizeof(value); + } + + void writePointer(InteropNativePointer value) { + int64_t value64 = static_cast(reinterpret_cast(value)); + check(sizeof(value64)); +#ifdef KOALA_NO_UNALIGNED_ACCESS + interop_memcpy(data + position, dataLength, &value64, sizeof(value64)); +#else + *(reinterpret_cast(data + position)) = value64; +#endif + position += sizeof(value64); + } + + void writeNumber(InteropNumber value) { + writeInt8(value.tag); + if (value.tag == InteropTag::INTEROP_TAG_INT32) { + writeInt32(value.i32); + } else if (value.tag == InteropTag::INTEROP_TAG_FLOAT32) { + writeFloat32(value.f32); + } else { + INTEROP_FATAL("Unknown tag number"); + } + } + + void writeString(InteropString value) { + writeInt32(value.length + 1); + check(value.length + 1); + interop_strcpy(reinterpret_cast(data + position), dataLength, + value.chars); + position += value.length + 1; + } + + void writeBoolean(InteropBoolean value) { writeInt8(value); } + + void writeCallbackResource(const InteropCallbackResource resource) { + writeInt32(resource.resourceId); + writePointer(reinterpret_cast(resource.hold)); + writePointer(reinterpret_cast(resource.release)); + if (this->resourceHolder != nullptr) { + this->resourceHolder->holdCallbackResource(&resource); + } + } + + void writeObject(InteropObject any) { writeCallbackResource(any.resource); } + + void writeCustomObject(std::string type, InteropCustomObject value) { + // Improve: implement + } + + void writeBuffer(InteropBuffer interopBuffer) { + writeCallbackResource(interopBuffer.resource); + writePointer(static_cast(interopBuffer.data)); + writeInt64(interopBuffer.length); + } + + KInteropReturnBuffer toReturnBuffer() { + if (this->ownData) { + KInteropReturnBuffer buffer{ + this->length(), this->release(), + [](KNativePointer data, KInt length) { free(data); }}; + // Improve: fix memory issues + return buffer; + } else { + return {this->length(), this->data, nullptr}; + } + } +}; + +#endif // _SERIALIZER_BASE_H diff --git a/ets1.2/interop/src/cpp/ani/convertors-ani.cc b/ets1.2/interop/src/cpp/ani/convertors-ani.cc new file mode 100644 index 0000000000000000000000000000000000000000..e0a605744c531444701e8fac4243e4412cb8251e --- /dev/null +++ b/ets1.2/interop/src/cpp/ani/convertors-ani.cc @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2022-2023 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. + */ +#include "convertors-ani.h" + +#include +#include + +#include "interop-types.h" +#include "signatures.h" + +static const char* callCallbackFromNative = "callCallbackFromNative"; +static const char* callCallbackFromNativeSig = "ili:i"; + +const bool registerByOne = true; + +static bool registerNatives( + ani_env* env, const ani_class clazz, const std::vector> impls) +{ + std::vector staticMethods; + staticMethods.reserve(impls.size()); + bool result = true; + for (const auto& [name, type, func, flag] : impls) { + ani_native_function staticMethod; + staticMethod.name = name.c_str(); + staticMethod.pointer = func; + staticMethod.signature = nullptr; + if (registerByOne) { + result &= env->Class_BindStaticNativeMethods(clazz, &staticMethod, 1) == ANI_OK; + ani_boolean isError = false; + CHECK_ANI_FATAL(env->ExistUnhandledError(&isError)); + if (isError) { + CHECK_ANI_FATAL(env->DescribeError()); + CHECK_ANI_FATAL(env->ResetError()); + } + } else { + staticMethods.push_back(staticMethod); + } + } + if (!registerByOne) { + result = env->Class_BindStaticNativeMethods( + clazz, staticMethods.data(), static_cast(staticMethods.size())) == ANI_OK; + } + return registerByOne ? true : result; +} + +bool registerAllModules(ani_env* aniEnv) +{ + auto moduleNames = AniExports::getInstance()->getModules(); + for (auto it = moduleNames.begin(); it != moduleNames.end(); ++it) { + std::string classpath = AniExports::getInstance()->getClasspath(*it); + ani_class nativeModule = nullptr; + CHECK_ANI_FATAL(aniEnv->FindClass(classpath.c_str(), &nativeModule)); + if (nativeModule == nullptr) { + LOGE("Cannot find managed class %s", classpath.c_str()); + continue; + } + if (!registerNatives(aniEnv, nativeModule, AniExports::getInstance()->getMethods(*it))) { + return false; + } + } + return true; +} + +ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result) +{ + LOGE("Use ANI") + ani_env* aniEnv = nullptr; + *result = 1; + CHECK_ANI_FATAL(vm->GetEnv(1, (ani_env**)&aniEnv)); + if (!registerAllModules(aniEnv)) { + LOGE("Failed to register ANI modules"); + return ANI_ERROR; + } + ani_boolean hasError = false; + CHECK_ANI_FATAL(aniEnv->ExistUnhandledError(&hasError)); + if (hasError) { + CHECK_ANI_FATAL(aniEnv->DescribeError()); + CHECK_ANI_FATAL(aniEnv->ResetError()); + } + auto interopClassName = AniExports::getInstance()->getClasspath("InteropNativeModule"); + ani_class interopClass = nullptr; + CHECK_ANI_FATAL(aniEnv->FindClass(interopClassName.c_str(), &interopClass)); + if (interopClass == nullptr) { + LOGE("Can not find InteropNativeModule class to set callback dispatcher"); + CHECK_ANI_FATAL(aniEnv->ExistUnhandledError(&hasError)); + if (hasError) { + CHECK_ANI_FATAL(aniEnv->DescribeError()); + CHECK_ANI_FATAL(aniEnv->ResetError()); + } + return ANI_OK; + } + if (!setKoalaANICallbackDispatcher(aniEnv, interopClass, callCallbackFromNative, callCallbackFromNativeSig)) { + LOGE("Failed to set ANI callback dispatcher"); + return ANI_ERROR; + } + return ANI_OK; +} + +AniExports* AniExports::getInstance() +{ + static AniExports* instance = nullptr; + if (instance == nullptr) { + instance = new AniExports(); + } + return instance; +} + +std::vector AniExports::getModules() +{ + std::vector result; + for (auto it = implementations.begin(); it != implementations.end(); ++it) { + result.push_back(it->first); + } + return result; +} + +const std::vector>& AniExports::getMethods(const std::string& module) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + LOGE("Module %s is not registered", module.c_str()); + } + return it->second; +} + +void AniExports::addMethod(const char* module, const char* name, const char* type, void* impl, int flags) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + it = implementations + .insert(std::make_pair(module, std::vector>())) + .first; + } + it->second.push_back(std::make_tuple(name, convertType(name, type), impl, flags)); +} + +void AniExports::setClasspath(const char* module, const char* classpath) +{ + auto it = classpaths.find(module); + if (it == classpaths.end()) { + classpaths.insert(std::make_pair(module, classpath)); + } else { + LOGE("Classpath for module %s was redefined", module); + } +} + +static std::map g_defaultClasspaths = { + { "InteropNativeModule", "@koalaui.interop.InteropNativeModule.InteropNativeModule" }, + // Improve: leave just InteropNativeModule, define others via KOALA_ETS_INTEROP_MODULE_CLASSPATH + { "TestNativeModule", "arkui.framework.arkts.TestNativeModule.TestNativeModule" }, + { "ArkUINativeModule", "arkui.framework.arkts.ArkUINativeModule.ArkUINativeModule" }, + { "ArkUIGeneratedNativeModule", "arkui.framework.arkts.ArkUIGeneratedNativeModule.ArkUIGeneratedNativeModule" }, +}; + +const std::string& AniExports::getClasspath(const std::string& module) +{ + auto it = classpaths.find(module); + if (it != classpaths.end()) { + return it->second; + } + auto defaultClasspath = g_defaultClasspaths.find(module); + if (defaultClasspath != g_defaultClasspaths.end()) { + return defaultClasspath->second; + } + INTEROP_FATAL("Classpath for module %s was not registered", module.c_str()); +} + +static struct { + ani_class clazz = nullptr; + ani_static_method method = nullptr; +} g_koalaANICallbackDispatcher; + +static thread_local ani_env* currentContext = nullptr; + +bool setKoalaANICallbackDispatcher( + ani_env* aniEnv, ani_class clazz, const char* dispatcherMethodName, const char* dispatcherMethodSig) +{ + currentContext = aniEnv; + g_koalaANICallbackDispatcher.clazz = clazz; + CHECK_ANI_FATAL(aniEnv->Class_FindStaticMethod( + clazz, dispatcherMethodName, dispatcherMethodSig, &g_koalaANICallbackDispatcher.method)); + if (g_koalaANICallbackDispatcher.method == nullptr) { + return false; + } + return true; +} + +void getKoalaANICallbackDispatcher(ani_class* clazz, ani_static_method* method) +{ + *clazz = g_koalaANICallbackDispatcher.clazz; + *method = g_koalaANICallbackDispatcher.method; +} + +ani_env* getKoalaANIContext(void* hint) +{ + if (currentContext) { + return currentContext; + } else { + return reinterpret_cast(hint); + } +} diff --git a/ets1.2/interop/src/cpp/ani/convertors-ani.h b/ets1.2/interop/src/cpp/ani/convertors-ani.h new file mode 100644 index 0000000000000000000000000000000000000000..79939d006896fb195805dad26eb262d3d2a08485 --- /dev/null +++ b/ets1.2/interop/src/cpp/ani/convertors-ani.h @@ -0,0 +1,1919 @@ +/* + * Copyright (c) 2022-2023 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. + */ +#ifndef CONVERTORS_ANI_H +#define CONVERTORS_ANI_H + +#ifdef KOALA_ANI + +#include +#include +#include +#include +#include +#include + +#include "ani.h" +#include "interop-logging.h" +#include "interop-utils.h" +#include "koala-types.h" + +inline static ani_env* getEnv() +{ + ani_vm* machines[] = { nullptr }; + ani_size vmCount = 0; + ANI_GetCreatedVMs(machines, sizeof(machines) / sizeof(ani_vm*), &vmCount); + + if (vmCount == 0 || !machines[0]) + return nullptr; + + ani_env* res = nullptr; + machines[0]->GetEnv(ANI_VERSION_1, &res); + return res; +} + +inline static void printErrorStack() +{ + auto* env = getEnv(); + if (!env) + return; + + ani_boolean isError = false; + env->ExistUnhandledError(&isError); + if (isError) { + env->DescribeError(); + } +} + +#define CHECK_ANI_FATAL(result) \ + do { \ + ani_status ___res___ = (result); \ + if (___res___ != ANI_OK) { \ + printErrorStack(); \ + INTEROP_FATAL("ANI function failed (status: %d) at " __FILE__ ": %d", ___res___, __LINE__); \ + } \ + } while (0) + +template +struct InteropTypeConverter { + using InteropType = T; + static T convertFrom(ani_env* env, InteropType value) = delete; + static InteropType convertTo(ani_env* env, T value) = delete; + static void release(ani_env* env, InteropType value, T converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_byte; + static inline KByte convertFrom(ani_env* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(ani_env* env, KByte value) + { + return value; + } + static inline void release(ani_env* env, InteropType value, KByte converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_boolean; + static inline KBoolean convertFrom(ani_env* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(ani_env* env, KBoolean value) + { + return value; + } + static inline void release(ani_env* env, InteropType value, KBoolean converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_int; + static inline KInt convertFrom(ani_env* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(ani_env* env, KInt value) + { + return value; + } + static inline void release(ani_env* env, InteropType value, KInt converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_int; + static inline KUInt convertFrom(ani_env* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(ani_env* env, KUInt value) + { + return value; + } + static inline void release(ani_env* env, InteropType value, KUInt converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_float; + static inline KFloat convertFrom(ani_env* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(ani_env* env, KFloat value) + { + return value; + } + static inline void release(ani_env* env, InteropType value, KFloat converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_double; + static inline KDouble convertFrom(ani_env* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(ani_env* env, KDouble value) + { + return value; + } + static inline void release(ani_env* env, InteropType value, KDouble converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_long; + static inline KLong convertFrom(ani_env* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(ani_env* env, KLong value) + { + return value; + } + static inline void release(ani_env* env, InteropType value, KLong converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_object; + static inline KVMObjectHandle convertFrom(ani_env* env, InteropType value) + { + return reinterpret_cast(value); + } + static inline InteropType convertTo(ani_env* env, KVMObjectHandle value) + { + return reinterpret_cast(value); + } + static inline void release(ani_env* env, InteropType value, KVMObjectHandle converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_arraybuffer; + static inline KInteropBuffer convertFrom(ani_env* env, InteropType value) + { + void* data {}; + size_t len {}; + CHECK_ANI_FATAL(env->ArrayBuffer_GetInfo(value, &data, &len)); + return { static_cast(len), data, 0, nullptr }; + } + + static inline InteropType convertTo(ani_env* env, KInteropBuffer value) + { + void* data {}; + ani_arraybuffer result; + CHECK_ANI_FATAL(env->CreateArrayBuffer(value.length, &data, &result)); + interop_memcpy(data, value.length, value.data, value.length); + value.dispose(value.resourceId); + return result; + } + static inline void release(ani_env* env, InteropType value, KInteropBuffer converted) + { + if (converted.dispose) { + converted.dispose(converted.resourceId); + } + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_long; + static KSerializerBuffer convertFrom(ani_env* env, InteropType value) + { + return reinterpret_cast(static_cast(value)); + } + static InteropType convertTo(ani_env* env, KSerializerBuffer value) = delete; + static inline void release(ani_env* env, InteropType value, KSerializerBuffer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_fixedarray_byte; + static inline KInteropReturnBuffer convertFrom(ani_env* env, InteropType value) = delete; + static inline InteropType convertTo(ani_env* env, KInteropReturnBuffer value) + { + ani_fixedarray_byte result; + CHECK_ANI_FATAL(env->FixedArray_New_Byte(value.length, &result)); + CHECK_ANI_FATAL( + env->FixedArray_SetRegion_Byte(result, 0, value.length, reinterpret_cast(value.data))); + value.dispose(value.data, value.length); + return result; + }; + static inline void release(ani_env* env, InteropType value, KInteropReturnBuffer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_string; + static KStringPtr convertFrom(ani_env* env, InteropType value) + { + if (value == nullptr) + return KStringPtr(); + KStringPtr result; + // Notice that we use UTF length for buffer size, but counter is expressed in number of Unicode chars. + ani_size lengthUtf8 = 0; + CHECK_ANI_FATAL(env->String_GetUTF8Size(value, &lengthUtf8)); + result.resize(lengthUtf8); + ani_size count = 0; + CHECK_ANI_FATAL(env->String_GetUTF8SubString(value, 0, lengthUtf8, result.data(), lengthUtf8 + 1, &count)); + result.data()[lengthUtf8] = 0; + return result; + } + static InteropType convertTo(ani_env* env, const KStringPtr& value) + { + ani_string result = nullptr; + int length = value.length(); + CHECK_ANI_FATAL(env->String_NewUTF8(value.c_str(), length, &result)); + return result; + } + static void release(ani_env* env, InteropType value, const KStringPtr& converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_long; + static KNativePointer convertFrom(ani_env* env, InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(ani_env* env, KNativePointer value) + { + return reinterpret_cast(value); + } + static void release(ani_env* env, InteropType value, KNativePointer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_array_int; + static KInt* convertFrom(ani_env* env, InteropType value) + { + if (!value) + return nullptr; + ani_size length = 0; + CHECK_ANI_FATAL(env->Array_GetLength(value, &length)); + KInt* data = new KInt[length]; + CHECK_ANI_FATAL(env->Array_GetRegion_Int(value, 0, length, (ani_int*)data)); + return data; + } + static InteropType convertTo(ani_env* env, KInt* value) = delete; + static void release(ani_env* env, InteropType value, KInt* converted) + { + if (converted) { + ani_size length = 0; + CHECK_ANI_FATAL(env->Array_GetLength(value, &length)); + CHECK_ANI_FATAL(env->Array_SetRegion_Int(value, 0, length, (ani_int*)converted)); + } + delete[] converted; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_array_float; + static KFloat* convertFrom(ani_env* env, InteropType value) + { + if (!value) + return nullptr; + ani_size length = 0; + CHECK_ANI_FATAL(env->Array_GetLength(value, &length)); + KFloat* data = new KFloat[length]; + CHECK_ANI_FATAL(env->Array_GetRegion_Float(value, 0, length, (ani_float*)data)); + return data; + } + static InteropType convertTo(ani_env* env, KFloat* value) = delete; + static void release(ani_env* env, InteropType value, KFloat* converted) + { + if (converted) { + ani_size length = 0; + CHECK_ANI_FATAL(env->Array_GetLength(value, &length)); + CHECK_ANI_FATAL(env->Array_SetRegion_Float(value, 0, length, (ani_float*)converted)); + } + delete[] converted; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_array_byte; + static KByte* convertFrom(ani_env* env, InteropType value) + { + if (!value) + return nullptr; + ani_size length = 0; + CHECK_ANI_FATAL(env->Array_GetLength(value, &length)); + KByte* data = new KByte[length]; + if (length > 0) { + CHECK_ANI_FATAL(env->Array_GetRegion_Byte(value, 0, length, (ani_byte*)data)); + } + return data; + } + static InteropType convertTo(ani_env* env, KByte* value) = delete; + static void release(ani_env* env, InteropType value, KByte* converted) + { + if (converted) { + ani_size length = 0; + CHECK_ANI_FATAL(env->Array_GetLength(value, &length)); + if (length > 0) { + CHECK_ANI_FATAL(env->Array_SetRegion_Byte(value, 0, length, (ani_byte*)converted)); + } + } + delete[] converted; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ani_double; + static KInteropNumber convertFrom(ani_env* env, InteropType value) + { + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(ani_env* env, KInteropNumber value) + { + return value.asDouble(); + } + static void release(ani_env* env, InteropType value, KInteropNumber converted) {} +}; + +template +inline typename InteropTypeConverter::InteropType makeResult(ani_env* env, Type value) +{ + return InteropTypeConverter::convertTo(env, value); +} + +template +inline Type getArgument(ani_env* env, typename InteropTypeConverter::InteropType arg) +{ + return InteropTypeConverter::convertFrom(env, arg); +} + +template +inline void releaseArgument(ani_env* env, typename InteropTypeConverter::InteropType arg, Type& data) +{ + InteropTypeConverter::release(env, arg, data); +} + +template +struct DirectInteropTypeConverter { + using InteropType = T; + static T convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(T value) + { + return value; + } +}; + +template<> +struct DirectInteropTypeConverter { + using InteropType = ani_long; + static KNativePointer convertFrom(InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(KNativePointer value) + { + return reinterpret_cast(value); + } +}; + +template<> +struct DirectInteropTypeConverter { + using InteropType = ani_long; + static KSerializerBuffer convertFrom(InteropType value) + { + return reinterpret_cast(static_cast(value)); + } + static InteropType convertTo(KSerializerBuffer value) = delete; +}; + +template<> +struct DirectInteropTypeConverter { + using InteropType = ani_double; + static KInteropNumber convertFrom(InteropType value) + { + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(KInteropNumber value) + { + return value.asDouble(); + } +}; + +#define ANI_SLOW_NATIVE_FLAG 1 + +class AniExports { + std::unordered_map>> implementations; + std::unordered_map classpaths; + +public: + static AniExports* getInstance(); + + std::vector getModules(); + void addMethod(const char* module, const char* name, const char* type, void* impl, int flags); + const std::vector>& getMethods(const std::string& module); + + void setClasspath(const char* module, const char* classpath); + const std::string& getClasspath(const std::string& module); +}; + +#define KOALA_QUOTE0(x) #x +#define KOALA_QUOTE(x) KOALA_QUOTE0(x) + +#ifdef _MSC_VER +#define MAKE_ANI_EXPORT(module, name, type, flag) \ + static void __init_##name() \ + { \ + AniExports::getInstance()->addMethod( \ + KOALA_QUOTE(module), "_" #name, type, reinterpret_cast(Ani_##name), flag); \ + } \ + namespace { \ + struct __Init_##name { \ + __Init_##name() \ + { \ + __init_##name(); \ + } \ + } __Init_##name##_v; \ + } +#define KOALA_ANI_INTEROP_MODULE_CLASSPATH(module, classpath) \ + static void __init_classpath_##module() \ + { \ + AniExports::getInstance()->setClasspath(KOALA_QUOTE(module), "L" classpath ";"); \ + } \ + namespace { \ + struct __Init_classpath_##module { \ + __Init_classpath_##module() \ + { \ + __init_classpath_##module(); \ + } \ + } __Init_classpath_##module##_v; \ + } +#else +#define MAKE_ANI_EXPORT(module, name, type, flag) \ + __attribute__((constructor)) static void __init_ani_##name() \ + { \ + AniExports::getInstance()->addMethod( \ + KOALA_QUOTE(module), "_" #name, type, reinterpret_cast(Ani_##name), flag); \ + } +#define KOALA_ANI_INTEROP_MODULE_CLASSPATH(module, classpath) \ + __attribute__((constructor)) static void __init_ani_classpath_##module() \ + { \ + AniExports::getInstance()->setClasspath(KOALA_QUOTE(module), "L" classpath ";"); \ + } +#endif + +#define KOALA_INTEROP_0(name, Ret) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz) \ + { \ + KOALA_MAYBE_LOG(name) \ + return makeResult(env, impl_##name()); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret, 0) + +#define KOALA_INTEROP_1(name, Ret, P0) \ + InteropTypeConverter::InteropType Ani_##name( \ + ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + auto rv = makeResult(env, impl_##name(p0)); \ + releaseArgument(env, _p0, p0); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0, 0) + +#define KOALA_INTEROP_2(name, Ret, P0, P1) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + auto rv = makeResult(env, impl_##name(p0, p1)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1, 0) + +#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2, 0) + +#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3, 0) + +#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, 0) + +#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, 0) + +#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, 0) + +#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, 0) + +#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + return rv; \ + } \ + MAKE_ANI_EXPORT( \ + KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, 0) + +#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, 0) + +#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, 0) + +#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10, InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11, 0) + +#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10, InteropTypeConverter::InteropType _p11, \ + InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12, \ + 0) + +#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10, InteropTypeConverter::InteropType _p11, \ + InteropTypeConverter::InteropType _p12, InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12 "|" #P13, \ + 0) + +#define KOALA_INTEROP_V0(name) \ + void Ani_##name(ani_env* env, ani_class clazz) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void", 0) + +#define KOALA_INTEROP_V1(name, P0) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + impl_##name(p0); \ + releaseArgument(env, _p0, p0); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0, 0) + +#define KOALA_INTEROP_V2(name, P0, P1) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + impl_##name(p0, p1); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1, 0) + +#define KOALA_INTEROP_V3(name, P0, P1, P2) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + impl_##name(p0, p1, p2); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2, 0) + +#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + impl_##name(p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3, 0) + +#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + impl_##name(p0, p1, p2, p3, p4); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, 0) + +#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + impl_##name(p0, p1, p2, p3, p4, p5); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, 0) + +#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, 0) + +#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, 0) + +#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + } \ + MAKE_ANI_EXPORT( \ + KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, 0) + +#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, 0) + +#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, 0) + +#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11, 0) + +#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12, \ + 0) + +#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12 \ + "|" #P13, \ + 0) + +#define KOALA_INTEROP_V15(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13, InteropTypeConverter::InteropType _p14) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + P14 p14 = getArgument(env, _p14); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + releaseArgument(env, _p14, p14); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12 \ + "|" #P13 "|" #P14, \ + 0) + +#define KOALA_INTEROP_CTX_0(name, Ret) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz) \ + { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx)); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_1(name, Ret, P0) \ + InteropTypeConverter::InteropType Ani_##name( \ + ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0)); \ + releaseArgument(env, _p0, p0); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1, p2)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1, p2, p3)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_5(name, Ret, P0, P1, P2, P3, P4) \ + InteropTypeConverter::InteropType Ani_##name(ani_env* env, ani_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1, p2, p3, p4)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + return rv; \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V0(name) \ + void Ani_##name(ani_env* env, ani_class clazz) \ + { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void", ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V1(name, P0) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0); \ + releaseArgument(env, _p0, p0); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V2(name, P0, P1) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V5(name, P0, P1, P2, P3, P4) \ + void Ani_##name(ani_env* env, ani_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3, p4); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, ANI_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_DIRECT_0(name, Ret) \ + inline InteropTypeConverter::InteropType Ani_##name() \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name()); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret, 0) +#define KOALA_INTEROP_DIRECT_1(name, Ret, P0) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo( \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0, 0) +#define KOALA_INTEROP_DIRECT_2(name, Ret, P0, P1) \ + inline InteropTypeConverter::InteropType Ani_##name( \ + InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name( \ + DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1, 0) +#define KOALA_INTEROP_DIRECT_3(name, Ret, P0, P1, P2) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2, 0) +#define KOALA_INTEROP_DIRECT_4(name, Ret, P0, P1, P2, P3) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3, 0) +#define KOALA_INTEROP_DIRECT_5(name, Ret, P0, P1, P2, P3, P4) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, 0) +#define KOALA_INTEROP_DIRECT_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, 0) +#define KOALA_INTEROP_DIRECT_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, 0) +#define KOALA_INTEROP_DIRECT_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, 0) +#define KOALA_INTEROP_DIRECT_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7, InteropTypeConverter::InteropType p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7), DirectInteropTypeConverter::convertFrom(p8))); \ + } \ + MAKE_ANI_EXPORT( \ + KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, 0) +#define KOALA_INTEROP_DIRECT_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7, InteropTypeConverter::InteropType p8, \ + InteropTypeConverter::InteropType p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7), DirectInteropTypeConverter::convertFrom(p8), \ + DirectInteropTypeConverter::convertFrom(p9))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, 0) +#define KOALA_INTEROP_DIRECT_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + inline InteropTypeConverter::InteropType Ani_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7, InteropTypeConverter::InteropType p8, \ + InteropTypeConverter::InteropType p9, InteropTypeConverter::InteropType p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7), DirectInteropTypeConverter::convertFrom(p8), \ + DirectInteropTypeConverter::convertFrom(p9), DirectInteropTypeConverter::convertFrom(p10))); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, 0) +#define KOALA_INTEROP_DIRECT_V0(name) \ + inline void Ani_##name() \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, "void", 0) +#define KOALA_INTEROP_DIRECT_V1(name, P0) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0, \ + 0) +#define KOALA_INTEROP_DIRECT_V2(name, P0, P1) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1, \ + 0) +#define KOALA_INTEROP_DIRECT_V3(name, P0, P1, P2) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2, \ + 0) +#define KOALA_INTEROP_DIRECT_V4(name, P0, P1, P2, P3) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3, \ + 0) +#define KOALA_INTEROP_DIRECT_V5(name, P0, P1, P2, P3, P4) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, \ + 0) +#define KOALA_INTEROP_DIRECT_V6(name, P0, P1, P2, P3, P4, P5) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, \ + 0) +#define KOALA_INTEROP_DIRECT_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, \ + 0) +#define KOALA_INTEROP_DIRECT_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, \ + 0) +#define KOALA_INTEROP_DIRECT_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7, \ + InteropTypeConverter::InteropType p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7), \ + DirectInteropTypeConverter::convertFrom(p8)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, \ + 0) +#define KOALA_INTEROP_DIRECT_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7, \ + InteropTypeConverter::InteropType p8, InteropTypeConverter::InteropType p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7), \ + DirectInteropTypeConverter::convertFrom(p8), DirectInteropTypeConverter::convertFrom(p9)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, \ + 0) +#define KOALA_INTEROP_DIRECT_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + inline void Ani_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7, \ + InteropTypeConverter::InteropType p8, InteropTypeConverter::InteropType p9, \ + InteropTypeConverter::InteropType p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7), \ + DirectInteropTypeConverter::convertFrom(p8), DirectInteropTypeConverter::convertFrom(p9), \ + DirectInteropTypeConverter::convertFrom(p10)); \ + } \ + MAKE_ANI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, \ + 0) + +bool setKoalaANICallbackDispatcher( + ani_env* ani_env, ani_class clazz, const char* dispatcherMethodName, const char* dispactherMethodSig); +void getKoalaANICallbackDispatcher(ani_class* clazz, ani_static_method* method); +ani_env* getKoalaANIContext(void* hint); + +// Improve: maybe use CreateArrayBufferExternal here instead, no need for allocations. +#define KOALA_INTEROP_CALL_VOID(venv, id, length, args) \ + { \ + ani_class clazz = nullptr; \ + ani_static_method method = nullptr; \ + getKoalaANICallbackDispatcher(&clazz, &method); \ + ani_env* env = getKoalaANIContext(venv); \ + ani_int result = 0; \ + long long args_casted = reinterpret_cast(args); \ + CHECK_ANI_FATAL(env->Class_CallStaticMethod_Int(clazz, method, &result, id, args_casted, length)); \ + } + +#define KOALA_INTEROP_CALL_INT(venv, id, length, args) \ + { \ + ani_class clazz = nullptr; \ + ani_static_method method = nullptr; \ + getKoalaANICallbackDispatcher(&clazz, &method); \ + ani_env* env = getKoalaANIContext(venv); \ + ani_int result = 0; \ + long long args_casted = reinterpret_cast(args); \ + CHECK_ANI_FATAL(env->Class_CallStaticMethod_Int(clazz, method, &result, id, args_casted, length)); \ + return result; \ + } + +#define KOALA_INTEROP_CALL_VOID_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_VOID(venv, id, (argc) * sizeof(int32_t), args) +#define KOALA_INTEROP_CALL_INT_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_INT(venv, id, (argc) * sizeof(int32_t), args) + +#define KOALA_INTEROP_THROW(vmContext, object, ...) \ + do { \ + ani_env* env = reinterpret_cast(vmContext); \ + CHECK_ANI_FATAL(env->ThrowError(object)); \ + return __VA_ARGS__; \ + } while (0) + +#define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \ + do { \ + ani_env* env = reinterpret_cast(vmContext); \ + ani_class errorClass {}; \ + CHECK_ANI_FATAL(env->FindClass("escompat.Error", &errorClass)); \ + ani_method errorCtor {}; \ + CHECK_ANI_FATAL( \ + env->Class_FindMethod(errorClass, "", "C{std.core.String}C{escompat.ErrorOptions}:", &errorCtor)); \ + ani_string messageObject {}; \ + CHECK_ANI_FATAL(env->String_NewUTF8(message, interop_strlen(message), &messageObject)); \ + ani_ref undefined {}; \ + CHECK_ANI_FATAL(env->GetUndefined(&undefined)); \ + ani_object throwObject {}; \ + CHECK_ANI_FATAL(env->Object_New(errorClass, errorCtor, &throwObject, messageObject, undefined)); \ + CHECK_ANI_FATAL(env->ThrowError(static_cast(throwObject))); \ + return __VA_ARGS__; \ + } while (0) + +#endif // KOALA_ANI + +#endif // CONVERTORS_ANI_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/ani/panda/ani.h b/ets1.2/interop/src/cpp/ani/panda/ani.h new file mode 100644 index 0000000000000000000000000000000000000000..6acd600cec34efe57dec8c33d790792e10a7bc7b --- /dev/null +++ b/ets1.2/interop/src/cpp/ani/panda/ani.h @@ -0,0 +1,8260 @@ +/** + * Copyright (c) 2025 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. + */ + +#ifndef __ANI_H__ +#define __ANI_H__ +// NOLINTBEGIN + +#ifdef __cplusplus +#include +#include +#include +#else +#include +#include +#include +#endif + +#define ANI_VERSION_1 1 + +#define ANI_FALSE 0 +#define ANI_TRUE 1 + +// Logger interface: +// typedef void (*ani_logger)(FILE *stream, int log_level, const char *component, const char *message); +// ani_option: +// 'option': "--logger" +// 'extra': ani_logger +// where 'log_level' can have the following values: +#define ANI_LOGLEVEL_FATAL 0 +#define ANI_LOGLEVEL_ERROR 1 +#define ANI_LOGLEVEL_WARNING 2 +#define ANI_LOGLEVEL_INFO 3 +#define ANI_LOGLEVEL_DEBUG 4 + +typedef size_t ani_size; + +// Primitive types: +typedef uint8_t ani_boolean; +typedef uint16_t ani_char; +typedef int8_t ani_byte; +typedef int16_t ani_short; +typedef int32_t ani_int; +typedef int64_t ani_long; +typedef float ani_float; +typedef double ani_double; + +// Reference types: +#ifdef __cplusplus +class __ani_ref {}; +class __ani_module : public __ani_ref {}; +class __ani_namespace : public __ani_ref {}; +class __ani_object : public __ani_ref {}; +class __ani_fn_object : public __ani_object {}; +class __ani_enum_item : public __ani_object {}; +class __ani_error : public __ani_object {}; +class __ani_tuple_value : public __ani_object {}; +class __ani_type : public __ani_object {}; +class __ani_arraybuffer : public __ani_object {}; +class __ani_string : public __ani_object {}; +class __ani_class : public __ani_type {}; +class __ani_enum : public __ani_type {}; +class __ani_array : public __ani_object {}; +class __ani_array_boolean : public __ani_array {}; +class __ani_array_char : public __ani_array {}; +class __ani_array_byte : public __ani_array {}; +class __ani_array_short : public __ani_array {}; +class __ani_array_int : public __ani_array {}; +class __ani_array_long : public __ani_array {}; +class __ani_array_float : public __ani_array {}; +class __ani_array_double : public __ani_array {}; +class __ani_array_ref : public __ani_array {}; +class __ani_fixedarray : public __ani_object {}; +class __ani_fixedarray_boolean : public __ani_fixedarray {}; +class __ani_fixedarray_char : public __ani_fixedarray {}; +class __ani_fixedarray_byte : public __ani_fixedarray {}; +class __ani_fixedarray_short : public __ani_fixedarray {}; +class __ani_fixedarray_int : public __ani_fixedarray {}; +class __ani_fixedarray_long : public __ani_fixedarray {}; +class __ani_fixedarray_float : public __ani_fixedarray {}; +class __ani_fixedarray_double : public __ani_fixedarray {}; +class __ani_fixedarray_ref : public __ani_fixedarray {}; +typedef __ani_ref* ani_ref; +typedef __ani_module* ani_module; +typedef __ani_namespace* ani_namespace; +typedef __ani_object* ani_object; +typedef __ani_fn_object* ani_fn_object; +typedef __ani_enum_item* ani_enum_item; +typedef __ani_error* ani_error; +typedef __ani_tuple_value* ani_tuple_value; +typedef __ani_type* ani_type; +typedef __ani_arraybuffer* ani_arraybuffer; +typedef __ani_string* ani_string; +typedef __ani_class* ani_class; +typedef __ani_enum* ani_enum; +typedef __ani_array* ani_array; +typedef __ani_array_boolean* ani_array_boolean; +typedef __ani_array_char* ani_array_char; +typedef __ani_array_byte* ani_array_byte; +typedef __ani_array_short* ani_array_short; +typedef __ani_array_int* ani_array_int; +typedef __ani_array_long* ani_array_long; +typedef __ani_array_float* ani_array_float; +typedef __ani_array_double* ani_array_double; +typedef __ani_array_ref* ani_array_ref; +typedef __ani_fixedarray* ani_fixedarray; +typedef __ani_fixedarray_boolean* ani_fixedarray_boolean; +typedef __ani_fixedarray_char* ani_fixedarray_char; +typedef __ani_fixedarray_byte* ani_fixedarray_byte; +typedef __ani_fixedarray_short* ani_fixedarray_short; +typedef __ani_fixedarray_int* ani_fixedarray_int; +typedef __ani_fixedarray_long* ani_fixedarray_long; +typedef __ani_fixedarray_float* ani_fixedarray_float; +typedef __ani_fixedarray_double* ani_fixedarray_double; +typedef __ani_fixedarray_ref* ani_fixedarray_ref; +#else // __cplusplus +struct __ani_ref; +typedef struct __ani_ref* ani_ref; +typedef ani_ref ani_module; +typedef ani_ref ani_namespace; +typedef ani_ref ani_object; +typedef ani_object ani_fn_object; +typedef ani_object ani_enum_item; +typedef ani_object ani_error; +typedef ani_object ani_tuple_value; +typedef ani_object ani_type; +typedef ani_object ani_arraybuffer; +typedef ani_object ani_string; +typedef ani_type ani_class; +typedef ani_type ani_enum; +typedef ani_object ani_array; +typedef ani_array ani_array_boolean; +typedef ani_array ani_array_char; +typedef ani_array ani_array_byte; +typedef ani_array ani_array_short; +typedef ani_array ani_array_int; +typedef ani_array ani_array_long; +typedef ani_array ani_array_float; +typedef ani_array ani_array_double; +typedef ani_array ani_array_ref; +typedef ani_object ani_fixedarray; +typedef ani_fixedarray ani_fixedarray_boolean; +typedef ani_fixedarray ani_fixedarray_char; +typedef ani_fixedarray ani_fixedarray_byte; +typedef ani_fixedarray ani_fixedarray_short; +typedef ani_fixedarray ani_fixedarray_int; +typedef ani_fixedarray ani_fixedarray_long; +typedef ani_fixedarray ani_fixedarray_float; +typedef ani_fixedarray ani_fixedarray_double; +typedef ani_fixedarray ani_fixedarray_ref; +#endif // __cplusplus + +struct __ani_wref; +typedef struct __ani_wref* ani_wref; + +struct __ani_variable; +typedef struct __ani_variable* ani_variable; + +struct __ani_function; +typedef struct __ani_function* ani_function; + +struct __ani_field; +typedef struct __ani_field* ani_field; + +struct __ani_static_field; +typedef struct __ani_satic_field* ani_static_field; + +struct __ani_method; +typedef struct __ani_method* ani_method; + +struct __ani_static_method; +typedef struct __ani_static_method* ani_static_method; + +struct __ani_resolver; +typedef struct __ani_resolver* ani_resolver; + +typedef union { + ani_boolean z; + ani_char c; + ani_byte b; + ani_short s; + ani_int i; + ani_long l; + ani_float f; + ani_double d; + ani_ref r; +} ani_value; + +typedef struct { + const char* name; + const char* signature; + const void* pointer; +} ani_native_function; + +#ifdef __cplusplus +typedef struct __ani_vm ani_vm; +typedef struct __ani_env ani_env; +#else +typedef const struct __ani_vm_api* ani_vm; +typedef const struct __ani_interaction_api* ani_env; +#endif + +typedef enum { + ANI_OK, + ANI_ERROR, + ANI_INVALID_ARGS, + ANI_INVALID_TYPE, + ANI_INVALID_DESCRIPTOR, + ANI_INCORRECT_REF, + ANI_PENDING_ERROR, + ANI_NOT_FOUND, + ANI_ALREADY_BINDED, + ANI_OUT_OF_REF, + ANI_OUT_OF_MEMORY, + ANI_OUT_OF_RANGE, + ANI_BUFFER_TO_SMALL, + ANI_INVALID_VERSION, + ANI_AMBIGUOUS, + // NOTE: Add necessary status codes +} ani_status; + +typedef struct { + const char* option; + void* extra; +} ani_option; + +typedef struct { + size_t nr_options; + const ani_option* options; +} ani_options; + +struct __ani_vm_api { + void* reserved0; + void* reserved1; + void* reserved2; + void* reserved3; + + ani_status (*DestroyVM)(ani_vm* vm); + ani_status (*GetEnv)(ani_vm* vm, uint32_t version, ani_env** result); + ani_status (*AttachCurrentThread)(ani_vm* vm, const ani_options* options, uint32_t version, ani_env** result); + ani_status (*DetachCurrentThread)(ani_vm* vm); +}; + +#define ANI_EXPORT __attribute__((visibility("default"))) + +#ifdef __cplusplus +extern "C" { +#endif + +ANI_EXPORT ani_status ANI_CreateVM(const ani_options* options, uint32_t version, ani_vm** result); +ANI_EXPORT ani_status ANI_GetCreatedVMs(ani_vm** vms_buffer, ani_size vms_buffer_length, ani_size* result); + +// Prototypes of exported functions for a shared library. +ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result); +ANI_EXPORT ani_status ANI_Destructor(ani_vm* vm); + +#ifdef __cplusplus +} +#endif + +struct __ani_interaction_api { + void* reserved0; + void* reserved1; + void* reserved2; + void* reserved3; + + /** + * @brief Retrieves the version information. + * + * This function retrieves the version information and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[out] result A pointer to a variable where the version information will be stored. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*GetVersion)(ani_env* env, uint32_t* result); + + /** + * @brief Retrieves the Virtual Machine (VM) instance. + * + * This function retrieves the VM instance and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[out] result A pointer to the VM instance to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*GetVM)(ani_env* env, ani_vm** result); + + /** + * @brief Creates a new object of a specified class using a constructor method. + * + * This function creates a new object of the given class and calls the specified constructor method with variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class of the object to create. + * @param[in] method The constructor method to invoke. + * @param[in] ... Variadic arguments to pass to the constructor method. + * @param[out] result A pointer to store the object return value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_New)(ani_env* env, ani_class cls, ani_method method, ani_object* result, ...); + + /** + * @brief Creates a new object of a specified class using a constructor method (array-based). + * + * This function creates a new object of the given class and calls the specified constructor method with arguments + * provided in an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class of the object to create. + * @param[in] method The constructor method to invoke. + * @param[in] args An array of arguments to pass to the constructor method. + * @param[out] result A pointer to store the object return value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_New_A)( + ani_env* env, ani_class cls, ani_method method, ani_object* result, const ani_value* args); + + /** + * @brief Creates a new object of a specified class using a constructor method (variadic arguments). + * + * This function creates a new object of the given class and calls the specified constructor method with a `va_list` + * of arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class of the object to create. + * @param[in] method The constructor method to invoke. + * @param[in] args A `va_list` of arguments to pass to the constructor method. + * @param[out] result A pointer to store the object return value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_New_V)(ani_env* env, ani_class cls, ani_method method, ani_object* result, va_list args); + + /** + * @brief Retrieves the type of a given object. + * + * This function retrieves the type of the specified object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object whose type is to be retrieved. + * @param[out] result A pointer to store the retrieved type. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetType)(ani_env* env, ani_object object, ani_type* result); + + /** + * @brief Checks if an object is an instance of a specified type. + * + * This function checks whether the given object is an instance of the specified type. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object to check. + * @param[in] type The type to compare against. + * @param[out] result A pointer to store the boolean result (true if the object is an instance of the type, false + * otherwise). + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_InstanceOf)(ani_env* env, ani_object object, ani_type type, ani_boolean* result); + + /** + * @brief Retrieves the superclass of a specified type. + * + * This function retrieves the superclass of a given type and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] type The type for which to retrieve the superclass. + * @param[out] result A pointer to the superclass to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Type_GetSuperClass)(ani_env* env, ani_type type, ani_class* result); + + /** + * @brief Determines if one type is assignable from another. + * + * This function checks if a type is assignable from another and stores the result in the output parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] from_type The source type. + * @param[in] to_type The target type. + * @param[out] result A pointer to a boolean indicating assignability. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Type_IsAssignableFrom)(ani_env* env, ani_type from_type, ani_type to_type, ani_boolean* result); + + /** + * @brief Finds a module by its descriptor. + * + * This function locates a module based on its descriptor and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] module_descriptor The descriptor of the module to find. + * @param[out] result A pointer to the module to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FindModule)(ani_env* env, const char* module_descriptor, ani_module* result); + + /** + * @brief Finds a namespace by its descriptor. + * + * This function locates a namespace based on its descriptor and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] namespace_descriptor The descriptor of the namespace to find. + * @param[out] result A pointer to the namespace to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FindNamespace)(ani_env* env, const char* namespace_descriptor, ani_namespace* result); + + /** + * @brief Finds a class by its descriptor. + * + * This function locates a class based on its descriptor and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] class_descriptor The descriptor of the class to find. + * @param[out] result A pointer to the class to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FindClass)(ani_env* env, const char* class_descriptor, ani_class* result); + + /** + * @brief Finds an enum by its descriptor. + * + * This function locates an enum based on its descriptor and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enum_descriptor The descriptor of the enum to find. + * @param[out] result A pointer to the enum to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FindEnum)(ani_env* env, const char* enum_descriptor, ani_enum* result); + + /** + * @brief Finds a function within a module by its name and signature. + * + * This function locates a function within the specified module based on its name and signature. + * + * @param[in] env A pointer to the environment structure. + * @param[in] module The module to search within. + * @param[in] name The name of the function to find. + * @param[in] signature The signature of the function to find. + * @param[out] result A pointer to the function object. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Module_FindFunction)( + ani_env* env, ani_module module, const char* name, const char* signature, ani_function* result); + + /** + * @brief Finds a variable within a module by its name. + * + * This function locates a variable within the specified module based on its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] module The module to search within. + * @param[in] name The name of the variable to find. + * @param[out] result A pointer to the variable object. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Module_FindVariable)(ani_env* env, ani_module module, const char* name, ani_variable* result); + + /** + * @brief Finds a function within a namespace by its name and signature. + * + * This function locates a function within the specified namespace based on its name and signature. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ns The namespace to search within. + * @param[in] name The name of the function to find. + * @param[in] signature The signature of the function to find. + * @param[out] result A pointer to the function object. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Namespace_FindFunction)( + ani_env* env, ani_namespace ns, const char* name, const char* signature, ani_function* result); + + /** + * @brief Finds a variable within a namespace by its name. + * + * This function locates a variable within the specified namespace based on its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ns The namespace to search within. + * @param[in] name The name of the variable to find. + * @param[out] result A pointer to the variable object. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Namespace_FindVariable)(ani_env* env, ani_namespace ns, const char* name, ani_variable* result); + + /** + * @brief Binds native functions to a module. + * + * This function binds an array of native functions to the specified module. + * + * @param[in] env A pointer to the environment structure. + * @param[in] module The module to which the native functions will be bound. + * @param[in] functions A pointer to an array of native functions to bind. + * @param[in] nr_functions The number of native functions in the array. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Module_BindNativeFunctions)( + ani_env* env, ani_module module, const ani_native_function* functions, ani_size nr_functions); + + /** + * @brief Binds native functions to a namespace. + * + * This function binds an array of native functions to the specified namespace. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ns The namespace to which the native functions will be bound. + * @param[in] functions A pointer to an array of native functions to bind. + * @param[in] nr_functions The number of native functions in the array. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Namespace_BindNativeFunctions)( + ani_env* env, ani_namespace ns, const ani_native_function* functions, ani_size nr_functions); + + /** + * @brief Binds native methods to a class. + * + * This function binds an array of native methods to the specified class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to which the native methods will be bound. + * @param[in] methods A pointer to an array of native methods to bind. + * @param[in] nr_methods The number of native methods in the array. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_BindNativeMethods)( + ani_env* env, ani_class cls, const ani_native_function* methods, ani_size nr_methods); + + /** + * @brief Deletes a local reference. + * + * This function deletes a specified local reference to free up resources. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference to be deleted. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Reference_Delete)(ani_env* env, ani_ref ref); + + /** + * @brief Ensures enough local references are available. + * + * This function checks and ensures that the specified number of local references can be created. + * + * @param[in] env A pointer to the environment structure. + * @param[in] nr_refs The number of local references to ensure availability for. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*EnsureEnoughReferences)(ani_env* env, ani_size nr_refs); + + /** + * @brief Creates a new local scope for references. + * + * This function creates a local scope for references with a specified capacity. + * + * @param[in] env A pointer to the environment structure. + * @param[in] nr_refs The maximum number of references that can be created in this scope. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*CreateLocalScope)(ani_env* env, ani_size nr_refs); + + /** + * @brief Destroys the current local scope. + * + * This function destroys the current local scope and frees all references within it. + * + * @param[in] env A pointer to the environment structure. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*DestroyLocalScope)(ani_env* env); + + /** + * @brief Creates a new escape local scope. + * + * This function creates a local scope for references with escape functionality, allowing objects to escape this + * scope. + * + * @param[in] env A pointer to the environment structure. + * @param[in] nr_refs The maximum number of references that can be created in this scope. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*CreateEscapeLocalScope)(ani_env* env, ani_size nr_refs); + + /** + * @brief Destroys the current escape local scope. + * + * This function destroys the current escape local scope and allows escaping references to be retrieved. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference to be escaped from the current scope. + * @param[out] result A pointer to the resulting reference that has escaped the scope. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*DestroyEscapeLocalScope)(ani_env* env, ani_ref ref, ani_ref* result); + + /** + * @brief Throws an error. + * + * This function throws the specified error in the current environment. + * + * @param[in] env A pointer to the environment structure. + * @param[in] err The error to throw. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*ThrowError)(ani_env* env, ani_error err); + + /** + * @brief Checks if there are unhandled errors. + * + * This function determines if there are unhandled errors in the current environment. + * + * @param[in] env A pointer to the environment structure. + * @param[out] result A pointer to a boolean indicating if unhandled errors exist. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*ExistUnhandledError)(ani_env* env, ani_boolean* result); + + /** + * @brief Retrieves the current unhandled error. + * + * This function fetches the unhandled error in the environment. + * + * @param[in] env A pointer to the environment structure. + * @param[out] result A pointer to store the unhandled error. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*GetUnhandledError)(ani_env* env, ani_error* result); + + /** + * @brief Resets the current error state. + * + * This function clears the error state in the current environment. + * + * @param[in] env A pointer to the environment structure. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*ResetError)(ani_env* env); + + /** + * @brief Provides a description of the current error. + * + * This function prints the stack trace or other debug information for the current error. + * + * @param[in] env A pointer to the environment structure. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*DescribeError)(ani_env* env); // NOTE: Print stacktrace for debugging? + + /** + * @brief Aborts execution with a message. + * + * This function terminates execution with the specified error message. + * + * @param[in] env A pointer to the environment structure. + * @param[in] message The error message to display on termination. + * @return Does not return; the process terminates. + */ + ani_status (*Abort)(ani_env* env, const char* message); + + /** + * @brief Retrieves a null reference. + * + * This function provides a null reference in the specified result. + * + * @param[in] env A pointer to the environment structure. + * @param[out] result A pointer to store the null reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*GetNull)(ani_env* env, ani_ref* result); + + /** + * @brief Retrieves an undefined reference. + * + * This function provides an undefined reference in the specified result. + * + * @param[in] env A pointer to the environment structure. + * @param[out] result A pointer to store the undefined reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*GetUndefined)(ani_env* env, ani_ref* result); + + /** + * @brief Checks if a reference is null. + * + * This function determines if the specified reference is null. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference to check. + * @param[out] result A pointer to a boolean indicating if the reference is null. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Reference_IsNull)(ani_env* env, ani_ref ref, ani_boolean* result); + + /** + * @brief Checks if a reference is undefined. + * + * This function determines if the specified reference is undefined. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference to check. + * @param[out] result A pointer to a boolean indicating if the reference is undefined. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Reference_IsUndefined)(ani_env* env, ani_ref ref, ani_boolean* result); + + /** + * @brief Checks if a reference is nullish value (null or undefined). + * + * This function determines if the specified reference is either null or undefined. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference to check. + * @param[out] result A pointer to a boolean indicating if the reference is nullish value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Reference_IsNullishValue)(ani_env* env, ani_ref ref, ani_boolean* result); + + /** + * @brief Compares two references for equality. + * + * This function checks if two references are equal. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref0 The first reference to compare. + * @param[in] ref1 The second reference to compare. + * @param[out] result A pointer to a boolean indicating if the references are equal. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Reference_Equals)(ani_env* env, ani_ref ref0, ani_ref ref1, ani_boolean* result); + + /** + * @brief Compares two references for strict equality. + * + * This function checks if two references are strictly equal. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref0 The first reference to compare. + * @param[in] ref1 The second reference to compare. + * @param[out] result A pointer to a boolean indicating if the references are strictly equal. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Reference_StrictEquals)(ani_env* env, ani_ref ref0, ani_ref ref1, ani_boolean* result); + + /** + * @brief Creates a new UTF-16 string. + * + * This function creates a new string from the provided UTF-16 encoded data. + * + * @param[in] env A pointer to the environment structure. + * @param[in] utf16_string A pointer to the UTF-16 encoded string data. + * @param[in] utf16_size The size of the UTF-16 string in code units. + * @param[out] result A pointer to store the created string. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_NewUTF16)(ani_env* env, const uint16_t* utf16_string, ani_size utf16_size, ani_string* result); + + /** + * @brief Retrieves the size of a UTF-16 string. + * + * This function retrieves the size (in code units) of the specified UTF-16 string. + * + * @param[in] env A pointer to the environment structure. + * @param[in] string The UTF-16 string to measure. + * @param[out] result A pointer to store the size of the string. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_GetUTF16Size)(ani_env* env, ani_string string, ani_size* result); + + /** + * @brief Retrieves the UTF-16 encoded data of a string. + * + * This function copies the UTF-16 encoded data of the string into the provided buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] string The string to retrieve data from. + * @param[out] utf16_buffer A buffer to store the UTF-16 encoded data. + * @param[in] utf16_buffer_size The size of the buffer in code units. + * @param[out] result A pointer to store the number of code units written. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_GetUTF16)( + ani_env* env, ani_string string, uint16_t* utf16_buffer, ani_size utf16_buffer_size, ani_size* result); + + /** + * @brief Retrieves a substring of a UTF-16 string. + * + * This function copies a portion of the UTF-16 string into the provided buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] string The string to retrieve data from. + * @param[in] substr_offset The starting offset of the substring. + * @param[in] substr_size The size of the substring in code units. + * @param[out] utf16_buffer A buffer to store the substring. + * @param[in] utf16_buffer_size The size of the buffer in code units. + * @param[out] result A pointer to store the number of code units written. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_GetUTF16SubString)(ani_env* env, ani_string string, ani_size substr_offset, + ani_size substr_size, uint16_t* utf16_buffer, ani_size utf16_buffer_size, ani_size* result); + + /** + * @brief Creates a new UTF-8 string. + * + * This function creates a new string from the provided UTF-8 encoded data. + * + * @param[in] env A pointer to the environment structure. + * @param[in] utf8_string A pointer to the UTF-8 encoded string data. + * @param[in] utf8_size The size of the UTF-8 string in bytes. + * @param[out] result A pointer to store the created string. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_NewUTF8)(ani_env* env, const char* utf8_string, ani_size utf8_size, ani_string* result); + + /** + * @brief Retrieves the size of a UTF-8 string. + * + * This function retrieves the size (in bytes) of the specified UTF-8 string. + * + * @param[in] env A pointer to the environment structure. + * @param[in] string The UTF-8 string to measure. + * @param[out] result A pointer to store the size of the string. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_GetUTF8Size)(ani_env* env, ani_string string, ani_size* result); + + /** + * @brief Retrieves the UTF-8 encoded data of a string. + * + * This function copies the UTF-8 encoded data of the string into the provided buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] string The string to retrieve data from. + * @param[out] utf8_buffer A buffer to store the UTF-8 encoded data. + * @param[in] utf8_buffer_size The size of the buffer in bytes. + * @param[out] result A pointer to store the number of bytes written. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_GetUTF8)( + ani_env* env, ani_string string, char* utf8_buffer, ani_size utf8_buffer_size, ani_size* result); + + /** + * @brief Retrieves a substring of a UTF-8 string. + * + * This function copies a portion of the UTF-8 string into the provided buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] string The string to retrieve data from. + * @param[in] substr_offset The starting offset of the substring. + * @param[in] substr_size The size of the substring in bytes. + * @param[out] utf8_buffer A buffer to store the substring. + * @param[in] utf8_buffer_size The size of the buffer in bytes. + * @param[out] result A pointer to store the number of bytes written. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*String_GetUTF8SubString)(ani_env* env, ani_string string, ani_size substr_offset, ani_size substr_size, + char* utf8_buffer, ani_size utf8_buffer_size, ani_size* result); + + /** + * @brief Retrieves the length of an array. + * + * This function retrieves the length of the specified array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array whose length is to be retrieved. + * @param[out] result A pointer to store the length of the array. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Array_GetLength)(ani_env* env, ani_array array, ani_size* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of booleans. + * + * This function creates a new array of the specified length for boolean values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Boolean)(ani_env* env, ani_size length, ani_array_boolean* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of characters. + * + * This function creates a new array of the specified length for character values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Char)(ani_env* env, ani_size length, ani_array_char* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of bytes. + * + * This function creates a new array of the specified length for byte values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Byte)(ani_env* env, ani_size length, ani_array_byte* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of shorts. + * + * This function creates a new array of the specified length for short integer values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Short)(ani_env* env, ani_size length, ani_array_short* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of integers. + * + * This function creates a new array of the specified length for integer values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Int)(ani_env* env, ani_size length, ani_array_int* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of long integers. + * + * This function creates a new array of the specified length for long integer values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Long)(ani_env* env, ani_size length, ani_array_long* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of floats. + * + * This function creates a new array of the specified length for float values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Float)(ani_env* env, ani_size length, ani_array_float* result); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of doubles. + * + * This function creates a new array of the specified length for double values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Double)(ani_env* env, ani_size length, ani_array_double* result); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of boolean values from an + * array. + * + * This function retrieves a portion of the specified boolean array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved boolean values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Boolean)( + ani_env* env, ani_array_boolean array, ani_size offset, ani_size length, ani_boolean* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of character values from an + * array. + * + * This function retrieves a portion of the specified character array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved character values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Char)( + ani_env* env, ani_array_char array, ani_size offset, ani_size length, ani_char* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of byte values from an + * array. + * + * This function retrieves a portion of the specified byte array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved byte values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Byte)( + ani_env* env, ani_array_byte array, ani_size offset, ani_size length, ani_byte* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of short values from an + * array. + * + * This function retrieves a portion of the specified short array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved short values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Short)( + ani_env* env, ani_array_short array, ani_size offset, ani_size length, ani_short* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of integer values from an + * array. + * + * This function retrieves a portion of the specified integer array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved integer values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Int)( + ani_env* env, ani_array_int array, ani_size offset, ani_size length, ani_int* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of long integer values from + * an array. + * + * This function retrieves a portion of the specified long integer array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved long integer values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Long)( + ani_env* env, ani_array_long array, ani_size offset, ani_size length, ani_long* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of float values from an + * array. + * + * This function retrieves a portion of the specified float array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved float values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Float)( + ani_env* env, ani_array_float array, ani_size offset, ani_size length, ani_float* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a region of double values from an + * array. + * + * This function retrieves a portion of the specified double array into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved double values. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_GetRegion_Double)( + ani_env* env, ani_array_double array, ani_size offset, ani_size length, ani_double* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of boolean values in an array. + * + * This function sets a portion of the specified boolean array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the boolean values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Boolean)( + ani_env* env, ani_array_boolean array, ani_size offset, ani_size length, const ani_boolean* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of character values in an array. + * + * This function sets a portion of the specified character array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the character values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Char)( + ani_env* env, ani_array_char array, ani_size offset, ani_size length, const ani_char* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of byte values in an array. + * + * This function sets a portion of the specified byte array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the byte values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Byte)( + ani_env* env, ani_array_byte array, ani_size offset, ani_size length, const ani_byte* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of short values in an array. + * + * This function sets a portion of the specified short array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the short values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Short)( + ani_env* env, ani_array_short array, ani_size offset, ani_size length, const ani_short* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of integer values in an array. + * + * This function sets a portion of the specified integer array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the integer values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Int)( + ani_env* env, ani_array_int array, ani_size offset, ani_size length, const ani_int* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of long integer values in an + * array. + * + * This function sets a portion of the specified long integer array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the long integer values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Long)( + ani_env* env, ani_array_long array, ani_size offset, ani_size length, const ani_long* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of float values in an array. + * + * This function sets a portion of the specified float array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the float values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Float)( + ani_env* env, ani_array_float array, ani_size offset, ani_size length, const ani_float* native_buffer); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a region of double values in an array. + * + * This function sets a portion of the specified double array using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the double values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_SetRegion_Double)( + ani_env* env, ani_array_double array, ani_size offset, ani_size length, const ani_double* native_buffer); + + /** + * @brief This function is deprecated, please use Array_New instead. Creates a new array of references. + * + * This function creates a new array of references, optionally initializing it with an array of references. + * + * @param[in] env A pointer to the environment structure. + * @param[in] type The type of the elements of the array. + * @param[in] length The length of the array to be created. + * @param[in] initial_element An optional reference to initialize the array. Can be null. + * @param[out] result A pointer to store the created array of references. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_New_Ref)( + ani_env* env, ani_type type, ani_size length, ani_ref initial_element, ani_array_ref* result); + + /** + * @brief This function is deprecated, please use Array_Set instead. Sets a reference at a specific index in an + * array. + * + * This function sets the value of a reference at the specified index in the array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array of references to modify. + * @param[in] index The index at which to set the reference. + * @param[in] ref The reference to set at the specified index. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_Set_Ref)(ani_env* env, ani_array_ref array, ani_size index, ani_ref ref); + + /** + * @brief This function is deprecated, please use Array_Get instead. Retrieves a reference from a specific index in + * an array. + * + * This function retrieves the value of a reference at the specified index in the array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array of references to query. + * @param[in] index The index from which to retrieve the reference. + * @param[out] result A pointer to store the retrieved reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + * + * @deprecated + */ + ani_status (*Array_Get_Ref)(ani_env* env, ani_array_ref array, ani_size index, ani_ref* result); + + /** + * @brief Creates a new array + * + * This function creates a new array of the specified length. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array to be created. + * @param[in] initial_element Element the array will be initialized with + * @param[out] result A pointer to store the created array. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Array_New)(ani_env* env, ani_size length, ani_ref initial_element, ani_array* result); + + /** + * @brief Sets a value to an array. + * + * This function sets a value to array from an ani_ref value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] index The index of element to retrieve. + * @param[in] ref Value to set + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Array_Set)(ani_env* env, ani_array array, ani_size index, ani_ref ref); + + /** + * @brief Retrieves a value from an array. + * + * This function retrieves a value from array into an ani_ref pointer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] index The index of element to retrieve. + * @param[out] result A pointer to store the retrieved value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Array_Get)(ani_env* env, ani_array array, ani_size index, ani_ref* result); + + /** + * @brief Push a value to the end of array. + * + * This function pushes value from an ani_ref to the end of array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array to retrieve values from. + * @param[in] ref Value to set + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Array_Push)(ani_env* env, ani_array array, ani_ref ref); + + /** + * @brief Retrieves the last element and erases it from array. + * + * This function retrieves the last element and erases it from array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array whose last element is to be retrieved. + * @param[out] result A pointer to store the last element of the array. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Array_Pop)(ani_env* env, ani_array array, ani_ref* result); + + /** + * @brief Retrieves the length of an fixedarray. + * + * This function retrieves the length of the specified array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray whose length is to be retrieved. + * @param[out] result A pointer to store the length of the fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetLength)(ani_env* env, ani_fixedarray array, ani_size* result); + + /** + * @brief Creates a new fixedarray of booleans. + * + * This function creates a new fixedarray of the specified length for boolean values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Boolean)(ani_env* env, ani_size length, ani_fixedarray_boolean* result); + + /** + * @brief Creates a new fixedarray of characters. + * + * This function creates a new fixedarray of the specified length for character values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Char)(ani_env* env, ani_size length, ani_fixedarray_char* result); + + /** + * @brief Creates a new fixedarray of bytes. + * + * This function creates a new fixedarray of the specified length for byte values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Byte)(ani_env* env, ani_size length, ani_fixedarray_byte* result); + + /** + * @brief Creates a new fixedarray of shorts. + * + * This function creates a new fixedarray of the specified length for short integer values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Short)(ani_env* env, ani_size length, ani_fixedarray_short* result); + + /** + * @brief Creates a new fixedarray of integers. + * + * This function creates a new fixedarray of the specified length for integer values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Int)(ani_env* env, ani_size length, ani_fixedarray_int* result); + + /** + * @brief Creates a new fixedarray of long integers. + * + * This function creates a new fixedarray of the specified length for long integer values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Long)(ani_env* env, ani_size length, ani_fixedarray_long* result); + + /** + * @brief Creates a new fixedarray of floats. + * + * This function creates a new fixedarray of the specified length for float values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Float)(ani_env* env, ani_size length, ani_fixedarray_float* result); + + /** + * @brief Creates a new fixedarray of doubles. + * + * This function creates a new fixedarray of the specified length for double values. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the fixedarray to be created. + * @param[out] result A pointer to store the created fixedarray. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Double)(ani_env* env, ani_size length, ani_fixedarray_double* result); + + /** + * @brief Retrieves a region of boolean values from an fixedarray. + * + * This function retrieves a portion of the specified boolean fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved boolean values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Boolean)( + ani_env* env, ani_fixedarray_boolean array, ani_size offset, ani_size length, ani_boolean* native_buffer); + + /** + * @brief Retrieves a region of character values from an fixedarray. + * + * This function retrieves a portion of the specified character fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved character values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Char)( + ani_env* env, ani_fixedarray_char array, ani_size offset, ani_size length, ani_char* native_buffer); + + /** + * @brief Retrieves a region of byte values from an fixedarray. + * + * This function retrieves a portion of the specified byte fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved byte values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Byte)( + ani_env* env, ani_fixedarray_byte array, ani_size offset, ani_size length, ani_byte* native_buffer); + + /** + * @brief Retrieves a region of short values from an fixedarray. + * + * This function retrieves a portion of the specified short fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved short values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Short)( + ani_env* env, ani_fixedarray_short array, ani_size offset, ani_size length, ani_short* native_buffer); + + /** + * @brief Retrieves a region of integer values from an fixedarray. + * + * This function retrieves a portion of the specified integer fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved integer values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Int)( + ani_env* env, ani_fixedarray_int array, ani_size offset, ani_size length, ani_int* native_buffer); + + /** + * @brief Retrieves a region of long integer values from an fixedarray. + * + * This function retrieves a portion of the specified long integer fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved long integer values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Long)( + ani_env* env, ani_fixedarray_long array, ani_size offset, ani_size length, ani_long* native_buffer); + + /** + * @brief Retrieves a region of float values from an fixedarray. + * + * This function retrieves a portion of the specified float fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved float values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Float)( + ani_env* env, ani_fixedarray_float array, ani_size offset, ani_size length, ani_float* native_buffer); + + /** + * @brief Retrieves a region of double values from an fixedarray. + * + * This function retrieves a portion of the specified double fixedarray into a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to retrieve values from. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to retrieve. + * @param[out] native_buffer A buffer to store the retrieved double values. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_GetRegion_Double)( + ani_env* env, ani_fixedarray_double array, ani_size offset, ani_size length, ani_double* native_buffer); + + /** + * @brief Sets a region of boolean values in an fixedarray. + * + * This function sets a portion of the specified boolean fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the boolean values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Boolean)( + ani_env* env, ani_fixedarray_boolean array, ani_size offset, ani_size length, const ani_boolean* native_buffer); + + /** + * @brief Sets a region of character values in an fixedarray. + * + * This function sets a portion of the specified character fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the character values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Char)( + ani_env* env, ani_fixedarray_char array, ani_size offset, ani_size length, const ani_char* native_buffer); + + /** + * @brief Sets a region of byte values in an fixedarray. + * + * This function sets a portion of the specified byte fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the byte values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Byte)( + ani_env* env, ani_fixedarray_byte array, ani_size offset, ani_size length, const ani_byte* native_buffer); + + /** + * @brief Sets a region of short values in an fixedarray. + * + * This function sets a portion of the specified short fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the short values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Short)( + ani_env* env, ani_fixedarray_short array, ani_size offset, ani_size length, const ani_short* native_buffer); + + /** + * @brief Sets a region of integer values in an fixedarray. + * + * This function sets a portion of the specified integer fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the integer values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Int)( + ani_env* env, ani_fixedarray_int array, ani_size offset, ani_size length, const ani_int* native_buffer); + + /** + * @brief Sets a region of long integer values in an fixedarray. + * + * This function sets a portion of the specified long integer fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the long integer values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Long)( + ani_env* env, ani_fixedarray_long array, ani_size offset, ani_size length, const ani_long* native_buffer); + + /** + * @brief Sets a region of float values in an fixedarray. + * + * This function sets a portion of the specified float fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the float values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Float)( + ani_env* env, ani_fixedarray_float array, ani_size offset, ani_size length, const ani_float* native_buffer); + + /** + * @brief Sets a region of double values in an fixedarray. + * + * This function sets a portion of the specified double fixedarray using a native buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray to set values in. + * @param[in] offset The starting offset of the region. + * @param[in] length The number of elements to set. + * @param[in] native_buffer A buffer containing the double values to set. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_SetRegion_Double)( + ani_env* env, ani_fixedarray_double array, ani_size offset, ani_size length, const ani_double* native_buffer); + + /** + * @brief Creates a new fixedarray of references. + * + * This function creates a new fixedarray of references, optionally initializing it with an initial_element ref. + * + * @param[in] env A pointer to the environment structure. + * @param[in] type The type of the elements of the fixedarray. + * @param[in] length The length of the fixedarray to be created. + * @param[in] initial_element An optional reference to initialize the fixedarray. Can be null. + * @param[out] result A pointer to store the created fixedarray of references. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_New_Ref)( + ani_env* env, ani_type type, ani_size length, ani_ref initial_element, ani_fixedarray_ref* result); + + /** + * @brief Sets a reference at a specific index in an fixedarray. + * + * This function sets the value of a reference at the specified index in the fixedarray. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The array of references to modify. + * @param[in] index The index at which to set the reference. + * @param[in] ref The reference to set at the specified index. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_Set_Ref)(ani_env* env, ani_fixedarray_ref array, ani_size index, ani_ref ref); + + /** + * @brief Retrieves a reference from a specific index in an fixedarray. + * + * This function retrieves the value of a reference at the specified index in the fixedarray. + * + * @param[in] env A pointer to the environment structure. + * @param[in] array The fixedarray of references to query. + * @param[in] index The index from which to retrieve the reference. + * @param[out] result A pointer to store the retrieved reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FixedArray_Get_Ref)(ani_env* env, ani_fixedarray_ref array, ani_size index, ani_ref* result); + + /** + * @brief Retrieves an enum item by its name. + * + * This function retrieves an enum item associated with the specified name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enm The enum to search within. + * @param[in] name The name of the enum item to retrieve. + * @param[out] result A pointer to store the retrieved enum item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Enum_GetEnumItemByName)(ani_env* env, ani_enum enm, const char* name, ani_enum_item* result); + + /** + * @brief Retrieves an enum item by its index. + * + * This function retrieves an enum item located at the specified index. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enm The enum to search within. + * @param[in] index The index of the enum item to retrieve. + * @param[out] result A pointer to store the retrieved enum item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Enum_GetEnumItemByIndex)(ani_env* env, ani_enum enm, ani_size index, ani_enum_item* result); + + /** + * @brief Retrieves the enum associated with an enum item. + * + * This function retrieves the enum to which the specified enum item belongs. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enum_item The enum item whose associated enum is to be retrieved. + * @param[out] result A pointer to store the retrieved enum. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*EnumItem_GetEnum)(ani_env* env, ani_enum_item enum_item, ani_enum* result); + + /** + * @brief Retrieves the integer value of an enum item. + * + * This function retrieves the integer representing the value of the specified enum item. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enum_item The enum item whose underlying value is to be retrieved. + * @param[out] result A pointer to store the retrieved integer. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*EnumItem_GetValue_Int)(ani_env* env, ani_enum_item enum_item, ani_int* result); + + /** + * @brief Retrieves the string value of an enum item. + * + * This function retrieves the string representing the value of the specified enum item. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enum_item The enum item whose underlying value is to be retrieved. + * @param[out] result A pointer to store the retrieved string. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*EnumItem_GetValue_String)(ani_env* env, ani_enum_item enum_item, ani_string* result); + + /** + * @brief Retrieves the name of an enum item. + * + * This function retrieves the name associated with the specified enum item. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enum_item The enum item whose name is to be retrieved. + * @param[out] result A pointer to store the retrieved name. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*EnumItem_GetName)(ani_env* env, ani_enum_item enum_item, ani_string* result); + + /** + * @brief Retrieves the index of an enum item. + * + * This function retrieves the index of the specified enum item within its enum. + * + * @param[in] env A pointer to the environment structure. + * @param[in] enum_item The enum item whose index is to be retrieved. + * @param[out] result A pointer to store the retrieved index. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*EnumItem_GetIndex)(ani_env* env, ani_enum_item enum_item, ani_size* result); + + /** + * @brief Invokes a functional object. + * + * This function invokes a functional object (e.g., a function or callable object) with the specified arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The functional object to invoke. + * @param[in] argc The number of arguments being passed to the functional object. + * @param[in] argv A pointer to an array of references representing the arguments. Can be null if `argc` is 0. + * @param[out] result A pointer to store the result of the invocation. Must be non null. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*FunctionalObject_Call)(ani_env* env, ani_fn_object fn, ani_size argc, ani_ref* argv, ani_ref* result); + + /** + * @brief Sets a boolean value to a variable. + * + * This function assigns a boolean value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The boolean value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Boolean)(ani_env* env, ani_variable variable, ani_boolean value); + + /** + * @brief Sets a character value to a variable. + * + * This function assigns a character value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The character value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Char)(ani_env* env, ani_variable variable, ani_char value); + + /** + * @brief Sets a byte value to a variable. + * + * This function assigns a byte value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The byte value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Byte)(ani_env* env, ani_variable variable, ani_byte value); + + /** + * @brief Sets a short value to a variable. + * + * This function assigns a short integer value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The short integer value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Short)(ani_env* env, ani_variable variable, ani_short value); + + /** + * @brief Sets an integer value to a variable. + * + * This function assigns an integer value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The integer value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Int)(ani_env* env, ani_variable variable, ani_int value); + + /** + * @brief Sets a long value to a variable. + * + * This function assigns a long integer value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The long integer value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Long)(ani_env* env, ani_variable variable, ani_long value); + + /** + * @brief Sets a float value to a variable. + * + * This function assigns a float value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The float value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Float)(ani_env* env, ani_variable variable, ani_float value); + + /** + * @brief Sets a double value to a variable. + * + * This function assigns a double value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The double value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Double)(ani_env* env, ani_variable variable, ani_double value); + + /** + * @brief Sets a reference value to a variable. + * + * This function assigns a reference value to the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to modify. + * @param[in] value The reference value to assign to the variable. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_SetValue_Ref)(ani_env* env, ani_variable variable, ani_ref value); + + /** + * @brief Retrieves a boolean value from a variable. + * + * This function fetches a boolean value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved boolean value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Boolean)(ani_env* env, ani_variable variable, ani_boolean* result); + + /** + * @brief Retrieves a character value from a variable. + * + * This function fetches a character value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved character value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Char)(ani_env* env, ani_variable variable, ani_char* result); + + /** + * @brief Retrieves a byte value from a variable. + * + * This function fetches a byte value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved byte value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Byte)(ani_env* env, ani_variable variable, ani_byte* result); + + /** + * @brief Retrieves a short value from a variable. + * + * This function fetches a short integer value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved short integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Short)(ani_env* env, ani_variable variable, ani_short* result); + + /** + * @brief Retrieves an integer value from a variable. + * + * This function fetches an integer value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Int)(ani_env* env, ani_variable variable, ani_int* result); + + /** + * @brief Retrieves a long value from a variable. + * + * This function fetches a long integer value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved long integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Long)(ani_env* env, ani_variable variable, ani_long* result); + + /** + * @brief Retrieves a float value from a variable. + * + * This function fetches a float value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved float value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Float)(ani_env* env, ani_variable variable, ani_float* result); + + /** + * @brief Retrieves a double value from a variable. + * + * This function fetches a double value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved double value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Double)(ani_env* env, ani_variable variable, ani_double* result); + + /** + * @brief Retrieves a reference value from a variable. + * + * This function fetches a reference value from the specified variable. + * + * @param[in] env A pointer to the environment structure. + * @param[in] variable The variable to query. + * @param[out] result A pointer to store the retrieved reference value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Variable_GetValue_Ref)(ani_env* env, ani_variable variable, ani_ref* result); + + /** + * @brief Calls a function and retrieves a boolean result. + * + * This function calls the specified function with variadic arguments and retrieves a boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Boolean)(ani_env* env, ani_function fn, ani_boolean* result, ...); + + /** + * @brief Calls a function and retrieves a boolean result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Boolean_A)(ani_env* env, ani_function fn, ani_boolean* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a boolean result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Boolean_V)(ani_env* env, ani_function fn, ani_boolean* result, va_list args); + + /** + * @brief Calls a function and retrieves a character result. + * + * This function calls the specified function with variadic arguments and retrieves a character result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the character result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Char)(ani_env* env, ani_function fn, ani_char* result, ...); + + /** + * @brief Calls a function and retrieves a character result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a character result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the character result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Char_A)(ani_env* env, ani_function fn, ani_char* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a character result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a character + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the character result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Char_V)(ani_env* env, ani_function fn, ani_char* result, va_list args); + + /** + * @brief Calls a function and retrieves a byte result. + * + * This function calls the specified function with variadic arguments and retrieves a byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the byte result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Byte)(ani_env* env, ani_function fn, ani_byte* result, ...); + + /** + * @brief Calls a function and retrieves a byte result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the byte result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Byte_A)(ani_env* env, ani_function fn, ani_byte* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a byte result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the byte result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Byte_V)(ani_env* env, ani_function fn, ani_byte* result, va_list args); + + /** + * @brief Calls a function and retrieves a short result. + * + * This function calls the specified function with variadic arguments and retrieves a short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the short result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Short)(ani_env* env, ani_function fn, ani_short* result, ...); + + /** + * @brief Calls a function and retrieves a short result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the short result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Short_A)(ani_env* env, ani_function fn, ani_short* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a short result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the short result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Short_V)(ani_env* env, ani_function fn, ani_short* result, va_list args); + + /** + * @brief Calls a function and retrieves an integer result. + * + * This function calls the specified function with variadic arguments and retrieves an integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the integer result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Int)(ani_env* env, ani_function fn, ani_int* result, ...); + + /** + * @brief Calls a function and retrieves an integer result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves an integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the integer result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Int_A)(ani_env* env, ani_function fn, ani_int* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves an integer result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves an integer + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the integer result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Int_V)(ani_env* env, ani_function fn, ani_int* result, va_list args); + + /** + * @brief Calls a function and retrieves a long result. + * + * This function calls the specified function with variadic arguments and retrieves a long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the long result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Long)(ani_env* env, ani_function fn, ani_long* result, ...); + + /** + * @brief Calls a function and retrieves a long result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the long result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Long_A)(ani_env* env, ani_function fn, ani_long* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a long result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the long result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Long_V)(ani_env* env, ani_function fn, ani_long* result, va_list args); + + /** + * @brief Calls a function and retrieves a float result. + * + * This function calls the specified function with variadic arguments and retrieves a float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the float result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Float)(ani_env* env, ani_function fn, ani_float* result, ...); + + /** + * @brief Calls a function and retrieves a float result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the float result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Float_A)(ani_env* env, ani_function fn, ani_float* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a float result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the float result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Float_V)(ani_env* env, ani_function fn, ani_float* result, va_list args); + + /** + * @brief Calls a function and retrieves a double result. + * + * This function calls the specified function with variadic arguments and retrieves a double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the double result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Double)(ani_env* env, ani_function fn, ani_double* result, ...); + + /** + * @brief Calls a function and retrieves a double result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the double result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Double_A)(ani_env* env, ani_function fn, ani_double* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a double result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the double result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Double_V)(ani_env* env, ani_function fn, ani_double* result, va_list args); + + /** + * @brief Calls a function and retrieves a reference result. + * + * This function calls the specified function with variadic arguments and retrieves a reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the reference result. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Ref)(ani_env* env, ani_function fn, ani_ref* result, ...); + + /** + * @brief Calls a function and retrieves a reference result (array-based). + * + * This function calls the specified function with arguments provided in an array and retrieves a reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the reference result. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Ref_A)(ani_env* env, ani_function fn, ani_ref* result, const ani_value* args); + + /** + * @brief Calls a function and retrieves a reference result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and retrieves a reference + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[out] result A pointer to store the reference result. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Ref_V)(ani_env* env, ani_function fn, ani_ref* result, va_list args); + + /** + * @brief Calls a function without returning a result. + * + * This function calls the specified function with variadic arguments and does not return a result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[in] ... Variadic arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Void)(ani_env* env, ani_function fn, ...); + + /** + * @brief Calls a function without returning a result (array-based). + * + * This function calls the specified function with arguments provided in an array and does not return a result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[in] args A pointer to an array of arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Void_A)(ani_env* env, ani_function fn, const ani_value* args); + + /** + * @brief Calls a function without returning a result (variadic arguments). + * + * This function calls the specified function with arguments provided in a `va_list` and does not return a result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] fn The function to call. + * @param[in] args A `va_list` containing the arguments to pass to the function. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Function_Call_Void_V)(ani_env* env, ani_function fn, va_list args); + + /** + * @brief Finds a field from by its name. + * + * This function locates a field based on its name and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] name The name of the field to find. + * @param[out] result A pointer to the field to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindField)(ani_env* env, ani_class cls, const char* name, ani_field* result); + + /** + * @brief Finds a static field by its name. + * + * This function locates a static field based on its name and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] name The name of the static field to find. + * @param[out] result A pointer to the static field to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindStaticField)(ani_env* env, ani_class cls, const char* name, ani_static_field* result); + + /** + * @brief Finds a method from by its name and signature. + * + * This function locates a method based on its name and signature and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] name The name of the method to find. + * @param[in] signature The signature of the method to find. + * @param[out] result A pointer to the method to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindMethod)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_method* result); + + /** + * @brief Finds a static method from by its name and signature. + * + * This function locates a static method based on its name and signature and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] name The name of the static method to find. + * @param[in] signature The signature of the static method to find. + * @param[out] result A pointer to the static method to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindStaticMethod)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_static_method* result); + + /** + * @brief Finds a setter method from by its name. + * + * This function locates a setter method based on its name and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] name The name of the property whose setter is to be found. + * @param[out] result A pointer to the method to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindSetter)(ani_env* env, ani_class cls, const char* name, ani_method* result); + + /** + * @brief Finds a getter method from by its name. + * + * This function locates a getter method based on its name and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] name The name of the property whose getter is to be found. + * @param[out] result A pointer to the method to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindGetter)(ani_env* env, ani_class cls, const char* name, ani_method* result); + + /** + * @brief Finds an indexable getter method from by its signature. + * + * This function locates an indexable getter method based on its signature and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] signature The signature of the indexable getter to find. + * @param[out] result A pointer to the method to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindIndexableGetter)(ani_env* env, ani_class cls, const char* signature, ani_method* result); + + /** + * @brief Finds an indexable setter method from by its signature. + * + * This function locates an indexable setter method based on its signature and stores it in the result parameter. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[in] signature The signature of the indexable setter to find. + * @param[out] result A pointer to the method to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindIndexableSetter)(ani_env* env, ani_class cls, const char* signature, ani_method* result); + + /** + * @brief Finds an iterator method. + * + * This function locates an iterator method + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to query. + * @param[out] result A pointer to the method to be populated. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_FindIterator)(ani_env* env, ani_class cls, ani_method* result); + + /** + * @brief Retrieves a boolean value from a static field of a class. + * + * This function retrieves the boolean value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved boolean value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Boolean)( + ani_env* env, ani_class cls, ani_static_field field, ani_boolean* result); + + /** + * @brief Retrieves a character value from a static field of a class. + * + * This function retrieves the character value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved character value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Char)(ani_env* env, ani_class cls, ani_static_field field, ani_char* result); + + /** + * @brief Retrieves a byte value from a static field of a class. + * + * This function retrieves the byte value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved byte value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Byte)(ani_env* env, ani_class cls, ani_static_field field, ani_byte* result); + + /** + * @brief Retrieves a short value from a static field of a class. + * + * This function retrieves the short value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved short value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Short)(ani_env* env, ani_class cls, ani_static_field field, ani_short* result); + + /** + * @brief Retrieves an integer value from a static field of a class. + * + * This function retrieves the integer value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Int)(ani_env* env, ani_class cls, ani_static_field field, ani_int* result); + + /** + * @brief Retrieves a long value from a static field of a class. + * + * This function retrieves the long value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved long value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Long)(ani_env* env, ani_class cls, ani_static_field field, ani_long* result); + + /** + * @brief Retrieves a float value from a static field of a class. + * + * This function retrieves the float value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved float value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Float)(ani_env* env, ani_class cls, ani_static_field field, ani_float* result); + + /** + * @brief Retrieves a double value from a static field of a class. + * + * This function retrieves the double value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved double value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Double)(ani_env* env, ani_class cls, ani_static_field field, ani_double* result); + + /** + * @brief Retrieves a reference value from a static field of a class. + * + * This function retrieves the reference value of the specified static field from the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to retrieve. + * @param[out] result A pointer to store the retrieved reference value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticField_Ref)(ani_env* env, ani_class cls, ani_static_field field, ani_ref* result); + + /** + * @brief Sets a boolean value to a static field of a class. + * + * This function assigns a boolean value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The boolean value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Boolean)(ani_env* env, ani_class cls, ani_static_field field, ani_boolean value); + + /** + * @brief Sets a character value to a static field of a class. + * + * This function assigns a character value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The character value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Char)(ani_env* env, ani_class cls, ani_static_field field, ani_char value); + + /** + * @brief Sets a byte value to a static field of a class. + * + * This function assigns a byte value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The byte value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Byte)(ani_env* env, ani_class cls, ani_static_field field, ani_byte value); + + /** + * @brief Sets a short value to a static field of a class. + * + * This function assigns a short value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The short value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Short)(ani_env* env, ani_class cls, ani_static_field field, ani_short value); + + /** + * @brief Sets an integer value to a static field of a class. + * + * This function assigns an integer value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The integer value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Int)(ani_env* env, ani_class cls, ani_static_field field, ani_int value); + + /** + * @brief Sets a long value to a static field of a class. + * + * This function assigns a long value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The long value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Long)(ani_env* env, ani_class cls, ani_static_field field, ani_long value); + + /** + * @brief Sets a float value to a static field of a class. + * + * This function assigns a float value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The float value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Float)(ani_env* env, ani_class cls, ani_static_field field, ani_float value); + + /** + * @brief Sets a double value to a static field of a class. + * + * This function assigns a double value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The double value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Double)(ani_env* env, ani_class cls, ani_static_field field, ani_double value); + + /** + * @brief Sets a reference value to a static field of a class. + * + * This function assigns a reference value to the specified static field of the given class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] field The static field to modify. + * @param[in] value The reference value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticField_Ref)(ani_env* env, ani_class cls, ani_static_field field, ani_ref value); + + /** + * @brief Retrieves a boolean value from a static field of a class by its name. + * + * This function retrieves the boolean value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved boolean value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Boolean)( + ani_env* env, ani_class cls, const char* name, ani_boolean* result); + + /** + * @brief Retrieves a character value from a static field of a class by its name. + * + * This function retrieves the character value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved character value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Char)(ani_env* env, ani_class cls, const char* name, ani_char* result); + + /** + * @brief Retrieves a byte value from a static field of a class by its name. + * + * This function retrieves the byte value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved byte value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Byte)(ani_env* env, ani_class cls, const char* name, ani_byte* result); + + /** + * @brief Retrieves a short value from a static field of a class by its name. + * + * This function retrieves the short value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved short value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Short)(ani_env* env, ani_class cls, const char* name, ani_short* result); + + /** + * @brief Retrieves an integer value from a static field of a class by its name. + * + * This function retrieves the integer value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Int)(ani_env* env, ani_class cls, const char* name, ani_int* result); + + /** + * @brief Retrieves a long value from a static field of a class by its name. + * + * This function retrieves the long value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved long value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Long)(ani_env* env, ani_class cls, const char* name, ani_long* result); + + /** + * @brief Retrieves a float value from a static field of a class by its name. + * + * This function retrieves the float value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved float value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Float)(ani_env* env, ani_class cls, const char* name, ani_float* result); + + /** + * @brief Retrieves a double value from a static field of a class by its name. + * + * This function retrieves the double value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved double value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Double)(ani_env* env, ani_class cls, const char* name, ani_double* result); + + /** + * @brief Retrieves a reference value from a static field of a class by its name. + * + * This function retrieves the reference value of the specified static field from the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to retrieve. + * @param[out] result A pointer to store the retrieved reference value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_GetStaticFieldByName_Ref)(ani_env* env, ani_class cls, const char* name, ani_ref* result); + + /** + * @brief Sets a boolean value to a static field of a class by its name. + * + * This function assigns a boolean value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The boolean value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Boolean)(ani_env* env, ani_class cls, const char* name, ani_boolean value); + + /** + * @brief Sets a character value to a static field of a class by its name. + * + * This function assigns a character value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The character value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Char)(ani_env* env, ani_class cls, const char* name, ani_char value); + + /** + * @brief Sets a byte value to a static field of a class by its name. + * + * This function assigns a byte value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The byte value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Byte)(ani_env* env, ani_class cls, const char* name, ani_byte value); + + /** + * @brief Sets a short value to a static field of a class by its name. + * + * This function assigns a short value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The short value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Short)(ani_env* env, ani_class cls, const char* name, ani_short value); + + /** + * @brief Sets an integer value to a static field of a class by its name. + * + * This function assigns an integer value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The integer value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Int)(ani_env* env, ani_class cls, const char* name, ani_int value); + + /** + * @brief Sets a long value to a static field of a class by its name. + * + * This function assigns a long value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The long value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Long)(ani_env* env, ani_class cls, const char* name, ani_long value); + + /** + * @brief Sets a float value to a static field of a class by its name. + * + * This function assigns a float value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The float value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Float)(ani_env* env, ani_class cls, const char* name, ani_float value); + + /** + * @brief Sets a double value to a static field of a class by its name. + * + * This function assigns a double value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The double value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Double)(ani_env* env, ani_class cls, const char* name, ani_double value); + + /** + * @brief Sets a reference value to a static field of a class by its name. + * + * This function assigns a reference value to the specified static field of the given class by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static field. + * @param[in] name The name of the static field to modify. + * @param[in] value The reference value to assign. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_SetStaticFieldByName_Ref)(ani_env* env, ani_class cls, const char* name, ani_ref value); + + /** + * @brief Calls a static method with a boolean return type. + * + * This function calls the specified static method of a class and retrieves a boolean result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Boolean)( + ani_env* env, ani_class cls, ani_static_method method, ani_boolean* result, ...); + + /** + * @brief Calls a static method with a boolean return type (array-based). + * + * This function calls the specified static method of a class and retrieves a boolean result using arguments from an + * array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Boolean_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_boolean* result, const ani_value* args); + + /** + * @brief Calls a static method with a boolean return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a boolean result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Boolean_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_boolean* result, va_list args); + + /** + * @brief Calls a static method with a character return type. + * + * This function calls the specified static method of a class and retrieves a character result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the character result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Char)( + ani_env* env, ani_class cls, ani_static_method method, ani_char* result, ...); + + /** + * @brief Calls a static method with a character return type (array-based). + * + * This function calls the specified static method of a class and retrieves a character result using arguments from + * an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the character result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Char_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_char* result, const ani_value* args); + + /** + * @brief Calls a static method with a character return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a character result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the character result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Char_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_char* result, va_list args); + + /** + * @brief Calls a static method with a byte return type. + * + * This function calls the specified static method of a class and retrieves a byte result using variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the byte result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Byte)( + ani_env* env, ani_class cls, ani_static_method method, ani_byte* result, ...); + + /** + * @brief Calls a static method with a byte return type (array-based). + * + * This function calls the specified static method of a class and retrieves a byte result using arguments from an + * array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the byte result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Byte_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_byte* result, const ani_value* args); + + /** + * @brief Calls a static method with a byte return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a byte result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the byte result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Byte_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_byte* result, va_list args); + + /** + * @brief Calls a static method with a short return type. + * + * This function calls the specified static method of a class and retrieves a short result using variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the short result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Short)( + ani_env* env, ani_class cls, ani_static_method method, ani_short* result, ...); + + /** + * @brief Calls a static method with a short return type (array-based). + * + * This function calls the specified static method of a class and retrieves a short result using arguments from an + * array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the short result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Short_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_short* result, const ani_value* args); + + /** + * @brief Calls a static method with a short return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a short result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the short result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Short_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_short* result, va_list args); + + /** + * @brief Calls a static method with an integer return type. + * + * This function calls the specified static method of a class and retrieves an integer result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the integer result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Int)( + ani_env* env, ani_class cls, ani_static_method method, ani_int* result, ...); + + /** + * @brief Calls a static method with an integer return type (array-based). + * + * This function calls the specified static method of a class and retrieves an integer result using arguments from + * an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the integer result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Int_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_int* result, const ani_value* args); + + /** + * @brief Calls a static method with an integer return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves an integer result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the integer result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Int_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_int* result, va_list args); + + /** + * @brief Calls a static method with a long return type. + * + * This function calls the specified static method of a class and retrieves a long result using variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the long result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Long)( + ani_env* env, ani_class cls, ani_static_method method, ani_long* result, ...); + + /** + * @brief Calls a static method with a long return type (array-based). + * + * This function calls the specified static method of a class and retrieves a long result using arguments from an + * array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the long result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Long_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_long* result, const ani_value* args); + + /** + * @brief Calls a static method with a long return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a long result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the long result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Long_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_long* result, va_list args); + + /** + * @brief Calls a static method with a float return type. + * + * This function calls the specified static method of a class and retrieves a float result using variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the float result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Float)( + ani_env* env, ani_class cls, ani_static_method method, ani_float* result, ...); + + /** + * @brief Calls a static method with a float return type (array-based). + * + * This function calls the specified static method of a class and retrieves a float result using arguments from an + * array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the float result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Float_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_float* result, const ani_value* args); + + /** + * @brief Calls a static method with a float return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a float result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the float result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Float_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_float* result, va_list args); + + /** + * @brief Calls a static method with a double return type. + * + * This function calls the specified static method of a class and retrieves a double result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the double result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Double)( + ani_env* env, ani_class cls, ani_static_method method, ani_double* result, ...); + + /** + * @brief Calls a static method with a double return type (array-based). + * + * This function calls the specified static method of a class and retrieves a double result using arguments from an + * array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the double result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Double_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_double* result, const ani_value* args); + + /** + * @brief Calls a static method with a double return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a double result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the double result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Double_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_double* result, va_list args); + + /** + * @brief Calls a static method with a reference return type. + * + * This function calls the specified static method of a class and retrieves a reference result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the reference result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Ref)( + ani_env* env, ani_class cls, ani_static_method method, ani_ref* result, ...); + + /** + * @brief Calls a static method with a reference return type (array-based). + * + * This function calls the specified static method of a class and retrieves a reference result using arguments from + * an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the reference result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Ref_A)( + ani_env* env, ani_class cls, ani_static_method method, ani_ref* result, const ani_value* args); + + /** + * @brief Calls a static method with a reference return type (variadic arguments). + * + * This function calls the specified static method of a class and retrieves a reference result using a `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[out] result A pointer to store the reference result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Ref_V)( + ani_env* env, ani_class cls, ani_static_method method, ani_ref* result, va_list args); + + /** + * @brief Calls a static method with no return value. + * + * This function calls the specified static method of a class using variadic arguments. The method does not return a + * value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Void)(ani_env* env, ani_class cls, ani_static_method method, ...); + + /** + * @brief Calls a static method with no return value (array-based). + * + * This function calls the specified static method of a class using arguments from an array. The method does not + * return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Void_A)( + ani_env* env, ani_class cls, ani_static_method method, const ani_value* args); + + /** + * @brief Calls a static method with no return value (variadic arguments). + * + * This function calls the specified static method of a class using a `va_list`. The method does not return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] method The static method to call. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethod_Void_V)(ani_env* env, ani_class cls, ani_static_method method, va_list args); + + /** + * @brief Calls a static method by name with a boolean return type. + * + * This function calls the specified static method of a class by its name and retrieves a boolean result using + * variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Boolean)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_boolean* result, ...); + + /** + * @brief Calls a static method by name with a boolean return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a boolean result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Boolean_A)(ani_env* env, ani_class cls, const char* name, + const char* signature, ani_boolean* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a boolean return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a boolean result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the boolean result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Boolean_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_boolean* result, va_list args); + + /** + * @brief Calls a static method by name with a char return type. + * + * This function calls the specified static method of a class by its name and retrieves a char result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the char result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Char)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_char* result, ...); + + /** + * @brief Calls a static method by name with a char return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a char result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the char result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Char_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_char* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a char return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a char result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the char result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Char_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_char* result, va_list args); + + /** + * @brief Calls a static method by name with a byte return type. + * + * This function calls the specified static method of a class by its name and retrieves a byte result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the byte result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Byte)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_byte* result, ...); + + /** + * @brief Calls a static method by name with a byte return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a byte result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the byte result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Byte_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_byte* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a byte return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a byte result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the byte result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Byte_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_byte* result, va_list args); + + /** + * @brief Calls a static method by name with a short return type. + * + * This function calls the specified static method of a class by its name and retrieves a short result using + * variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the short result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Short)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_short* result, ...); + + /** + * @brief Calls a static method by name with a short return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a short result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the short result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Short_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_short* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a short return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a short result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the short result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Short_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_short* result, va_list args); + + /** + * @brief Calls a static method by name with a integer return type. + * + * This function calls the specified static method of a class by its name and retrieves a integer result using + * variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the integer result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Int)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_int* result, ...); + + /** + * @brief Calls a static method by name with a integer return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a integer result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the integer result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Int_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_int* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a integer return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a integer result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the integer result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Int_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_int* result, va_list args); + + /** + * @brief Calls a static method by name with a long return type. + * + * This function calls the specified static method of a class by its name and retrieves a long result using variadic + * arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the long result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Long)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_long* result, ...); + + /** + * @brief Calls a static method by name with a long return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a long result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the long result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Long_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_long* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a long return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a long result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the long result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Long_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_long* result, va_list args); + + /** + * @brief Calls a static method by name with a float return type. + * + * This function calls the specified static method of a class by its name and retrieves a float result using + * variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the float result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Float)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_float* result, ...); + + /** + * @brief Calls a static method by name with a float return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a float result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the float result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Float_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_float* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a float return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a float result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the float result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Float_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_float* result, va_list args); + + /** + * @brief Calls a static method by name with a double return type. + * + * This function calls the specified static method of a class by its name and retrieves a double result using + * variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the double result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Double)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_double* result, ...); + + /** + * @brief Calls a static method by name with a double return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a double result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the double result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Double_A)(ani_env* env, ani_class cls, const char* name, + const char* signature, ani_double* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a double return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a double result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the double result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Double_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_double* result, va_list args); + + /** + * @brief Calls a static method by name with a reference return type. + * + * This function calls the specified static method of a class by its name and retrieves a reference result using + * variadic arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the reference result. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Ref)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_ref* result, ...); + + /** + * @brief Calls a static method by name with a reference return type (array-based). + * + * This function calls the specified static method of a class by its name and retrieves a reference result using + * arguments from an array. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the reference result. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Ref_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_ref* result, const ani_value* args); + + /** + * @brief Calls a static method by name with a reference return type (variadic arguments). + * + * This function calls the specified static method of a class by its name and retrieves a reference result using a + * `va_list`. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[out] result A pointer to store the reference result. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Ref_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, ani_ref* result, va_list args); + + /** + * @brief Calls a static method by name with no return value. + * + * This function calls the specified static method of a class by its name using variadic arguments. The method does + * not return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Void)( + ani_env* env, ani_class cls, const char* name, const char* signature, ...); + + /** + * @brief Calls a static method by name with no return value (array-based). + * + * This function calls the specified static method of a class by its name using arguments from an array. The method + * does not return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Void_A)( + ani_env* env, ani_class cls, const char* name, const char* signature, const ani_value* args); + + /** + * @brief Calls a static method by name with no return value (variadic arguments). + * + * This function calls the specified static method of a class by its name using a `va_list`. The method does not + * return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class containing the static method. + * @param[in] name The name of the static method to call. + * @param[in] signature The signature of the static method to call. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_CallStaticMethodByName_Void_V)( + ani_env* env, ani_class cls, const char* name, const char* signature, va_list args); + + /** + * @brief Retrieves a boolean value from a field of an object. + * + * This function retrieves the boolean value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the boolean value from. + * @param[out] result A pointer to store the retrieved boolean value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Boolean)(ani_env* env, ani_object object, ani_field field, ani_boolean* result); + + /** + * @brief Retrieves a char value from a field of an object. + * + * This function retrieves the char value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the char value from. + * @param[out] result A pointer to store the retrieved char value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Char)(ani_env* env, ani_object object, ani_field field, ani_char* result); + + /** + * @brief Retrieves a byte value from a field of an object. + * + * This function retrieves the byte value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the byte value from. + * @param[out] result A pointer to store the retrieved byte value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Byte)(ani_env* env, ani_object object, ani_field field, ani_byte* result); + + /** + * @brief Retrieves a short value from a field of an object. + * + * This function retrieves the short value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the short value from. + * @param[out] result A pointer to store the retrieved short value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Short)(ani_env* env, ani_object object, ani_field field, ani_short* result); + + /** + * @brief Retrieves a integer value from a field of an object. + * + * This function retrieves the integer value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the integer value from. + * @param[out] result A pointer to store the retrieved integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Int)(ani_env* env, ani_object object, ani_field field, ani_int* result); + + /** + * @brief Retrieves a long value from a field of an object. + * + * This function retrieves the long value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the long value from. + * @param[out] result A pointer to store the retrieved long value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Long)(ani_env* env, ani_object object, ani_field field, ani_long* result); + + /** + * @brief Retrieves a float value from a field of an object. + * + * This function retrieves the float value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the float value from. + * @param[out] result A pointer to store the retrieved float value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Float)(ani_env* env, ani_object object, ani_field field, ani_float* result); + + /** + * @brief Retrieves a double value from a field of an object. + * + * This function retrieves the double value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the double value from. + * @param[out] result A pointer to store the retrieved double value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Double)(ani_env* env, ani_object object, ani_field field, ani_double* result); + + /** + * @brief Retrieves a reference value from a field of an object. + * + * This function retrieves the reference value of the specified field from the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to retrieve the reference value from. + * @param[out] result A pointer to store the retrieved reference value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetField_Ref)(ani_env* env, ani_object object, ani_field field, ani_ref* result); + + /** + * @brief Sets a boolean value to a field of an object. + * + * This function assigns a boolean value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the boolean value to. + * @param[in] value The boolean value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Boolean)(ani_env* env, ani_object object, ani_field field, ani_boolean value); + + /** + * @brief Sets a char value to a field of an object. + * + * This function assigns a char value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the char value to. + * @param[in] value The char value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Char)(ani_env* env, ani_object object, ani_field field, ani_char value); + + /** + * @brief Sets a byte value to a field of an object. + * + * This function assigns a byte value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the byte value to. + * @param[in] value The byte value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Byte)(ani_env* env, ani_object object, ani_field field, ani_byte value); + + /** + * @brief Sets a short value to a field of an object. + * + * This function assigns a short value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the short value to. + * @param[in] value The short value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Short)(ani_env* env, ani_object object, ani_field field, ani_short value); + + /** + * @brief Sets a integer value to a field of an object. + * + * This function assigns a integer value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the integer value to. + * @param[in] value The integer value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Int)(ani_env* env, ani_object object, ani_field field, ani_int value); + + /** + * @brief Sets a long value to a field of an object. + * + * This function assigns a long value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the long value to. + * @param[in] value The long value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Long)(ani_env* env, ani_object object, ani_field field, ani_long value); + + /** + * @brief Sets a float value to a field of an object. + * + * This function assigns a float value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the float value to. + * @param[in] value The float value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Float)(ani_env* env, ani_object object, ani_field field, ani_float value); + + /** + * @brief Sets a double value to a field of an object. + * + * This function assigns a double value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the double value to. + * @param[in] value The double value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Double)(ani_env* env, ani_object object, ani_field field, ani_double value); + + /** + * @brief Sets a reference value to a field of an object. + * + * This function assigns a reference value to the specified field of the given object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] field The field to set the reference value to. + * @param[in] value The reference value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetField_Ref)(ani_env* env, ani_object object, ani_field field, ani_ref value); + + /** + * @brief Retrieves a boolean value from a field of an object by its name. + * + * This function retrieves the boolean value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the boolean value from. + * @param[out] result A pointer to store the retrieved boolean value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Boolean)(ani_env* env, ani_object object, const char* name, ani_boolean* result); + + /** + * @brief Retrieves a char value from a field of an object by its name. + * + * This function retrieves the char value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the char value from. + * @param[out] result A pointer to store the retrieved char value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Char)(ani_env* env, ani_object object, const char* name, ani_char* result); + + /** + * @brief Retrieves a byte value from a field of an object by its name. + * + * This function retrieves the byte value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the byte value from. + * @param[out] result A pointer to store the retrieved byte value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Byte)(ani_env* env, ani_object object, const char* name, ani_byte* result); + + /** + * @brief Retrieves a short value from a field of an object by its name. + * + * This function retrieves the short value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the short value from. + * @param[out] result A pointer to store the retrieved short value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Short)(ani_env* env, ani_object object, const char* name, ani_short* result); + + /** + * @brief Retrieves a integer value from a field of an object by its name. + * + * This function retrieves the integer value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the integer value from. + * @param[out] result A pointer to store the retrieved integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Int)(ani_env* env, ani_object object, const char* name, ani_int* result); + + /** + * @brief Retrieves a long value from a field of an object by its name. + * + * This function retrieves the long value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the long value from. + * @param[out] result A pointer to store the retrieved long value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Long)(ani_env* env, ani_object object, const char* name, ani_long* result); + + /** + * @brief Retrieves a float value from a field of an object by its name. + * + * This function retrieves the float value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the float value from. + * @param[out] result A pointer to store the retrieved float value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Float)(ani_env* env, ani_object object, const char* name, ani_float* result); + + /** + * @brief Retrieves a double value from a field of an object by its name. + * + * This function retrieves the double value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the double value from. + * @param[out] result A pointer to store the retrieved double value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Double)(ani_env* env, ani_object object, const char* name, ani_double* result); + + /** + * @brief Retrieves a reference value from a field of an object by its name. + * + * This function retrieves the reference value of the specified field from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to retrieve the reference value from. + * @param[out] result A pointer to store the retrieved reference value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetFieldByName_Ref)(ani_env* env, ani_object object, const char* name, ani_ref* result); + + /** + * @brief Sets a boolean value to a field of an object by its name. + * + * This function assigns a boolean value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the boolean value to. + * @param[in] value The boolean value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Boolean)(ani_env* env, ani_object object, const char* name, ani_boolean value); + + /** + * @brief Sets a char value to a field of an object by its name. + * + * This function assigns a char value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the char value to. + * @param[in] value The char value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Char)(ani_env* env, ani_object object, const char* name, ani_char value); + + /** + * @brief Sets a byte value to a field of an object by its name. + * + * This function assigns a byte value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the byte value to. + * @param[in] value The byte value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Byte)(ani_env* env, ani_object object, const char* name, ani_byte value); + + /** + * @brief Sets a short value to a field of an object by its name. + * + * This function assigns a short value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the short value to. + * @param[in] value The short value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Short)(ani_env* env, ani_object object, const char* name, ani_short value); + + /** + * @brief Sets a integer value to a field of an object by its name. + * + * This function assigns a integer value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the integer value to. + * @param[in] value The integer value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Int)(ani_env* env, ani_object object, const char* name, ani_int value); + + /** + * @brief Sets a long value to a field of an object by its name. + * + * This function assigns a long value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the long value to. + * @param[in] value The long value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Long)(ani_env* env, ani_object object, const char* name, ani_long value); + + /** + * @brief Sets a float value to a field of an object by its name. + * + * This function assigns a float value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the float value to. + * @param[in] value The float value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Float)(ani_env* env, ani_object object, const char* name, ani_float value); + + /** + * @brief Sets a double value to a field of an object by its name. + * + * This function assigns a double value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the double value to. + * @param[in] value The double value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Double)(ani_env* env, ani_object object, const char* name, ani_double value); + + /** + * @brief Sets a reference value to a field of an object by its name. + * + * This function assigns a reference value to the specified field of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the field. + * @param[in] name The name of the field to set the reference value to. + * @param[in] value The reference value to assign to the field. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetFieldByName_Ref)(ani_env* env, ani_object object, const char* name, ani_ref value); + + /** + * @brief Retrieves a boolean value from a property of an object by its name. + * + * This function retrieves the boolean value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the boolean value from. + * @param[out] result A pointer to store the retrieved boolean value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Boolean)( + ani_env* env, ani_object object, const char* name, ani_boolean* result); + + /** + * @brief Retrieves a char value from a property of an object by its name. + * + * This function retrieves the char value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the char value from. + * @param[out] result A pointer to store the retrieved char value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Char)(ani_env* env, ani_object object, const char* name, ani_char* result); + + /** + * @brief Retrieves a byte value from a property of an object by its name. + * + * This function retrieves the byte value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the byte value from. + * @param[out] result A pointer to store the retrieved byte value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Byte)(ani_env* env, ani_object object, const char* name, ani_byte* result); + + /** + * @brief Retrieves a short value from a property of an object by its name. + * + * This function retrieves the short value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the short value from. + * @param[out] result A pointer to store the retrieved short value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Short)(ani_env* env, ani_object object, const char* name, ani_short* result); + + /** + * @brief Retrieves a integer value from a property of an object by its name. + * + * This function retrieves the integer value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the integer value from. + * @param[out] result A pointer to store the retrieved integer value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Int)(ani_env* env, ani_object object, const char* name, ani_int* result); + + /** + * @brief Retrieves a long value from a property of an object by its name. + * + * This function retrieves the long value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the long value from. + * @param[out] result A pointer to store the retrieved long value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Long)(ani_env* env, ani_object object, const char* name, ani_long* result); + + /** + * @brief Retrieves a float value from a property of an object by its name. + * + * This function retrieves the float value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the float value from. + * @param[out] result A pointer to store the retrieved float value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Float)(ani_env* env, ani_object object, const char* name, ani_float* result); + + /** + * @brief Retrieves a double value from a property of an object by its name. + * + * This function retrieves the double value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the double value from. + * @param[out] result A pointer to store the retrieved double value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Double)( + ani_env* env, ani_object object, const char* name, ani_double* result); + + /** + * @brief Retrieves a reference value from a property of an object by its name. + * + * This function retrieves the reference value of the specified property from the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to retrieve the reference value from. + * @param[out] result A pointer to store the retrieved reference value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_GetPropertyByName_Ref)(ani_env* env, ani_object object, const char* name, ani_ref* result); + + /** + * @brief Sets a boolean value to a property of an object by its name. + * + * This function assigns a boolean value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the boolean value to. + * @param[in] value The boolean value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Boolean)( + ani_env* env, ani_object object, const char* name, ani_boolean value); + + /** + * @brief Sets a char value to a property of an object by its name. + * + * This function assigns a char value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the char value to. + * @param[in] value The char value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Char)(ani_env* env, ani_object object, const char* name, ani_char value); + + /** + * @brief Sets a byte value to a property of an object by its name. + * + * This function assigns a byte value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the byte value to. + * @param[in] value The byte value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Byte)(ani_env* env, ani_object object, const char* name, ani_byte value); + + /** + * @brief Sets a short value to a property of an object by its name. + * + * This function assigns a short value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the short value to. + * @param[in] value The short value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Short)(ani_env* env, ani_object object, const char* name, ani_short value); + + /** + * @brief Sets a integer value to a property of an object by its name. + * + * This function assigns a integer value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the integer value to. + * @param[in] value The integer value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Int)(ani_env* env, ani_object object, const char* name, ani_int value); + + /** + * @brief Sets a long value to a property of an object by its name. + * + * This function assigns a long value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the long value to. + * @param[in] value The long value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Long)(ani_env* env, ani_object object, const char* name, ani_long value); + + /** + * @brief Sets a float value to a property of an object by its name. + * + * This function assigns a float value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the float value to. + * @param[in] value The float value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Float)(ani_env* env, ani_object object, const char* name, ani_float value); + + /** + * @brief Sets a double value to a property of an object by its name. + * + * This function assigns a double value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the double value to. + * @param[in] value The double value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Double)(ani_env* env, ani_object object, const char* name, ani_double value); + + /** + * @brief Sets a reference value to a property of an object by its name. + * + * This function assigns a reference value to the specified property of the given object by its name. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object containing the property. + * @param[in] name The name of the property to set the reference value to. + * @param[in] value The reference value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_SetPropertyByName_Ref)(ani_env* env, ani_object object, const char* name, ani_ref value); + + /** + * @brief Calls a method on an object and retrieves a boolean return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the boolean return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Boolean)( + ani_env* env, ani_object object, ani_method method, ani_boolean* result, ...); + + /** + * @brief Calls a method on an object and retrieves a boolean return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a + * boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the boolean return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Boolean_A)( + ani_env* env, ani_object object, ani_method method, ani_boolean* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a boolean return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the boolean return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Boolean_V)( + ani_env* env, ani_object object, ani_method method, ani_boolean* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a char return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a char result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the char return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Char)(ani_env* env, ani_object object, ani_method method, ani_char* result, ...); + + /** + * @brief Calls a method on an object and retrieves a char return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a char + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the char return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Char_A)( + ani_env* env, ani_object object, ani_method method, ani_char* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a char return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a char result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the char return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Char_V)( + ani_env* env, ani_object object, ani_method method, ani_char* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a byte return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the byte return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Byte)(ani_env* env, ani_object object, ani_method method, ani_byte* result, ...); + + /** + * @brief Calls a method on an object and retrieves a byte return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a byte + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the byte return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Byte_A)( + ani_env* env, ani_object object, ani_method method, ani_byte* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a byte return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the byte return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Byte_V)( + ani_env* env, ani_object object, ani_method method, ani_byte* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a short return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the short return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Short)(ani_env* env, ani_object object, ani_method method, ani_short* result, ...); + + /** + * @brief Calls a method on an object and retrieves a short return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a short + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the short return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Short_A)( + ani_env* env, ani_object object, ani_method method, ani_short* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a short return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the short return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Short_V)( + ani_env* env, ani_object object, ani_method method, ani_short* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a integer return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the integer return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Int)(ani_env* env, ani_object object, ani_method method, ani_int* result, ...); + + /** + * @brief Calls a method on an object and retrieves a integer return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a + * integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the integer return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Int_A)( + ani_env* env, ani_object object, ani_method method, ani_int* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a integer return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the integer return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Int_V)( + ani_env* env, ani_object object, ani_method method, ani_int* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a long return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the long return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Long)(ani_env* env, ani_object object, ani_method method, ani_long* result, ...); + + /** + * @brief Calls a method on an object and retrieves a long return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a long + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the long return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Long_A)( + ani_env* env, ani_object object, ani_method method, ani_long* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a long return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the long return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Long_V)( + ani_env* env, ani_object object, ani_method method, ani_long* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a float return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the float return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Float)(ani_env* env, ani_object object, ani_method method, ani_float* result, ...); + + /** + * @brief Calls a method on an object and retrieves a float return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a float + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the float return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Float_A)( + ani_env* env, ani_object object, ani_method method, ani_float* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a float return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the float return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Float_V)( + ani_env* env, ani_object object, ani_method method, ani_float* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a double return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the double return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Double)(ani_env* env, ani_object object, ani_method method, ani_double* result, ...); + + /** + * @brief Calls a method on an object and retrieves a double return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a double + * result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the double return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Double_A)( + ani_env* env, ani_object object, ani_method method, ani_double* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a double return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the double return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Double_V)( + ani_env* env, ani_object object, ani_method method, ani_double* result, va_list args); + + /** + * @brief Calls a method on an object and retrieves a reference return value. + * + * This function calls the specified method of an object using variadic arguments and retrieves a reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the reference return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Ref)(ani_env* env, ani_object object, ani_method method, ani_ref* result, ...); + + /** + * @brief Calls a method on an object and retrieves a reference return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array and retrieves a + * reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the reference return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Ref_A)( + ani_env* env, ani_object object, ani_method method, ani_ref* result, const ani_value* args); + + /** + * @brief Calls a method on an object and retrieves a reference return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list` and retrieves a reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[out] result A pointer to store the reference return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Ref_V)( + ani_env* env, ani_object object, ani_method method, ani_ref* result, va_list args); + + /** + * @brief Calls a method on an object with no return value. + * + * This function calls the specified method of an object using variadic arguments. The method does not return a + * value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Void)(ani_env* env, ani_object object, ani_method method, ...); + + /** + * @brief Calls a method on an object with no return value (array-based). + * + * This function calls the specified method of an object using arguments provided in an array. The method does not + * return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Void_A)(ani_env* env, ani_object object, ani_method method, const ani_value* args); + + /** + * @brief Calls a method on an object with no return value (variadic arguments). + * + * This function calls the specified method of an object using a `va_list`. The method does not return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] method The method to call. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethod_Void_V)(ani_env* env, ani_object object, ani_method method, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a boolean return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the boolean return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Boolean)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_boolean* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a boolean return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the boolean return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Boolean_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_boolean* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a boolean return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * boolean result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the boolean return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Boolean_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_boolean* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a char return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a char result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the char return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Char)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_char* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a char return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a char result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the char return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Char_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_char* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a char return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * char result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the char return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Char_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_char* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a byte return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the byte return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Byte)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_byte* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a byte return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the byte return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Byte_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_byte* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a byte return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * byte result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the byte return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Byte_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_byte* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a short return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the short return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Short)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_short* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a short return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the short return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Short_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_short* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a short return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * short result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the short return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Short_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_short* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a integer return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the integer return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Int)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_int* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a integer return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the integer return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Int_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_int* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a integer return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * integer result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the integer return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Int_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_int* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a long return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the long return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Long)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_long* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a long return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the long return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Long_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_long* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a long return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * long result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the long return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Long_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_long* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a float return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the float return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Float)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_float* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a float return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the float return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Float_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_float* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a float return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * float result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the float return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Float_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_float* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a double return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the double return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Double)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_double* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a double return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the double return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Double_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_double* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a double return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * double result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the double return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Double_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_double* result, va_list args); + + /** + * @brief Calls a method by name on an object and retrieves a reference return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments and + * retrieves a reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the reference return value. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Ref)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_ref* result, ...); + + /** + * @brief Calls a method by name on an object and retrieves a reference return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array and retrieves a reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the reference return value. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Ref_A)(ani_env* env, ani_object object, const char* name, + const char* signature, ani_ref* result, const ani_value* args); + + /** + * @brief Calls a method by name on an object and retrieves a reference return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list` and retrieves a + * reference result. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[out] result A pointer to store the reference return value. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Ref_V)( + ani_env* env, ani_object object, const char* name, const char* signature, ani_ref* result, va_list args); + + /** + * @brief Calls a method by name on an object with no return value. + * + * This function calls the specified method by its name and signature on an object using variadic arguments. The + * method does not return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[in] ... Variadic arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Void)( + ani_env* env, ani_object object, const char* name, const char* signature, ...); + + /** + * @brief Calls a method by name on an object with no return value (array-based). + * + * This function calls the specified method by its name and signature on an object using arguments provided in an + * array. The method does not return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[in] args An array of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Void_A)( + ani_env* env, ani_object object, const char* name, const char* signature, const ani_value* args); + + /** + * @brief Calls a method by name on an object with no return value (variadic arguments). + * + * This function calls the specified method by its name and signature on an object using a `va_list`. The method + * does not return a value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] object The object on which the method is to be called. + * @param[in] name The name of the method to call. + * @param[in] signature The signature of the method to call. + * @param[in] args A `va_list` of arguments to pass to the method. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Object_CallMethodByName_Void_V)( + ani_env* env, ani_object object, const char* name, const char* signature, va_list args); + + /** + * @brief Retrieves the number of items in a tuple value. + * + * This function retrieves the total number of items in the specified tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value whose number of items is to be retrieved. + * @param[out] result A pointer to store the number of items. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetNumberOfItems)(ani_env* env, ani_tuple_value tuple_value, ani_size* result); + + /** + * @brief Retrieves a boolean item from a tuple value. + * + * This function retrieves the boolean value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the boolean value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Boolean)( + ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_boolean* result); + + /** + * @brief Retrieves a char item from a tuple value. + * + * This function retrieves the char value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the char value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Char)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_char* result); + + /** + * @brief Retrieves a byte item from a tuple value. + * + * This function retrieves the byte value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the byte value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Byte)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_byte* result); + + /** + * @brief Retrieves a short item from a tuple value. + * + * This function retrieves the short value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the short value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Short)( + ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_short* result); + + /** + * @brief Retrieves a integer item from a tuple value. + * + * This function retrieves the integer value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the integer value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Int)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_int* result); + + /** + * @brief Retrieves a long item from a tuple value. + * + * This function retrieves the long value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the long value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Long)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_long* result); + + /** + * @brief Retrieves a float item from a tuple value. + * + * This function retrieves the float value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the float value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Float)( + ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_float* result); + + /** + * @brief Retrieves a double item from a tuple value. + * + * This function retrieves the double value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the double value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Double)( + ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_double* result); + + /** + * @brief Retrieves a reference item from a tuple value. + * + * This function retrieves the reference value of the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[out] result A pointer to store the reference value of the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_GetItem_Ref)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_ref* result); + + /** + * @brief Sets a boolean value to an item in a tuple value. + * + * This function assigns a boolean value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The boolean value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Boolean)( + ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_boolean value); + + /** + * @brief Sets a char value to an item in a tuple value. + * + * This function assigns a char value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The char value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Char)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_char value); + + /** + * @brief Sets a byte value to an item in a tuple value. + * + * This function assigns a byte value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The byte value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Byte)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_byte value); + + /** + * @brief Sets a short value to an item in a tuple value. + * + * This function assigns a short value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The short value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Short)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_short value); + + /** + * @brief Sets a integer value to an item in a tuple value. + * + * This function assigns a integer value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The integer value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Int)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_int value); + + /** + * @brief Sets a long value to an item in a tuple value. + * + * This function assigns a long value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The long value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Long)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_long value); + + /** + * @brief Sets a float value to an item in a tuple value. + * + * This function assigns a float value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The float value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Float)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_float value); + + /** + * @brief Sets a double value to an item in a tuple value. + * + * This function assigns a double value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The double value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Double)( + ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_double value); + + /** + * @brief Sets a reference value to an item in a tuple value. + * + * This function assigns a reference value to the item at the specified index in the tuple value. + * + * @param[in] env A pointer to the environment structure. + * @param[in] tuple_value The tuple value containing the item. + * @param[in] index The index of the item. + * @param[in] value The reference value to assign to the item. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*TupleValue_SetItem_Ref)(ani_env* env, ani_tuple_value tuple_value, ani_size index, ani_ref value); + + /** + * @brief Creates a global reference. + * + * This function creates a global reference from a local reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The local reference to convert to a global reference. + * @param[out] result A pointer to store the created global reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*GlobalReference_Create)(ani_env* env, ani_ref ref, ani_ref* result); + + /** + * @brief Deletes a global reference. + * + * This function deletes the specified global reference, releasing all associated resources. + * + * @param[in] env A pointer to the environment structure. + * @param[in] gref The global reference to delete. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*GlobalReference_Delete)(ani_env* env, ani_ref gref); + + /** + * @brief Creates a weak reference. + * + * This function creates a weak reference from a local reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The local reference to convert to a weak reference. + * @param[out] result A pointer to store the created weak reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*WeakReference_Create)(ani_env* env, ani_ref ref, ani_wref* result); + + /** + * @brief Deletes a weak reference. + * + * This function deletes the specified weak reference, releasing all associated resources. + * + * @param[in] env A pointer to the environment structure. + * @param[in] wref The weak reference to delete. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*WeakReference_Delete)(ani_env* env, ani_wref wref); + + /** + * @brief Retrieves the local reference associated with a weak reference. + * + * This function retrieves the local reference that corresponds to the specified weak reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] wref The weak reference to query. + * @param[out] was_released_result A pointer to boolean flag which indicates that wref is GC collected. + * @param[out] ref_result A pointer to store the retrieved local reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*WeakReference_GetReference)( + ani_env* env, ani_wref wref, ani_boolean* was_released_result, ani_ref* ref_result); + + /** + * @brief Creates a new array buffer. + * + * This function creates a new array buffer with the specified length and returns a pointer to the allocated data. + * + * @param[in] env A pointer to the environment structure. + * @param[in] length The length of the array buffer in bytes. + * @param[out] data_result A pointer to store the allocated data of the array buffer. + * @param[out] arraybuffer_result A pointer to store the created array buffer object. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*CreateArrayBuffer)( + ani_env* env, size_t length, void** data_result, ani_arraybuffer* arraybuffer_result); + + /** + * @brief Retrieves information about an array buffer. + * + * This function retrieves the data pointer and length of the specified array buffer. + * + * @param[in] env A pointer to the environment structure. + * @param[in] arraybuffer The array buffer to query. + * @param[out] data_result A pointer to store the data of the array buffer. + * @param[out] length_result A pointer to store the length of the array buffer in bytes. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*ArrayBuffer_GetInfo)( + ani_env* env, ani_arraybuffer arraybuffer, void** data_result, size_t* length_result); + + /** + * @brief Creates a new Promise. + * + * This function creates a new promise and a resolver to manage it. + * + * @param[in] env A pointer to the environment structure. + * @param[out] result_resolver A pointer to store the created resolver. + * @param[out] result_promise A pointer to store the created promise. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Promise_New)(ani_env* env, ani_resolver* result_resolver, ani_object* result_promise); + + /** + * @brief Resolves a promise. + * + * This function resolves a promise by way of the resolver with which it is associated + * and queues promise `then` callbacks. + * + * @param[in] env A pointer to the environment structure. + * @param[in] resolver A resolver whose associated promise to resolve. + * @param[in] resolution A reference with which to resolve the promise. + * @return Returns a status code of type `ani_status` indicating success or failure. + * The `resolver` is freed upon successful completion. + */ + ani_status (*PromiseResolver_Resolve)(ani_env* env, ani_resolver resolver, ani_ref resolution); + + /** + * @brief Rejects a promise. + * + * This function rejects a promise by way of the resolver with which it is associated + * and queues promise `catch` callbacks. + * + * @param[in] env A pointer to the environment structure. + * @param[in] resolver A resolver whose associated promise to resolve. + * @param[in] rejection An error with which to reject the promise. + * @return Returns a status code of type `ani_status` indicating success or failure. + * The `resolver` is freed upon successful completion. + */ + ani_status (*PromiseResolver_Reject)(ani_env* env, ani_resolver resolver, ani_error rejection); + + /** + * @brief Checks if Any reference is an instance of a specified Any type. + * + * This function checks whether the given Any reference is an instance of the specified Any type. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference to check. + * @param[in] type The type to compare against. + * @param[out] result A pointer to store the boolean result (true if the reference is an instance of the type, + * false otherwise). + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_InstanceOf)(ani_env* env, ani_ref ref, ani_ref type, ani_boolean* result); + + /** + * @brief Gets a property of an Any reference by name. + * + * This function retrieves the value of a named property from the given Any reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference from which to retrieve the property. + * @param[in] name The name of the property to retrieve. + * @param[out] result A pointer to store the retrieved property value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_GetProperty)(ani_env* env, ani_ref ref, const char* name, ani_ref* result); + + /** + * @brief Sets a property of an Any reference by name. + * + * This function sets the value of a named property on the given Any reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference on which to set the property. + * @param[in] name The name of the property to set. + * @param[in] value The value to assign to the property. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_SetProperty)(ani_env* env, ani_ref ref, const char* name, ani_ref value); + + /** + * @brief Gets an element of an Any reference by index. + * + * This function retrieves the value at a specific index from the given Any reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference from which to retrieve the element. + * @param[in] index The index of the element to retrieve. + * @param[out] result A pointer to store the retrieved value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_GetByIndex)(ani_env* env, ani_ref ref, ani_size index, ani_ref* result); + + /** + * @brief Sets an element of an Any reference by index. + * + * This function sets the value at a specific index on the given Any reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference on which to set the element. + * @param[in] index The index of the element to set. + * @param[in] value The value to assign to the specified index. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_SetByIndex)(ani_env* env, ani_ref ref, ani_size index, ani_ref value); + + /** + * @brief Gets a property of an Any reference by key reference. + * + * This function retrieves the value of a property using another Any reference as the key. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference from which to retrieve the property. + * @param[in] key The key reference used to access the property. + * @param[out] result A pointer to store the retrieved property value. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_GetByValue)(ani_env* env, ani_ref ref, ani_ref key, ani_ref* result); + + /** + * @brief Sets a property of an Any reference by key reference. + * + * This function sets the value of a property using another Any reference as the key. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ref The reference on which to set the property. + * @param[in] key The key reference used to access the property. + * @param[in] value The value to assign to the specified key. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_SetByValue)(ani_env* env, ani_ref ref, ani_ref key, ani_ref value); + + /** + * @brief Calls an Any reference as a function. + * + * This function invokes the given Any reference if it represents a callable object. + * + * @param[in] env A pointer to the environment structure. + * @param[in] func The function reference to invoke. + * @param[in] argc The number of arguments. + * @param[in] argv An array of argument references. + * @param[out] result A pointer to store the function call result. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_Call)(ani_env* env, ani_ref func, ani_size argc, ani_ref* argv, ani_ref* result); + + /** + * @brief Calls a method of an Any reference by name. + * + * This function invokes a named method on the given Any reference. + * + * @param[in] env A pointer to the environment structure. + * @param[in] self The object reference on which to invoke the method. + * @param[in] name The name of the method to invoke. + * @param[in] argc The number of arguments. + * @param[in] argv An array of argument references. + * @param[out] result A pointer to store the method call result. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_CallMethod)( + ani_env* env, ani_ref self, const char* name, ani_size argc, ani_ref* argv, ani_ref* result); + + /** + * @brief Constructs a new object using an Any reference as a constructor. + * + * This function creates a new object using the given constructor reference and arguments. + * + * @param[in] env A pointer to the environment structure. + * @param[in] ctor The constructor function reference. + * @param[in] argc The number of arguments. + * @param[in] argv An array of argument references. + * @param[out] result A pointer to store the created object reference. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Any_New)(ani_env* env, ani_ref ctor, ani_size argc, ani_ref* argv, ani_ref* result); + + /** + * @brief Binds static native methods to a class. + * + * This function binds an array of static native methods to the specified class. + * + * @param[in] env A pointer to the environment structure. + * @param[in] cls The class to which the native methods will be bound. + * @param[in] methods A pointer to an array of static native methods to bind. + * @param[in] nr_methods The number of static native methods in the array. + * @return Returns a status code of type `ani_status` indicating success or failure. + */ + ani_status (*Class_BindStaticNativeMethods)( + ani_env* env, ani_class cls, const ani_native_function* methods, ani_size nr_methods); +}; + +// C++ API +struct __ani_vm { + const struct __ani_vm_api* c_api; + +#ifdef __cplusplus + ani_status DestroyVM() + { + return c_api->DestroyVM(this); + } + ani_status GetEnv(uint32_t version, ani_env** result) + { + return c_api->GetEnv(this, version, result); + } + ani_status AttachCurrentThread(const ani_options* options, uint32_t version, ani_env** result) + { + return c_api->AttachCurrentThread(this, options, version, result); + } + ani_status DetachCurrentThread() + { + return c_api->DetachCurrentThread(this); + } +#endif // __cplusplus +}; + +struct __ani_env { + const struct __ani_interaction_api* c_api; + +#ifdef __cplusplus + ani_status GetVersion(uint32_t* result) + { + return c_api->GetVersion(this, result); + } + ani_status GetVM(ani_vm** result) + { + return c_api->GetVM(this, result); + } + ani_status Object_New(ani_class cls, ani_method method, ani_object* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_New_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Object_New_A(ani_class cls, ani_method method, ani_object* result, const ani_value* args) + { + return c_api->Object_New_A(this, cls, method, result, args); + } + ani_status Object_New_V(ani_class cls, ani_method method, ani_object* result, va_list args) + { + return c_api->Object_New_V(this, cls, method, result, args); + } + ani_status Object_GetType(ani_object object, ani_type* result) + { + return c_api->Object_GetType(this, object, result); + } + ani_status Object_InstanceOf(ani_object object, ani_type type, ani_boolean* result) + { + return c_api->Object_InstanceOf(this, object, type, result); + } + ani_status Type_GetSuperClass(ani_type type, ani_class* result) + { + return c_api->Type_GetSuperClass(this, type, result); + } + ani_status Type_IsAssignableFrom(ani_type from_type, ani_type to_type, ani_boolean* result) + { + return c_api->Type_IsAssignableFrom(this, from_type, to_type, result); + } + ani_status FindModule(const char* module_descriptor, ani_module* result) + { + return c_api->FindModule(this, module_descriptor, result); + } + ani_status FindNamespace(const char* namespace_descriptor, ani_namespace* result) + { + return c_api->FindNamespace(this, namespace_descriptor, result); + } + ani_status FindClass(const char* class_descriptor, ani_class* result) + { + return c_api->FindClass(this, class_descriptor, result); + } + ani_status FindEnum(const char* enum_descriptor, ani_enum* result) + { + return c_api->FindEnum(this, enum_descriptor, result); + } + ani_status Module_FindFunction(ani_module module, const char* name, const char* signature, ani_function* result) + { + return c_api->Module_FindFunction(this, module, name, signature, result); + } + ani_status Module_FindVariable(ani_module module, const char* name, ani_variable* result) + { + return c_api->Module_FindVariable(this, module, name, result); + } + ani_status Namespace_FindFunction(ani_namespace ns, const char* name, const char* signature, ani_function* result) + { + return c_api->Namespace_FindFunction(this, ns, name, signature, result); + } + ani_status Namespace_FindVariable(ani_namespace ns, const char* name, ani_variable* result) + { + return c_api->Namespace_FindVariable(this, ns, name, result); + } + ani_status Module_BindNativeFunctions( + ani_module module, const ani_native_function* functions, ani_size nr_functions) + { + return c_api->Module_BindNativeFunctions(this, module, functions, nr_functions); + } + ani_status Namespace_BindNativeFunctions( + ani_namespace ns, const ani_native_function* functions, ani_size nr_functions) + { + return c_api->Namespace_BindNativeFunctions(this, ns, functions, nr_functions); + } + ani_status Class_BindNativeMethods(ani_class cls, const ani_native_function* methods, ani_size nr_methods) + { + return c_api->Class_BindNativeMethods(this, cls, methods, nr_methods); + } + ani_status Reference_Delete(ani_ref ref) + { + return c_api->Reference_Delete(this, ref); + } + ani_status EnsureEnoughReferences(ani_size nr_refs) + { + return c_api->EnsureEnoughReferences(this, nr_refs); + } + ani_status CreateLocalScope(ani_size nr_refs) + { + return c_api->CreateLocalScope(this, nr_refs); + } + ani_status DestroyLocalScope() + { + return c_api->DestroyLocalScope(this); + } + ani_status CreateEscapeLocalScope(ani_size nr_refs) + { + return c_api->CreateEscapeLocalScope(this, nr_refs); + } + ani_status DestroyEscapeLocalScope(ani_ref ref, ani_ref* result) + { + return c_api->DestroyEscapeLocalScope(this, ref, result); + } + ani_status ThrowError(ani_error err) + { + return c_api->ThrowError(this, err); + } + ani_status ExistUnhandledError(ani_boolean* result) + { + return c_api->ExistUnhandledError(this, result); + } + ani_status GetUnhandledError(ani_error* result) + { + return c_api->GetUnhandledError(this, result); + } + ani_status ResetError() + { + return c_api->ResetError(this); + } + ani_status DescribeError() + { + return c_api->DescribeError(this); + } + ani_status Abort(const char* message) + { + return c_api->Abort(this, message); + } + ani_status GetNull(ani_ref* result) + { + return c_api->GetNull(this, result); + } + ani_status GetUndefined(ani_ref* result) + { + return c_api->GetUndefined(this, result); + } + ani_status Reference_IsNull(ani_ref ref, ani_boolean* result) + { + return c_api->Reference_IsNull(this, ref, result); + } + ani_status Reference_IsUndefined(ani_ref ref, ani_boolean* result) + { + return c_api->Reference_IsUndefined(this, ref, result); + } + ani_status Reference_IsNullishValue(ani_ref ref, ani_boolean* result) + { + return c_api->Reference_IsNullishValue(this, ref, result); + } + ani_status Reference_Equals(ani_ref ref0, ani_ref ref1, ani_boolean* result) + { + return c_api->Reference_Equals(this, ref0, ref1, result); + } + ani_status Reference_StrictEquals(ani_ref ref0, ani_ref ref1, ani_boolean* result) + { + return c_api->Reference_StrictEquals(this, ref0, ref1, result); + } + ani_status String_NewUTF16(const uint16_t* utf16_string, ani_size utf16_size, ani_string* result) + { + return c_api->String_NewUTF16(this, utf16_string, utf16_size, result); + } + ani_status String_GetUTF16Size(ani_string string, ani_size* result) + { + return c_api->String_GetUTF16Size(this, string, result); + } + ani_status String_GetUTF16(ani_string string, uint16_t* utf16_buffer, ani_size utf16_buffer_size, ani_size* result) + { + return c_api->String_GetUTF16(this, string, utf16_buffer, utf16_buffer_size, result); + } + ani_status String_GetUTF16SubString(ani_string string, ani_size substr_offset, ani_size substr_size, + uint16_t* utf16_buffer, ani_size utf16_buffer_size, ani_size* result) + { + return c_api->String_GetUTF16SubString( + this, string, substr_offset, substr_size, utf16_buffer, utf16_buffer_size, result); + } + ani_status String_NewUTF8(const char* utf8_string, ani_size utf8_size, ani_string* result) + { + return c_api->String_NewUTF8(this, utf8_string, utf8_size, result); + } + ani_status String_GetUTF8Size(ani_string string, ani_size* result) + { + return c_api->String_GetUTF8Size(this, string, result); + } + ani_status String_GetUTF8(ani_string string, char* utf8_buffer, ani_size utf8_buffer_size, ani_size* result) + { + return c_api->String_GetUTF8(this, string, utf8_buffer, utf8_buffer_size, result); + } + ani_status String_GetUTF8SubString(ani_string string, ani_size substr_offset, ani_size substr_size, + char* utf8_buffer, ani_size utf8_buffer_size, ani_size* result) + { + return c_api->String_GetUTF8SubString( + this, string, substr_offset, substr_size, utf8_buffer, utf8_buffer_size, result); + } + ani_status Array_GetLength(ani_array array, ani_size* result) + { + return c_api->Array_GetLength(this, array, result); + } + ani_status Array_New_Boolean(ani_size length, ani_array_boolean* result) + { + return c_api->Array_New_Boolean(this, length, result); + } + ani_status Array_New_Char(ani_size length, ani_array_char* result) + { + return c_api->Array_New_Char(this, length, result); + } + ani_status Array_New_Byte(ani_size length, ani_array_byte* result) + { + return c_api->Array_New_Byte(this, length, result); + } + ani_status Array_New_Short(ani_size length, ani_array_short* result) + { + return c_api->Array_New_Short(this, length, result); + } + ani_status Array_New_Int(ani_size length, ani_array_int* result) + { + return c_api->Array_New_Int(this, length, result); + } + ani_status Array_New_Long(ani_size length, ani_array_long* result) + { + return c_api->Array_New_Long(this, length, result); + } + ani_status Array_New_Float(ani_size length, ani_array_float* result) + { + return c_api->Array_New_Float(this, length, result); + } + ani_status Array_New_Double(ani_size length, ani_array_double* result) + { + return c_api->Array_New_Double(this, length, result); + } + ani_status Array_GetRegion_Boolean( + ani_array_boolean array, ani_size offset, ani_size length, ani_boolean* native_buffer) + { + return c_api->Array_GetRegion_Boolean(this, array, offset, length, native_buffer); + } + ani_status Array_GetRegion_Char(ani_array_char array, ani_size offset, ani_size length, ani_char* native_buffer) + { + return c_api->Array_GetRegion_Char(this, array, offset, length, native_buffer); + } + ani_status Array_GetRegion_Byte(ani_array_byte array, ani_size offset, ani_size length, ani_byte* native_buffer) + { + return c_api->Array_GetRegion_Byte(this, array, offset, length, native_buffer); + } + ani_status Array_GetRegion_Short(ani_array_short array, ani_size offset, ani_size length, ani_short* native_buffer) + { + return c_api->Array_GetRegion_Short(this, array, offset, length, native_buffer); + } + ani_status Array_GetRegion_Int(ani_array_int array, ani_size offset, ani_size length, ani_int* native_buffer) + { + return c_api->Array_GetRegion_Int(this, array, offset, length, native_buffer); + } + ani_status Array_GetRegion_Long(ani_array_long array, ani_size offset, ani_size length, ani_long* native_buffer) + { + return c_api->Array_GetRegion_Long(this, array, offset, length, native_buffer); + } + ani_status Array_GetRegion_Float(ani_array_float array, ani_size offset, ani_size length, ani_float* native_buffer) + { + return c_api->Array_GetRegion_Float(this, array, offset, length, native_buffer); + } + ani_status Array_GetRegion_Double( + ani_array_double array, ani_size offset, ani_size length, ani_double* native_buffer) + { + return c_api->Array_GetRegion_Double(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Boolean( + ani_array_boolean array, ani_size offset, ani_size length, const ani_boolean* native_buffer) + { + return c_api->Array_SetRegion_Boolean(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Char( + ani_array_char array, ani_size offset, ani_size length, const ani_char* native_buffer) + { + return c_api->Array_SetRegion_Char(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Byte( + ani_array_byte array, ani_size offset, ani_size length, const ani_byte* native_buffer) + { + return c_api->Array_SetRegion_Byte(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Short( + ani_array_short array, ani_size offset, ani_size length, const ani_short* native_buffer) + { + return c_api->Array_SetRegion_Short(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Int(ani_array_int array, ani_size offset, ani_size length, const ani_int* native_buffer) + { + return c_api->Array_SetRegion_Int(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Long( + ani_array_long array, ani_size offset, ani_size length, const ani_long* native_buffer) + { + return c_api->Array_SetRegion_Long(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Float( + ani_array_float array, ani_size offset, ani_size length, const ani_float* native_buffer) + { + return c_api->Array_SetRegion_Float(this, array, offset, length, native_buffer); + } + ani_status Array_SetRegion_Double( + ani_array_double array, ani_size offset, ani_size length, const ani_double* native_buffer) + { + return c_api->Array_SetRegion_Double(this, array, offset, length, native_buffer); + } + ani_status Array_New_Ref(ani_type type, ani_size length, ani_ref initial_element, ani_array_ref* result) + { + return c_api->Array_New_Ref(this, type, length, initial_element, result); + } + ani_status Array_Set_Ref(ani_array_ref array, ani_size index, ani_ref ref) + { + return c_api->Array_Set_Ref(this, array, index, ref); + } + ani_status Array_Get_Ref(ani_array_ref array, ani_size index, ani_ref* result) + { + return c_api->Array_Get_Ref(this, array, index, result); + } + ani_status Array_New(ani_size length, ani_ref initial_element, ani_array* result) + { + return c_api->Array_New(this, length, initial_element, result); + } + ani_status Array_Set(ani_array array, ani_size index, ani_ref ref) + { + return c_api->Array_Set(this, array, index, ref); + } + ani_status Array_Get(ani_array array, ani_size index, ani_ref* result) + { + return c_api->Array_Get(this, array, index, result); + } + ani_status Array_Push(ani_array array, ani_ref ref) + { + return c_api->Array_Push(this, array, ref); + } + ani_status Array_Pop(ani_array array, ani_ref* result) + { + return c_api->Array_Pop(this, array, result); + } + ani_status FixedArray_GetLength(ani_fixedarray array, ani_size* result) + { + return c_api->FixedArray_GetLength(this, array, result); + } + ani_status FixedArray_New_Boolean(ani_size length, ani_fixedarray_boolean* result) + { + return c_api->FixedArray_New_Boolean(this, length, result); + } + ani_status FixedArray_New_Char(ani_size length, ani_fixedarray_char* result) + { + return c_api->FixedArray_New_Char(this, length, result); + } + ani_status FixedArray_New_Byte(ani_size length, ani_fixedarray_byte* result) + { + return c_api->FixedArray_New_Byte(this, length, result); + } + ani_status FixedArray_New_Short(ani_size length, ani_fixedarray_short* result) + { + return c_api->FixedArray_New_Short(this, length, result); + } + ani_status FixedArray_New_Int(ani_size length, ani_fixedarray_int* result) + { + return c_api->FixedArray_New_Int(this, length, result); + } + ani_status FixedArray_New_Long(ani_size length, ani_fixedarray_long* result) + { + return c_api->FixedArray_New_Long(this, length, result); + } + ani_status FixedArray_New_Float(ani_size length, ani_fixedarray_float* result) + { + return c_api->FixedArray_New_Float(this, length, result); + } + ani_status FixedArray_New_Double(ani_size length, ani_fixedarray_double* result) + { + return c_api->FixedArray_New_Double(this, length, result); + } + ani_status FixedArray_GetRegion_Boolean( + ani_fixedarray_boolean array, ani_size offset, ani_size length, ani_boolean* native_buffer) + { + return c_api->FixedArray_GetRegion_Boolean(this, array, offset, length, native_buffer); + } + ani_status FixedArray_GetRegion_Char( + ani_fixedarray_char array, ani_size offset, ani_size length, ani_char* native_buffer) + { + return c_api->FixedArray_GetRegion_Char(this, array, offset, length, native_buffer); + } + ani_status FixedArray_GetRegion_Byte( + ani_fixedarray_byte array, ani_size offset, ani_size length, ani_byte* native_buffer) + { + return c_api->FixedArray_GetRegion_Byte(this, array, offset, length, native_buffer); + } + ani_status FixedArray_GetRegion_Short( + ani_fixedarray_short array, ani_size offset, ani_size length, ani_short* native_buffer) + { + return c_api->FixedArray_GetRegion_Short(this, array, offset, length, native_buffer); + } + ani_status FixedArray_GetRegion_Int( + ani_fixedarray_int array, ani_size offset, ani_size length, ani_int* native_buffer) + { + return c_api->FixedArray_GetRegion_Int(this, array, offset, length, native_buffer); + } + ani_status FixedArray_GetRegion_Long( + ani_fixedarray_long array, ani_size offset, ani_size length, ani_long* native_buffer) + { + return c_api->FixedArray_GetRegion_Long(this, array, offset, length, native_buffer); + } + ani_status FixedArray_GetRegion_Float( + ani_fixedarray_float array, ani_size offset, ani_size length, ani_float* native_buffer) + { + return c_api->FixedArray_GetRegion_Float(this, array, offset, length, native_buffer); + } + ani_status FixedArray_GetRegion_Double( + ani_fixedarray_double array, ani_size offset, ani_size length, ani_double* native_buffer) + { + return c_api->FixedArray_GetRegion_Double(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Boolean( + ani_fixedarray_boolean array, ani_size offset, ani_size length, const ani_boolean* native_buffer) + { + return c_api->FixedArray_SetRegion_Boolean(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Char( + ani_fixedarray_char array, ani_size offset, ani_size length, const ani_char* native_buffer) + { + return c_api->FixedArray_SetRegion_Char(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Byte( + ani_fixedarray_byte array, ani_size offset, ani_size length, const ani_byte* native_buffer) + { + return c_api->FixedArray_SetRegion_Byte(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Short( + ani_fixedarray_short array, ani_size offset, ani_size length, const ani_short* native_buffer) + { + return c_api->FixedArray_SetRegion_Short(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Int( + ani_fixedarray_int array, ani_size offset, ani_size length, const ani_int* native_buffer) + { + return c_api->FixedArray_SetRegion_Int(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Long( + ani_fixedarray_long array, ani_size offset, ani_size length, const ani_long* native_buffer) + { + return c_api->FixedArray_SetRegion_Long(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Float( + ani_fixedarray_float array, ani_size offset, ani_size length, const ani_float* native_buffer) + { + return c_api->FixedArray_SetRegion_Float(this, array, offset, length, native_buffer); + } + ani_status FixedArray_SetRegion_Double( + ani_fixedarray_double array, ani_size offset, ani_size length, const ani_double* native_buffer) + { + return c_api->FixedArray_SetRegion_Double(this, array, offset, length, native_buffer); + } + ani_status FixedArray_New_Ref(ani_type type, ani_size length, ani_ref initial_element, ani_fixedarray_ref* result) + { + return c_api->FixedArray_New_Ref(this, type, length, initial_element, result); + } + ani_status FixedArray_Set_Ref(ani_fixedarray_ref array, ani_size index, ani_ref ref) + { + return c_api->FixedArray_Set_Ref(this, array, index, ref); + } + ani_status FixedArray_Get_Ref(ani_fixedarray_ref array, ani_size index, ani_ref* result) + { + return c_api->FixedArray_Get_Ref(this, array, index, result); + } + ani_status Enum_GetEnumItemByName(ani_enum enm, const char* name, ani_enum_item* result) + { + return c_api->Enum_GetEnumItemByName(this, enm, name, result); + } + ani_status Enum_GetEnumItemByIndex(ani_enum enm, ani_size index, ani_enum_item* result) + { + return c_api->Enum_GetEnumItemByIndex(this, enm, index, result); + } + ani_status EnumItem_GetEnum(ani_enum_item enum_item, ani_enum* result) + { + return c_api->EnumItem_GetEnum(this, enum_item, result); + } + ani_status EnumItem_GetValue_Int(ani_enum_item enum_item, ani_int* result) + { + return c_api->EnumItem_GetValue_Int(this, enum_item, result); + } + ani_status EnumItem_GetValue_String(ani_enum_item enum_item, ani_string* result) + { + return c_api->EnumItem_GetValue_String(this, enum_item, result); + } + ani_status EnumItem_GetName(ani_enum_item enum_item, ani_string* result) + { + return c_api->EnumItem_GetName(this, enum_item, result); + } + ani_status EnumItem_GetIndex(ani_enum_item enum_item, ani_size* result) + { + return c_api->EnumItem_GetIndex(this, enum_item, result); + } + ani_status FunctionalObject_Call(ani_fn_object fn, ani_size argc, ani_ref* argv, ani_ref* result) + { + return c_api->FunctionalObject_Call(this, fn, argc, argv, result); + } + ani_status Variable_SetValue_Boolean(ani_variable variable, ani_boolean value) + { + return c_api->Variable_SetValue_Boolean(this, variable, value); + } + ani_status Variable_SetValue_Char(ani_variable variable, ani_char value) + { + return c_api->Variable_SetValue_Char(this, variable, value); + } + ani_status Variable_SetValue_Byte(ani_variable variable, ani_byte value) + { + return c_api->Variable_SetValue_Byte(this, variable, value); + } + ani_status Variable_SetValue_Short(ani_variable variable, ani_short value) + { + return c_api->Variable_SetValue_Short(this, variable, value); + } + ani_status Variable_SetValue_Int(ani_variable variable, ani_int value) + { + return c_api->Variable_SetValue_Int(this, variable, value); + } + ani_status Variable_SetValue_Long(ani_variable variable, ani_long value) + { + return c_api->Variable_SetValue_Long(this, variable, value); + } + ani_status Variable_SetValue_Float(ani_variable variable, ani_float value) + { + return c_api->Variable_SetValue_Float(this, variable, value); + } + ani_status Variable_SetValue_Double(ani_variable variable, ani_double value) + { + return c_api->Variable_SetValue_Double(this, variable, value); + } + ani_status Variable_SetValue_Ref(ani_variable variable, ani_ref value) + { + return c_api->Variable_SetValue_Ref(this, variable, value); + } + ani_status Variable_GetValue_Boolean(ani_variable variable, ani_boolean* result) + { + return c_api->Variable_GetValue_Boolean(this, variable, result); + } + ani_status Variable_GetValue_Char(ani_variable variable, ani_char* result) + { + return c_api->Variable_GetValue_Char(this, variable, result); + } + ani_status Variable_GetValue_Byte(ani_variable variable, ani_byte* result) + { + return c_api->Variable_GetValue_Byte(this, variable, result); + } + ani_status Variable_GetValue_Short(ani_variable variable, ani_short* result) + { + return c_api->Variable_GetValue_Short(this, variable, result); + } + ani_status Variable_GetValue_Int(ani_variable variable, ani_int* result) + { + return c_api->Variable_GetValue_Int(this, variable, result); + } + ani_status Variable_GetValue_Long(ani_variable variable, ani_long* result) + { + return c_api->Variable_GetValue_Long(this, variable, result); + } + ani_status Variable_GetValue_Float(ani_variable variable, ani_float* result) + { + return c_api->Variable_GetValue_Float(this, variable, result); + } + ani_status Variable_GetValue_Double(ani_variable variable, ani_double* result) + { + return c_api->Variable_GetValue_Double(this, variable, result); + } + ani_status Variable_GetValue_Ref(ani_variable variable, ani_ref* result) + { + return c_api->Variable_GetValue_Ref(this, variable, result); + } + ani_status Function_Call_Boolean(ani_function fn, ani_boolean* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Boolean_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Boolean_A(ani_function fn, ani_boolean* result, const ani_value* args) + { + return c_api->Function_Call_Boolean_A(this, fn, result, args); + } + ani_status Function_Call_Boolean_V(ani_function fn, ani_boolean* result, va_list args) + { + return c_api->Function_Call_Boolean_V(this, fn, result, args); + } + ani_status Function_Call_Char(ani_function fn, ani_char* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Char_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Char_A(ani_function fn, ani_char* result, const ani_value* args) + { + return c_api->Function_Call_Char_A(this, fn, result, args); + } + ani_status Function_Call_Char_V(ani_function fn, ani_char* result, va_list args) + { + return c_api->Function_Call_Char_V(this, fn, result, args); + } + ani_status Function_Call_Byte(ani_function fn, ani_byte* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Byte_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Byte_A(ani_function fn, ani_byte* result, const ani_value* args) + { + return c_api->Function_Call_Byte_A(this, fn, result, args); + } + ani_status Function_Call_Byte_V(ani_function fn, ani_byte* result, va_list args) + { + return c_api->Function_Call_Byte_V(this, fn, result, args); + } + ani_status Function_Call_Short(ani_function fn, ani_short* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Short_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Short_A(ani_function fn, ani_short* result, const ani_value* args) + { + return c_api->Function_Call_Short_A(this, fn, result, args); + } + ani_status Function_Call_Short_V(ani_function fn, ani_short* result, va_list args) + { + return c_api->Function_Call_Short_V(this, fn, result, args); + } + ani_status Function_Call_Int(ani_function fn, ani_int* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Int_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Int_A(ani_function fn, ani_int* result, const ani_value* args) + { + return c_api->Function_Call_Int_A(this, fn, result, args); + } + ani_status Function_Call_Int_V(ani_function fn, ani_int* result, va_list args) + { + return c_api->Function_Call_Int_V(this, fn, result, args); + } + ani_status Function_Call_Long(ani_function fn, ani_long* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Long_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Long_A(ani_function fn, ani_long* result, const ani_value* args) + { + return c_api->Function_Call_Long_A(this, fn, result, args); + } + ani_status Function_Call_Long_V(ani_function fn, ani_long* result, va_list args) + { + return c_api->Function_Call_Long_V(this, fn, result, args); + } + ani_status Function_Call_Float(ani_function fn, ani_float* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Float_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Float_A(ani_function fn, ani_float* result, const ani_value* args) + { + return c_api->Function_Call_Float_A(this, fn, result, args); + } + ani_status Function_Call_Float_V(ani_function fn, ani_float* result, va_list args) + { + return c_api->Function_Call_Float_V(this, fn, result, args); + } + ani_status Function_Call_Double(ani_function fn, ani_double* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Double_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Double_A(ani_function fn, ani_double* result, const ani_value* args) + { + return c_api->Function_Call_Double_A(this, fn, result, args); + } + ani_status Function_Call_Double_V(ani_function fn, ani_double* result, va_list args) + { + return c_api->Function_Call_Double_V(this, fn, result, args); + } + ani_status Function_Call_Ref(ani_function fn, ani_ref* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Function_Call_Ref_V(this, fn, result, args); + va_end(args); + return status; + } + ani_status Function_Call_Ref_A(ani_function fn, ani_ref* result, const ani_value* args) + { + return c_api->Function_Call_Ref_A(this, fn, result, args); + } + ani_status Function_Call_Ref_V(ani_function fn, ani_ref* result, va_list args) + { + return c_api->Function_Call_Ref_V(this, fn, result, args); + } + ani_status Function_Call_Void(ani_function fn, ...) + { + va_list args; + va_start(args, fn); + ani_status status = c_api->Function_Call_Void_V(this, fn, args); + va_end(args); + return status; + } + ani_status Function_Call_Void_A(ani_function fn, const ani_value* args) + { + return c_api->Function_Call_Void_A(this, fn, args); + } + ani_status Function_Call_Void_V(ani_function fn, va_list args) + { + return c_api->Function_Call_Void_V(this, fn, args); + } + ani_status Class_FindField(ani_class cls, const char* name, ani_field* result) + { + return c_api->Class_FindField(this, cls, name, result); + } + ani_status Class_FindStaticField(ani_class cls, const char* name, ani_static_field* result) + { + return c_api->Class_FindStaticField(this, cls, name, result); + } + ani_status Class_FindMethod(ani_class cls, const char* name, const char* signature, ani_method* result) + { + return c_api->Class_FindMethod(this, cls, name, signature, result); + } + ani_status Class_FindStaticMethod(ani_class cls, const char* name, const char* signature, ani_static_method* result) + { + return c_api->Class_FindStaticMethod(this, cls, name, signature, result); + } + ani_status Class_FindSetter(ani_class cls, const char* name, ani_method* result) + { + return c_api->Class_FindSetter(this, cls, name, result); + } + ani_status Class_FindGetter(ani_class cls, const char* name, ani_method* result) + { + return c_api->Class_FindGetter(this, cls, name, result); + } + ani_status Class_FindIndexableGetter(ani_class cls, const char* signature, ani_method* result) + { + return c_api->Class_FindIndexableGetter(this, cls, signature, result); + } + ani_status Class_FindIndexableSetter(ani_class cls, const char* signature, ani_method* result) + { + return c_api->Class_FindIndexableSetter(this, cls, signature, result); + } + ani_status Class_FindIterator(ani_class cls, ani_method* result) + { + return c_api->Class_FindIterator(this, cls, result); + } + ani_status Class_GetStaticField_Boolean(ani_class cls, ani_static_field field, ani_boolean* result) + { + return c_api->Class_GetStaticField_Boolean(this, cls, field, result); + } + ani_status Class_GetStaticField_Char(ani_class cls, ani_static_field field, ani_char* result) + { + return c_api->Class_GetStaticField_Char(this, cls, field, result); + } + ani_status Class_GetStaticField_Byte(ani_class cls, ani_static_field field, ani_byte* result) + { + return c_api->Class_GetStaticField_Byte(this, cls, field, result); + } + ani_status Class_GetStaticField_Short(ani_class cls, ani_static_field field, ani_short* result) + { + return c_api->Class_GetStaticField_Short(this, cls, field, result); + } + ani_status Class_GetStaticField_Int(ani_class cls, ani_static_field field, ani_int* result) + { + return c_api->Class_GetStaticField_Int(this, cls, field, result); + } + ani_status Class_GetStaticField_Long(ani_class cls, ani_static_field field, ani_long* result) + { + return c_api->Class_GetStaticField_Long(this, cls, field, result); + } + ani_status Class_GetStaticField_Float(ani_class cls, ani_static_field field, ani_float* result) + { + return c_api->Class_GetStaticField_Float(this, cls, field, result); + } + ani_status Class_GetStaticField_Double(ani_class cls, ani_static_field field, ani_double* result) + { + return c_api->Class_GetStaticField_Double(this, cls, field, result); + } + ani_status Class_GetStaticField_Ref(ani_class cls, ani_static_field field, ani_ref* result) + { + return c_api->Class_GetStaticField_Ref(this, cls, field, result); + } + ani_status Class_SetStaticField_Boolean(ani_class cls, ani_static_field field, ani_boolean value) + { + return c_api->Class_SetStaticField_Boolean(this, cls, field, value); + } + ani_status Class_SetStaticField_Char(ani_class cls, ani_static_field field, ani_char value) + { + return c_api->Class_SetStaticField_Char(this, cls, field, value); + } + ani_status Class_SetStaticField_Byte(ani_class cls, ani_static_field field, ani_byte value) + { + return c_api->Class_SetStaticField_Byte(this, cls, field, value); + } + ani_status Class_SetStaticField_Short(ani_class cls, ani_static_field field, ani_short value) + { + return c_api->Class_SetStaticField_Short(this, cls, field, value); + } + ani_status Class_SetStaticField_Int(ani_class cls, ani_static_field field, ani_int value) + { + return c_api->Class_SetStaticField_Int(this, cls, field, value); + } + ani_status Class_SetStaticField_Long(ani_class cls, ani_static_field field, ani_long value) + { + return c_api->Class_SetStaticField_Long(this, cls, field, value); + } + ani_status Class_SetStaticField_Float(ani_class cls, ani_static_field field, ani_float value) + { + return c_api->Class_SetStaticField_Float(this, cls, field, value); + } + ani_status Class_SetStaticField_Double(ani_class cls, ani_static_field field, ani_double value) + { + return c_api->Class_SetStaticField_Double(this, cls, field, value); + } + ani_status Class_SetStaticField_Ref(ani_class cls, ani_static_field field, ani_ref value) + { + return c_api->Class_SetStaticField_Ref(this, cls, field, value); + } + ani_status Class_GetStaticFieldByName_Boolean(ani_class cls, const char* name, ani_boolean* result) + { + return c_api->Class_GetStaticFieldByName_Boolean(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Char(ani_class cls, const char* name, ani_char* result) + { + return c_api->Class_GetStaticFieldByName_Char(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Byte(ani_class cls, const char* name, ani_byte* result) + { + return c_api->Class_GetStaticFieldByName_Byte(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Short(ani_class cls, const char* name, ani_short* result) + { + return c_api->Class_GetStaticFieldByName_Short(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Int(ani_class cls, const char* name, ani_int* result) + { + return c_api->Class_GetStaticFieldByName_Int(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Long(ani_class cls, const char* name, ani_long* result) + { + return c_api->Class_GetStaticFieldByName_Long(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Float(ani_class cls, const char* name, ani_float* result) + { + return c_api->Class_GetStaticFieldByName_Float(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Double(ani_class cls, const char* name, ani_double* result) + { + return c_api->Class_GetStaticFieldByName_Double(this, cls, name, result); + } + ani_status Class_GetStaticFieldByName_Ref(ani_class cls, const char* name, ani_ref* result) + { + return c_api->Class_GetStaticFieldByName_Ref(this, cls, name, result); + } + ani_status Class_SetStaticFieldByName_Boolean(ani_class cls, const char* name, ani_boolean value) + { + return c_api->Class_SetStaticFieldByName_Boolean(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Char(ani_class cls, const char* name, ani_char value) + { + return c_api->Class_SetStaticFieldByName_Char(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Byte(ani_class cls, const char* name, ani_byte value) + { + return c_api->Class_SetStaticFieldByName_Byte(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Short(ani_class cls, const char* name, ani_short value) + { + return c_api->Class_SetStaticFieldByName_Short(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Int(ani_class cls, const char* name, ani_int value) + { + return c_api->Class_SetStaticFieldByName_Int(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Long(ani_class cls, const char* name, ani_long value) + { + return c_api->Class_SetStaticFieldByName_Long(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Float(ani_class cls, const char* name, ani_float value) + { + return c_api->Class_SetStaticFieldByName_Float(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Double(ani_class cls, const char* name, ani_double value) + { + return c_api->Class_SetStaticFieldByName_Double(this, cls, name, value); + } + ani_status Class_SetStaticFieldByName_Ref(ani_class cls, const char* name, ani_ref value) + { + return c_api->Class_SetStaticFieldByName_Ref(this, cls, name, value); + } + ani_status Class_CallStaticMethod_Boolean(ani_class cls, ani_static_method method, ani_boolean* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Boolean_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Boolean_A( + ani_class cls, ani_static_method method, ani_boolean* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Boolean_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Boolean_V( + ani_class cls, ani_static_method method, ani_boolean* result, va_list args) + { + return c_api->Class_CallStaticMethod_Boolean_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Char(ani_class cls, ani_static_method method, ani_char* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Char_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Char_A( + ani_class cls, ani_static_method method, ani_char* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Char_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Char_V(ani_class cls, ani_static_method method, ani_char* result, va_list args) + { + return c_api->Class_CallStaticMethod_Char_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Byte(ani_class cls, ani_static_method method, ani_byte* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Byte_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Byte_A( + ani_class cls, ani_static_method method, ani_byte* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Byte_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Byte_V(ani_class cls, ani_static_method method, ani_byte* result, va_list args) + { + return c_api->Class_CallStaticMethod_Byte_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Short(ani_class cls, ani_static_method method, ani_short* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Short_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Short_A( + ani_class cls, ani_static_method method, ani_short* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Short_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Short_V(ani_class cls, ani_static_method method, ani_short* result, va_list args) + { + return c_api->Class_CallStaticMethod_Short_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Int(ani_class cls, ani_static_method method, ani_int* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Int_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Int_A( + ani_class cls, ani_static_method method, ani_int* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Int_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Int_V(ani_class cls, ani_static_method method, ani_int* result, va_list args) + { + return c_api->Class_CallStaticMethod_Int_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Long(ani_class cls, ani_static_method method, ani_long* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Long_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Long_A( + ani_class cls, ani_static_method method, ani_long* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Long_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Long_V(ani_class cls, ani_static_method method, ani_long* result, va_list args) + { + return c_api->Class_CallStaticMethod_Long_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Float(ani_class cls, ani_static_method method, ani_float* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Float_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Float_A( + ani_class cls, ani_static_method method, ani_float* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Float_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Float_V(ani_class cls, ani_static_method method, ani_float* result, va_list args) + { + return c_api->Class_CallStaticMethod_Float_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Double(ani_class cls, ani_static_method method, ani_double* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Double_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Double_A( + ani_class cls, ani_static_method method, ani_double* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Double_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Double_V( + ani_class cls, ani_static_method method, ani_double* result, va_list args) + { + return c_api->Class_CallStaticMethod_Double_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Ref(ani_class cls, ani_static_method method, ani_ref* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethod_Ref_V(this, cls, method, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Ref_A( + ani_class cls, ani_static_method method, ani_ref* result, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Ref_A(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Ref_V(ani_class cls, ani_static_method method, ani_ref* result, va_list args) + { + return c_api->Class_CallStaticMethod_Ref_V(this, cls, method, result, args); + } + ani_status Class_CallStaticMethod_Void(ani_class cls, ani_static_method method, ...) + { + va_list args; + va_start(args, method); + ani_status status = c_api->Class_CallStaticMethod_Void_V(this, cls, method, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethod_Void_A(ani_class cls, ani_static_method method, const ani_value* args) + { + return c_api->Class_CallStaticMethod_Void_A(this, cls, method, args); + } + ani_status Class_CallStaticMethod_Void_V(ani_class cls, ani_static_method method, va_list args) + { + return c_api->Class_CallStaticMethod_Void_V(this, cls, method, args); + } + ani_status Class_CallStaticMethodByName_Boolean( + ani_class cls, const char* name, const char* signature, ani_boolean* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Boolean_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Boolean_A( + ani_class cls, const char* name, const char* signature, ani_boolean* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Boolean_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Boolean_V( + ani_class cls, const char* name, const char* signature, ani_boolean* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Boolean_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Char( + ani_class cls, const char* name, const char* signature, ani_char* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Char_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Char_A( + ani_class cls, const char* name, const char* signature, ani_char* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Char_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Char_V( + ani_class cls, const char* name, const char* signature, ani_char* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Char_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Byte( + ani_class cls, const char* name, const char* signature, ani_byte* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Byte_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Byte_A( + ani_class cls, const char* name, const char* signature, ani_byte* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Byte_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Byte_V( + ani_class cls, const char* name, const char* signature, ani_byte* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Byte_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Short( + ani_class cls, const char* name, const char* signature, ani_short* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Short_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Short_A( + ani_class cls, const char* name, const char* signature, ani_short* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Short_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Short_V( + ani_class cls, const char* name, const char* signature, ani_short* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Short_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Int( + ani_class cls, const char* name, const char* signature, ani_int* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Int_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Int_A( + ani_class cls, const char* name, const char* signature, ani_int* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Int_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Int_V( + ani_class cls, const char* name, const char* signature, ani_int* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Int_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Long( + ani_class cls, const char* name, const char* signature, ani_long* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Long_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Long_A( + ani_class cls, const char* name, const char* signature, ani_long* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Long_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Long_V( + ani_class cls, const char* name, const char* signature, ani_long* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Long_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Float( + ani_class cls, const char* name, const char* signature, ani_float* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Float_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Float_A( + ani_class cls, const char* name, const char* signature, ani_float* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Float_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Float_V( + ani_class cls, const char* name, const char* signature, ani_float* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Float_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Double( + ani_class cls, const char* name, const char* signature, ani_double* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Double_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Double_A( + ani_class cls, const char* name, const char* signature, ani_double* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Double_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Double_V( + ani_class cls, const char* name, const char* signature, ani_double* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Double_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Ref( + ani_class cls, const char* name, const char* signature, ani_ref* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Class_CallStaticMethodByName_Ref_V(this, cls, name, signature, result, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Ref_A( + ani_class cls, const char* name, const char* signature, ani_ref* result, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Ref_A(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Ref_V( + ani_class cls, const char* name, const char* signature, ani_ref* result, va_list args) + { + return c_api->Class_CallStaticMethodByName_Ref_V(this, cls, name, signature, result, args); + } + ani_status Class_CallStaticMethodByName_Void(ani_class cls, const char* name, const char* signature, ...) + { + va_list args; + va_start(args, signature); + ani_status status = c_api->Class_CallStaticMethodByName_Void_V(this, cls, name, signature, args); + va_end(args); + return status; + } + ani_status Class_CallStaticMethodByName_Void_A( + ani_class cls, const char* name, const char* signature, const ani_value* args) + { + return c_api->Class_CallStaticMethodByName_Void_A(this, cls, name, signature, args); + } + ani_status Class_CallStaticMethodByName_Void_V(ani_class cls, const char* name, const char* signature, va_list args) + { + return c_api->Class_CallStaticMethodByName_Void_V(this, cls, name, signature, args); + } + ani_status Object_GetField_Boolean(ani_object object, ani_field field, ani_boolean* result) + { + return c_api->Object_GetField_Boolean(this, object, field, result); + } + ani_status Object_GetField_Char(ani_object object, ani_field field, ani_char* result) + { + return c_api->Object_GetField_Char(this, object, field, result); + } + ani_status Object_GetField_Byte(ani_object object, ani_field field, ani_byte* result) + { + return c_api->Object_GetField_Byte(this, object, field, result); + } + ani_status Object_GetField_Short(ani_object object, ani_field field, ani_short* result) + { + return c_api->Object_GetField_Short(this, object, field, result); + } + ani_status Object_GetField_Int(ani_object object, ani_field field, ani_int* result) + { + return c_api->Object_GetField_Int(this, object, field, result); + } + ani_status Object_GetField_Long(ani_object object, ani_field field, ani_long* result) + { + return c_api->Object_GetField_Long(this, object, field, result); + } + ani_status Object_GetField_Float(ani_object object, ani_field field, ani_float* result) + { + return c_api->Object_GetField_Float(this, object, field, result); + } + ani_status Object_GetField_Double(ani_object object, ani_field field, ani_double* result) + { + return c_api->Object_GetField_Double(this, object, field, result); + } + ani_status Object_GetField_Ref(ani_object object, ani_field field, ani_ref* result) + { + return c_api->Object_GetField_Ref(this, object, field, result); + } + ani_status Object_SetField_Boolean(ani_object object, ani_field field, ani_boolean value) + { + return c_api->Object_SetField_Boolean(this, object, field, value); + } + ani_status Object_SetField_Char(ani_object object, ani_field field, ani_char value) + { + return c_api->Object_SetField_Char(this, object, field, value); + } + ani_status Object_SetField_Byte(ani_object object, ani_field field, ani_byte value) + { + return c_api->Object_SetField_Byte(this, object, field, value); + } + ani_status Object_SetField_Short(ani_object object, ani_field field, ani_short value) + { + return c_api->Object_SetField_Short(this, object, field, value); + } + ani_status Object_SetField_Int(ani_object object, ani_field field, ani_int value) + { + return c_api->Object_SetField_Int(this, object, field, value); + } + ani_status Object_SetField_Long(ani_object object, ani_field field, ani_long value) + { + return c_api->Object_SetField_Long(this, object, field, value); + } + ani_status Object_SetField_Float(ani_object object, ani_field field, ani_float value) + { + return c_api->Object_SetField_Float(this, object, field, value); + } + ani_status Object_SetField_Double(ani_object object, ani_field field, ani_double value) + { + return c_api->Object_SetField_Double(this, object, field, value); + } + ani_status Object_SetField_Ref(ani_object object, ani_field field, ani_ref value) + { + return c_api->Object_SetField_Ref(this, object, field, value); + } + ani_status Object_GetFieldByName_Boolean(ani_object object, const char* name, ani_boolean* result) + { + return c_api->Object_GetFieldByName_Boolean(this, object, name, result); + } + ani_status Object_GetFieldByName_Char(ani_object object, const char* name, ani_char* result) + { + return c_api->Object_GetFieldByName_Char(this, object, name, result); + } + ani_status Object_GetFieldByName_Byte(ani_object object, const char* name, ani_byte* result) + { + return c_api->Object_GetFieldByName_Byte(this, object, name, result); + } + ani_status Object_GetFieldByName_Short(ani_object object, const char* name, ani_short* result) + { + return c_api->Object_GetFieldByName_Short(this, object, name, result); + } + ani_status Object_GetFieldByName_Int(ani_object object, const char* name, ani_int* result) + { + return c_api->Object_GetFieldByName_Int(this, object, name, result); + } + ani_status Object_GetFieldByName_Long(ani_object object, const char* name, ani_long* result) + { + return c_api->Object_GetFieldByName_Long(this, object, name, result); + } + ani_status Object_GetFieldByName_Float(ani_object object, const char* name, ani_float* result) + { + return c_api->Object_GetFieldByName_Float(this, object, name, result); + } + ani_status Object_GetFieldByName_Double(ani_object object, const char* name, ani_double* result) + { + return c_api->Object_GetFieldByName_Double(this, object, name, result); + } + ani_status Object_GetFieldByName_Ref(ani_object object, const char* name, ani_ref* result) + { + return c_api->Object_GetFieldByName_Ref(this, object, name, result); + } + ani_status Object_SetFieldByName_Boolean(ani_object object, const char* name, ani_boolean value) + { + return c_api->Object_SetFieldByName_Boolean(this, object, name, value); + } + ani_status Object_SetFieldByName_Char(ani_object object, const char* name, ani_char value) + { + return c_api->Object_SetFieldByName_Char(this, object, name, value); + } + ani_status Object_SetFieldByName_Byte(ani_object object, const char* name, ani_byte value) + { + return c_api->Object_SetFieldByName_Byte(this, object, name, value); + } + ani_status Object_SetFieldByName_Short(ani_object object, const char* name, ani_short value) + { + return c_api->Object_SetFieldByName_Short(this, object, name, value); + } + ani_status Object_SetFieldByName_Int(ani_object object, const char* name, ani_int value) + { + return c_api->Object_SetFieldByName_Int(this, object, name, value); + } + ani_status Object_SetFieldByName_Long(ani_object object, const char* name, ani_long value) + { + return c_api->Object_SetFieldByName_Long(this, object, name, value); + } + ani_status Object_SetFieldByName_Float(ani_object object, const char* name, ani_float value) + { + return c_api->Object_SetFieldByName_Float(this, object, name, value); + } + ani_status Object_SetFieldByName_Double(ani_object object, const char* name, ani_double value) + { + return c_api->Object_SetFieldByName_Double(this, object, name, value); + } + ani_status Object_SetFieldByName_Ref(ani_object object, const char* name, ani_ref value) + { + return c_api->Object_SetFieldByName_Ref(this, object, name, value); + } + ani_status Object_GetPropertyByName_Boolean(ani_object object, const char* name, ani_boolean* result) + { + return c_api->Object_GetPropertyByName_Boolean(this, object, name, result); + } + ani_status Object_GetPropertyByName_Char(ani_object object, const char* name, ani_char* result) + { + return c_api->Object_GetPropertyByName_Char(this, object, name, result); + } + ani_status Object_GetPropertyByName_Byte(ani_object object, const char* name, ani_byte* result) + { + return c_api->Object_GetPropertyByName_Byte(this, object, name, result); + } + ani_status Object_GetPropertyByName_Short(ani_object object, const char* name, ani_short* result) + { + return c_api->Object_GetPropertyByName_Short(this, object, name, result); + } + ani_status Object_GetPropertyByName_Int(ani_object object, const char* name, ani_int* result) + { + return c_api->Object_GetPropertyByName_Int(this, object, name, result); + } + ani_status Object_GetPropertyByName_Long(ani_object object, const char* name, ani_long* result) + { + return c_api->Object_GetPropertyByName_Long(this, object, name, result); + } + ani_status Object_GetPropertyByName_Float(ani_object object, const char* name, ani_float* result) + { + return c_api->Object_GetPropertyByName_Float(this, object, name, result); + } + ani_status Object_GetPropertyByName_Double(ani_object object, const char* name, ani_double* result) + { + return c_api->Object_GetPropertyByName_Double(this, object, name, result); + } + ani_status Object_GetPropertyByName_Ref(ani_object object, const char* name, ani_ref* result) + { + return c_api->Object_GetPropertyByName_Ref(this, object, name, result); + } + ani_status Object_SetPropertyByName_Boolean(ani_object object, const char* name, ani_boolean value) + { + return c_api->Object_SetPropertyByName_Boolean(this, object, name, value); + } + ani_status Object_SetPropertyByName_Char(ani_object object, const char* name, ani_char value) + { + return c_api->Object_SetPropertyByName_Char(this, object, name, value); + } + ani_status Object_SetPropertyByName_Byte(ani_object object, const char* name, ani_byte value) + { + return c_api->Object_SetPropertyByName_Byte(this, object, name, value); + } + ani_status Object_SetPropertyByName_Short(ani_object object, const char* name, ani_short value) + { + return c_api->Object_SetPropertyByName_Short(this, object, name, value); + } + ani_status Object_SetPropertyByName_Int(ani_object object, const char* name, ani_int value) + { + return c_api->Object_SetPropertyByName_Int(this, object, name, value); + } + ani_status Object_SetPropertyByName_Long(ani_object object, const char* name, ani_long value) + { + return c_api->Object_SetPropertyByName_Long(this, object, name, value); + } + ani_status Object_SetPropertyByName_Float(ani_object object, const char* name, ani_float value) + { + return c_api->Object_SetPropertyByName_Float(this, object, name, value); + } + ani_status Object_SetPropertyByName_Double(ani_object object, const char* name, ani_double value) + { + return c_api->Object_SetPropertyByName_Double(this, object, name, value); + } + ani_status Object_SetPropertyByName_Ref(ani_object object, const char* name, ani_ref value) + { + return c_api->Object_SetPropertyByName_Ref(this, object, name, value); + } + ani_status Object_CallMethod_Boolean(ani_object object, ani_method method, ani_boolean* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Boolean_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Boolean_A( + ani_object object, ani_method method, ani_boolean* result, const ani_value* args) + { + return c_api->Object_CallMethod_Boolean_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Boolean_V(ani_object object, ani_method method, ani_boolean* result, va_list args) + { + return c_api->Object_CallMethod_Boolean_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Char(ani_object object, ani_method method, ani_char* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Char_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Char_A(ani_object object, ani_method method, ani_char* result, const ani_value* args) + { + return c_api->Object_CallMethod_Char_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Char_V(ani_object object, ani_method method, ani_char* result, va_list args) + { + return c_api->Object_CallMethod_Char_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Byte(ani_object object, ani_method method, ani_byte* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Byte_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Byte_A(ani_object object, ani_method method, ani_byte* result, const ani_value* args) + { + return c_api->Object_CallMethod_Byte_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Byte_V(ani_object object, ani_method method, ani_byte* result, va_list args) + { + return c_api->Object_CallMethod_Byte_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Short(ani_object object, ani_method method, ani_short* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Short_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Short_A(ani_object object, ani_method method, ani_short* result, const ani_value* args) + { + return c_api->Object_CallMethod_Short_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Short_V(ani_object object, ani_method method, ani_short* result, va_list args) + { + return c_api->Object_CallMethod_Short_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Int(ani_object object, ani_method method, ani_int* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Int_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Int_A(ani_object object, ani_method method, ani_int* result, const ani_value* args) + { + return c_api->Object_CallMethod_Int_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Int_V(ani_object object, ani_method method, ani_int* result, va_list args) + { + return c_api->Object_CallMethod_Int_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Long(ani_object object, ani_method method, ani_long* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Long_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Long_A(ani_object object, ani_method method, ani_long* result, const ani_value* args) + { + return c_api->Object_CallMethod_Long_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Long_V(ani_object object, ani_method method, ani_long* result, va_list args) + { + return c_api->Object_CallMethod_Long_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Float(ani_object object, ani_method method, ani_float* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Float_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Float_A(ani_object object, ani_method method, ani_float* result, const ani_value* args) + { + return c_api->Object_CallMethod_Float_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Float_V(ani_object object, ani_method method, ani_float* result, va_list args) + { + return c_api->Object_CallMethod_Float_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Double(ani_object object, ani_method method, ani_double* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Double_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Double_A( + ani_object object, ani_method method, ani_double* result, const ani_value* args) + { + return c_api->Object_CallMethod_Double_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Double_V(ani_object object, ani_method method, ani_double* result, va_list args) + { + return c_api->Object_CallMethod_Double_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Ref(ani_object object, ani_method method, ani_ref* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethod_Ref_V(this, object, method, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Ref_A(ani_object object, ani_method method, ani_ref* result, const ani_value* args) + { + return c_api->Object_CallMethod_Ref_A(this, object, method, result, args); + } + ani_status Object_CallMethod_Ref_V(ani_object object, ani_method method, ani_ref* result, va_list args) + { + return c_api->Object_CallMethod_Ref_V(this, object, method, result, args); + } + ani_status Object_CallMethod_Void(ani_object object, ani_method method, ...) + { + va_list args; + va_start(args, method); + ani_status status = c_api->Object_CallMethod_Void_V(this, object, method, args); + va_end(args); + return status; + } + ani_status Object_CallMethod_Void_A(ani_object object, ani_method method, const ani_value* args) + { + return c_api->Object_CallMethod_Void_A(this, object, method, args); + } + ani_status Object_CallMethod_Void_V(ani_object object, ani_method method, va_list args) + { + return c_api->Object_CallMethod_Void_V(this, object, method, args); + } + ani_status Object_CallMethodByName_Boolean( + ani_object object, const char* name, const char* signature, ani_boolean* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Boolean_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Boolean_A( + ani_object object, const char* name, const char* signature, ani_boolean* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Boolean_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Boolean_V( + ani_object object, const char* name, const char* signature, ani_boolean* result, va_list args) + { + return c_api->Object_CallMethodByName_Boolean_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Char( + ani_object object, const char* name, const char* signature, ani_char* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Char_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Char_A( + ani_object object, const char* name, const char* signature, ani_char* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Char_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Char_V( + ani_object object, const char* name, const char* signature, ani_char* result, va_list args) + { + return c_api->Object_CallMethodByName_Char_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Byte( + ani_object object, const char* name, const char* signature, ani_byte* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Byte_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Byte_A( + ani_object object, const char* name, const char* signature, ani_byte* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Byte_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Byte_V( + ani_object object, const char* name, const char* signature, ani_byte* result, va_list args) + { + return c_api->Object_CallMethodByName_Byte_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Short( + ani_object object, const char* name, const char* signature, ani_short* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Short_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Short_A( + ani_object object, const char* name, const char* signature, ani_short* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Short_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Short_V( + ani_object object, const char* name, const char* signature, ani_short* result, va_list args) + { + return c_api->Object_CallMethodByName_Short_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Int( + ani_object object, const char* name, const char* signature, ani_int* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Int_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Int_A( + ani_object object, const char* name, const char* signature, ani_int* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Int_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Int_V( + ani_object object, const char* name, const char* signature, ani_int* result, va_list args) + { + return c_api->Object_CallMethodByName_Int_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Long( + ani_object object, const char* name, const char* signature, ani_long* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Long_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Long_A( + ani_object object, const char* name, const char* signature, ani_long* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Long_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Long_V( + ani_object object, const char* name, const char* signature, ani_long* result, va_list args) + { + return c_api->Object_CallMethodByName_Long_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Float( + ani_object object, const char* name, const char* signature, ani_float* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Float_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Float_A( + ani_object object, const char* name, const char* signature, ani_float* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Float_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Float_V( + ani_object object, const char* name, const char* signature, ani_float* result, va_list args) + { + return c_api->Object_CallMethodByName_Float_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Double( + ani_object object, const char* name, const char* signature, ani_double* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Double_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Double_A( + ani_object object, const char* name, const char* signature, ani_double* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Double_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Double_V( + ani_object object, const char* name, const char* signature, ani_double* result, va_list args) + { + return c_api->Object_CallMethodByName_Double_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Ref( + ani_object object, const char* name, const char* signature, ani_ref* result, ...) + { + va_list args; + va_start(args, result); + ani_status status = c_api->Object_CallMethodByName_Ref_V(this, object, name, signature, result, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Ref_A( + ani_object object, const char* name, const char* signature, ani_ref* result, const ani_value* args) + { + return c_api->Object_CallMethodByName_Ref_A(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Ref_V( + ani_object object, const char* name, const char* signature, ani_ref* result, va_list args) + { + return c_api->Object_CallMethodByName_Ref_V(this, object, name, signature, result, args); + } + ani_status Object_CallMethodByName_Void(ani_object object, const char* name, const char* signature, ...) + { + va_list args; + va_start(args, signature); + ani_status status = c_api->Object_CallMethodByName_Void_V(this, object, name, signature, args); + va_end(args); + return status; + } + ani_status Object_CallMethodByName_Void_A( + ani_object object, const char* name, const char* signature, const ani_value* args) + { + return c_api->Object_CallMethodByName_Void_A(this, object, name, signature, args); + } + ani_status Object_CallMethodByName_Void_V(ani_object object, const char* name, const char* signature, va_list args) + { + return c_api->Object_CallMethodByName_Void_V(this, object, name, signature, args); + } + ani_status TupleValue_GetNumberOfItems(ani_tuple_value tuple_value, ani_size* result) + { + return c_api->TupleValue_GetNumberOfItems(this, tuple_value, result); + } + ani_status TupleValue_GetItem_Boolean(ani_tuple_value tuple_value, ani_size index, ani_boolean* result) + { + return c_api->TupleValue_GetItem_Boolean(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Char(ani_tuple_value tuple_value, ani_size index, ani_char* result) + { + return c_api->TupleValue_GetItem_Char(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Byte(ani_tuple_value tuple_value, ani_size index, ani_byte* result) + { + return c_api->TupleValue_GetItem_Byte(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Short(ani_tuple_value tuple_value, ani_size index, ani_short* result) + { + return c_api->TupleValue_GetItem_Short(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Int(ani_tuple_value tuple_value, ani_size index, ani_int* result) + { + return c_api->TupleValue_GetItem_Int(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Long(ani_tuple_value tuple_value, ani_size index, ani_long* result) + { + return c_api->TupleValue_GetItem_Long(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Float(ani_tuple_value tuple_value, ani_size index, ani_float* result) + { + return c_api->TupleValue_GetItem_Float(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Double(ani_tuple_value tuple_value, ani_size index, ani_double* result) + { + return c_api->TupleValue_GetItem_Double(this, tuple_value, index, result); + } + ani_status TupleValue_GetItem_Ref(ani_tuple_value tuple_value, ani_size index, ani_ref* result) + { + return c_api->TupleValue_GetItem_Ref(this, tuple_value, index, result); + } + ani_status TupleValue_SetItem_Boolean(ani_tuple_value tuple_value, ani_size index, ani_boolean value) + { + return c_api->TupleValue_SetItem_Boolean(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Char(ani_tuple_value tuple_value, ani_size index, ani_char value) + { + return c_api->TupleValue_SetItem_Char(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Byte(ani_tuple_value tuple_value, ani_size index, ani_byte value) + { + return c_api->TupleValue_SetItem_Byte(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Short(ani_tuple_value tuple_value, ani_size index, ani_short value) + { + return c_api->TupleValue_SetItem_Short(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Int(ani_tuple_value tuple_value, ani_size index, ani_int value) + { + return c_api->TupleValue_SetItem_Int(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Long(ani_tuple_value tuple_value, ani_size index, ani_long value) + { + return c_api->TupleValue_SetItem_Long(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Float(ani_tuple_value tuple_value, ani_size index, ani_float value) + { + return c_api->TupleValue_SetItem_Float(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Double(ani_tuple_value tuple_value, ani_size index, ani_double value) + { + return c_api->TupleValue_SetItem_Double(this, tuple_value, index, value); + } + ani_status TupleValue_SetItem_Ref(ani_tuple_value tuple_value, ani_size index, ani_ref value) + { + return c_api->TupleValue_SetItem_Ref(this, tuple_value, index, value); + } + ani_status GlobalReference_Create(ani_ref ref, ani_ref* result) + { + return c_api->GlobalReference_Create(this, ref, result); + } + ani_status GlobalReference_Delete(ani_ref ref) + { + return c_api->GlobalReference_Delete(this, ref); + } + ani_status WeakReference_Create(ani_ref ref, ani_wref* result) + { + return c_api->WeakReference_Create(this, ref, result); + } + ani_status WeakReference_Delete(ani_wref wref) + { + return c_api->WeakReference_Delete(this, wref); + } + ani_status WeakReference_GetReference(ani_wref wref, ani_boolean* was_released_result, ani_ref* ref_result) + { + return c_api->WeakReference_GetReference(this, wref, was_released_result, ref_result); + } + ani_status CreateArrayBuffer(size_t length, void** data_result, ani_arraybuffer* arraybuffer_result) + { + return c_api->CreateArrayBuffer(this, length, data_result, arraybuffer_result); + } + ani_status ArrayBuffer_GetInfo(ani_arraybuffer arraybuffer, void** data_result, size_t* length_result) + { + return c_api->ArrayBuffer_GetInfo(this, arraybuffer, data_result, length_result); + } + ani_status Promise_New(ani_resolver* result_resolver, ani_object* result_promise) + { + return c_api->Promise_New(this, result_resolver, result_promise); + } + ani_status PromiseResolver_Resolve(ani_resolver resolver, ani_ref resolution) + { + return c_api->PromiseResolver_Resolve(this, resolver, resolution); + } + ani_status PromiseResolver_Reject(ani_resolver resolver, ani_error rejection) + { + return c_api->PromiseResolver_Reject(this, resolver, rejection); + } + ani_status Any_InstanceOf(ani_ref ref, ani_ref type, ani_boolean* result) + { + return c_api->Any_InstanceOf(this, ref, type, result); + } + ani_status Any_GetProperty(ani_ref ref, const char* name, ani_ref* result) + { + return c_api->Any_GetProperty(this, ref, name, result); + } + ani_status Any_SetProperty(ani_ref ref, const char* name, ani_ref value) + { + return c_api->Any_SetProperty(this, ref, name, value); + } + ani_status Any_GetByIndex(ani_ref ref, ani_size index, ani_ref* result) + { + return c_api->Any_GetByIndex(this, ref, index, result); + } + ani_status Any_SetByIndex(ani_ref ref, ani_size index, ani_ref value) + { + return c_api->Any_SetByIndex(this, ref, index, value); + } + ani_status Any_GetByValue(ani_ref ref, ani_ref key, ani_ref* result) + { + return c_api->Any_GetByValue(this, ref, key, result); + } + ani_status Any_SetByValue(ani_ref ref, ani_ref key, ani_ref value) + { + return c_api->Any_SetByValue(this, ref, key, value); + } + ani_status Any_Call(ani_ref func, ani_size argc, ani_ref* argv, ani_ref* result) + { + return c_api->Any_Call(this, func, argc, argv, result); + } + ani_status Any_CallMethod(ani_ref self, const char* name, ani_size argc, ani_ref* argv, ani_ref* result) + { + return c_api->Any_CallMethod(this, self, name, argc, argv, result); + } + ani_status Any_New(ani_ref ctor, ani_size argc, ani_ref* argv, ani_ref* result) + { + return c_api->Any_New(this, ctor, argc, argv, result); + } + ani_status Class_BindStaticNativeMethods(ani_class cls, const ani_native_function* methods, ani_size nr_methods) + { + return c_api->Class_BindStaticNativeMethods(this, cls, methods, nr_methods); + } +#endif // __cplusplus +}; + +// NOLINTEND +#endif // __ANI_H__ diff --git a/ets1.2/interop/src/cpp/callback-resource.cc b/ets1.2/interop/src/cpp/callback-resource.cc new file mode 100644 index 0000000000000000000000000000000000000000..ef09a583d27960cb1f9dfc72463bb754f83cff1c --- /dev/null +++ b/ets1.2/interop/src/cpp/callback-resource.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 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. + */ + +#undef KOALA_INTEROP_MODULE +#define KOALA_INTEROP_MODULE InteropNativeModule +#include "callback-resource.h" + +#include +#include +#include +#include + +#include "SerializerBase.h" +#include "common-interop.h" +#include "interop-types.h" +#include "interop-utils.h" + +static bool needReleaseFront = false; +static std::deque callbackEventsQueue; +static std::deque> callbackCallSubqueue; +static std::deque callbackResourceSubqueue; + +static std::atomic currentDeferred(nullptr); + +static KVMDeferred* takeCurrent(KNativePointer waitContext) +{ + KVMDeferred* current; + do { + current = currentDeferred.load(); + } while (!currentDeferred.compare_exchange_strong(current, nullptr)); + return current; +} + +void notifyWaiter() +{ + auto current = takeCurrent(nullptr); + if (current) + current->resolve(current, nullptr, 0); +} + +KVMObjectHandle impl_CallbackAwait(KVMContext vmContext, KNativePointer waitContext) +{ + KVMObjectHandle result = nullptr; + auto* current = takeCurrent(waitContext); + if (current) { + current->reject(current, "Wrong"); + } + auto next = CreateDeferred(vmContext, &result); + KVMDeferred* null = nullptr; + while (!currentDeferred.compare_exchange_strong(null, next)) { + } + return result; +} +KOALA_INTEROP_CTX_1(CallbackAwait, KVMObjectHandle, KNativePointer) + +void impl_UnblockCallbackWait(KNativePointer waitContext) +{ + auto current = takeCurrent(waitContext); + if (current) + current->resolve(current, nullptr, 0); +} +KOALA_INTEROP_V1(UnblockCallbackWait, KNativePointer) + +void enqueueCallback(int apiKind, const CallbackBuffer* event) +{ + callbackEventsQueue.push_back(Event_CallCallback); + callbackCallSubqueue.push_back({ apiKind, *event }); + notifyWaiter(); +} + +void holdManagedCallbackResource(InteropInt32 resourceId) +{ + callbackEventsQueue.push_back(Event_HoldManagedResource); + callbackResourceSubqueue.push_back(resourceId); + notifyWaiter(); +} + +void releaseManagedCallbackResource(InteropInt32 resourceId) +{ + callbackEventsQueue.push_back(Event_ReleaseManagedResource); + callbackResourceSubqueue.push_back(resourceId); + notifyWaiter(); +} + +KInt impl_CheckCallbackEvent(KSerializerBuffer buffer, KInt size) +{ + KByte* result = (KByte*)buffer; + if (needReleaseFront) { + switch (callbackEventsQueue.front()) { + case Event_CallCallback: + callbackCallSubqueue.front().second.resourceHolder.release(); + callbackCallSubqueue.pop_front(); + break; + case Event_HoldManagedResource: + case Event_ReleaseManagedResource: + callbackResourceSubqueue.pop_front(); + break; + default: + INTEROP_FATAL("Unknown event kind"); + } + callbackEventsQueue.pop_front(); + needReleaseFront = false; + } + if (callbackEventsQueue.empty()) { + return 0; + } + + SerializerBase serializer(result, size); + const CallbackEventKind frontEventKind = callbackEventsQueue.front(); + serializer.writeInt32(frontEventKind); + + switch (frontEventKind) { + case Event_CallCallback: { + std::pair& callback = callbackCallSubqueue.front(); + serializer.writeInt32(callback.first); + interop_memcpy(result + serializer.length(), size - serializer.length(), callback.second.buffer, + sizeof(CallbackBuffer::buffer)); + break; + } + case Event_HoldManagedResource: + case Event_ReleaseManagedResource: { + const InteropInt32 resourceId = callbackResourceSubqueue.front(); + interop_memcpy(result + serializer.length(), size - serializer.length(), &resourceId, sizeof(InteropInt32)); + break; + } + default: + INTEROP_FATAL("Unknown event kind"); + } + needReleaseFront = true; + return 1; +} +KOALA_INTEROP_DIRECT_2(CheckCallbackEvent, KInt, KSerializerBuffer, KInt) + +void impl_ReleaseCallbackResource(InteropInt32 resourceId) +{ + releaseManagedCallbackResource(resourceId); +} +KOALA_INTEROP_V1(ReleaseCallbackResource, KInt) + +void impl_HoldCallbackResource(InteropInt32 resourceId) +{ + holdManagedCallbackResource(resourceId); +} +KOALA_INTEROP_V1(HoldCallbackResource, KInt) diff --git a/ets1.2/interop/src/cpp/callback-resource.h b/ets1.2/interop/src/cpp/callback-resource.h new file mode 100644 index 0000000000000000000000000000000000000000..d55e50f41103279c8231905cc20c72457ca6a7a0 --- /dev/null +++ b/ets1.2/interop/src/cpp/callback-resource.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _INTEROP_CALLBACK_RESOURCE_H +#define _INTEROP_CALLBACK_RESOURCE_H + +#include + +#include "interop-types.h" + +#ifdef KOALA_WINDOWS +#define DLL_EXPORT __declspec(dllexport) +#else +#define DLL_EXPORT __attribute__((visibility("default"))) +#endif + +class CallbackResourceHolder { +private: + std::vector heldResources; + +public: + void holdCallbackResource(const InteropCallbackResource* resource) + { + resource->hold(resource->resourceId); + this->heldResources.push_back(*resource); + } + void release() + { + for (auto resource : this->heldResources) { + resource.release(resource.resourceId); + } + this->heldResources.clear(); + } +}; + +struct CallbackBuffer { + uint8_t buffer[4096]; + CallbackResourceHolder resourceHolder; +}; + +enum CallbackEventKind { + Event_CallCallback = 0, + Event_HoldManagedResource = 1, + Event_ReleaseManagedResource = 2, +}; + +extern "C" DLL_EXPORT void enqueueCallback(int apiKind, const CallbackBuffer* event); +extern "C" DLL_EXPORT void holdManagedCallbackResource(InteropInt32 resourceId); +extern "C" DLL_EXPORT void releaseManagedCallbackResource(InteropInt32 resourceId); + +#endif diff --git a/ets1.2/interop/src/cpp/common-interop.cc b/ets1.2/interop/src/cpp/common-interop.cc new file mode 100644 index 0000000000000000000000000000000000000000..ce615df1a32c0c8ddaff775f3713dede82475cda --- /dev/null +++ b/ets1.2/interop/src/cpp/common-interop.cc @@ -0,0 +1,826 @@ +/* + * Copyright (c) 2022-2023 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. + */ +#include +#include +#include + +#ifndef KOALA_INTEROP_MEM_ANALYZER +#include +#endif + +#ifdef KOALA_INTEROP_MODULE +#undef KOALA_INTEROP_MODULE +#endif + +#define KOALA_INTEROP_MODULE InteropNativeModule +#include "common-interop.h" +#include "dynamic-loader.h" +#include "interop-logging.h" +#include "interop-utils.h" + +#ifdef KOALA_FOREIGN_NAPI +#ifndef KOALA_FOREIGN_NAPI_OHOS +#include +#else +#include +#include +#endif +#endif + +#if KOALA_INTEROP_PROFILER +#include "profiler.h" + +InteropProfiler *InteropProfiler::_instance = nullptr; + +#endif + +using std::string; + +#ifndef KOALA_INTEROP_MEM_ANALYZER +static std::atomic mallocCounter{0}; +#endif + +#if defined(KOALA_NAPI) || defined(KOALA_ANI) +// Callback dispatcher MOVED to convertors-napi.cc. +// Let's keep platform-specific parts of the code together + +typedef void (*hold_t)(KInt); + +KInteropBuffer impl_MaterializeBuffer(KNativePointer data, KLong length, + KInt resourceId, KNativePointer holdPtr, + KNativePointer releasePtr) { + auto hold = reinterpret_cast(holdPtr); + auto release = reinterpret_cast(releasePtr); + hold(resourceId); + return KInteropBuffer{length, data, resourceId, release}; +} +KOALA_INTEROP_5(MaterializeBuffer, KInteropBuffer, KNativePointer, KLong, KInt, + KNativePointer, KNativePointer) + +KNativePointer impl_GetNativeBufferPointer(KInteropBuffer buffer) { + return buffer.data; +} +KOALA_INTEROP_1(GetNativeBufferPointer, KNativePointer, KInteropBuffer) + +#endif + +#ifdef KOALA_ETS_NAPI +#include "etsapi.h" + +static struct { + ets_class clazz = nullptr; + ets_method method = nullptr; +} g_koalaEtsNapiCallbackDispatcher; + +bool setKoalaEtsNapiCallbackDispatcher(EtsEnv *etsEnv, ets_class clazz, + const char *dispatcherMethodName, + const char *dispactherMethodSig) { + g_koalaEtsNapiCallbackDispatcher.clazz = clazz; + etsEnv->NewGlobalRef(clazz); + ets_method method = etsEnv->GetStaticp_method(clazz, dispatcherMethodName, + dispactherMethodSig); + if (method == nullptr) { + return false; + } + g_koalaEtsNapiCallbackDispatcher.method = method; + return true; +} + +void getKoalaEtsNapiCallbackDispatcher(ets_class *clazz, ets_method *method) { + *clazz = g_koalaEtsNapiCallbackDispatcher.clazz; + *method = g_koalaEtsNapiCallbackDispatcher.method; +} +#endif + +// Improve: move callback dispetchers to convertors-.cc. +#ifdef KOALA_JNI +#include "jni.h" +static struct { + jclass clazz = nullptr; + jmethodID method = nullptr; +} g_koalaJniCallbackDispatcher; + +bool setKoalaJniCallbackDispatcher(JNIEnv *jniEnv, jclass clazz, + const char *dispatcherMethodName, + const char *dispactherMethodSig) { + g_koalaJniCallbackDispatcher.clazz = clazz; + jniEnv->NewGlobalRef(clazz); + jmethodID method = jniEnv->GetStaticMethodID(clazz, dispatcherMethodName, + dispactherMethodSig); + if (method == nullptr) { + return false; + } + g_koalaJniCallbackDispatcher.method = method; + return true; +} + +void getKoalaJniCallbackDispatcher(jclass *clazz, jmethodID *method) { + *clazz = g_koalaJniCallbackDispatcher.clazz; + *method = g_koalaJniCallbackDispatcher.method; +} +#endif + +KInt impl_StringLength(KNativePointer ptr) { + string *s = reinterpret_cast(ptr); + return s->length(); +} +KOALA_INTEROP_1(StringLength, KInt, KNativePointer) + +void impl_StringData(KNativePointer ptr, KByte *bytes, KInt size) { + string *s = reinterpret_cast(ptr); + if (s) { + interop_memcpy(bytes, size, s->c_str(), size); + } +} +KOALA_INTEROP_V3(StringData, KNativePointer, KByte *, KInt) + +#ifdef KOALA_JNI +// For Java only yet. +KInteropBuffer impl_StringDataBytes(KVMContext vmContext, KNativePointer ptr) { + string *s = reinterpret_cast(ptr); + KInteropBuffer result = {(int32_t)s->length(), (void *)s->c_str()}; + return result; +} +KOALA_INTEROP_CTX_1(StringDataBytes, KInteropBuffer, KNativePointer) +#endif + +KNativePointer impl_StringMake(const KStringPtr &str) { + return new string(str.c_str()); +} +KOALA_INTEROP_1(StringMake, KNativePointer, KStringPtr) + +// For slow runtimes w/o fast encoders. +KInt impl_ManagedStringWrite(const KStringPtr &string, KSerializerBuffer buffer, + KInt bufferSize, KInt offset) { + interop_memcpy((uint8_t *)buffer + offset, bufferSize, string.c_str(), + string.length() + 1); + return string.length() + 1; +} +KOALA_INTEROP_4(ManagedStringWrite, KInt, KStringPtr, KSerializerBuffer, KInt, + KInt) + +void stringFinalizer(string *ptr) { delete ptr; } +KNativePointer impl_GetStringFinalizer() { + return fnPtr(stringFinalizer); +} +KOALA_INTEROP_0(GetStringFinalizer, KNativePointer) + +void impl_InvokeFinalizer(KNativePointer obj, KNativePointer finalizer) { + auto finalizer_f = reinterpret_cast(finalizer); + finalizer_f(obj); +} +KOALA_INTEROP_V2(InvokeFinalizer, KNativePointer, KNativePointer) + +KInteropReturnBuffer impl_GetPtrVector(KNativePointer ptr) { + auto vector = reinterpret_cast *>(ptr); + return KInteropReturnBuffer::from(*vector, nullptr); +} +KOALA_INTEROP_1(GetPtrVector, KInteropReturnBuffer, KNativePointer) + +KInt impl_GetPtrVectorSize(KNativePointer ptr) { + return reinterpret_cast *>(ptr)->size(); +} +KOALA_INTEROP_1(GetPtrVectorSize, KInt, KNativePointer) + +KNativePointer impl_GetPtrVectorElement(KNativePointer ptr, KInt index) { + auto vector = reinterpret_cast *>(ptr); + auto element = vector->at(index); + return nativePtr(element); +} +KOALA_INTEROP_2(GetPtrVectorElement, KNativePointer, KNativePointer, KInt) + +inline KUInt unpackUInt(const KByte *bytes) { + return (bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24)); +} + +KNativePointer impl_GetGroupedLog(KInt index) { + return new std::string(GetDefaultLogger()->getGroupedLog(index)); +} +KOALA_INTEROP_1(GetGroupedLog, KNativePointer, KInt) + +void impl_StartGroupedLog(KInt index) { + GetDefaultLogger()->startGroupedLog(index); +} +KOALA_INTEROP_V1(StartGroupedLog, KInt) + +void impl_StopGroupedLog(KInt index) { + GetDefaultLogger()->stopGroupedLog(index); +} +KOALA_INTEROP_V1(StopGroupedLog, KInt) + +void impl_AppendGroupedLog(KInt index, const KStringPtr &message) { + if (GetDefaultLogger()->needGroupedLog(index)) + GetDefaultLogger()->appendGroupedLog(index, message.c_str()); +} +KOALA_INTEROP_V2(AppendGroupedLog, KInt, KStringPtr) + +void impl_PrintGroupedLog(KInt index) { +#ifdef KOALA_OHOS + LOGI("%" LOG_PUBLIC "s", GetDefaultLogger()->getGroupedLog(index)); +#else + fprintf(stdout, "%s\n", GetDefaultLogger()->getGroupedLog(index)); + fflush(stdout); +#endif +} +KOALA_INTEROP_V1(PrintGroupedLog, KInt) + +int32_t callCallback(KVMContext context, int32_t methodId, uint8_t *argsData, + int32_t argsLength) { +#if KOALA_USE_NODE_VM || KOALA_USE_HZ_VM || KOALA_USE_PANDA_VM || \ + KOALA_USE_JAVA_VM || KOALA_CJ + KOALA_INTEROP_CALL_INT(context, methodId, argsLength, argsData); + return 0; +#else + return 0; +#endif +} + +struct ForeignVMContext { + KVMContext vmContext; + int32_t (*callSync)(KVMContext vmContext, int32_t callback, uint8_t *data, + int32_t length); +}; +typedef KInt (*LoadVirtualMachine_t)(KInt vmKind, const char *bootFiles, + const char *userFiles, + const char *libraryPath, + const struct ForeignVMContext *foreignVM); +typedef KNativePointer (*StartApplication_t)(const char *appUrl, + const char *appParams, + int32_t loopIterationr); +typedef KBoolean (*RunApplication_t)(const KInt arg0, const KInt arg1); +typedef const char *(*EmitEvent_t)(const KInt type, const KInt target, + const KInt arg0, const KInt arg1); +typedef void (*RestartWith_t)(const char *page); +typedef const char *(*LoadView_t)(const char *className, const char *params); + +void *getImpl(const char *path, const char *name) { + static void *lib = nullptr; + if (!lib && name) { + auto name = +#ifndef KOALA_OHOS // dlopen on OHOS doesn't like paths + std::string(path) + "/" + +#endif + libName("vmloader"); + lib = loadLibrary(name); + if (!lib) { + fprintf(stderr, "Ensure vmloader library %s was built\n", name.c_str()); + } + } + return findSymbol(lib, name); +} + +KInt impl_LoadVirtualMachine(KVMContext vmContext, KInt vmKind, + const KStringPtr &bootFiles, + const KStringPtr &userFiles, + const KStringPtr &libraryPath) { + const char *envClassPath = std::getenv("PANDA_CLASS_PATH"); + if (envClassPath) { + LOGI("CLASS PATH updated from env var PANDA_CLASS_PATH, %" LOG_PUBLIC "s", + envClassPath); + } + const char *bootFilesPath = envClassPath ? envClassPath : bootFiles.c_str(); + const char *nativeLibPath = envClassPath ? envClassPath : libraryPath.c_str(); + + static LoadVirtualMachine_t impl = nullptr; + if (!impl) + impl = reinterpret_cast( + getImpl(nativeLibPath, "LoadVirtualMachine")); + if (!impl) + KOALA_INTEROP_THROW_STRING(vmContext, "Cannot load VM", -1); + const ForeignVMContext foreignVM = {vmContext, &callCallback}; + return impl(vmKind, bootFilesPath, userFiles.c_str(), nativeLibPath, + &foreignVM); +} +KOALA_INTEROP_CTX_4(LoadVirtualMachine, KInt, KInt, KStringPtr, KStringPtr, + KStringPtr) + +KNativePointer impl_StartApplication(const KStringPtr &appUrl, + const KStringPtr &appParams, + KInt loopIterations) { + static StartApplication_t impl = nullptr; + if (!impl) + impl = reinterpret_cast( + getImpl(nullptr, "StartApplication")); + return impl(appUrl.c_str(), appParams.c_str(), loopIterations); +} +KOALA_INTEROP_3(StartApplication, KNativePointer, KStringPtr, KStringPtr, KInt) + +KBoolean impl_RunApplication(const KInt arg0, const KInt arg1) { + static RunApplication_t impl = nullptr; + if (!impl) + impl = + reinterpret_cast(getImpl(nullptr, "RunApplication")); + return impl(arg0, arg1); +} +KOALA_INTEROP_2(RunApplication, KBoolean, KInt, KInt) + +KStringPtr impl_EmitEvent(KVMContext vmContext, KInt type, KInt target, + KInt arg0, KInt arg1) { + static EmitEvent_t impl = nullptr; + if (!impl) + impl = reinterpret_cast(getImpl(nullptr, "EmitEvent")); + const char *out = impl(type, target, arg0, arg1); + auto size = std::string(out).size(); + KStringPtr result(out, size, true); + return result; +} +KOALA_INTEROP_CTX_4(EmitEvent, KStringPtr, KInt, KInt, KInt, KInt) + +void impl_RestartWith(const KStringPtr &page) { + static RestartWith_t impl = nullptr; + if (!impl) + impl = reinterpret_cast(getImpl(nullptr, "RestartWith")); + impl(page.c_str()); +} +KOALA_INTEROP_V1(RestartWith, KStringPtr) + +#ifdef KOALA_ANI +KStringPtr impl_LoadView(const KStringPtr &className, + const KStringPtr ¶ms) { + static LoadView_t impl = nullptr; + if (!impl) + impl = reinterpret_cast(getImpl(nullptr, "LoadView")); + const char *result = impl(className.c_str(), params.c_str()); + return KStringPtr(result, interop_strlen(result), true); +} +KOALA_INTEROP_2(LoadView, KStringPtr, KStringPtr, KStringPtr) +#endif // KOALA_ANI + +KNativePointer impl_Malloc(KLong length) { + const auto ptr = static_cast(malloc(length)); + if (ptr == nullptr) { + INTEROP_FATAL("Memory allocation failed!"); + } +#ifndef KOALA_INTEROP_MEM_ANALYZER + mallocCounter.fetch_add(1, std::memory_order_release); +#endif + return ptr; +} +KOALA_INTEROP_DIRECT_1(Malloc, KNativePointer, KLong) + +void malloc_finalize(KNativePointer data) { + if (data) { + free(data); +#ifndef KOALA_INTEROP_MEM_ANALYZER + if (mallocCounter.fetch_sub(1, std::memory_order_release) == 0) { + INTEROP_FATAL("Double-free detected!"); + } +#endif + } +} + +KNativePointer impl_GetMallocFinalizer() { + return reinterpret_cast(malloc_finalize); +} +KOALA_INTEROP_DIRECT_0(GetMallocFinalizer, KNativePointer) + +void impl_Free(KNativePointer data) { malloc_finalize(data); } +KOALA_INTEROP_DIRECT_V1(Free, KNativePointer) + +KInt impl_ReadByte(KNativePointer data, KLong index, KLong length) { + if (index >= length) + INTEROP_FATAL( + "impl_ReadByte: index %lld is equal or greater than length %lld", + (long long)index, (long long)length); + uint8_t *ptr = reinterpret_cast(data); + return ptr[index]; +} +KOALA_INTEROP_DIRECT_3(ReadByte, KInt, KNativePointer, KLong, KLong) + +void impl_WriteByte(KNativePointer data, KInt index, KLong length, KInt value) { + if (index >= length) + INTEROP_FATAL( + "impl_WriteByte: index %lld is equal or greater than length %lld", + (long long)index, (long long)length); + uint8_t *ptr = reinterpret_cast(data); + ptr[index] = value; +} +KOALA_INTEROP_DIRECT_V4(WriteByte, KNativePointer, KLong, KLong, KInt) + +void impl_CopyArray(KNativePointer data, KLong length, KByte *array) { + if (!array || !data) { + INTEROP_FATAL( + "CopyArray called with incorrect nullptr args (array, data):(%p, %p)", + array, data); + } + + interop_memcpy(data, length, array, length); +} +KOALA_INTEROP_V3(CopyArray, KNativePointer, KLong, KByte *) + +static const int API_KIND_MAX = 100; +static Callback_Caller_t g_callbackCaller[API_KIND_MAX] = {0}; +static Callback_Caller_Sync_t g_callbackCallerSync[API_KIND_MAX] = {0}; + +#define CHECK_VALID_API_KIND(apiKind) \ + if ((apiKind) < 0 || (apiKind) > API_KIND_MAX) \ + INTEROP_FATAL("Maximum api kind is %d, received %d", API_KIND_MAX, apiKind); +#define CHECK_HAS_CALLBACK_CALLER(apiKind, callbackCallers) \ + CHECK_VALID_API_KIND(apiKind); \ + if ((callbackCallers)[apiKind] == nullptr) \ + INTEROP_FATAL("Callback caller for api kind %d was not set", apiKind) +#define CHECK_HAS_NOT_CALLBACK_CALLER(apiKind, callbackCallers) \ + CHECK_VALID_API_KIND(apiKind); \ + if ((callbackCallers)[apiKind] != nullptr) \ + INTEROP_FATAL("Callback caller for api kind %d already was set", apiKind); + +void setCallbackCaller(int apiKind, Callback_Caller_t callbackCaller) { + CHECK_HAS_NOT_CALLBACK_CALLER(apiKind, g_callbackCaller); + g_callbackCaller[apiKind] = callbackCaller; +} + +void impl_CallCallback(KInt apiKind, KInt callbackKind, KSerializerBuffer args, + KInt argsSize) { + CHECK_HAS_CALLBACK_CALLER(apiKind, g_callbackCaller); + g_callbackCaller[apiKind](callbackKind, args, argsSize); +} +KOALA_INTEROP_V4(CallCallback, KInt, KInt, KSerializerBuffer, KInt) + +void setCallbackCallerSync(int apiKind, + Callback_Caller_Sync_t callbackCallerSync) { + CHECK_HAS_NOT_CALLBACK_CALLER(apiKind, g_callbackCallerSync); + g_callbackCallerSync[apiKind] = callbackCallerSync; +} + +void impl_CallCallbackSync(KVMContext vmContext, KInt apiKind, + KInt callbackKind, KSerializerBuffer args, + KInt argsSize) { + CHECK_HAS_CALLBACK_CALLER(apiKind, g_callbackCallerSync); + g_callbackCallerSync[apiKind](vmContext, callbackKind, args, argsSize); +} +KOALA_INTEROP_CTX_V4(CallCallbackSync, KInt, KInt, KSerializerBuffer, KInt) + +void impl_CallCallbackResourceHolder(KNativePointer holder, KInt resourceId) { + reinterpret_cast(holder)(resourceId); +} +KOALA_INTEROP_V2(CallCallbackResourceHolder, KNativePointer, KInt) + +void impl_CallCallbackResourceReleaser(KNativePointer releaser, + KInt resourceId) { + reinterpret_cast(releaser)(resourceId); +} +KOALA_INTEROP_V2(CallCallbackResourceReleaser, KNativePointer, KInt) + +KInt impl_CallForeignVM(KNativePointer foreignContextRaw, KInt function, + KSerializerBuffer data, KInt length) { + const ForeignVMContext *foreignContext = + (const ForeignVMContext *)foreignContextRaw; + // Improve: set actuall callbacks caller/holder/releaser. + /* + *(int64_t*)(data + 8) = impl_CallCallbackSync; + *(int64_t*)(data + 16) = 0; + *(int64_t*)(data + 24) = 0; */ + return foreignContext->callSync(foreignContext->vmContext, function, + reinterpret_cast(data), length); +} +KOALA_INTEROP_4(CallForeignVM, KInt, KNativePointer, KInt, KSerializerBuffer, + KInt) + +#ifdef KOALA_FOREIGN_NAPI +KVMContext g_foreignVMContext = nullptr; +#endif +void impl_SetForeignVMContext(KNativePointer foreignVMContextRaw) { +#ifdef KOALA_FOREIGN_NAPI + if (foreignVMContextRaw == nullptr) { + g_foreignVMContext = nullptr; + } else { + auto foreignContext = (const ForeignVMContext *)foreignVMContextRaw; + g_foreignVMContext = foreignContext->vmContext; + } +#endif + + /* supress unused private fields */ + (void)foreignVMContextRaw; +} +KOALA_INTEROP_V1(SetForeignVMContext, KNativePointer) + +#define QUOTE2(x) #x + +#define QUOTE(x) QUOTE2(x) + +void impl_NativeLog(const KStringPtr &str) { +#ifdef KOALA_OHOS + LOGI("%{public}s: %{public}s", QUOTE(INTEROP_LIBRARY_NAME), str.c_str()); +#else + fprintf(stdout, "%s: %s\n", QUOTE(INTEROP_LIBRARY_NAME), str.c_str()); + fflush(stdout); +#endif +} +KOALA_INTEROP_V1(NativeLog, KStringPtr) + +void resolveDeferred(KVMDeferred *deferred, uint8_t *argsData, + int32_t argsLength) { +#ifdef KOALA_NAPI + auto status = + napi_call_threadsafe_function((napi_threadsafe_function)deferred->handler, + deferred, napi_tsfn_nonblocking); + if (status != napi_ok) + LOGE("cannot call thread-safe function; status=%d", status); + if (deferred->handler) { + napi_release_threadsafe_function( + (napi_threadsafe_function)deferred->handler, napi_tsfn_release); + deferred->handler = nullptr; + } +#endif +#ifdef KOALA_ANI + ani_vm *vm = (ani_vm *)deferred->context; + ani_env *env = nullptr; + ani_status status = vm->GetEnv(ANI_VERSION_1, &env); + if (env == nullptr || status != ANI_OK) { + status = vm->AttachCurrentThread(nullptr, ANI_VERSION_1, &env); + CHECK_ANI_FATAL(status); + } + ani_ref undef = nullptr; + status = env->GetUndefined(&undef); + CHECK_ANI_FATAL(status); + status = env->PromiseResolver_Resolve((ani_resolver)deferred->handler, undef); + CHECK_ANI_FATAL(status); +#endif +} + +void rejectDeferred(KVMDeferred *deferred, const char *message) { +#ifdef KOALA_NAPI + if (deferred->handler) { + napi_release_threadsafe_function( + (napi_threadsafe_function)deferred->handler, napi_tsfn_release); + deferred->handler = nullptr; + } +#endif +#ifdef KOALA_ANI + if (deferred->handler) { + ani_vm *vm = (ani_vm *)deferred->context; + ani_env *env = nullptr; + ani_status status = vm->GetEnv(ANI_VERSION_1, &env); + if (env == nullptr || status != ANI_OK) { + status = vm->AttachCurrentThread(nullptr, ANI_VERSION_1, &env); + CHECK_ANI_FATAL(status); + } + status = + env->PromiseResolver_Reject((ani_resolver)deferred->handler, nullptr); + CHECK_ANI_FATAL(status); + deferred->handler = nullptr; + } +#endif +} + +#ifdef KOALA_NAPI +void resolveDeferredImpl(napi_env env, napi_value js_callback, + KVMDeferred *deferred, void *data) { + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + auto status = + napi_resolve_deferred(env, (napi_deferred)deferred->context, undefined); + if (status != napi_ok) + LOGE("cannot resolve deferred; status=%d", status); + delete deferred; +} +#endif + +KVMDeferred *CreateDeferred(KVMContext vmContext, + KVMObjectHandle *promiseHandle) { + KVMDeferred *deferred = new KVMDeferred(); + deferred->resolve = resolveDeferred; + deferred->reject = rejectDeferred; +#ifdef KOALA_NAPI + // Improve: move to interop! + napi_env env = (napi_env)vmContext; + napi_value promise; + napi_value resourceName; + napi_create_string_utf8(env, "Async", sizeof("Async"), &resourceName); + auto status = + napi_create_promise(env, (napi_deferred *)&deferred->context, &promise); + if (status != napi_ok) + LOGE("cannot make a promise; status=%d", status); + status = napi_create_threadsafe_function( + env, nullptr, nullptr, resourceName, 0, 1, nullptr, nullptr, deferred, + (napi_threadsafe_function_call_js)resolveDeferredImpl, + (napi_threadsafe_function *)&deferred->handler); + if (status != napi_ok) + LOGE("cannot make threadsafe function; status=%d", status); + *promiseHandle = (KVMObjectHandle)promise; +#endif +#ifdef KOALA_ANI + ani_env *env = (ani_env *)vmContext; + ani_object promise = nullptr; + ani_resolver resolver = nullptr; + ani_status status = env->Promise_New(&resolver, &promise); + deferred->handler = resolver; + CHECK_ANI_FATAL(status); + *promiseHandle = (KVMObjectHandle)promise; + ani_vm *vm = nullptr; + status = env->GetVM(&vm); + CHECK_ANI_FATAL(status); + deferred->context = vm; +#endif + return deferred; +} + +class KoalaWork { +protected: + InteropVMContext vmContext; +#ifdef KOALA_FOREIGN_NAPI + KVMContext foreignVMContext; +#endif + void *vmWork; + void *handle; + void (*execute)(void *handle); + void (*complete)(void *handle); + +public: + KoalaWork(InteropVMContext vmContext, InteropNativePointer handle, + void (*execute)(InteropNativePointer handle), + void (*complete)(InteropNativePointer handle)); + void Queue(); + void Execute(); + void Cancel(); + void Complete(); +}; +static void DoQueue(void *handle) { ((KoalaWork *)handle)->Queue(); } +static void DoCancel(void *handle) { ((KoalaWork *)handle)->Cancel(); } + +InteropAsyncWork +koalaCreateWork(InteropVMContext vmContext, InteropNativePointer handle, + void (*execute)(InteropNativePointer handle), + void (*complete)(InteropNativePointer handle)) { + return { + new KoalaWork(vmContext, handle, execute, complete), + DoQueue, + DoCancel, + }; +} + +const InteropAsyncWorker *GetAsyncWorker() { + static InteropAsyncWorker worker = {koalaCreateWork}; + return &worker; +} + +#if defined(KOALA_NAPI) +static void DoExecute(napi_env env, void *handle) { + ((KoalaWork *)handle)->Execute(); +} +static void DoComplete(napi_env env, napi_status status, void *handle) { + ((KoalaWork *)handle)->Complete(); +} +KoalaWork::KoalaWork(InteropVMContext vmContext, InteropNativePointer handle, + void (*execute)(InteropNativePointer handle), + void (*complete)(InteropNativePointer handle)) + : vmContext(vmContext), handle(handle), execute(execute), + complete(complete) { + napi_env env = (napi_env)vmContext; + napi_value resourceName = nullptr; + napi_create_string_utf8(env, "KoalaAsyncOperation", NAPI_AUTO_LENGTH, + &resourceName); + napi_create_async_work(env, nullptr, resourceName, DoExecute, DoComplete, + this, (napi_async_work *)&vmWork); + /* supress unused private fields */ + (void)vmContext; + (void)vmWork; +} +void KoalaWork::Queue() { + napi_env env = (napi_env)vmContext; + napi_queue_async_work(env, (napi_async_work)vmWork); +} +void KoalaWork::Execute() { execute(handle); } +void KoalaWork::Cancel() { + napi_env env = (napi_env)vmContext; + napi_cancel_async_work(env, (napi_async_work)vmWork); +} +void KoalaWork::Complete() { + complete(handle); + delete this; +} +#else +#ifdef KOALA_FOREIGN_NAPI +static void DoExecute(napi_env env, void *handle) { + ((KoalaWork *)handle)->Execute(); +} +static void DoComplete(napi_env env, napi_status status, void *handle) { + ((KoalaWork *)handle)->Complete(); +} +#endif +KoalaWork::KoalaWork(InteropVMContext vmContext, InteropNativePointer handle, + void (*execute)(InteropNativePointer handle), + void (*complete)(InteropNativePointer handle)) + : vmContext(vmContext), handle(handle), execute(execute), + complete(complete) { +#ifdef KOALA_FOREIGN_NAPI + if (g_foreignVMContext == nullptr) + INTEROP_FATAL("Can not launch async work while foreign VM context is not " + "available. Please ensure you have " + "called SetForeignVMContext"); + foreignVMContext = g_foreignVMContext; + napi_env env = (napi_env)foreignVMContext; + napi_value resourceName = nullptr; + napi_create_string_utf8(env, "KoalaAsyncOperation", NAPI_AUTO_LENGTH, + &resourceName); + napi_create_async_work(env, nullptr, resourceName, DoExecute, DoComplete, + this, (napi_async_work *)&vmWork); +#endif + /* supress unused private fields */ + (void)vmContext; + (void)vmWork; +} +void KoalaWork::Queue() { +#ifdef KOALA_FOREIGN_NAPI + napi_env env = (napi_env)foreignVMContext; + napi_queue_async_work(env, (napi_async_work)vmWork); +#else + Execute(); + Complete(); +#endif +} +void KoalaWork::Execute() { execute(handle); } +void KoalaWork::Cancel() { +#ifdef KOALA_FOREIGN_NAPI + napi_env env = (napi_env)foreignVMContext; + napi_cancel_async_work(env, (napi_async_work)vmWork); +#else + INTEROP_FATAL("Cancelling async work is disabled for any VM except of Node"); +#endif +} +void KoalaWork::Complete() { + complete(handle); + delete this; +} +#endif + +#if defined(KOALA_ETS_NAPI) || defined(KOALA_ANI) +KStringPtr impl_Utf8ToString(KVMContext vmContext, KNativePointer data, + KInt offset, KInt length) { + KStringPtr result((const char *)data + offset, length, false); + return result; +} +KOALA_INTEROP_CTX_3(Utf8ToString, KStringPtr, KNativePointer, KInt, KInt) +#elif defined(KOALA_NAPI) || defined(KOALA_JNI) || defined(KOALA_CJ) +// Allocate, so CTX versions. +KStringPtr impl_Utf8ToString(KVMContext vmContext, KByte *data, KInt offset, + KInt length) { + KStringPtr result((const char *)(data + offset), length, false); + return result; +} +KOALA_INTEROP_CTX_3(Utf8ToString, KStringPtr, KByte *, KInt, KInt) +#endif + +#if defined(KOALA_NAPI) || defined(KOALA_ANI) +KStringPtr impl_RawUtf8ToString(KVMContext vmContext, KNativePointer data) { + auto string = (const char *)data; + KStringPtr result(string, interop_strlen(string), false); + return result; +} +KOALA_INTEROP_CTX_1(RawUtf8ToString, KStringPtr, KNativePointer) +#endif + +#if defined(KOALA_NAPI) || defined(KOALA_JNI) || defined(KOALA_CJ) || \ + defined(KOALA_ETS_NAPI) || defined(KOALA_ANI) || defined(KOALA_KOTLIN) +KStringPtr impl_StdStringToString(KVMContext vmContext, + KNativePointer stringPtr) { + std::string *string = reinterpret_cast(stringPtr); + KStringPtr result(string->c_str(), string->size(), false); + return result; +} +KOALA_INTEROP_CTX_1(StdStringToString, KStringPtr, KNativePointer) + +KInteropReturnBuffer impl_RawReturnData(KVMContext vmContext, KInt v1, + KInt v2) { + void *data = new int8_t[v1]; + interop_memset(data, v1, v2, v1); + KInteropReturnBuffer buffer = { + v1, data, [](KNativePointer ptr, KInt) { delete[] (int8_t *)ptr; }}; + return buffer; +} +KOALA_INTEROP_CTX_2(RawReturnData, KInteropReturnBuffer, KInt, KInt) + +KInteropNumber impl_IncrementNumber(KInteropNumber number) { + if (number.tag == 102) + number.i32++; + else + number.f32 += 1.f; + return number; +} +KOALA_INTEROP_1(IncrementNumber, KInteropNumber, KInteropNumber) + +void impl_ReportMemLeaks() { +#ifndef KOALA_INTEROP_MEM_ANALYZER + const auto count = mallocCounter.load(std::memory_order_acquire); + if (count > 0) { + fprintf(stderr, "Memory leaks detected: %d blocks\n", count); + } else { + fprintf(stderr, "No memory leaks\n"); + } +#endif +} +KOALA_INTEROP_V0(ReportMemLeaks) + +#endif diff --git a/ets1.2/interop/src/cpp/common-interop.h b/ets1.2/interop/src/cpp/common-interop.h new file mode 100644 index 0000000000000000000000000000000000000000..3a5fa5cfcf98e48fb9406d6beceefdb8ce91a258 --- /dev/null +++ b/ets1.2/interop/src/cpp/common-interop.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#ifndef COMMON_INTEROP_BASE_H +#define COMMON_INTEROP_BASE_H + +#include + +#include "koala-types.h" + +#define KOALA_INTEROP_PROFILER 0 +#define KOALA_INTEROP_TRACER 0 + +#if KOALA_INTEROP_PROFILER +#include "profiler.h" +#define KOALA_INTEROP_LOGGER(name) InteropMethodCall logger(#name); +#endif + +#if KOALA_INTEROP_TRACER +#include "tracer.h" +#define KOALA_INTEROP_LOGGER(name) InteropMethodCall logger(#name); +#endif + +#ifdef KOALA_INTEROP_LOGGER +#define KOALA_MAYBE_LOG(name) KOALA_INTEROP_LOGGER(name); +#else +#define KOALA_MAYBE_LOG(name) +#endif + +#ifdef KOALA_WINDOWS +#define DLL_EXPORT __declspec(dllexport) +#else +#define DLL_EXPORT __attribute__((visibility("default"))) +#endif + +typedef void (*Callback_Caller_t)(KInt callbackKind, KSerializerBuffer argsData, KInt argsLength); +typedef void (*Callback_Caller_Sync_t)( + KVMContext vmContext, KInt callbackKind, KSerializerBuffer argsData, KInt argsLength); +extern "C" DLL_EXPORT void setCallbackCaller(int apiKind, Callback_Caller_t caller); +extern "C" DLL_EXPORT void setCallbackCallerSync(int apiKind, Callback_Caller_Sync_t callerSync); + +extern "C" DLL_EXPORT KVMDeferred* CreateDeferred(KVMContext context, KVMObjectHandle* promise); +extern "C" DLL_EXPORT const InteropAsyncWorker* GetAsyncWorker(); + +#if KOALA_USE_NODE_VM || KOALA_USE_HZ_VM +#include "convertors-napi.h" +#elif KOALA_USE_JSC_VM +#include "convertors-jsc.h" +#elif KOALA_ETS_NAPI +#include "convertors-ets.h" +#elif KOALA_USE_JAVA_VM +#include "convertors-jni.h" +#elif KOALA_WASM +#include "convertors-wasm.h" +#elif KOALA_CJ +#include "convertors-cj.h" +#elif KOALA_ANI +#include "convertors-ani.h" +#elif KOALA_KOTLIN +#include "convertors-kotlin.h" +#else +#error "One of above branches must be taken" +#endif + +#endif // COMMON_INTEROP_BASE_H diff --git a/ets1.2/interop/src/cpp/crashdump.h b/ets1.2/interop/src/cpp/crashdump.h new file mode 100644 index 0000000000000000000000000000000000000000..4e7bf71bc7d6d1b45b9f0fa1dd47ece165935e8a --- /dev/null +++ b/ets1.2/interop/src/cpp/crashdump.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _INTEROP_CRASHDUMP_H +#define _INTEROP_CRASHDUMP_H + +#ifdef KOALA_LINUX +#include +#include + +sighandler_t oldCrashHandler = nullptr; + +static void onCrashHandler(int signo) +{ + void* stack[20]; + size_t size = backtrace(stack, 20); + backtrace_symbols_fd(stack, size, STDERR_FILENO); + if (oldCrashHandler) + oldCrashHandler(signo); +} + +static void installCrashHandlers() +{ + static bool installed = false; + if (!installed) { + oldCrashHandler = signal(SIGSEGV, onCrashHandler); + installed = true; + } +} +#else +static void installCrashHandlers() {} +#endif + +#endif // _INTEROP_CRASHDUMP_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/dynamic-loader.h b/ets1.2/interop/src/cpp/dynamic-loader.h new file mode 100644 index 0000000000000000000000000000000000000000..d4f8b2ccc1607b230374a5b95fcc2277cb49b314 --- /dev/null +++ b/ets1.2/interop/src/cpp/dynamic-loader.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _DYNAMIC_LOADER_H +#define _DYNAMIC_LOADER_H + +#include + +#include "interop-utils.h" + +#ifdef KOALA_WINDOWS +#include +// Here we need to find module where GetArkUINodeAPI() +// function is implemented. +inline void* loadLibrary(const std::string& libPath) +{ + return LoadLibraryA(libPath.c_str()); +} + +inline const char* libraryError() +{ + static char error[256]; + interop_snprintf(error, sizeof error, "error %lu", GetLastError()); + return error; +} + +inline void* findSymbol(void* library, const char* name) +{ + return (void*)GetProcAddress(reinterpret_cast(library), name); +} + +inline std::string libName(const char* lib) +{ + return std::string(lib) + ".dll"; +} + +#elif defined(KOALA_LINUX) || defined(KOALA_MACOS) || defined(KOALA_OHOS) +#include + +inline void* loadLibrary(const std::string& libPath) +{ + void* handle = dlopen(libPath.c_str(), RTLD_LOCAL | RTLD_NOW); + if (!handle) { + return nullptr; + } + return handle; +} + +inline const char* libraryError() +{ + return dlerror(); +} + +inline std::string symbolName(const char* name) +{ + return name; +} + +inline void* findSymbol(void* library, const char* name) +{ + return dlsym(library, symbolName(name).c_str()); +} + +inline std::string libName(const char* lib) +{ + std::string result; + std::string suffix = +#ifdef KOALA_MACOS + ".dylib" +#else + ".so" +#endif + ; + result = "lib" + std::string(lib) + suffix; + return result; +} + +#else + +#include + +inline void* loadLibrary(const std::string& libPath) +{ + fprintf(stderr, "No loadLibrary() on this platform\n"); + return nullptr; +} + +inline const char* libraryError() +{ + fprintf(stderr, "No libraryError() on this platform\n"); + return nullptr; +} + +inline std::string symbolName(const char* name) +{ + fprintf(stderr, "No symbolName() on this platform\n"); + return ""; +} + +inline void* findSymbol(void* library, const char* name) +{ + fprintf(stderr, "No findSymbol() on this platform\n"); + return nullptr; +} + +inline std::string libName(const char* lib) +{ + fprintf(stderr, "No libName() on this platform\n"); + return ""; +} + +#endif + +#endif // _DYNAMIC_LOADER_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/ets/convertors-ets.cc b/ets1.2/interop/src/cpp/ets/convertors-ets.cc new file mode 100644 index 0000000000000000000000000000000000000000..dc595a00fc66c216eea7b5d2ffcd25a85325569a --- /dev/null +++ b/ets1.2/interop/src/cpp/ets/convertors-ets.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#include "convertors-ets.h" + +#include + +#include "interop-logging.h" +#include "interop-types.h" +#include "signatures.h" + +static const char* callCallbackFromNative = "callCallbackFromNative"; +static const char* callCallbackFromNativeSig = "IJI:I"; + +static const char* FAST_NATIVE_PREFIX = "#F$"; + +const bool registerByOne = true; + +static bool registerNatives( + ets_env* env, const ets_class clazz, const std::vector> impls) +{ + std::vector methods; + methods.reserve(impls.size()); + bool result = true; + for (const auto& [name, type, func, flag] : impls) { + EtsNativeMethod method; + method.name = name.c_str(); + method.func = func; + method.signature = (flag & ETS_SLOW_NATIVE_FLAG) == 0 ? FAST_NATIVE_PREFIX : nullptr; + if (registerByOne) { + result &= env->RegisterNatives(clazz, &method, 1) >= 0; + if (env->ErrorCheck()) { + env->ErrorClear(); + } + } else { + methods.push_back(method); + } + } + if (!registerByOne) { + result = env->RegisterNatives(clazz, methods.data(), static_cast(methods.size())) >= 0; + } + return registerByOne ? true : result; +} + +bool registerAllModules(ets_env* env) +{ + auto moduleNames = EtsExports::getInstance()->getModules(); + + for (auto it = moduleNames.begin(); it != moduleNames.end(); ++it) { + std::string className = EtsExports::getInstance()->getClasspath(*it); + ets_class nativeModule = env->FindClass(className.c_str()); + if (nativeModule == nullptr) { + LOGE("Cannot find managed class %s", className.c_str()); + continue; + } + if (!registerNatives(env, nativeModule, EtsExports::getInstance()->getMethods(*it))) { + return false; + } + } + + return true; +} + +extern "C" ETS_EXPORT ets_int ETS_CALL EtsNapiOnLoad(ets_env* env) +{ + LOGE("Use ETSNAPI") + if (!registerAllModules(env)) { + LOGE("Failed to register ets modules"); + return ETS_ERR; + } + auto interopClasspath = EtsExports::getInstance()->getClasspath("InteropNativeModule"); + auto interopClass = env->FindClass(interopClasspath.c_str()); + if (interopClass == nullptr) { + LOGE("Can not find InteropNativeModule classpath to set callback dispatcher"); + return ETS_ERR; + } + if (!setKoalaEtsNapiCallbackDispatcher(env, interopClass, callCallbackFromNative, callCallbackFromNativeSig)) { + LOGE("Failed to set koala ets callback dispatcher"); + return ETS_ERR; + } + return ETS_NAPI_VERSION_1_0; +} + +EtsExports* EtsExports::getInstance() +{ + static EtsExports* instance = nullptr; + if (instance == nullptr) { + instance = new EtsExports(); + } + return instance; +} + +std::vector EtsExports::getModules() +{ + std::vector result; + for (auto it = implementations.begin(); it != implementations.end(); ++it) { + result.push_back(it->first); + } + return result; +} + +const std::vector>& EtsExports::getMethods(const std::string& module) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + LOGE("Module %s is not registered", module.c_str()); + } + return it->second; +} + +void EtsExports::addMethod(const char* module, const char* name, const char* type, void* impl, int flags) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + it = implementations + .insert(std::make_pair(module, std::vector>())) + .first; + } + it->second.push_back(std::make_tuple(name, convertType(name, type), impl, flags)); +} + +void EtsExports::setClasspath(const char* module, const char* classpath) +{ + auto it = classpaths.find(module); + if (it == classpaths.end()) { + classpaths.insert(std::make_pair(module, classpath)); + } else { + LOGE("Classpath for module %s was redefined", module); + } +} + +static std::map g_defaultClasspaths = { + { "InteropNativeModule", "@koalaui/interop/InteropNativeModule/InteropNativeModule" }, + // Improve: leave just InteropNativeModule, define others via KOALA_ETS_INTEROP_MODULE_CLASSPATH + { "TestNativeModule", "arkui/generated/arkts/TestNativeModule/TestNativeModule" }, + { "ArkUINativeModule", "arkui/generated/arkts/ArkUINativeModule/ArkUINativeModule" }, + { "ArkUIGeneratedNativeModule", "arkui/generated/arkts/ArkUIGeneratedNativeModule/ArkUIGeneratedNativeModule" }, +}; +const std::string& EtsExports::getClasspath(const std::string& module) +{ + auto it = classpaths.find(module); + if (it != classpaths.end()) { + return it->second; + } + auto defaultClasspath = g_defaultClasspaths.find(module); + if (defaultClasspath != g_defaultClasspaths.end()) { + return defaultClasspath->second; + } + INTEROP_FATAL("Classpath for module %s was not registered", module.c_str()); +} diff --git a/ets1.2/interop/src/cpp/ets/convertors-ets.h b/ets1.2/interop/src/cpp/ets/convertors-ets.h new file mode 100644 index 0000000000000000000000000000000000000000..8a28df7b105cdbc7ca2ab7d4f541650dabc03133 --- /dev/null +++ b/ets1.2/interop/src/cpp/ets/convertors-ets.h @@ -0,0 +1,1850 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#ifndef CONVERTORS_ETS_H +#define CONVERTORS_ETS_H + +#ifdef KOALA_ETS_NAPI + +#include +#include +#include +#include +#include +#include + +#include "etsapi.h" +#include "interop-utils.h" +#include "koala-types.h" + +template +struct InteropTypeConverter { + using InteropType = T; + static T convertFrom(EtsEnv* env, InteropType value) = delete; + static InteropType convertTo(EtsEnv* env, T value) = delete; + static void release(EtsEnv* env, InteropType value, T converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_boolean; + static KBoolean convertFrom(EtsEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(EtsEnv* env, KBoolean value) + { + return value; + } + static void release(EtsEnv* env, InteropType value, KBoolean converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_int; + static KInt convertFrom(EtsEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(EtsEnv* env, KInt value) + { + return value; + } + static void release(EtsEnv* env, InteropType value, KInt converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_int; + static KUInt convertFrom(EtsEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(EtsEnv* env, KUInt value) + { + return value; + } + static void release(EtsEnv* env, InteropType value, KUInt converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_byte; + static KByte convertFrom(EtsEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(EtsEnv* env, KByte value) + { + return value; + } + static void release(EtsEnv* env, InteropType value, KByte converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_float; + static KFloat convertFrom(EtsEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(EtsEnv* env, InteropFloat32 value) + { + return value; + } + static void release(EtsEnv* env, InteropType value, KFloat converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_double; + static KDouble convertFrom(EtsEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(EtsEnv* env, InteropFloat64 value) + { + return value; + } + static void release(EtsEnv* env, InteropType value, KDouble converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_long; + static KSerializerBuffer convertFrom(EtsEnv* env, InteropType value) + { + return reinterpret_cast(static_cast(value)); + } + static InteropType convertTo(EtsEnv* env, KSerializerBuffer value) = delete; + static void release(EtsEnv* env, InteropType value, KSerializerBuffer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_object; + static KVMObjectHandle convertFrom(EtsEnv* env, InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(EtsEnv* env, KVMObjectHandle value) + { + return reinterpret_cast(value); + } + static void release(EtsEnv* env, InteropType value, KVMObjectHandle converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_byteArray; + static KInteropBuffer convertFrom(EtsEnv* env, InteropType value) + { + if (!value) + return KInteropBuffer(); + KInteropBuffer result; + result.data = (KByte*)env->PinByteArray(value); + result.length = env->GetArrayLength(value); + return result; + } + static InteropType convertTo(EtsEnv* env, KInteropBuffer value) + { + int bufferLength = value.length; + ets_byteArray array = env->NewByteArray(bufferLength); + KByte* data = (KByte*)env->PinByteArray(array); + interop_memcpy(data, bufferLength, (KByte*)value.data, bufferLength); + env->UnpinByteArray(array); + value.dispose(value.resourceId); + return array; + } + static void release(EtsEnv* env, InteropType value, KInteropBuffer converted) + { + env->UnpinByteArray(value); + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_string; + static KStringPtr convertFrom(EtsEnv* env, InteropType value) + { + if (value == nullptr) + return KStringPtr(); + KStringPtr result; + // Notice that we use UTF length for buffer size, but counter is expressed in number of Unicode chars. + result.resize(env->GetStringUTFLength(value)); + env->GetStringUTFRegion(value, 0, env->GetStringLength(value), result.data()); + return result; + } + static InteropType convertTo(EtsEnv* env, const KStringPtr& value) + { + return env->NewStringUTF(value.c_str()); + } + static void release(EtsEnv* env, InteropType value, const KStringPtr& converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_long; + static KNativePointer convertFrom(EtsEnv* env, InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(EtsEnv* env, KNativePointer value) + { + return reinterpret_cast(value); + } + static void release(EtsEnv* env, InteropType value, KNativePointer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_long; + static KLong convertFrom(EtsEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(EtsEnv* env, KLong value) + { + return value; + } + static void release(EtsEnv* env, InteropType value, KLong converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_long; + static KULong convertFrom(EtsEnv* env, InteropType value) + { + return static_cast(value); + } + static InteropType convertTo(EtsEnv* env, KULong value) + { + return static_cast(value); + } + static void release(EtsEnv* env, InteropType value, KULong converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_intArray; + static KInt* convertFrom(EtsEnv* env, InteropType value) + { + if (!value) + return nullptr; + return env->PinIntArray(value); + } + static InteropType convertTo(EtsEnv* env, KInt* value) = delete; + static void release(EtsEnv* env, InteropType value, KInt* converted) + { + if (value) + env->UnpinIntArray(value); + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_floatArray; + static KFloat* convertFrom(EtsEnv* env, InteropType value) + { + if (!value) + return nullptr; + return env->PinFloatArray(value); + } + static InteropType convertTo(EtsEnv* env, KFloat* value) = delete; + static void release(EtsEnv* env, InteropType value, KFloat* converted) + { + if (value) + env->UnpinFloatArray(value); + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_byteArray; + static KInteropReturnBuffer convertFrom(EtsEnv* env, InteropType value) = delete; + static InteropType convertTo(EtsEnv* env, KInteropReturnBuffer value) + { + int bufferLength = value.length; + ets_byteArray array = env->NewByteArray(bufferLength); + KByte* data = (KByte*)env->PinByteArray(array); + interop_memcpy(data, bufferLength, (KByte*)value.data, bufferLength); + env->UnpinByteArray(array); + value.dispose(value.data, bufferLength); + return array; + }; + static void release(EtsEnv* env, InteropType value, KInteropReturnBuffer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_byteArray; + static KByte* convertFrom(EtsEnv* env, InteropType value) + { + if (!value) + return nullptr; + return (KByte*)env->PinByteArray(value); + } + static InteropType convertTo(EtsEnv* env, KByte* value) = delete; + static void release(EtsEnv* env, InteropType value, KByte* converted) + { + if (value) + env->UnpinByteArray((ets_byteArray)value); + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = ets_double; + static KInteropNumber convertFrom(EtsEnv* env, InteropType value) + { + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(EtsEnv* env, KInteropNumber value) + { + return value.asDouble(); + } + static void release(EtsEnv* env, InteropType value, KInteropNumber converted) {} +}; + +template +inline typename InteropTypeConverter::InteropType makeResult(EtsEnv* env, Type value) +{ + return InteropTypeConverter::convertTo(env, value); +} + +template +inline Type getArgument(EtsEnv* env, typename InteropTypeConverter::InteropType arg) +{ + return InteropTypeConverter::convertFrom(env, arg); +} + +template +inline void releaseArgument(EtsEnv* env, typename InteropTypeConverter::InteropType arg, Type& data) +{ + InteropTypeConverter::release(env, arg, data); +} + +template +struct DirectInteropTypeConverter { + using InteropType = T; + static T convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(T value) + { + return value; + } +}; + +template<> +struct DirectInteropTypeConverter { + using InteropType = ets_long; + static KNativePointer convertFrom(InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(KNativePointer value) + { + return reinterpret_cast(value); + } +}; + +template<> +struct DirectInteropTypeConverter { + using InteropType = ets_long; + static KSerializerBuffer convertFrom(InteropType value) + { + return reinterpret_cast(static_cast(value)); + } + static InteropType convertTo(KSerializerBuffer value) = delete; +}; + +template<> +struct DirectInteropTypeConverter { + using InteropType = ets_double; + static KInteropNumber convertFrom(InteropType value) + { + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(KInteropNumber value) + { + return value.asDouble(); + } +}; + +#define ETS_SLOW_NATIVE_FLAG 1 + +class EtsExports { + std::unordered_map>> implementations; + std::unordered_map classpaths; + +public: + static EtsExports* getInstance(); + + std::vector getModules(); + void addMethod(const char* module, const char* name, const char* type, void* impl, int flags); + const std::vector>& getMethods(const std::string& module); + + void setClasspath(const char* module, const char* classpath); + const std::string& getClasspath(const std::string& module); +}; + +#define KOALA_QUOTE0(x) #x +#define KOALA_QUOTE(x) KOALA_QUOTE0(x) + +#ifdef _MSC_VER +#define MAKE_ETS_EXPORT(module, name, type, flag) \ + static void __init_##name() \ + { \ + EtsExports::getInstance()->addMethod( \ + KOALA_QUOTE(module), "_" #name, type, reinterpret_cast(Ark_##name), flag); \ + } \ + namespace { \ + struct __Init_##name { \ + __Init_##name() \ + { \ + __init_##name(); \ + } \ + } __Init_##name##_v; \ + } +#define KOALA_ETS_INTEROP_MODULE_CLASSPATH(module, classpath) \ + static void __init_classpath_##module() \ + { \ + EtsExports::getInstance()->setClasspath(KOALA_QUOTE(module), classpath); \ + } \ + namespace { \ + struct __Init_classpath_##module { \ + __Init_classpath_##module() \ + { \ + __init_classpath_##module(); \ + } \ + } __Init_classpath_##module##_v; \ + } +#else +#define MAKE_ETS_EXPORT(module, name, type, flag) \ + __attribute__((constructor)) static void __init_ets_##name() \ + { \ + EtsExports::getInstance()->addMethod( \ + KOALA_QUOTE(module), "_" #name, type, reinterpret_cast(Ark_##name), flag); \ + } +#define KOALA_ETS_INTEROP_MODULE_CLASSPATH(module, classpath) \ + __attribute__((constructor)) static void __init_ets_classpath_##module() \ + { \ + EtsExports::getInstance()->setClasspath(KOALA_QUOTE(module), classpath); \ + } +#endif + +#define KOALA_INTEROP_0(name, Ret) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz) \ + { \ + KOALA_MAYBE_LOG(name) \ + return makeResult(env, impl_##name()); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret, 0) + +#define KOALA_INTEROP_1(name, Ret, P0) \ + InteropTypeConverter::InteropType Ark_##name( \ + EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + auto rv = makeResult(env, impl_##name(p0)); \ + releaseArgument(env, _p0, p0); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0, 0) + +#define KOALA_INTEROP_2(name, Ret, P0, P1) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + auto rv = makeResult(env, impl_##name(p0, p1)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1, 0) + +#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2, 0) + +#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3, 0) + +#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, 0) + +#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, 0) + +#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, 0) + +#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, 0) + +#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + return rv; \ + } \ + MAKE_ETS_EXPORT( \ + KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, 0) + +#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, 0) + +#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, 0) + +#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10, InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11, 0) + +#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10, InteropTypeConverter::InteropType _p11, \ + InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12, \ + 0) + +#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4, InteropTypeConverter::InteropType _p5, \ + InteropTypeConverter::InteropType _p6, InteropTypeConverter::InteropType _p7, \ + InteropTypeConverter::InteropType _p8, InteropTypeConverter::InteropType _p9, \ + InteropTypeConverter::InteropType _p10, InteropTypeConverter::InteropType _p11, \ + InteropTypeConverter::InteropType _p12, InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + auto rv = makeResult(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12 "|" #P13, \ + 0) + +#define KOALA_INTEROP_V0(name) \ + void Ark_##name(EtsEnv* env) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void", 0) + +#define KOALA_INTEROP_V1(name, P0) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + impl_##name(p0); \ + releaseArgument(env, _p0, p0); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0, 0) + +#define KOALA_INTEROP_V2(name, P0, P1) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + impl_##name(p0, p1); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1, 0) + +#define KOALA_INTEROP_V3(name, P0, P1, P2) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + impl_##name(p0, p1, p2); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2, 0) + +#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + impl_##name(p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3, 0) + +#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + impl_##name(p0, p1, p2, p3, p4); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, 0) + +#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + impl_##name(p0, p1, p2, p3, p4, p5); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, 0) + +#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, 0) + +#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, 0) + +#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + } \ + MAKE_ETS_EXPORT( \ + KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, 0) + +#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, 0) + +#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, 0) + +#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11, 0) + +#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12, \ + 0) + +#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12 \ + "|" #P13, \ + 0) + +#define KOALA_INTEROP_V15(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13, InteropTypeConverter::InteropType _p14) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + P14 p14 = getArgument(env, _p14); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + releaseArgument(env, _p14, p14); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12 \ + "|" #P13 "|" #P14, \ + 0) + +#define KOALA_INTEROP_CTX_0(name, Ret) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz) \ + { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx)); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_1(name, Ret, P0) \ + InteropTypeConverter::InteropType Ark_##name( \ + EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0)); \ + releaseArgument(env, _p0, p0); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1, p2)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1, p2, p3)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_5(name, Ret, P0, P1, P2, P3, P4) \ + InteropTypeConverter::InteropType Ark_##name(EtsEnv* env, ets_class clazz, \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1, \ + InteropTypeConverter::InteropType _p2, InteropTypeConverter::InteropType _p3, \ + InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = makeResult(env, impl_##name(ctx, p0, p1, p2, p3, p4)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + return rv; \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V0(name) \ + void Ark_##name(EtsEnv* env, ets_class clazz) \ + { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void", ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V1(name, P0) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0); \ + releaseArgument(env, _p0, p0); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V2(name, P0, P1) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_CTX_V5(name, P0, P1, P2, P3, P4) \ + void Ark_##name(EtsEnv* env, ets_class clazz, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3, p4); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, ETS_SLOW_NATIVE_FLAG) + +#define KOALA_INTEROP_DIRECT_0(name, Ret) \ + inline InteropTypeConverter::InteropType Ark_##name() \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name()); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret, 0) +#define KOALA_INTEROP_DIRECT_1(name, Ret, P0) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo( \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0, 0) +#define KOALA_INTEROP_DIRECT_2(name, Ret, P0, P1) \ + inline InteropTypeConverter::InteropType Ark_##name( \ + InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name( \ + DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1, 0) +#define KOALA_INTEROP_DIRECT_3(name, Ret, P0, P1, P2) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2, 0) +#define KOALA_INTEROP_DIRECT_4(name, Ret, P0, P1, P2, P3) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3, 0) +#define KOALA_INTEROP_DIRECT_5(name, Ret, P0, P1, P2, P3, P4) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, 0) +#define KOALA_INTEROP_DIRECT_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, 0) +#define KOALA_INTEROP_DIRECT_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, 0) +#define KOALA_INTEROP_DIRECT_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, 0) +#define KOALA_INTEROP_DIRECT_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7, InteropTypeConverter::InteropType p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7), DirectInteropTypeConverter::convertFrom(p8))); \ + } \ + MAKE_ETS_EXPORT( \ + KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, 0) +#define KOALA_INTEROP_DIRECT_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7, InteropTypeConverter::InteropType p8, \ + InteropTypeConverter::InteropType p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7), DirectInteropTypeConverter::convertFrom(p8), \ + DirectInteropTypeConverter::convertFrom(p9))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, 0) +#define KOALA_INTEROP_DIRECT_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + inline InteropTypeConverter::InteropType Ark_##name(InteropTypeConverter::InteropType p0, \ + InteropTypeConverter::InteropType p1, InteropTypeConverter::InteropType p2, \ + InteropTypeConverter::InteropType p3, InteropTypeConverter::InteropType p4, \ + InteropTypeConverter::InteropType p5, InteropTypeConverter::InteropType p6, \ + InteropTypeConverter::InteropType p7, InteropTypeConverter::InteropType p8, \ + InteropTypeConverter::InteropType p9, InteropTypeConverter::InteropType p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + return DirectInteropTypeConverter::convertTo(impl_##name(DirectInteropTypeConverter::convertFrom(p0), \ + DirectInteropTypeConverter::convertFrom(p1), DirectInteropTypeConverter::convertFrom(p2), \ + DirectInteropTypeConverter::convertFrom(p3), DirectInteropTypeConverter::convertFrom(p4), \ + DirectInteropTypeConverter::convertFrom(p5), DirectInteropTypeConverter::convertFrom(p6), \ + DirectInteropTypeConverter::convertFrom(p7), DirectInteropTypeConverter::convertFrom(p8), \ + DirectInteropTypeConverter::convertFrom(p9), DirectInteropTypeConverter::convertFrom(p10))); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, 0) +#define KOALA_INTEROP_DIRECT_V0(name) \ + inline void Ark_##name() \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, "void", 0) +#define KOALA_INTEROP_DIRECT_V1(name, P0) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0, \ + 0) +#define KOALA_INTEROP_DIRECT_V2(name, P0, P1) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1, \ + 0) +#define KOALA_INTEROP_DIRECT_V3(name, P0, P1, P2) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2, \ + 0) +#define KOALA_INTEROP_DIRECT_V4(name, P0, P1, P2, P3) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3, \ + 0) +#define KOALA_INTEROP_DIRECT_V5(name, P0, P1, P2, P3, P4) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, \ + 0) +#define KOALA_INTEROP_DIRECT_V6(name, P0, P1, P2, P3, P4, P5) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, \ + 0) +#define KOALA_INTEROP_DIRECT_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, \ + 0) +#define KOALA_INTEROP_DIRECT_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, \ + 0) +#define KOALA_INTEROP_DIRECT_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7, \ + InteropTypeConverter::InteropType p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7), \ + DirectInteropTypeConverter::convertFrom(p8)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, \ + 0) +#define KOALA_INTEROP_DIRECT_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7, \ + InteropTypeConverter::InteropType p8, InteropTypeConverter::InteropType p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7), \ + DirectInteropTypeConverter::convertFrom(p8), DirectInteropTypeConverter::convertFrom(p9)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, \ + 0) +#define KOALA_INTEROP_DIRECT_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + inline void Ark_##name(InteropTypeConverter::InteropType p0, InteropTypeConverter::InteropType p1, \ + InteropTypeConverter::InteropType p2, InteropTypeConverter::InteropType p3, \ + InteropTypeConverter::InteropType p4, InteropTypeConverter::InteropType p5, \ + InteropTypeConverter::InteropType p6, InteropTypeConverter::InteropType p7, \ + InteropTypeConverter::InteropType p8, InteropTypeConverter::InteropType p9, \ + InteropTypeConverter::InteropType p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(DirectInteropTypeConverter::convertFrom(p0), DirectInteropTypeConverter::convertFrom(p1), \ + DirectInteropTypeConverter::convertFrom(p2), DirectInteropTypeConverter::convertFrom(p3), \ + DirectInteropTypeConverter::convertFrom(p4), DirectInteropTypeConverter::convertFrom(p5), \ + DirectInteropTypeConverter::convertFrom(p6), DirectInteropTypeConverter::convertFrom(p7), \ + DirectInteropTypeConverter::convertFrom(p8), DirectInteropTypeConverter::convertFrom(p9), \ + DirectInteropTypeConverter::convertFrom(p10)); \ + } \ + MAKE_ETS_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void" \ + "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, \ + 0) + +bool setKoalaEtsNapiCallbackDispatcher( + EtsEnv* etsEnv, ets_class clazz, const char* dispatcherMethodName, const char* dispactherMethodSig); +void getKoalaEtsNapiCallbackDispatcher(ets_class* clazz, ets_method* method); + +#define KOALA_INTEROP_CALL_VOID(venv, id, length, args) \ + { \ + ets_class clazz = nullptr; \ + ets_method method = nullptr; \ + getKoalaEtsNapiCallbackDispatcher(&clazz, &method); \ + EtsEnv* etsEnv = reinterpret_cast(vmContext); \ + etsEnv->PushLocalFrame(1); \ + etsEnv->CallStaticIntMethod(clazz, method, id, args, length); \ + etsEnv->PopLocalFrame(nullptr); \ + } + +#define KOALA_INTEROP_CALL_INT(venv, id, length, args) \ + { \ + ets_class clazz = nullptr; \ + ets_method method = nullptr; \ + getKoalaEtsNapiCallbackDispatcher(&clazz, &method); \ + EtsEnv* etsEnv = reinterpret_cast(venv); \ + etsEnv->PushLocalFrame(1); \ + int32_t rv = etsEnv->CallStaticIntMethod(clazz, method, id, args, length); \ + etsEnv->PopLocalFrame(nullptr); \ + return rv; \ + } + +#define KOALA_INTEROP_CALL_VOID_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_VOID(venv, id, (argc) * sizeof(int32_t), args) +#define KOALA_INTEROP_CALL_INT_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_INT(venv, id, (argc) * sizeof(int32_t), args) + +#define KOALA_INTEROP_THROW(vmContext, object, ...) \ + do { \ + EtsEnv* env = reinterpret_cast(vmContext); \ + env->ThrowError(object); \ + return __VA_ARGS__; \ + } while (0) + +#define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \ + do { \ + EtsEnv* env = reinterpret_cast(vmContext); \ + const static ets_class errorClass = env->FindClass("std/core/Error"); \ + env->ThrowErrorNew(errorClass, message); \ + } while (0) + +#endif // KOALA_ETS_NAPI + +#endif // CONVERTORS_ETS_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/ets/etsapi.h b/ets1.2/interop/src/cpp/ets/etsapi.h new file mode 100644 index 0000000000000000000000000000000000000000..144d600906379d829d61858bdfc32d0f2765beed --- /dev/null +++ b/ets1.2/interop/src/cpp/ets/etsapi.h @@ -0,0 +1,1545 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef PANDA_RUNTIME_INTEROP_ETS_NAPI_H +#define PANDA_RUNTIME_INTEROP_ETS_NAPI_H + +// NOLINTBEGIN(modernize-use-using, readability-identifier-naming, cppcoreguidelines-pro-type-vararg) + +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif + +// NOLINTBEGIN(cppcoreguidelines-macro-usage) + +// Version Constants +#define ETS_NAPI_VERSION_1_0 0x00010000 + +// General return value constants +#define ETS_OK 0 // success +#define ETS_ERR (-1) // unknown error +#define ETS_ERR_VER (-2) // ETS version error +#define ETS_ERR_NOMEM (-3) // not enough memory +#define ETS_ERR_EXIST (-4) // VM already created +#define ETS_ERR_INVAL (-5) // invalid arguments + +// Boolean Constants +#define ETS_FALSE 0 +#define ETS_TRUE 1 + +// Mode Constants +#define ETS_COMMIT 1 +#define ETS_ABORT 2 + +// NOLINTEND(cppcoreguidelines-macro-usage) + +// Primitive Types +typedef uint8_t ets_boolean; +typedef int8_t ets_byte; +typedef uint16_t ets_char; +typedef int16_t ets_short; +typedef int32_t ets_int; +typedef int64_t ets_long; +typedef float ets_float; +typedef double ets_double; +typedef ets_int ets_size; + +// Reference Types +#ifdef __cplusplus +class __ets_object {}; +class __ets_class : public __ets_object {}; +class __ets_string : public __ets_object {}; +class __ets_array : public __ets_object {}; +class __ets_objectArray : public __ets_array {}; +class __ets_booleanArray : public __ets_array {}; +class __ets_byteArray : public __ets_array {}; +class __ets_charArray : public __ets_array {}; +class __ets_shortArray : public __ets_array {}; +class __ets_intArray : public __ets_array {}; +class __ets_longArray : public __ets_array {}; +class __ets_floatArray : public __ets_array {}; +class __ets_doubleArray : public __ets_array {}; +class __ets_error : public __ets_object {}; + +typedef __ets_object* ets_object; +typedef __ets_class* ets_class; +typedef __ets_string* ets_string; +typedef __ets_array* ets_array; +typedef __ets_objectArray* ets_objectArray; +typedef __ets_booleanArray* ets_booleanArray; +typedef __ets_byteArray* ets_byteArray; +typedef __ets_charArray* ets_charArray; +typedef __ets_shortArray* ets_shortArray; +typedef __ets_intArray* ets_intArray; +typedef __ets_longArray* ets_longArray; +typedef __ets_floatArray* ets_floatArray; +typedef __ets_doubleArray* ets_doubleArray; +typedef __ets_error* ets_error; +typedef __ets_object* ets_weak; + +#else // __cplusplus + +struct __ets_object; +typedef struct __ets_object* ets_object; +typedef ets_object ets_class; +typedef ets_object ets_string; +typedef ets_object ets_error; +typedef ets_object ets_weak; +typedef ets_object ets_array; +typedef ets_array ets_objectArray; +typedef ets_array ets_booleanArray; +typedef ets_array ets_byteArray; +typedef ets_array ets_charArray; +typedef ets_array ets_shortArray; +typedef ets_array ets_intArray; +typedef ets_array ets_longArray; +typedef ets_array ets_floatArray; +typedef ets_array ets_doubleArray; +#endif // __cplusplus + +struct __ets_deferred; +typedef struct __ets_deferred* ets_deferred; + +// Field and Method IDs +struct __ets_method; +struct __ets_field; +typedef struct __ets_method* ets_method; +typedef struct __ets_field* ets_field; + +// The Value Type +typedef union ets_value { + ets_boolean z; + ets_byte b; + ets_char c; + ets_short s; + ets_int i; + ets_long j; + ets_float f; + ets_double d; + ets_object l; +} ets_value; + +// Describe native method by name, signature and function pointer +typedef struct { + const char* name; + const char* signature; + void* func; +} EtsNativeMethod; + +// The object reference types +typedef enum { + ETS_INVALID_REF_TYPE = 0, + ETS_LOCAL_REF_TYPE = 1, + ETS_GLOBAL_REF_TYPE = 2, + ETS_WEAK_GLOBAL_REF_TYPE = 3 +} ets_objectRefType; + +#ifdef __cplusplus +typedef struct __EtsVM EtsVM; +typedef struct __EtsEnv ets_env; +#else +typedef const struct ETS_InvokeInterface* EtsVM; +typedef const struct ETS_NativeInterface* ets_env; +#endif + +// Deprecated types: +typedef ets_env EtsEnv; + +typedef enum { + ETS_OKAY, + ETS_INVALID_ARG, + ETS_GENERIC_FAILURE, + ETS_PENDING_EXCEPTION, + ETS_INVALID_VERSION, // NOTE(v.cherkashin): This status code doesn't match to napi interface. + // Should we probably delete this status code? +} ets_status; + +// clang-format off +// Interface Function Table +struct ETS_NativeInterface { + // NOTE(a.urakov): solve the "Array" naming problem + ets_int (*GetVersion)(EtsEnv *env); +#ifdef ETS_NAPI_DESIGN_FINISHED + ets_class (*DefineClass)(EtsEnv *env, const char *name, ets_object loader, const ets_byte *buf, ets_size bufLen); +#endif + ets_class (*FindClass)(EtsEnv *env, const char *name); +#ifdef ETS_NAPI_DESIGN_FINISHED + ets_method (*FromReflectedMethod)(EtsEnv *env, ets_object method); + ets_field (*FromReflectedField)(EtsEnv *env, ets_object field); + ets_object (*ToReflectedMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ets_boolean isStatic); +#endif + ets_class (*GetSuperclass)(EtsEnv *env, ets_class cls); + ets_boolean (*IsAssignableFrom)(EtsEnv *env, ets_class cls1, ets_class cls2); +#ifdef ETS_NAPI_DESIGN_FINISHED + ets_object (*ToReflectedField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_boolean isStatic); +#endif + ets_int (*ThrowError)(EtsEnv *env, ets_error obj); + ets_int (*ThrowErrorNew)(EtsEnv *env, ets_class cls, const char *message); + ets_error (*ErrorOccurred)(EtsEnv *env); + void (*ErrorDescribe)(EtsEnv *env); + void (*ErrorClear)(EtsEnv *env); + void (*FatalError)(EtsEnv *env, const char *message); + ets_int (*PushLocalFrame)(EtsEnv *env, ets_int capacity); + ets_object (*PopLocalFrame)(EtsEnv *env, ets_object result); + ets_object (*NewGlobalRef)(EtsEnv *env, ets_object obj); + void (*DeleteGlobalRef)(EtsEnv *env, ets_object globalRef); + void (*DeleteLocalRef)(EtsEnv *env, ets_object localRef); + ets_boolean (*IsSameObject)(EtsEnv *env, ets_object ref1, ets_object ref2); + ets_object (*NewLocalRef)(EtsEnv *env, ets_object ref); + ets_int (*EnsureLocalCapacity)(EtsEnv *env, ets_int capacity); + ets_object (*AllocObject)(EtsEnv *env, ets_class cls); + ets_object (*NewObject)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_object (*NewObjectList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_object (*NewObjectArray)(EtsEnv *env, ets_class cls, ets_method p_method, const ets_value *args); + ets_class (*GetObjectClass)(EtsEnv *env, ets_object obj); + ets_boolean (*IsInstanceOf)(EtsEnv *env, ets_object obj, ets_class cls); + ets_method (*Getp_method)(EtsEnv *env, ets_class cls, const char *name, const char *sig); + ets_object (*CallObjectMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_object (*CallObjectMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_object (*CallObjectMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_boolean (*CallBooleanMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_boolean (*CallBooleanMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_boolean (*CallBooleanMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_byte (*CallByteMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_byte (*CallByteMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_byte (*CallByteMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_char (*CallCharMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_char (*CallCharMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_char (*CallCharMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_short (*CallShortMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_short (*CallShortMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_short (*CallShortMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_int (*CallIntMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_int (*CallIntMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_int (*CallIntMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_long (*CallLongMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_long (*CallLongMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_long (*CallLongMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_float (*CallFloatMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_float (*CallFloatMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_float (*CallFloatMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + ets_double (*CallDoubleMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + ets_double (*CallDoubleMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + ets_double (*CallDoubleMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + void (*CallVoidMethod)(EtsEnv *env, ets_object obj, ets_method p_method, ...); + void (*CallVoidMethodList)(EtsEnv *env, ets_object obj, ets_method p_method, va_list args); + void (*CallVoidMethodArray)(EtsEnv *env, ets_object obj, ets_method p_method, const ets_value *args); + + ets_object (*CallNonvirtualObjectMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_object (*CallNonvirtualObjectMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_object (*CallNonvirtualObjectMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_boolean (*CallNonvirtualBooleanMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_boolean (*CallNonvirtualBooleanMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_boolean (*CallNonvirtualBooleanMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_byte (*CallNonvirtualByteMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_byte (*CallNonvirtualByteMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_byte (*CallNonvirtualByteMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_char (*CallNonvirtualCharMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_char (*CallNonvirtualCharMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_char (*CallNonvirtualCharMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_short (*CallNonvirtualShortMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_short (*CallNonvirtualShortMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_short (*CallNonvirtualShortMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_int (*CallNonvirtualIntMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_int (*CallNonvirtualIntMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_int (*CallNonvirtualIntMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_long (*CallNonvirtualLongMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_long (*CallNonvirtualLongMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_long (*CallNonvirtualLongMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_float (*CallNonvirtualFloatMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_float (*CallNonvirtualFloatMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_float (*CallNonvirtualFloatMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_double (*CallNonvirtualDoubleMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + ets_double (*CallNonvirtualDoubleMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + va_list args); + ets_double (*CallNonvirtualDoubleMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + void (*CallNonvirtualVoidMethod)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, ...); + void (*CallNonvirtualVoidMethodList)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, va_list args); + void (*CallNonvirtualVoidMethodArray)(EtsEnv *env, ets_object obj, ets_class cls, ets_method p_method, + const ets_value *args); + ets_field (*Getp_field)(EtsEnv *env, ets_class cls, const char *name, const char *sig); + ets_object (*GetObjectField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_boolean (*GetBooleanField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_byte (*GetByteField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_char (*GetCharField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_short (*GetShortField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_int (*GetIntField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_long (*GetLongField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_float (*GetFloatField)(EtsEnv *env, ets_object obj, ets_field p_field); + ets_double (*GetDoubleField)(EtsEnv *env, ets_object obj, ets_field p_field); + void (*SetObjectField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_object value); + void (*SetBooleanField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_boolean value); + void (*SetByteField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_byte value); + void (*SetCharField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_char value); + void (*SetShortField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_short value); + void (*SetIntField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_int value); + void (*SetLongField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_long value); + void (*SetFloatField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_float value); + void (*SetDoubleField)(EtsEnv *env, ets_object obj, ets_field p_field, ets_double value); + ets_method (*GetStaticp_method)(EtsEnv *env, ets_class cls, const char *name, const char *sig); + ets_object (*CallStaticObjectMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_object (*CallStaticObjectMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_object (*CallStaticObjectMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_boolean (*CallStaticBooleanMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_boolean (*CallStaticBooleanMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_boolean (*CallStaticBooleanMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_byte (*CallStaticByteMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_byte (*CallStaticByteMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_byte (*CallStaticByteMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_char (*CallStaticCharMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_char (*CallStaticCharMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_char (*CallStaticCharMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_short (*CallStaticShortMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_short (*CallStaticShortMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_short (*CallStaticShortMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_int (*CallStaticIntMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_int (*CallStaticIntMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_int (*CallStaticIntMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_long (*CallStaticLongMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_long (*CallStaticLongMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_long (*CallStaticLongMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_float (*CallStaticFloatMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_float (*CallStaticFloatMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_float (*CallStaticFloatMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_double (*CallStaticDoubleMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + ets_double (*CallStaticDoubleMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + ets_double (*CallStaticDoubleMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + void (*CallStaticVoidMethod)(EtsEnv *env, ets_class cls, ets_method p_method, ...); + void (*CallStaticVoidMethodList)(EtsEnv *env, ets_class cls, ets_method p_method, va_list args); + void (*CallStaticVoidMethodArray)(EtsEnv *env, ets_class cls, ets_method p_method, ets_value *args); + ets_field (*GetStaticp_field)(EtsEnv *env, ets_class cls, const char *name, const char *sig); + ets_object (*GetStaticObjectField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_boolean (*GetStaticBooleanField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_byte (*GetStaticByteField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_char (*GetStaticCharField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_short (*GetStaticShortField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_int (*GetStaticIntField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_long (*GetStaticLongField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_float (*GetStaticFloatField)(EtsEnv *env, ets_class cls, ets_field p_field); + ets_double (*GetStaticDoubleField)(EtsEnv *env, ets_class cls, ets_field p_field); + void (*SetStaticObjectField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_object value); + void (*SetStaticBooleanField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_boolean value); + void (*SetStaticByteField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_byte value); + void (*SetStaticCharField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_char value); + void (*SetStaticShortField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_short value); + void (*SetStaticIntField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_int value); + void (*SetStaticLongField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_long value); + void (*SetStaticFloatField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_float value); + void (*SetStaticDoubleField)(EtsEnv *env, ets_class cls, ets_field p_field, ets_double value); + ets_string (*NewString)(EtsEnv *env, const ets_char *unicodeChars, ets_size len); + ets_size (*GetStringLength)(EtsEnv *env, ets_string string); + const ets_char *(*GetStringChars)(EtsEnv *env, ets_string string, ets_boolean *isCopy); + void (*ReleaseStringChars)(EtsEnv *env, ets_string string, const ets_char *chars); + ets_string (*NewStringUTF)(EtsEnv *env, const char *bytes); + ets_size (*GetStringUTFLength)(EtsEnv *env, ets_string string); + const char *(*GetStringUTFChars)(EtsEnv *env, ets_string string, ets_boolean *isCopy); + void (*ReleaseStringUTFChars)(EtsEnv *env, ets_string string, const char *utf); + ets_size (*GetArrayLength)(EtsEnv *env, ets_array array); + ets_objectArray (*NewObjectsArray)(EtsEnv *env, ets_size length, ets_class element_class, + ets_object initial_element); + ets_object (*GetObjectArrayElement)(EtsEnv *env, ets_objectArray array, ets_size index); + void (*SetObjectArrayElement)(EtsEnv *env, ets_objectArray array, ets_size index, ets_object value); + ets_booleanArray (*NewBooleanArray)(EtsEnv *env, ets_size length); + ets_byteArray (*NewByteArray)(EtsEnv *env, ets_size length); + ets_charArray (*NewCharArray)(EtsEnv *env, ets_size length); + ets_shortArray (*NewShortArray)(EtsEnv *env, ets_size length); + ets_intArray (*NewIntArray)(EtsEnv *env, ets_size length); + ets_longArray (*NewLongArray)(EtsEnv *env, ets_size length); + ets_floatArray (*NewFloatArray)(EtsEnv *env, ets_size length); + ets_doubleArray (*NewDoubleArray)(EtsEnv *env, ets_size length); + ets_boolean *(*PinBooleanArray)(EtsEnv *env, ets_booleanArray array); + ets_byte *(*PinByteArray)(EtsEnv *env, ets_byteArray array); + ets_char *(*PinCharArray)(EtsEnv *env, ets_charArray array); + ets_short *(*PinShortArray)(EtsEnv *env, ets_shortArray array); + ets_int *(*PinIntArray)(EtsEnv *env, ets_intArray array); + ets_long *(*PinLongArray)(EtsEnv *env, ets_longArray array); + ets_float *(*PinFloatArray)(EtsEnv *env, ets_floatArray array); + ets_double *(*PinDoubleArray)(EtsEnv *env, ets_doubleArray array); + void (*UnpinBooleanArray)(EtsEnv *env, ets_booleanArray array); + void (*UnpinByteArray)(EtsEnv *env, ets_byteArray array); + void (*UnpinCharArray)(EtsEnv *env, ets_charArray array); + void (*UnpinShortArray)(EtsEnv *env, ets_shortArray array); + void (*UnpinIntArray)(EtsEnv *env, ets_intArray array); + void (*UnpinLongArray)(EtsEnv *env, ets_longArray array); + void (*UnpinFloatArray)(EtsEnv *env, ets_floatArray array); + void (*UnpinDoubleArray)(EtsEnv *env, ets_doubleArray array); + void (*GetBooleanArrayRegion)(EtsEnv *env, ets_booleanArray array, ets_size start, ets_size len, ets_boolean *buf); + void (*GetByteArrayRegion)(EtsEnv *env, ets_byteArray array, ets_size start, ets_size len, ets_byte *buf); + void (*GetCharArrayRegion)(EtsEnv *env, ets_charArray array, ets_size start, ets_size len, ets_char *buf); + void (*GetShortArrayRegion)(EtsEnv *env, ets_shortArray array, ets_size start, ets_size len, ets_short *buf); + void (*GetIntArrayRegion)(EtsEnv *env, ets_intArray array, ets_size start, ets_size len, ets_int *buf); + void (*GetLongArrayRegion)(EtsEnv *env, ets_longArray array, ets_size start, ets_size len, ets_long *buf); + void (*GetFloatArrayRegion)(EtsEnv *env, ets_floatArray array, ets_size start, ets_size len, ets_float *buf); + void (*GetDoubleArrayRegion)(EtsEnv *env, ets_doubleArray array, ets_size start, ets_size len, ets_double *buf); + void (*SetBooleanArrayRegion)(EtsEnv *env, ets_booleanArray array, ets_size start, ets_size len, + const ets_boolean *buf); + void (*SetByteArrayRegion)(EtsEnv *env, ets_byteArray array, ets_size start, ets_size len, const ets_byte *buf); + void (*SetCharArrayRegion)(EtsEnv *env, ets_charArray array, ets_size start, ets_size len, const ets_char *buf); + void (*SetShortArrayRegion)(EtsEnv *env, ets_shortArray array, ets_size start, ets_size len, const ets_short *buf); + void (*SetIntArrayRegion)(EtsEnv *env, ets_intArray array, ets_size start, ets_size len, const ets_int *buf); + void (*SetLongArrayRegion)(EtsEnv *env, ets_longArray array, ets_size start, ets_size len, const ets_long *buf); + void (*SetFloatArrayRegion)(EtsEnv *env, ets_floatArray array, ets_size start, ets_size len, const ets_float *buf); + void (*SetDoubleArrayRegion)(EtsEnv *env, ets_doubleArray array, ets_size start, ets_size len, + const ets_double *buf); + ets_int (*RegisterNatives)(EtsEnv *env, ets_class cls, const EtsNativeMethod *methods, ets_int nMethods); + ets_int (*UnregisterNatives)(EtsEnv *env, ets_class cls); + ets_int (*GetEtsVM)(EtsEnv *env, EtsVM **vm); + void (*GetStringRegion)(EtsEnv *env, ets_string str, ets_size start, ets_size len, ets_char *buf); + void (*GetStringUTFRegion)(EtsEnv *env, ets_string str, ets_size start, ets_size len, char *buf); + ets_weak (*NewWeakGlobalRef)(EtsEnv *env, ets_object obj); + void (*DeleteWeakGlobalRef)(EtsEnv *env, ets_weak obj); + ets_boolean (*ErrorCheck)(EtsEnv *env); +#ifdef ETS_NAPI_DESIGN_FINISHED + ets_object (*NewDirectByteBuffer)(EtsEnv *env, void *address, ets_long capacity); + void *(*GetDirectBufferAddress)(EtsEnv *env, ets_object buf); + ets_long (*GetDirectBufferCapacity)(EtsEnv *env, ets_object buf); +#endif + ets_objectRefType (*GetObjectRefType)(EtsEnv *env, ets_object obj); + + /* 227 methods */ + + // Promise API + ets_status (*PromiseCreate)(EtsEnv *env, ets_deferred *deferred, ets_object *promise); + ets_status (*DeferredResolve)(EtsEnv *env, ets_deferred deferred, ets_object resolution); + ets_status (*DeferredReject)(EtsEnv *env, ets_deferred deferred, ets_object rejection); +}; +// clang-format on + +// Invocation API Functions +typedef enum { + ETS_LOG_LEVEL, + ETS_MOBILE_LOG, + ETS_BOOT_FILE, + ETS_AOT_FILE, + ETS_ARK_FILE, + ETS_JIT, + ETS_NO_JIT, + ETS_AOT, + ETS_NO_AOT, + ETS_GC_TRIGGER_TYPE, + ETS_GC_TYPE, + ETS_RUN_GC_IN_PLACE, + ETS_INTERPRETER_TYPE, + ETS_NATIVE_LIBRARY_PATH, + ETS_VERIFICATION_MODE +} EtsOptionType; + +typedef struct EtsVMOption { + EtsOptionType option; + const void* extraInfo; +} EtsVMOption; + +typedef struct EtsVMInitArgs { + ets_int version; + ets_int nOptions; + EtsVMOption* options; +} EtsVMInitArgs; + +typedef enum { + ETS_MOBILE_LOG_LEVEL_UNKNOWN = 0, + ETS_MOBILE_LOG_LEVEL_DEFAULT, + ETS_MOBILE_LOG_LEVEL_VERBOSE, + ETS_MOBILE_LOG_LEVEL_DEBUG, + ETS_MOBILE_LOG_LEVEL_INFO, + ETS_MOBILE_LOG_LEVEL_WARN, + ETS_MOBILE_LOG_LEVEL_ERROR, + ETS_MOBILE_LOG_LEVEL_FATAL, + ETS_MOBILE_LOG_LEVEL_SILENT +} EtsMobileLogggerLevel; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#define ETS_EXPORT __declspec(dllexport) +#else +#define ETS_EXPORT __attribute__((visibility("default"))) +#endif +#define ETS_IMPORT +#define ETS_CALL + +ETS_EXPORT ets_int ETS_GetDefaultVMInitArgs(EtsVMInitArgs* vmArgs); +ETS_EXPORT ets_int ETS_GetCreatedVMs(EtsVM** vmBuf, ets_size bufLen, ets_size* nVms); +ETS_EXPORT ets_int ETS_CreateVM(EtsVM** pVm, EtsEnv** pEnv, EtsVMInitArgs* vmArgs); + +#ifdef __cplusplus +} +#endif + +struct ETS_InvokeInterface { + ets_int (*DestroyEtsVM)(EtsVM* vm); + ets_int (*GetEnv)(EtsVM* vm, EtsEnv** pEnv, ets_int version); +}; + +struct __EtsVM { + // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) + const struct ETS_InvokeInterface* invoke_interface; + +#ifdef __cplusplus + ets_int DestroyEtsVM() + { + return invoke_interface->DestroyEtsVM(this); + } + + ets_int GetEnv(EtsEnv** pEnv, ets_int version) + { + return invoke_interface->GetEnv(this, pEnv, version); + } +#endif +}; + +struct __EtsEnv { + // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) + const struct ETS_NativeInterface* native_interface; + +#ifdef __cplusplus + + ets_int GetVersion() + { + return native_interface->GetVersion(this); + } + // DefineClass, + ets_class FindClass(const char* name) + { + return native_interface->FindClass(this, name); + } + // FromReflectedMethod, + // FromReflectedField, + // ToReflectedMethod, + ets_class GetSuperclass(ets_class cls) + { + return native_interface->GetSuperclass(this, cls); + } + ets_boolean IsAssignableFrom(ets_class cls1, ets_class cls2) + { + return native_interface->IsAssignableFrom(this, cls1, cls2); + } + // ToReflectedField, + ets_int ThrowError(ets_error obj) + { + return native_interface->ThrowError(this, obj); + } + ets_int ThrowErrorNew(ets_class cls, const char* message) + { + return native_interface->ThrowErrorNew(this, cls, message); + } + ets_error ErrorOccurred() + { + return native_interface->ErrorOccurred(this); + } + void ErrorDescribe() + { + native_interface->ErrorDescribe(this); + } + void ErrorClear() + { + native_interface->ErrorClear(this); + } + void FatalError(const char* message) + { + native_interface->FatalError(this, message); + } + ets_int PushLocalFrame(ets_int capacity) + { + return native_interface->PushLocalFrame(this, capacity); + } + ets_object PopLocalFrame(ets_object result) + { + return native_interface->PopLocalFrame(this, result); + } + ets_object NewGlobalRef(ets_object obj) + { + return native_interface->NewGlobalRef(this, obj); + } + void DeleteGlobalRef(ets_object globalRef) + { + native_interface->DeleteGlobalRef(this, globalRef); + } + void DeleteLocalRef(ets_object localRef) + { + native_interface->DeleteLocalRef(this, localRef); + } + ets_boolean IsSameObject(ets_object ref1, ets_object ref2) + { + return native_interface->IsSameObject(this, ref1, ref2); + } + ets_object NewLocalRef(ets_object ref) + { + return native_interface->NewLocalRef(this, ref); + } + ets_int EnsureLocalCapacity(ets_int capacity) + { + return native_interface->EnsureLocalCapacity(this, capacity); + } + ets_object AllocObject(ets_class cls) + { + return native_interface->AllocObject(this, cls); + } + ets_object NewObject(ets_class cls, ets_method p_method, ...) + { + va_list args; + va_start(args, p_method); + ets_object ret = native_interface->NewObjectList(this, cls, p_method, args); + va_end(args); + return ret; + } + ets_object NewObjectList(ets_class cls, ets_method p_method, va_list args) + { + return native_interface->NewObjectList(this, cls, p_method, args); + } + ets_object NewObjectArray(ets_class cls, ets_method p_method, const ets_value* args) + { + return native_interface->NewObjectArray(this, cls, p_method, args); + } + ets_class GetObjectClass(ets_object obj) + { + return native_interface->GetObjectClass(this, obj); + } + ets_boolean IsInstanceOf(ets_object obj, ets_class cls) + { + return native_interface->IsInstanceOf(this, obj, cls); + } + ets_method Getp_method(ets_class cls, const char* name, const char* sig) + { + return native_interface->Getp_method(this, cls, name, sig); + } + ets_object CallObjectMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_object res = native_interface->CallObjectMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_object CallObjectMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallObjectMethodList(this, obj, method_id, args); + } + ets_object CallObjectMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallObjectMethodArray(this, obj, method_id, args); + } + ets_boolean CallBooleanMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_boolean res = native_interface->CallBooleanMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_boolean CallBooleanMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallBooleanMethodList(this, obj, method_id, args); + } + ets_boolean CallBooleanMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallBooleanMethodArray(this, obj, method_id, args); + } + ets_byte CallByteMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_byte res = native_interface->CallByteMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_byte CallByteMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallByteMethodList(this, obj, method_id, args); + } + ets_byte CallByteMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallByteMethodArray(this, obj, method_id, args); + } + ets_char CallCharMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_char res = native_interface->CallCharMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_char CallCharMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallCharMethodList(this, obj, method_id, args); + } + ets_char CallCharMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallCharMethodArray(this, obj, method_id, args); + } + ets_short CallShortMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_short res = native_interface->CallShortMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_short CallShortMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallShortMethodList(this, obj, method_id, args); + } + ets_short CallShortMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallShortMethodArray(this, obj, method_id, args); + } + ets_int CallIntMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_int res = native_interface->CallIntMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_int CallIntMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallIntMethodList(this, obj, method_id, args); + } + ets_int CallIntMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallIntMethodArray(this, obj, method_id, args); + } + ets_long CallLongMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_long res = native_interface->CallLongMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_long CallLongMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallLongMethodList(this, obj, method_id, args); + } + ets_long CallLongMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallLongMethodArray(this, obj, method_id, args); + } + ets_float CallFloatMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_float res = native_interface->CallFloatMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_float CallFloatMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallFloatMethodList(this, obj, method_id, args); + } + ets_float CallFloatMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallFloatMethodArray(this, obj, method_id, args); + } + ets_double CallDoubleMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_double res = native_interface->CallDoubleMethodList(this, obj, method_id, args); + va_end(args); + return res; + } + ets_double CallDoubleMethodList(ets_object obj, ets_method method_id, va_list args) + { + return native_interface->CallDoubleMethodList(this, obj, method_id, args); + } + ets_double CallDoubleMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + return native_interface->CallDoubleMethodArray(this, obj, method_id, args); + } + void CallVoidMethod(ets_object obj, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + native_interface->CallVoidMethodList(this, obj, method_id, args); + va_end(args); + } + void CallVoidMethodList(ets_object obj, ets_method method_id, va_list args) + { + native_interface->CallVoidMethodList(this, obj, method_id, args); + } + void CallVoidMethodArray(ets_object obj, ets_method method_id, const ets_value* args) + { + native_interface->CallVoidMethodArray(this, obj, method_id, args); + } + ets_object CallNonvirtualObjectMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_object res = native_interface->CallNonvirtualObjectMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_object CallNonvirtualObjectMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualObjectMethodList(this, obj, cls, method_id, args); + } + ets_object CallNonvirtualObjectMethodArray( + ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualObjectMethodArray(this, obj, cls, method_id, args); + } + ets_boolean CallNonvirtualBooleanMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_boolean res = native_interface->CallNonvirtualBooleanMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_boolean CallNonvirtualBooleanMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualBooleanMethodList(this, obj, cls, method_id, args); + } + ets_boolean CallNonvirtualBooleanMethodArray( + ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualBooleanMethodArray(this, obj, cls, method_id, args); + } + ets_byte CallNonvirtualByteMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_byte res = native_interface->CallNonvirtualByteMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_byte CallNonvirtualByteMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualByteMethodList(this, obj, cls, method_id, args); + } + ets_byte CallNonvirtualByteMethodArray(ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualByteMethodArray(this, obj, cls, method_id, args); + } + ets_char CallNonvirtualCharMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_char res = native_interface->CallNonvirtualCharMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_char CallNonvirtualCharMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualCharMethodList(this, obj, cls, method_id, args); + } + ets_char CallNonvirtualCharMethodArray(ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualCharMethodArray(this, obj, cls, method_id, args); + } + ets_short CallNonvirtualShortMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_short res = native_interface->CallNonvirtualShortMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_short CallNonvirtualShortMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualShortMethodList(this, obj, cls, method_id, args); + } + ets_short CallNonvirtualShortMethodArray(ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualShortMethodArray(this, obj, cls, method_id, args); + } + ets_int CallNonvirtualIntMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_int res = native_interface->CallNonvirtualIntMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_int CallNonvirtualIntMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualIntMethodList(this, obj, cls, method_id, args); + } + ets_int CallNonvirtualIntMethodArray(ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualIntMethodArray(this, obj, cls, method_id, args); + } + ets_long CallNonvirtualLongMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_long res = native_interface->CallNonvirtualLongMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_long CallNonvirtualLongMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualLongMethodList(this, obj, cls, method_id, args); + } + ets_long CallNonvirtualLongMethodArray(ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualLongMethodArray(this, obj, cls, method_id, args); + } + ets_float CallNonvirtualFloatMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_float res = native_interface->CallNonvirtualFloatMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_float CallNonvirtualFloatMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualFloatMethodList(this, obj, cls, method_id, args); + } + ets_float CallNonvirtualFloatMethodArray(ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualFloatMethodArray(this, obj, cls, method_id, args); + } + ets_double CallNonvirtualDoubleMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_double res = native_interface->CallNonvirtualDoubleMethodList(this, obj, cls, method_id, args); + va_end(args); + return res; + } + ets_double CallNonvirtualDoubleMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallNonvirtualDoubleMethodList(this, obj, cls, method_id, args); + } + ets_double CallNonvirtualDoubleMethodArray( + ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + return native_interface->CallNonvirtualDoubleMethodArray(this, obj, cls, method_id, args); + } + void CallNonvirtualVoidMethod(ets_object obj, ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + native_interface->CallNonvirtualVoidMethodList(this, obj, cls, method_id, args); + va_end(args); + } + void CallNonvirtualVoidMethodList(ets_object obj, ets_class cls, ets_method method_id, va_list args) + { + native_interface->CallNonvirtualVoidMethodList(this, obj, cls, method_id, args); + } + void CallNonvirtualVoidMethodArray(ets_object obj, ets_class cls, ets_method method_id, const ets_value* args) + { + native_interface->CallNonvirtualVoidMethodArray(this, obj, cls, method_id, args); + } + ets_field Getp_field(ets_class cls, const char* name, const char* sig) + { + return native_interface->Getp_field(this, cls, name, sig); + } + ets_object GetObjectField(ets_object obj, ets_field p_field) + { + return native_interface->GetObjectField(this, obj, p_field); + } + ets_boolean GetBooleanField(ets_object obj, ets_field p_field) + { + return native_interface->GetBooleanField(this, obj, p_field); + } + ets_byte GetByteField(ets_object obj, ets_field p_field) + { + return native_interface->GetByteField(this, obj, p_field); + } + ets_char GetCharField(ets_object obj, ets_field p_field) + { + return native_interface->GetCharField(this, obj, p_field); + } + ets_short GetShortField(ets_object obj, ets_field p_field) + { + return native_interface->GetShortField(this, obj, p_field); + } + ets_int GetIntField(ets_object obj, ets_field p_field) + { + return native_interface->GetIntField(this, obj, p_field); + } + ets_long GetLongField(ets_object obj, ets_field p_field) + { + return native_interface->GetLongField(this, obj, p_field); + } + ets_float GetFloatField(ets_object obj, ets_field p_field) + { + return native_interface->GetFloatField(this, obj, p_field); + } + ets_double GetDoubleField(ets_object obj, ets_field p_field) + { + return native_interface->GetDoubleField(this, obj, p_field); + } + void SetObjectField(ets_object obj, ets_field p_field, ets_object value) + { + return native_interface->SetObjectField(this, obj, p_field, value); + } + void SetBooleanField(ets_object obj, ets_field p_field, ets_boolean value) + { + return native_interface->SetBooleanField(this, obj, p_field, value); + } + void SetByteField(ets_object obj, ets_field p_field, ets_byte value) + { + return native_interface->SetByteField(this, obj, p_field, value); + } + void SetCharField(ets_object obj, ets_field p_field, ets_char value) + { + return native_interface->SetCharField(this, obj, p_field, value); + } + void SetShortField(ets_object obj, ets_field p_field, ets_short value) + { + return native_interface->SetShortField(this, obj, p_field, value); + } + void SetIntField(ets_object obj, ets_field p_field, ets_int value) + { + return native_interface->SetIntField(this, obj, p_field, value); + } + void SetLongField(ets_object obj, ets_field p_field, ets_long value) + { + return native_interface->SetLongField(this, obj, p_field, value); + } + void SetFloatField(ets_object obj, ets_field p_field, ets_float value) + { + return native_interface->SetFloatField(this, obj, p_field, value); + } + void SetDoubleField(ets_object obj, ets_field p_field, ets_double value) + { + return native_interface->SetDoubleField(this, obj, p_field, value); + } + ets_method GetStaticp_method(ets_class cls, const char* name, const char* sig) + { + return native_interface->GetStaticp_method(this, cls, name, sig); + } + ets_object CallStaticObjectMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_object res = native_interface->CallStaticObjectMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_object CallStaticObjectMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticObjectMethodList(this, cls, method_id, args); + } + ets_object CallStaticObjectMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticObjectMethodArray(this, cls, method_id, args); + } + ets_boolean CallStaticBooleanMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_boolean res = native_interface->CallStaticBooleanMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_boolean CallStaticBooleanMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticBooleanMethodList(this, cls, method_id, args); + } + ets_boolean CallStaticBooleanMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticBooleanMethodArray(this, cls, method_id, args); + } + ets_byte CallStaticByteMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_byte res = native_interface->CallStaticByteMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_byte CallStaticByteMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticByteMethodList(this, cls, method_id, args); + } + ets_byte CallStaticByteMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticByteMethodArray(this, cls, method_id, args); + } + ets_char CallStaticCharMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_char res = native_interface->CallStaticCharMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_char CallStaticCharMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticCharMethodList(this, cls, method_id, args); + } + ets_char CallStaticCharMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticCharMethodArray(this, cls, method_id, args); + } + ets_short CallStaticShortMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_short res = native_interface->CallStaticShortMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_short CallStaticShortMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticShortMethodList(this, cls, method_id, args); + } + ets_short CallStaticShortMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticShortMethodArray(this, cls, method_id, args); + } + ets_int CallStaticIntMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_int res = native_interface->CallStaticIntMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_int CallStaticIntMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticIntMethodList(this, cls, method_id, args); + } + ets_int CallStaticIntMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticIntMethodArray(this, cls, method_id, args); + } + ets_long CallStaticLongMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_long res = native_interface->CallStaticLongMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_long CallStaticLongMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticLongMethodList(this, cls, method_id, args); + } + ets_long CallStaticLongMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticLongMethodArray(this, cls, method_id, args); + } + ets_float CallStaticFloatMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_float res = native_interface->CallStaticFloatMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_float CallStaticFloatMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticFloatMethodList(this, cls, method_id, args); + } + ets_float CallStaticFloatMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticFloatMethodArray(this, cls, method_id, args); + } + ets_double CallStaticDoubleMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + ets_double res = native_interface->CallStaticDoubleMethodList(this, cls, method_id, args); + va_end(args); + return res; + } + ets_double CallStaticDoubleMethodList(ets_class cls, ets_method method_id, va_list args) + { + return native_interface->CallStaticDoubleMethodList(this, cls, method_id, args); + } + ets_double CallStaticDoubleMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + return native_interface->CallStaticDoubleMethodArray(this, cls, method_id, args); + } + void CallStaticVoidMethod(ets_class cls, ets_method method_id, ...) + { + va_list args; + va_start(args, method_id); + native_interface->CallStaticVoidMethodList(this, cls, method_id, args); + va_end(args); + } + void CallStaticVoidMethodList(ets_class cls, ets_method method_id, va_list args) + { + native_interface->CallStaticVoidMethodList(this, cls, method_id, args); + } + void CallStaticVoidMethodArray(ets_class cls, ets_method method_id, ets_value* args) + { + native_interface->CallStaticVoidMethodArray(this, cls, method_id, args); + } + ets_field GetStaticp_field(ets_class cls, const char* name, const char* sig) + { + return native_interface->GetStaticp_field(this, cls, name, sig); + } + ets_object GetStaticObjectField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticObjectField(this, cls, p_field); + } + ets_boolean GetStaticBooleanField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticBooleanField(this, cls, p_field); + } + ets_byte GetStaticByteField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticByteField(this, cls, p_field); + } + ets_char GetStaticCharField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticCharField(this, cls, p_field); + } + ets_short GetStaticShortField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticShortField(this, cls, p_field); + } + ets_int GetStaticIntField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticIntField(this, cls, p_field); + } + ets_long GetStaticLongField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticLongField(this, cls, p_field); + } + ets_float GetStaticFloatField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticFloatField(this, cls, p_field); + } + ets_double GetStaticDoubleField(ets_class cls, ets_field p_field) + { + return native_interface->GetStaticDoubleField(this, cls, p_field); + } + void SetStaticObjectField(ets_class cls, ets_field p_field, ets_object value) + { + return native_interface->SetStaticObjectField(this, cls, p_field, value); + } + void SetStaticBooleanField(ets_class cls, ets_field p_field, ets_boolean value) + { + return native_interface->SetStaticBooleanField(this, cls, p_field, value); + } + void SetStaticByteField(ets_class cls, ets_field p_field, ets_byte value) + { + return native_interface->SetStaticByteField(this, cls, p_field, value); + } + void SetStaticCharField(ets_class cls, ets_field p_field, ets_char value) + { + return native_interface->SetStaticCharField(this, cls, p_field, value); + } + void SetStaticShortField(ets_class cls, ets_field p_field, ets_short value) + { + return native_interface->SetStaticShortField(this, cls, p_field, value); + } + void SetStaticIntField(ets_class cls, ets_field p_field, ets_int value) + { + return native_interface->SetStaticIntField(this, cls, p_field, value); + } + void SetStaticLongField(ets_class cls, ets_field p_field, ets_long value) + { + return native_interface->SetStaticLongField(this, cls, p_field, value); + } + void SetStaticFloatField(ets_class cls, ets_field p_field, ets_float value) + { + return native_interface->SetStaticFloatField(this, cls, p_field, value); + } + void SetStaticDoubleField(ets_class cls, ets_field p_field, ets_double value) + { + return native_interface->SetStaticDoubleField(this, cls, p_field, value); + } + ets_string NewString(const ets_char* unicode_chars, ets_size len) + { + return native_interface->NewString(this, unicode_chars, len); + } + ets_size GetStringLength(ets_string string) + { + return native_interface->GetStringLength(this, string); + } + const ets_char* GetStringChars(ets_string string, ets_boolean* is_copy) + { + return native_interface->GetStringChars(this, string, is_copy); + } + void ReleaseStringChars(ets_string string, const ets_char* chars) + { + native_interface->ReleaseStringChars(this, string, chars); + } + ets_string NewStringUTF(const char* bytes) + { + return native_interface->NewStringUTF(this, bytes); + } + ets_size GetStringUTFLength(ets_string string) + { + return native_interface->GetStringUTFLength(this, string); + } + const char* GetStringUTFChars(ets_string string, ets_boolean* is_copy) + { + return native_interface->GetStringUTFChars(this, string, is_copy); + } + void ReleaseStringUTFChars(ets_string string, const char* chars) + { + native_interface->ReleaseStringUTFChars(this, string, chars); + } + ets_size GetArrayLength(ets_array array) + { + return native_interface->GetArrayLength(this, array); + } + ets_objectArray NewObjectsArray(ets_size length, ets_class element_class, ets_object initial_element) + { + return native_interface->NewObjectsArray(this, length, element_class, initial_element); + } + ets_object GetObjectArrayElement(ets_objectArray array, ets_size index) + { + return native_interface->GetObjectArrayElement(this, array, index); + } + + void SetObjectArrayElement(ets_objectArray array, ets_size index, ets_object value) + { + native_interface->SetObjectArrayElement(this, array, index, value); + } + + // SetObjectArrayElement, + ets_booleanArray NewBooleanArray(ets_size length) + { + return native_interface->NewBooleanArray(this, length); + } + ets_byteArray NewByteArray(ets_size length) + { + return native_interface->NewByteArray(this, length); + } + ets_charArray NewCharArray(ets_size length) + { + return native_interface->NewCharArray(this, length); + } + ets_shortArray NewShortArray(ets_size length) + { + return native_interface->NewShortArray(this, length); + } + ets_intArray NewIntArray(ets_size length) + { + return native_interface->NewIntArray(this, length); + } + ets_longArray NewLongArray(ets_size length) + { + return native_interface->NewLongArray(this, length); + } + ets_floatArray NewFloatArray(ets_size length) + { + return native_interface->NewFloatArray(this, length); + } + ets_doubleArray NewDoubleArray(ets_size length) + { + return native_interface->NewDoubleArray(this, length); + } + ets_boolean* PinBooleanArray(ets_booleanArray array) + { + return native_interface->PinBooleanArray(this, array); + } + ets_byte* PinByteArray(ets_byteArray array) + { + return native_interface->PinByteArray(this, array); + } + ets_char* PinCharArray(ets_charArray array) + { + return native_interface->PinCharArray(this, array); + } + ets_short* PinShortArray(ets_shortArray array) + { + return native_interface->PinShortArray(this, array); + } + ets_int* PinIntArray(ets_intArray array) + { + return native_interface->PinIntArray(this, array); + } + ets_long* PinLongArray(ets_longArray array) + { + return native_interface->PinLongArray(this, array); + } + ets_float* PinFloatArray(ets_floatArray array) + { + return native_interface->PinFloatArray(this, array); + } + ets_double* PinDoubleArray(ets_doubleArray array) + { + return native_interface->PinDoubleArray(this, array); + } + void UnpinBooleanArray(ets_booleanArray array) + { + return native_interface->UnpinBooleanArray(this, array); + } + void UnpinByteArray(ets_byteArray array) + { + return native_interface->UnpinByteArray(this, array); + } + void UnpinCharArray(ets_charArray array) + { + return native_interface->UnpinCharArray(this, array); + } + void UnpinShortArray(ets_shortArray array) + { + return native_interface->UnpinShortArray(this, array); + } + void UnpinIntArray(ets_intArray array) + { + return native_interface->UnpinIntArray(this, array); + } + void UnpinLongArray(ets_longArray array) + { + return native_interface->UnpinLongArray(this, array); + } + void UnpinFloatArray(ets_floatArray array) + { + return native_interface->UnpinFloatArray(this, array); + } + void UnpinDoubleArray(ets_doubleArray array) + { + return native_interface->UnpinDoubleArray(this, array); + } + void GetBooleanArrayRegion(ets_booleanArray array, ets_size start, ets_size len, ets_boolean* buf) + { + return native_interface->GetBooleanArrayRegion(this, array, start, len, buf); + } + void GetByteArrayRegion(ets_byteArray array, ets_size start, ets_size len, ets_byte* buf) + { + return native_interface->GetByteArrayRegion(this, array, start, len, buf); + } + void GetCharArrayRegion(ets_charArray array, ets_size start, ets_size len, ets_char* buf) + { + return native_interface->GetCharArrayRegion(this, array, start, len, buf); + } + void GetShortArrayRegion(ets_shortArray array, ets_size start, ets_size len, ets_short* buf) + { + return native_interface->GetShortArrayRegion(this, array, start, len, buf); + } + void GetIntArrayRegion(ets_intArray array, ets_size start, ets_size len, ets_int* buf) + { + return native_interface->GetIntArrayRegion(this, array, start, len, buf); + } + void GetLongArrayRegion(ets_longArray array, ets_size start, ets_size len, ets_long* buf) + { + return native_interface->GetLongArrayRegion(this, array, start, len, buf); + } + void GetFloatArrayRegion(ets_floatArray array, ets_size start, ets_size len, ets_float* buf) + { + return native_interface->GetFloatArrayRegion(this, array, start, len, buf); + } + void GetDoubleArrayRegion(ets_doubleArray array, ets_size start, ets_size len, ets_double* buf) + { + return native_interface->GetDoubleArrayRegion(this, array, start, len, buf); + } + void SetBooleanArrayRegion(ets_booleanArray array, ets_size start, ets_size length, const ets_boolean* buf) + { + native_interface->SetBooleanArrayRegion(this, array, start, length, buf); + } + void SetByteArrayRegion(ets_byteArray array, ets_size start, ets_size length, const ets_byte* buf) + { + native_interface->SetByteArrayRegion(this, array, start, length, buf); + } + void SetCharArrayRegion(ets_charArray array, ets_size start, ets_size length, const ets_char* buf) + { + native_interface->SetCharArrayRegion(this, array, start, length, buf); + } + void SetShortArrayRegion(ets_shortArray array, ets_size start, ets_size length, const ets_short* buf) + { + native_interface->SetShortArrayRegion(this, array, start, length, buf); + } + void SetIntArrayRegion(ets_intArray array, ets_size start, ets_size length, const ets_int* buf) + { + native_interface->SetIntArrayRegion(this, array, start, length, buf); + } + void SetLongArrayRegion(ets_longArray array, ets_size start, ets_size length, const ets_long* buf) + { + native_interface->SetLongArrayRegion(this, array, start, length, buf); + } + void SetFloatArrayRegion(ets_floatArray array, ets_size start, ets_size length, const ets_float* buf) + { + native_interface->SetFloatArrayRegion(this, array, start, length, buf); + } + void SetDoubleArrayRegion(ets_doubleArray array, ets_size start, ets_size length, const ets_double* buf) + { + native_interface->SetDoubleArrayRegion(this, array, start, length, buf); + } + ets_int RegisterNatives(ets_class cls, const EtsNativeMethod* methods, ets_int nMethods) + { + return native_interface->RegisterNatives(this, cls, methods, nMethods); + } + ets_int UnregisterNatives(ets_class cls) + { + return native_interface->UnregisterNatives(this, cls); + } + ets_int GetEtsVM(EtsVM** vm) + { + return native_interface->GetEtsVM(this, vm); + } + void GetStringRegion(ets_string str, ets_size start, ets_size len, ets_char* buf) + { + native_interface->GetStringRegion(this, str, start, len, buf); + } + void GetStringUTFRegion(ets_string str, ets_size start, ets_size len, char* buf) + { + native_interface->GetStringUTFRegion(this, str, start, len, buf); + } + ets_weak NewWeakGlobalRef(ets_object obj) + { + return native_interface->NewWeakGlobalRef(this, obj); + } + void DeleteWeakGlobalRef(ets_weak obj) + { + native_interface->DeleteWeakGlobalRef(this, obj); + } + ets_boolean ErrorCheck() + { + return native_interface->ErrorCheck(this); + } + // NewDirectByteBuffer, + // GetDirectBufferAddress, + // GetDirectBufferCapacity, + ets_objectRefType GetObjectRefType(ets_object obj) + { + return native_interface->GetObjectRefType(this, obj); + } + + // Promise + ets_status PromiseCreate(ets_deferred* deferred, ets_object* promise) + { + return native_interface->PromiseCreate(this, deferred, promise); + } + ets_status DeferredResolve(ets_deferred deferred, ets_object resolution) + { + return native_interface->DeferredResolve(this, deferred, resolution); + } + ets_status DeferredReject(ets_deferred deferred, ets_object rejection) + { + return native_interface->DeferredReject(this, deferred, rejection); + } +#endif +}; + +// NOLINTEND(modernize-use-using, readability-identifier-naming, cppcoreguidelines-pro-type-vararg) + +#endif // PANDA_RUNTIME_INTEROP_ETS_NAPI_H diff --git a/ets1.2/interop/src/cpp/interop-logging.cc b/ets1.2/interop/src/cpp/interop-logging.cc new file mode 100644 index 0000000000000000000000000000000000000000..cf8f809ba294943a457bcb111d5f7ce38d06ae25 --- /dev/null +++ b/ets1.2/interop/src/cpp/interop-logging.cc @@ -0,0 +1,100 @@ +/* + * Copyright (c) 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. + */ +#include "interop-logging.h" + +#include +#include +#include + +#include "interop-utils.h" + +namespace { + +struct Log { + std::string log; + bool isActive = true; +}; + +std::vector groupedLogs; + +void startGroupedLog(int index) +{ + if (index >= static_cast(groupedLogs.size())) { + groupedLogs.resize(index + 1); + for (int i = 0; i <= index; i++) { + if (!groupedLogs[i]) + groupedLogs[i] = new Log(); + } + } + groupedLogs[index]->isActive = true; + groupedLogs[index]->log.clear(); +} + +void stopGroupedLog(int index) +{ + if (index < static_cast(groupedLogs.size())) { + groupedLogs[index]->isActive = false; + } +} + +void appendGroupedLog(int index, const char* str) +{ + if (index < static_cast(groupedLogs.size())) { + groupedLogs[index]->log.append(str); + } +} + +const char* getGroupedLog(int index) +{ + if (index < static_cast(groupedLogs.size())) { + // G.STD.04-CPP: Do not hold pointer returned from std::string c_str() method. + return std::move(groupedLogs[index]->log.c_str()); + } + return ""; +} + +int needGroupedLog(int index) +{ + if (index < static_cast(groupedLogs.size())) { + return groupedLogs[index]->isActive; + } + return 0; +} + +const GroupLogger defaultInstance = { + startGroupedLog, + stopGroupedLog, + appendGroupedLog, + getGroupedLog, + needGroupedLog, +}; + +} // namespace + +const GroupLogger* GetDefaultLogger() +{ + return &defaultInstance; +} + +extern "C" [[noreturn]] void InteropLogFatal(const char* format, ...) +{ + va_list args; + va_start(args, format); + char buffer[4096]; + interop_vsnprintf(buffer, sizeof(buffer) - 1, format, args); + LOGE("FATAL: %s", buffer); + va_end(args); + abort(); +} diff --git a/ets1.2/interop/src/cpp/interop-logging.h b/ets1.2/interop/src/cpp/interop-logging.h new file mode 100644 index 0000000000000000000000000000000000000000..9b338baeecf9a177a0a2ebc73d955ef5c4bfbe1f --- /dev/null +++ b/ets1.2/interop/src/cpp/interop-logging.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 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. + */ +#ifndef _INTEROP_LGGING_H +#define _INTEROP_LGGING_H + +#ifdef __cplusplus +#include +#include +#include +#else +#include +#include +#include +#endif + +#if defined(KOALA_OHOS) +#include "oh_sk_log.h" +#define LOG(msg) OH_SK_LOG_INFO(msg); +#define LOGI(msg, ...) OH_SK_LOG_INFO_A(msg, ##__VA_ARGS__); +#define LOGE(msg, ...) OH_SK_LOG_ERROR_A(msg, ##__VA_ARGS__); +#define LOG_PUBLIC "{public}" +#else +#define LOG(msg) fprintf(stdout, msg "\n"); +#define LOGI(msg, ...) fprintf(stdout, msg "\n", ##__VA_ARGS__); +#define LOGE(msg, ...) fprintf(stderr, msg "\n", ##__VA_ARGS__); +#define LOG_PUBLIC "" +#endif + +#if defined(KOALA_WINDOWS) +#define INTEROP_API_EXPORT __declspec(dllexport) +#else +#define INTEROP_API_EXPORT __attribute__((visibility("default"))) +#endif + +#ifndef ASSERT +#define ASSERT(expression) assert(expression) +#endif + +// Grouped logs. Keep consistent with type in ServiceGroupLogger +typedef struct GroupLogger { + void (*startGroupedLog)(int kind); + void (*stopGroupedLog)(int kind); + void (*appendGroupedLog)(int kind, const char* str); + const char* (*getGroupedLog)(int kind); + int (*needGroupedLog)(int kind); +} GroupLogger; + +extern "C" INTEROP_API_EXPORT const GroupLogger* GetDefaultLogger(); + +#endif // _INTEROP_LOGGING_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/interop-types.h b/ets1.2/interop/src/cpp/interop-types.h new file mode 100644 index 0000000000000000000000000000000000000000..8e4802fec75b5109105aa82d290af7892e19b3a1 --- /dev/null +++ b/ets1.2/interop/src/cpp/interop-types.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _INTEROP_TYPES_H_ +#define _INTEROP_TYPES_H_ + +#ifdef __cplusplus +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" + [[noreturn]] +#endif + void + InteropLogFatal(const char* format, ...); +#define INTEROP_FATAL(msg, ...) \ + do { \ + InteropLogFatal(msg, ##__VA_ARGS__); \ + } while (0) + +typedef enum InteropTag { + INTEROP_TAG_UNDEFINED = 101, + INTEROP_TAG_INT32 = 102, + INTEROP_TAG_FLOAT32 = 103, + INTEROP_TAG_STRING = 104, + INTEROP_TAG_LENGTH = 105, + INTEROP_TAG_RESOURCE = 106, + INTEROP_TAG_OBJECT = 107, +} InteropTag; + +typedef enum InteropRuntimeType { + INTEROP_RUNTIME_UNEXPECTED = -1, + INTEROP_RUNTIME_NUMBER = 1, + INTEROP_RUNTIME_STRING = 2, + INTEROP_RUNTIME_OBJECT = 3, + INTEROP_RUNTIME_BOOLEAN = 4, + INTEROP_RUNTIME_UNDEFINED = 5, + INTEROP_RUNTIME_BIGINT = 6, + INTEROP_RUNTIME_FUNCTION = 7, + INTEROP_RUNTIME_SYMBOL = 8, + INTEROP_RUNTIME_MATERIALIZED = 9, +} InteropRuntimeType; + +typedef float InteropFloat32; +typedef double InteropFloat64; +typedef int32_t InteropInt32; +typedef unsigned int InteropUInt32; // Improve: update unsigned int +typedef int64_t InteropInt64; +typedef uint64_t InteropUInt64; +typedef int8_t InteropInt8; +typedef uint8_t InteropUInt8; +typedef int64_t InteropDate; +typedef int8_t InteropBoolean; +typedef const char* InteropCharPtr; +typedef void* InteropNativePointer; + +struct _InteropVMContext; +typedef struct _InteropVMContext* InteropVMContext; +struct _InteropPipelineContext; +typedef struct _InteropPipelineContext* InteropPipelineContext; +struct _InteropVMObject; +typedef struct _InteropVMObject* InteropVMObject; +struct _InteropNode; +typedef struct _InteropNode* InteropNodeHandle; +typedef struct InteropDeferred { + void* handler; + void* context; + void (*resolve)(struct InteropDeferred* thiz, uint8_t* data, int32_t length); + void (*reject)(struct InteropDeferred* thiz, const char* message); +} InteropDeferred; + +// Binary layout of InteropString must match that of KStringPtrImpl. +typedef struct InteropString { + const char* chars; + InteropInt32 length; +} InteropString; + +typedef struct InteropEmpty { + InteropInt32 dummy; // Empty structs are forbidden in C. +} InteropEmpty; + +typedef struct InteropNumber { + InteropInt8 tag; + union { + InteropFloat32 f32; + InteropInt32 i32; + }; +} InteropNumber; + +typedef struct InteropCustomObject { + char kind[20]; + InteropInt32 id; + // Data of custom object. + union { + InteropInt32 ints[4]; + InteropFloat32 floats[4]; + void* pointers[4]; + InteropString string; + }; +} InteropCustomObject; + +typedef struct InteropUndefined { + InteropInt32 dummy; // Empty structs are forbidden in C. +} InteropUndefined; + +typedef struct InteropVoid { + InteropInt32 dummy; // Empty structs are forbidden in C. +} InteropVoid; + +typedef struct InteropFunction { + InteropInt32 id; +} InteropFunction; +typedef InteropFunction InteropCallback; +typedef InteropFunction InteropErrorCallback; + +typedef struct InteropMaterialized { + InteropNativePointer ptr; +} InteropMaterialized; + +typedef struct InteropCallbackResource { + InteropInt32 resourceId; + void (*hold)(InteropInt32 resourceId); + void (*release)(InteropInt32 resourceId); +} InteropCallbackResource; + +typedef struct InteropBuffer { + InteropCallbackResource resource; + InteropNativePointer data; + InteropInt64 length; +} InteropBuffer; + +typedef struct InteropAsyncWork { + InteropNativePointer workId; + void (*queue)(InteropNativePointer workId); + void (*cancel)(InteropNativePointer workId); +} InteropAsyncWork; + +typedef struct InteropAsyncWorker { + InteropAsyncWork (*createWork)(InteropVMContext context, InteropNativePointer handle, + void (*execute)(InteropNativePointer handle), void (*complete)(InteropNativePointer handle)); +} InteropAsyncWorker; +typedef const InteropAsyncWorker* InteropAsyncWorkerPtr; + +typedef struct InteropObject { + InteropCallbackResource resource; +} InteropObject; + +#endif // _INTEROP_TYPES_H_ diff --git a/ets1.2/interop/src/cpp/interop-utils.h b/ets1.2/interop/src/cpp/interop-utils.h new file mode 100644 index 0000000000000000000000000000000000000000..6ba18695f860d1815f05a00d4a63852296ed7800 --- /dev/null +++ b/ets1.2/interop/src/cpp/interop-utils.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 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. + */ + +#ifndef _INTEROP_UTILS_H_ +#define _INTEROP_UTILS_H_ + +#include +#include + +#ifdef __STDC_LIB_EXT1__ +#include "securec.h" +#define USE_SAFE(name, ...) name##_s(__VA_ARGS__) +#else +/* handle possible unsafe case */ +#define USE_SAFE(name, ...) name(__VA_ARGS__) +#endif + +inline char* interop_strcpy(char* dest, size_t destsz, const char* src) +{ +#ifdef __STDC_LIB_EXT1__ + return reinterpret_cast(USE_SAFE(strcpy, dest, reinterpret_cast(destsz), src)); +#else + /* handle possible unsafe case */ + return USE_SAFE(strcpy, dest, src); +#endif +} + +inline char* interop_strcat(char* dest, size_t destsz, const char* src) +{ +#ifdef __STDC_LIB_EXT1__ + return reinterpret_cast(USE_SAFE(strcat, dest, reinterpret_cast(destsz), src)); +#else + /* handle possible unsafe case */ + return USE_SAFE(strcat, dest, src); +#endif +} + +inline void* interop_memcpy(void* dest, size_t destsz, const void* src, size_t count) +{ +#ifdef __STDC_LIB_EXT1__ + return reinterpret_cast(USE_SAFE(memcpy, dest, reinterpret_cast(destsz), src, count)); +#else + /* handle possible unsafe case */ + return USE_SAFE(memcpy, dest, src, count); +#endif +} + +inline void* interop_memset(void* dest, size_t destsz, int ch, size_t count) +{ +#ifdef __STDC_LIB_EXT1__ + return reinterpret_cast(USE_SAFE(memset, dest, reinterpret_cast(destsz), ch, count)) +#else + /* handle possible unsafe case */ + return USE_SAFE(memset, dest, ch, count); +#endif +} + +template +inline int interop_sprintf(char* buffer, size_t bufsz, const char* format, T... args) +{ +#ifdef __STDC_LIB_EXT1__ + return USE_SAFE(sprintf, buffer, reinterpret_cast(bufsz), format, args...); +#else + /* handle possible unsafe case */ + return USE_SAFE(sprintf, buffer, format, args...); +#endif +} + +template +inline int interop_snprintf(char* buffer, size_t bufsz, const char* format, T... args) +{ + return USE_SAFE(snprintf, buffer, bufsz, format, args...); +} + +inline int interop_vsnprintf(char* buffer, size_t bufsz, const char* format, va_list vlist) +{ + return USE_SAFE(vsnprintf, buffer, bufsz, format, vlist); +} + +inline size_t interop_strlen(const char* str) +{ +#ifdef __STDC_LIB_EXT1__ + return USE_SAFE(strnlen, str, UINT_MAX); +#else + /* handle possible unsafe case */ + return USE_SAFE(strlen, str); +#endif +} + +#endif // _INTEROP_UTILS_H_ \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/jni/convertors-jni.cc b/ets1.2/interop/src/cpp/jni/convertors-jni.cc new file mode 100644 index 0000000000000000000000000000000000000000..38071548f68fe469641d90c447c16b78e5a2a7c2 --- /dev/null +++ b/ets1.2/interop/src/cpp/jni/convertors-jni.cc @@ -0,0 +1,115 @@ +/* + * Copyright (c) 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. + */ + +#define KOALA_INTEROP_MODULE +#include "convertors-jni.h" + +#include "interop-logging.h" +#include "interop-types.h" +#include "signatures.h" + +static const char* nativeModule = "org/koalaui/arkoala/InteropNativeModule"; +static const char* nativeModulePrefix = "org/koalaui/arkoala/"; +static const char* callCallbackFromNative = "callCallbackFromNative"; +static const char* callCallbackFromNativeSig = "(I[BI)I"; + +const bool registerByOne = true; + +static bool registerNatives( + JNIEnv* env, jclass clazz, const std::vector> impls) +{ + constexpr auto NUM_0{0}; + constexpr auto NUM_1{1}; + constexpr auto NUM_2{2}; + size_t numMethods = impls.size(); + JNINativeMethod* methods = new JNINativeMethod[numMethods]; + bool result = true; + for (size_t i = 0; i < numMethods; i++) { + methods[i].name = (char*)std::get(impls[i]).c_str(); + methods[i].signature = (char*)std::get(impls[i]).c_str(); + methods[i].fnPtr = std::get(impls[i]); + if (registerByOne) { + result &= (env->RegisterNatives(clazz, methods + i, 1) >= 0); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + result = false; + } + } + } + return registerByOne ? true : env->RegisterNatives(clazz, methods, numMethods) >= 0; +} + +constexpr bool splitPerModule = true; + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_8) != JNI_OK) { + return JNI_ERR; + } + auto modules = JniExports::getInstance()->getModules(); + jclass defaultNativeModule = env->FindClass(nativeModule); + for (auto it = modules.begin(); it != modules.end(); ++it) { + std::string className = std::string(nativeModulePrefix) + *it; + jclass nativeModule = (!splitPerModule) ? defaultNativeModule : env->FindClass(className.c_str()); + if (nativeModule == nullptr) { + LOGE("Cannot find managed class %s", className.c_str()); + continue; + } + registerNatives(env, nativeModule, JniExports::getInstance()->getMethods(*it)); + } + if (!setKoalaJniCallbackDispatcher(env, defaultNativeModule, callCallbackFromNative, callCallbackFromNativeSig)) + return JNI_ERR; + return JNI_VERSION_1_8; +} + +JniExports* JniExports::getInstance() +{ + static JniExports* instance = nullptr; + if (instance == nullptr) { + instance = new JniExports(); + } + return instance; +} + +std::vector JniExports::getModules() +{ + std::vector result; + for (auto it = implementations.begin(); it != implementations.end(); ++it) { + result.push_back(it->first); + } + return result; +} + +const std::vector>& JniExports::getMethods(const std::string& module) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + LOGE("Module %s is not registered", module.c_str()); + INTEROP_FATAL("Fatal error: not registered module %s", module.c_str()); + } + return it->second; +} + +void JniExports::addMethod(const char* module, const char* name, const char* type, void* impl) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + it = implementations.insert(std::make_pair(module, std::vector>())) + .first; + } + it->second.push_back(std::make_tuple(name, convertType(name, type), impl)); +} diff --git a/ets1.2/interop/src/cpp/jni/convertors-jni.h b/ets1.2/interop/src/cpp/jni/convertors-jni.h new file mode 100644 index 0000000000000000000000000000000000000000..7d249e3691bcbd947c89708e68c584f2b6dbcfa1 --- /dev/null +++ b/ets1.2/interop/src/cpp/jni/convertors-jni.h @@ -0,0 +1,1518 @@ +/* + * Copyright (c) 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. + */ + +#ifndef CONVERTORS_JNI_H +#define CONVERTORS_JNI_H + +#ifdef KOALA_JNI + +#include +#include +#include +#include +#include +#include + +#include "interop-utils.h" +#include "koala-types.h" + +#define KOALA_JNI_CALL(type) extern "C" JNIEXPORT type JNICALL + +class JniExports { + std::unordered_map>> implementations; + +public: + static JniExports* getInstance(); + + std::vector getModules(); + void addMethod(const char* module, const char* name, const char* type, void* impl); + const std::vector>& getMethods(const std::string& module); +}; + +#define KOALA_QUOTE0(x) #x +#define KOALA_QUOTE(x) KOALA_QUOTE0(x) + +#ifdef _MSC_VER +#define MAKE_JNI_EXPORT(module, name, type) \ + static void __init_##name() \ + { \ + JniExports::getInstance()->addMethod( \ + KOALA_QUOTE(module), "_" #name, type, reinterpret_cast(Java_org_##name)); \ + } \ + namespace { \ + struct __Init_##name { \ + __Init_##name() \ + { \ + __init_##name(); \ + } \ + } __Init_##name##_v; \ + } +#else +#define MAKE_JNI_EXPORT(module, name, type) \ + __attribute__((constructor)) static void __init_jni_##name() \ + { \ + JniExports::getInstance()->addMethod( \ + KOALA_QUOTE(module), "_" #name, type, reinterpret_cast(Java_org_##name)); \ + } +#endif + +template +struct InteropTypeConverter { + using InteropType = T; + static T convertFrom(JNIEnv* env, InteropType value) + { + return value; + } + static InteropType convertTo(JNIEnv* env, T value) + { + return value; + } + static void release(JNIEnv* env, InteropType value, T converted) {} +}; + +template +struct SlowInteropTypeConverter { + using InteropType = T; + static inline T convertFrom(JNIEnv* env, InteropType value) + { + return value; + } + static inline InteropType convertTo(JNIEnv* env, T value) + { + return value; + } + static void release(JNIEnv* env, InteropType value, T converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = jstring; + static inline KStringPtr convertFrom0(JNIEnv* env, InteropType value) + { + if (value == nullptr) + return KStringPtr(); + jboolean isCopy; + // Improve: use GetStringCritical() instead and utf-8 encode manually. + const char* str_value = env->GetStringUTFChars(value, &isCopy); + int len = env->GetStringUTFLength(value); + KStringPtr result(str_value, len, false); + return result; + } + static KStringPtr convertFrom(JNIEnv* env, InteropType value) + { + if (value == nullptr) + return KStringPtr(); + KStringPtr result; + // Notice that we use UTF length for buffer size, but counter is expressed in number of Unicode chars. + result.resize(env->GetStringUTFLength(value)); + env->GetStringUTFRegion(value, 0, env->GetStringLength(value), result.data()); + return result; + } + static InteropType convertTo(JNIEnv* env, KStringPtr value) + { + return env->NewStringUTF(value.c_str()); + } + static inline void release(JNIEnv* env, InteropType value, const KStringPtr& converted) {} +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jobject; + static inline KVMObjectHandle convertFrom(JNIEnv* env, InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(JNIEnv* env, KVMObjectHandle value) + { + return reinterpret_cast(value); + } + static inline void release(JNIEnv* env, InteropType value, KVMObjectHandle converted) {} +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jstring; + static inline KStringPtr convertFrom(JNIEnv* env, InteropType value) + { + if (value == nullptr) + return KStringPtr(); + jboolean isCopy; + const char* str_value = env->GetStringUTFChars(value, &isCopy); + int len = env->GetStringLength(value); + KStringPtr result(str_value, len, false); + return result; + } + static InteropType convertTo(JNIEnv* env, KStringPtr value) + { + return env->NewStringUTF(value.c_str()); + } + static inline void release(JNIEnv* env, InteropType value, const KStringPtr& converted) + { + env->ReleaseStringUTFChars(value, converted.data()); + } +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jarray; + static inline KInteropBuffer convertFrom(JNIEnv* env, InteropType value) + { + if (value == nullptr) + return KInteropBuffer(); + KInteropBuffer result( + { env->GetArrayLength(value), reinterpret_cast(env->GetPrimitiveArrayCritical(value, nullptr)) }); + return result; + } + static InteropType convertTo(JNIEnv* env, KInteropBuffer value) + { + int bufferLength = value.length; + jarray result = env->NewByteArray(bufferLength); + void* data = env->GetPrimitiveArrayCritical(result, nullptr); + interop_memcpy(data, bufferLength, value.data, bufferLength); + env->ReleasePrimitiveArrayCritical(result, data, 0); + return result; + } + static inline void release(JNIEnv* env, InteropType value, const KInteropBuffer& converted) + { + env->ReleasePrimitiveArrayCritical(value, converted.data, 0); + } +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jarray; + static inline KInteropReturnBuffer convertFrom(JNIEnv* env, InteropType value) = delete; + static InteropType convertTo(JNIEnv* env, KInteropReturnBuffer value) + { + int bufferLength = value.length; + jarray result = env->NewByteArray(bufferLength); + void* data = env->GetPrimitiveArrayCritical(result, nullptr); + interop_memcpy(data, bufferLength, value.data, bufferLength); + env->ReleasePrimitiveArrayCritical(result, data, 0); + value.dispose(value.data, bufferLength); + return result; + } + static inline void release(JNIEnv* env, InteropType value, const KInteropReturnBuffer& converted) = delete; +}; + +template<> +struct InteropTypeConverter { + using InteropType = jbyteArray; + static inline KByte* convertFrom(JNIEnv* env, InteropType value) + { + return value ? reinterpret_cast(env->GetPrimitiveArrayCritical(value, nullptr)) : nullptr; + } + static InteropType convertTo(JNIEnv* env, KByte* value) = delete; + static inline void release(JNIEnv* env, InteropType value, KByte* converted) + { + if (converted) + env->ReleasePrimitiveArrayCritical(value, converted, 0); + } +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jbyteArray; + static inline KByte* convertFrom(JNIEnv* env, InteropType value) + { + return value ? reinterpret_cast(env->GetByteArrayElements(value, nullptr)) : nullptr; + } + static InteropType convertTo(JNIEnv* env, KByte* value) = delete; + static inline void release(JNIEnv* env, InteropType value, KByte* converted) + { + if (converted) + env->ReleaseByteArrayElements(value, reinterpret_cast(converted), 0); + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = jintArray; + static KInt* convertFrom(JNIEnv* env, InteropType value) + { + return value ? reinterpret_cast(env->GetPrimitiveArrayCritical(value, nullptr)) : nullptr; + } + static InteropType convertTo(JNIEnv* env, KInt* value) = delete; + static void release(JNIEnv* env, InteropType value, KInt* converted) + { + env->ReleasePrimitiveArrayCritical(value, converted, 0); + } +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jintArray; + static KInt* convertFrom(JNIEnv* env, InteropType value) + { + return value ? reinterpret_cast(env->GetIntArrayElements(value, nullptr)) : nullptr; + } + static InteropType convertTo(JNIEnv* env, KInt* value) = delete; + static void release(JNIEnv* env, InteropType value, KInt* converted) + { + env->ReleaseIntArrayElements(value, reinterpret_cast(converted), 0); + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = jfloatArray; + static KFloat* convertFrom(JNIEnv* env, InteropType value) + { + return value ? reinterpret_cast(env->GetPrimitiveArrayCritical(value, nullptr)) : nullptr; + } + static InteropType convertTo(JNIEnv* env, KFloat* value) = delete; + static void release(JNIEnv* env, InteropType value, KFloat* converted) + { + env->ReleasePrimitiveArrayCritical(value, converted, 0); + } +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jfloatArray; + static KFloat* convertFrom(JNIEnv* env, InteropType value) + { + return value ? reinterpret_cast(env->GetFloatArrayElements(value, nullptr)) : nullptr; + } + static InteropType convertTo(JNIEnv* env, KFloat* value) = delete; + static void release(JNIEnv* env, InteropType value, KFloat* converted) + { + env->ReleaseFloatArrayElements(value, reinterpret_cast(converted), 0); + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = jlong; + static KNativePointer convertFrom(JNIEnv* env, InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(JNIEnv* env, KNativePointer value) + { + return reinterpret_cast(value); + } + static inline void release(JNIEnv* env, InteropType value, KNativePointer converted) {} +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jlong; + static KNativePointer convertFrom(JNIEnv* env, InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(JNIEnv* env, KNativePointer value) + { + return reinterpret_cast(value); + } + static void release(JNIEnv* env, InteropType value, KNativePointer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = jdouble; + static KInteropNumber convertFrom(JNIEnv* env, InteropType value) + { + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(JNIEnv* env, KInteropNumber value) + { + return value.asDouble(); + } + static inline void release(JNIEnv* env, InteropType value, KInteropNumber converted) {} +}; + +template<> +struct SlowInteropTypeConverter { + using InteropType = jdouble; + static KInteropNumber convertFrom(JNIEnv* env, InteropType value) + { + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(JNIEnv* env, KInteropNumber value) + { + return value.asDouble(); + } + static void release(JNIEnv* env, InteropType value, KInteropNumber converted) {} +}; + +template +inline Type getArgument(JNIEnv* env, typename InteropTypeConverter::InteropType arg) +{ + return InteropTypeConverter::convertFrom(env, arg); +} + +template +inline void releaseArgument(JNIEnv* env, typename InteropTypeConverter::InteropType arg, Type& data) +{ + InteropTypeConverter::release(env, arg, data); +} + +#ifndef KOALA_INTEROP_MODULE +#error KOALA_INTEROP_MODULE is undefined +#endif + +#define KOALA_INTEROP_0(name, Ret) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) Java_org_##name(JNIEnv* env, jclass instance) \ + { \ + KOALA_MAYBE_LOG(name) \ + return InteropTypeConverter::convertTo(env, impl_##name()); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret) + +#define KOALA_INTEROP_1(name, Ret, P0) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0)); \ + releaseArgument(env, _p0, p0); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0) + +#define KOALA_INTEROP_2(name, Ret, P0, P1) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1) + +#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2) + +#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3) + +#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4) + +#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4, p5)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5) + +#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6) + +#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7) + +#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + return rv; \ + } \ + MAKE_JNI_EXPORT( \ + KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8) + +#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9) + +#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + auto rv = InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10) + +#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + auto rv = \ + InteropTypeConverter::convertTo(env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11) + +#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + auto rv = InteropTypeConverter::convertTo( \ + env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12) + +#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + KOALA_JNI_CALL(InteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + auto rv = InteropTypeConverter::convertTo( \ + env, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12 "|" #P13) + +#define KOALA_INTEROP_V0(name) \ + KOALA_JNI_CALL(void) Java_org_##name(JNIEnv* env, jclass instance) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void") + +#define KOALA_INTEROP_V1(name, P0) \ + KOALA_JNI_CALL(void) Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + impl_##name(p0); \ + releaseArgument(env, _p0, p0); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0) + +#define KOALA_INTEROP_V2(name, P0, P1) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + impl_##name(p0, p1); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1) + +#define KOALA_INTEROP_V3(name, P0, P1, P2) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + impl_##name(p0, p1, p2); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2) + +#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + impl_##name(p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3) + +#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + impl_##name(p0, p1, p2, p3, p4); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4) + +#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + impl_##name(p0, p1, p2, p3, p4, p5); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5) + +#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6) + +#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7) + +#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + } \ + MAKE_JNI_EXPORT( \ + KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8) + +#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9) + +#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10) + +#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11) + +#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 \ + "|" #P12) + +#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12 \ + "|" #P13) + +#define KOALA_INTEROP_V15(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13, InteropTypeConverter::InteropType _p14) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + P5 p5 = getArgument(env, _p5); \ + P6 p6 = getArgument(env, _p6); \ + P7 p7 = getArgument(env, _p7); \ + P8 p8 = getArgument(env, _p8); \ + P9 p9 = getArgument(env, _p9); \ + P10 p10 = getArgument(env, _p10); \ + P11 p11 = getArgument(env, _p11); \ + P12 p12 = getArgument(env, _p12); \ + P13 p13 = getArgument(env, _p13); \ + P14 p14 = getArgument(env, _p14); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + releaseArgument(env, _p5, p5); \ + releaseArgument(env, _p6, p6); \ + releaseArgument(env, _p7, p7); \ + releaseArgument(env, _p8, p8); \ + releaseArgument(env, _p9, p9); \ + releaseArgument(env, _p10, p10); \ + releaseArgument(env, _p11, p11); \ + releaseArgument(env, _p12, p12); \ + releaseArgument(env, _p13, p13); \ + releaseArgument(env, _p14, p14); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, \ + "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12 \ + "|" #P13 "|" #P14) + +#define KOALA_INTEROP_CTX_0(name, Ret) \ + KOALA_JNI_CALL(SlowInteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance) \ + { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = (KVMContext)env; \ + auto rv = SlowInteropTypeConverter::convertTo(env, impl_##name(ctx)); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret) + +#define KOALA_INTEROP_CTX_1(name, Ret, P0) \ + KOALA_JNI_CALL(SlowInteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = SlowInteropTypeConverter::convertTo(env, impl_##name(ctx, p0)); \ + releaseArgument(env, _p0, p0); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0) + +#define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \ + KOALA_JNI_CALL(SlowInteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = SlowInteropTypeConverter::convertTo(env, impl_##name(ctx, p0, p1)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1) + +#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ + KOALA_JNI_CALL(SlowInteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1, SlowInteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = SlowInteropTypeConverter::convertTo(env, impl_##name(ctx, p0, p1, p2)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2) + +#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \ + KOALA_JNI_CALL(SlowInteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1, SlowInteropTypeConverter::InteropType _p2, \ + SlowInteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = SlowInteropTypeConverter::convertTo(env, impl_##name(ctx, p0, p1, p2, p3)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3) + +#define KOALA_INTEROP_CTX_5(name, Ret, P0, P1, P2, P3, P4) \ + KOALA_JNI_CALL(SlowInteropTypeConverter::InteropType) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1, SlowInteropTypeConverter::InteropType _p2, \ + SlowInteropTypeConverter::InteropType _p3, SlowInteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + KVMContext ctx = (KVMContext)env; \ + auto rv = SlowInteropTypeConverter::convertTo(env, impl_##name(ctx, p0, p1, p2, p3, p4)); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + return rv; \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4) + +#define KOALA_INTEROP_CTX_V0(name) \ + KOALA_JNI_CALL(void) Java_org_##name(JNIEnv* env, jclass instance) \ + { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void") + +#define KOALA_INTEROP_CTX_V1(name, P0) \ + KOALA_JNI_CALL(void) Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0); \ + releaseArgument(env, _p0, p0); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0) + +#define KOALA_INTEROP_CTX_V2(name, P0, P1) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1) + +#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1, SlowInteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2) + +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1, SlowInteropTypeConverter::InteropType _p2, \ + SlowInteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3) + +#define KOALA_INTEROP_CTX_V5(name, P0, P1, P2, P3, P4) \ + KOALA_JNI_CALL(void) \ + Java_org_##name(JNIEnv* env, jclass instance, SlowInteropTypeConverter::InteropType _p0, \ + SlowInteropTypeConverter::InteropType _p1, SlowInteropTypeConverter::InteropType _p2, \ + SlowInteropTypeConverter::InteropType _p3, SlowInteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(env, _p0); \ + P1 p1 = getArgument(env, _p1); \ + P2 p2 = getArgument(env, _p2); \ + P3 p3 = getArgument(env, _p3); \ + P4 p4 = getArgument(env, _p4); \ + KVMContext ctx = (KVMContext)env; \ + impl_##name(ctx, p0, p1, p2, p3, p4); \ + releaseArgument(env, _p0, p0); \ + releaseArgument(env, _p1, p1); \ + releaseArgument(env, _p2, p2); \ + releaseArgument(env, _p3, p3); \ + releaseArgument(env, _p4, p4); \ + } \ + MAKE_JNI_EXPORT(KOALA_INTEROP_MODULE, name, "void|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4) + +#define KOALA_INTEROP_DIRECT_0(name, Ret) KOALA_INTEROP_0(name, Ret) +#define KOALA_INTEROP_DIRECT_1(name, Ret, P0) KOALA_INTEROP_1(name, Ret, P0) +#define KOALA_INTEROP_DIRECT_2(name, Ret, P0, P1) KOALA_INTEROP_2(name, Ret, P0, P1) +#define KOALA_INTEROP_DIRECT_3(name, Ret, P0, P1, P2) KOALA_INTEROP_3(name, Ret, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_4(name, Ret, P0, P1, P2, P3) KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_5(name, Ret, P0, P1, P2, P3, P4) KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_6(name, Ret, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) +#define KOALA_INTEROP_DIRECT_V0(name) KOALA_INTEROP_V0(name) +#define KOALA_INTEROP_DIRECT_V1(name, P0) KOALA_INTEROP_V1(name, P0) +#define KOALA_INTEROP_DIRECT_V2(name, P0, P1) KOALA_INTEROP_V2(name, P0, P1) +#define KOALA_INTEROP_DIRECT_V3(name, P0, P1, P2) KOALA_INTEROP_V3(name, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_V4(name, P0, P1, P2, P3) KOALA_INTEROP_V4(name, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_V5(name, P0, P1, P2, P3, P4) KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_V6(name, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_V7(name, P0, P1, P2, P3, P4, P5, P6) KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) + +bool setKoalaJniCallbackDispatcher( + JNIEnv* env, jclass clazz, const char* dispatcherMethodName, const char* dispactherMethodSig); +void getKoalaJniCallbackDispatcher(jclass* clazz, jmethodID* method); + +#define KOALA_INTEROP_CALL_VOID(venv, id, length, args) \ + { \ + jclass clazz = nullptr; \ + jmethodID method = nullptr; \ + getKoalaJniCallbackDispatcher(&clazz, &method); \ + JNIEnv* jniEnv = reinterpret_cast(venv); \ + jniEnv->PushLocalFrame(1); \ + jbyteArray args_jni = jniEnv->NewByteArray(length); \ + jniEnv->SetByteArrayRegion(args_jni, 0, length, reinterpret_cast(args)); \ + jniEnv->CallStaticIntMethod(clazz, method, id, args_jni, length); \ + jniEnv->GetByteArrayRegion(args_jni, 0, length, reinterpret_cast(args)); \ + jniEnv->PopLocalFrame(nullptr); \ + } + +#define KOALA_INTEROP_CALL_INT(venv, id, length, args) \ + { \ + jclass clazz = nullptr; \ + jmethodID method = nullptr; \ + getKoalaJniCallbackDispatcher(&clazz, &method); \ + JNIEnv* jniEnv = reinterpret_cast(venv); \ + jniEnv->PushLocalFrame(1); \ + jbyteArray args_jni = jniEnv->NewByteArray(length); \ + jniEnv->SetByteArrayRegion(args_jni, 0, length, reinterpret_cast(args)); \ + int32_t rv = jniEnv->CallStaticIntMethod(clazz, method, id, args_jni, length); \ + jniEnv->GetByteArrayRegion(args_jni, 0, length, reinterpret_cast(args)); \ + jniEnv->PopLocalFrame(nullptr); \ + return rv; \ + } + +#define KOALA_INTEROP_CALL_VOID_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_VOID(venv, id, (argc) * sizeof(int32_t), args) +#define KOALA_INTEROP_CALL_INT_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_INT(venv, id, (argc) * sizeof(int32_t), args) + +#define KOALA_INTEROP_THROW(vmContext, object, ...) \ + do { \ + JNIEnv* env = reinterpret_cast(vmContext); \ + env->Throw(object); \ + return __VA_ARGS__; \ + } while (0) + +#define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \ + do { \ + JNIEnv* env = reinterpret_cast(vmContext); \ + const static jclass errorClass = env->FindClass("java/lang/RuntimeException"); \ + env->ThrowNew(errorClass, message); \ + } while (0) + +#endif // KOALA_JNI_CALL + +#endif // CONVERTORS_JNI_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/jsc/convertors-jsc.cc b/ets1.2/interop/src/cpp/jsc/convertors-jsc.cc new file mode 100644 index 0000000000000000000000000000000000000000..0c0b56f140c78778fdd73c8519ed2eb3c25b7cc4 --- /dev/null +++ b/ets1.2/interop/src/cpp/jsc/convertors-jsc.cc @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#include "convertors-jsc.h" + +#include +#include <_types/_uint32_t.h> +#include <_types/_uint8_t.h> +#include + +#include "interop-logging.h" +#include "interop-utils.h" + +// See +// https://github.com/BabylonJS/BabylonNative/blob/master/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore.cc +// for convertors logic. + +KInt* getInt32Elements(JSContextRef context, const JSValueRef arguments) +{ + return getTypedElements(context, arguments); +} + +uint32_t* getUInt32Elements(JSContextRef context, const JSValueRef arguments) +{ + return getTypedElements(context, arguments); +} + +float* getFloat32Elements(JSContextRef context, const JSValueRef arguments) +{ + return getTypedElements(context, arguments); +} + +KByte* getByteElements(JSContextRef context, const JSValueRef arguments) +{ + return getTypedElements(context, arguments); +} + +KStringArray getKStringArray(JSContextRef context, const JSValueRef arguments) +{ + return getTypedElements(context, arguments); +} + +KUShort* getUShortElements(JSContextRef context, const JSValueRef arguments) +{ + return getTypedElements(context, arguments); +} + +KShort* getShortElements(JSContextRef context, const JSValueRef arguments) +{ + return getTypedElements(context, arguments); +} + +int32_t getInt32(JSContextRef context, JSValueRef value) +{ + JSValueRef exception {}; + if (JSValueIsNull(context, value)) { + return 0; + } + if (JSValueIsUndefined(context, value)) { + ASSERT(false); + return 0; + } + double result = JSValueToNumber(context, value, &exception); + return static_cast(result); +} + +uint32_t getUInt32(JSContextRef context, JSValueRef value) +{ + JSValueRef exception {}; + if (JSValueIsNull(context, value)) { + return 0; + } + if (JSValueIsUndefined(context, value)) { + ASSERT(false); + return 0; + } + double result = JSValueToNumber(context, value, &exception); + return static_cast(result); +} + +uint8_t getUInt8(JSContextRef context, JSValueRef value) +{ + JSValueRef exception {}; + if (JSValueIsNull(context, value)) { + return 0; + } + if (JSValueIsUndefined(context, value)) { + ASSERT(false); + return 0; + } + double result = JSValueToNumber(context, value, &exception); + return static_cast(result); +} + +/* +static JSStringRef bigintToArrayCastFuncName = JSStringCreateWithUTF8CString("__JSC__castFromBigInt"); +static JSStringRef bigintToArrayCastFuncParams[] = { JSStringCreateWithUTF8CString("ptr") }; +static JSStringRef bigintToArrayCastFuncBody = JSStringCreateWithUTF8CString( + "return new Uint32Array([ptr & 0xFFFFFFFFn, (ptr >> 32n) & 0xFFFFFFFFn]);" +); + +static JSStringRef arrayToBigintCastFuncName = JSStringCreateWithUTF8CString("__JSC__castToBigInt"); +static JSStringRef arrayToBigintCastFuncParams[] = { JSStringCreateWithUTF8CString("ptr") }; +static JSStringRef arrayToBigintCastFuncBody = JSStringCreateWithUTF8CString( + "return BigInt(ptr[1]) << 32n | BigInt(ptr[0])" +); +*/ + +#ifdef KOALA_JSC_USE_CALLBACK_CAST + +static JSStringRef bigIntFromPartsFuncName = JSStringCreateWithUTF8CString("__JSC__bigIntFromParts"); +static JSStringRef bigIntFromPartsFuncParams[] = { JSStringCreateWithUTF8CString("hi"), + JSStringCreateWithUTF8CString("lo") }; +static JSStringRef bigIntFromPartsFuncBody = JSStringCreateWithUTF8CString("return BigInt(hi) << 32n | BigInt(lo);"); + +static JSObjectRef getGlobalCallback(JSContextRef context, JSStringRef name, JSStringRef params[], JSStringRef body) +{ + JSObjectRef globalThis = JSContextGetGlobalObject(context); + JSValueRef propname = JSValueMakeString(context, name); + JSValueRef castFunc = JSObjectGetPropertyForKey(context, globalThis, propname, nullptr); + if (JSValueIsUndefined(context, castFunc)) { + JSObjectRef castFuncObj = JSObjectMakeFunction(context, name, 1, params, body, nullptr, 0, nullptr); + JSPropertyAttributes attributes = kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum; + JSObjectSetPropertyForKey(context, globalThis, propname, castFuncObj, attributes, nullptr); + return castFuncObj; + } + return JSValueToObject(context, castFunc, nullptr); +} + +static JSObjectRef getBigIntFromParts(JSContextRef context) +{ + return getGlobalCallback(context, bigIntFromPartsFuncName, bigIntFromPartsFuncParams, bigIntFromPartsFuncBody); +} + +#endif + +static JSValueRef u64ToBigInt(JSContextRef context, uint64_t value) +{ + JSValueRef bigint; +#ifdef KOALA_JSC_USE_CALLBACK_CAST + // Improve: benchmark this + JSObjectRef bigIntFromParts = getBigIntFromParts(context); + JSValueRef parts[2] = { + JSValueMakeNumber(context, (double)(value >> 32)), + JSValueMakeNumber(context, (double)(value & 0xFFFFFFFF)), + }; + contexpr auto ARGUMENT_COUNT{sizeof(parts)/sizeof(parts[0])}; + bigint = JSObjectCallAsFunction(context, bigIntFromParts, nullptr, ARGUMENT_COUNT, parts, nullptr); +#else + char buffer[128] = { 0 }; + interop_snprintf(buffer, sizeof(buffer) - 1, "%zun", static_cast(value)); + JSStringRef script = JSStringCreateWithUTF8CString(buffer); + contexpr auto ARGUMENT_COUNT{0}; + bigint = JSEvaluateScript(context, script, nullptr, nullptr, ARGUMENT_COUNT, nullptr); + JSStringRelease(script); +#endif + return bigint; +} + +static uint64_t bigIntToU64(JSContextRef ctx, JSValueRef value) +{ + char buf[128]; + JSStringRef strRef = JSValueToStringCopy(ctx, value, nullptr); + size_t len = JSStringGetUTF8CString(strRef, buf, sizeof(buf)); + JSStringRelease(strRef); + ASSERT(len < sizeof(buf)); + char* suf; + uint64_t numValue = std::strtoull(buf, &suf, 10); + ASSERT(*suf == '\0'); + return numValue; +} + +KNativePointer getPointer(JSContextRef context, JSValueRef value) +{ + uint64_t raw = bigIntToU64(context, value); + return reinterpret_cast(static_cast(raw)); +} + +KNativePointerArray getPointerElements(JSContextRef context, JSValueRef value) +{ + if (JSValueIsNull(context, value) || JSValueIsUndefined(context, value)) { + return nullptr; + } + + ASSERT(JSValueIsObject(context, value)); + ASSERT(JSValueGetTypedArrayType(context, value, nullptr) == kJSTypedArrayTypeBigUint64Array); + + JSObjectRef typedArray = JSValueToObject(context, value, nullptr); + return reinterpret_cast(JSObjectGetTypedArrayBytesPtr(context, typedArray, nullptr)); +} + +KFloat getFloat(JSContextRef context, JSValueRef value) +{ + JSValueRef exception {}; + if (JSValueIsNull(context, value)) { + return 0; + } + if (JSValueIsUndefined(context, value)) { + ASSERT(false); + return 0; + } + double result = JSValueToNumber(context, value, &exception); + return static_cast(result); +} + +KDouble getDouble(JSContextRef context, JSValueRef value) +{ + JSValueRef exception {}; + if (JSValueIsNull(context, value)) { + return 0; + } + if (JSValueIsUndefined(context, value)) { + ASSERT(false); + return 0; + } + return JSValueToNumber(context, value, &exception); +} + +KShort getShort(JSContextRef context, JSValueRef value) +{ + JSValueRef exception {}; + if (JSValueIsNull(context, value)) { + return 0; + } + if (JSValueIsUndefined(context, value)) { + ASSERT(false); + return 0; + } + double result = JSValueToNumber(context, value, &exception); + return static_cast(result); +} + +KUShort getUShort(JSContextRef context, JSValueRef value) +{ + JSValueRef exception {}; + if (JSValueIsNull(context, value)) { + return 0; + } + if (JSValueIsUndefined(context, value)) { + ASSERT(false); + return 0; + } + double result = JSValueToNumber(context, value, &exception); + return static_cast(result); +} + +KStringPtr getString(JSContextRef context, JSValueRef value) +{ + if (JSValueIsNull(context, value)) { + return KStringPtr(); + } + if (JSValueIsUndefined(context, value)) { + return KStringPtr(); + } + KStringPtr result; + JSStringRef valueString = JSValueToStringCopy(context, value, NULL); + size_t size = JSStringGetMaximumUTF8CStringSize(valueString); + result.resize(size); + JSStringGetUTF8CString(valueString, result.data(), size); + JSStringRelease(valueString); + return result; +} + +KBoolean getBoolean(JSContextRef context, JSValueRef value) +{ + bool result = JSValueToBoolean(context, value); + return static_cast(result); +} + +JSValueRef makeInt32(JSContextRef context, int32_t value) +{ + return JSValueMakeNumber(context, value); +} + +JSValueRef makeUInt32(JSContextRef context, uint32_t value) +{ + return JSValueMakeNumber(context, value); +} + +JSValueRef makePointer(JSContextRef context, KNativePointer value) +{ + return u64ToBigInt(context, static_cast(reinterpret_cast(value))); +} + +JSValueRef makeFloat(JSContextRef context, KFloat value) +{ + return JSValueMakeNumber(context, value); +} + +JSValueRef makeDouble(JSContextRef context, KDouble value) +{ + return JSValueMakeNumber(context, value); +} + +JSValueRef makeBoolean(JSContextRef context, KBoolean value) +{ + return JSValueMakeBoolean(context, value); +} + +JSValueRef makeVoid(JSContextRef context) +{ + return JSValueMakeUndefined(context); +} + +Exports* Exports::getInstance() +{ + static Exports* instance = nullptr; + if (instance == nullptr) { + instance = new Exports(); + } + return instance; +} + +void InitExports(JSGlobalContextRef globalContext) +{ + JSObjectRef globalObject = JSContextGetGlobalObject(globalContext); + for (auto impl : Exports::getInstance()->getImpls()) { + JSStringRef functionName = JSStringCreateWithUTF8CString(impl.first.c_str()); + JSObjectRef functionObject = JSObjectMakeFunctionWithCallback(globalContext, functionName, impl.second); + JSObjectSetProperty( + globalContext, globalObject, functionName, functionObject, kJSPropertyAttributeNone, nullptr); + JSStringRelease(functionName); + } +} diff --git a/ets1.2/interop/src/cpp/jsc/convertors-jsc.h b/ets1.2/interop/src/cpp/jsc/convertors-jsc.h new file mode 100644 index 0000000000000000000000000000000000000000..c00fb7ebc8e71919108725ed9232089174b5b219 --- /dev/null +++ b/ets1.2/interop/src/cpp/jsc/convertors-jsc.h @@ -0,0 +1,870 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#ifndef CONVERTORS_JSC_H +#define CONVERTORS_JSC_H + +#if defined(linux) +#include // For IDE completion +#else +#include +#endif +#include <_types/_uint8_t.h> +#include +#include +#include + +#include "interop-logging.h" +#include "koala-types.h" + +template +inline ElemType* getTypedElements(JSContextRef context, const JSValueRef arguments) +{ + if (JSValueIsNull(context, arguments)) { + return nullptr; + } + if (JSValueIsUndefined(context, arguments)) { + ASSERT(false); + return nullptr; + } + JSValueRef exception {}; + ElemType* data = reinterpret_cast( + JSObjectGetTypedArrayBytesPtr(context, JSValueToObject(context, arguments, &exception), &exception)); + return data; +} + +template +inline ElemType* getTypedElements(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getTypedElements(context, arguments[index]); +} + +uint8_t* getUInt8Elements(JSContextRef context, const JSValueRef arguments); +int32_t* getInt32Elements(JSContextRef context, const JSValueRef arguments); +uint32_t* getUInt32Elements(JSContextRef context, const JSValueRef arguments); +float* getFloat32Elements(JSContextRef context, const JSValueRef arguments); +KByte* getByteElements(JSContextRef context, const JSValueRef arguments); +KUShort* getUShortElements(JSContextRef context, const JSValueRef arguments); +KShort* getShortElements(JSContextRef context, const JSValueRef arguments); +KNativePointerArray getPointerElements(JSContextRef context, const JSValueRef arguments); +KStringArray getKStringArray(JSContextRef context, const JSValueRef arguments); + +uint8_t getUInt8(JSContextRef context, JSValueRef value); +int32_t getInt32(JSContextRef context, JSValueRef value); +uint32_t getUInt32(JSContextRef context, JSValueRef value); +KNativePointer getPointer(JSContextRef context, JSValueRef value); +KFloat getFloat(JSContextRef context, JSValueRef value); +KDouble getDouble(JSContextRef context, JSValueRef value); +KStringPtr getString(JSContextRef context, JSValueRef value); +KBoolean getBoolean(JSContextRef context, JSValueRef value); +KStringPtr getString(JSContextRef context, JSValueRef value); + +template +inline Type getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) = delete; + +template<> +inline int32_t getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getInt32(context, arguments[index]); +} + +template<> +inline uint32_t getArgument( + JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getUInt32(context, arguments[index]); +} + +template<> +inline uint8_t getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getUInt8(context, arguments[index]); +} + +template<> +inline KNativePointer getArgument( + JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getPointer(context, arguments[index]); +} + +template<> +inline KFloat getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getFloat(context, arguments[index]); +} + +template<> +inline KDouble getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getDouble(context, arguments[index]); +} + +template<> +inline KStringPtr getArgument( + JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getString(context, arguments[index]); +} + +template<> +inline KBoolean getArgument( + JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getBoolean(context, arguments[index]); +} + +template<> +inline KInt* getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getInt32Elements(context, arguments[index]); +} + +template<> +inline float* getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getFloat32Elements(context, arguments[index]); +} + +template<> +inline KByte* getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getByteElements(context, arguments[index]); +} + +template<> +inline KStringArray getArgument( + JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getKStringArray(context, arguments[index]); +} + +template<> +inline KUShort* getArgument( + JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getUShortElements(context, arguments[index]); +} + +template<> +inline KNativePointerArray getArgument( + JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getPointerElements(context, arguments[index]); +} + +template<> +inline KShort* getArgument(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], int index) +{ + ASSERT(index < argumentCount); + return getShortElements(context, arguments[index]); +} + +JSValueRef makeInt32(JSContextRef context, int32_t value); +JSValueRef makeUInt32(JSContextRef context, uint32_t value); +JSValueRef makePointer(JSContextRef context, KNativePointer value); +JSValueRef makeFloat(JSContextRef context, KFloat value); +JSValueRef makeDouble(JSContextRef context, KDouble value); +JSValueRef makeBoolean(JSContextRef context, KBoolean value); +JSValueRef makeVoid(JSContextRef context); + +template +inline JSValueRef makeResult(JSContextRef context, Type value) = delete; + +template<> +inline JSValueRef makeResult(JSContextRef context, int32_t value) +{ + return makeInt32(context, value); +} + +template<> +inline JSValueRef makeResult(JSContextRef context, uint32_t value) +{ + return makeUInt32(context, value); +} + +template<> +inline JSValueRef makeResult(JSContextRef context, KNativePointer value) +{ + return makePointer(context, value); +} + +template<> +inline JSValueRef makeResult(JSContextRef context, KFloat value) +{ + return makeFloat(context, value); +} + +template<> +inline JSValueRef makeResult(JSContextRef context, KDouble value) +{ + return makeDouble(context, value); +} + +template<> +inline JSValueRef makeResult(JSContextRef context, KBoolean value) +{ + return makeBoolean(context, value); +} + +typedef JSValueRef (*jsc_type_t)(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, + const JSValueRef arguments[], JSValueRef* exception); + +class Exports { + std::vector> implementations; + +public: + static Exports* getInstance(); + + void addImpl(const char* name, jsc_type_t impl) + { + implementations.push_back(std::make_pair(name, impl)); + } + + const std::vector>& getImpls() + { + return implementations; + } +}; + +void InitExports(JSGlobalContextRef globalContext); + +#define MAKE_JSC_EXPORT(name) \ + __attribute__((constructor)) static void __init_##name() \ + { \ + Exports::getInstance()->addImpl("_" #name, Jsc_##name); \ + } + +#define MAKE_JSC_EXPORT_V1(name) \ + __attribute__((constructor)) static void __init_##name() \ + { \ + Exports::getInstance()->addImpl(#name, Jsc_##name); \ + } + +#define KOALA_INTEROP_0(name, Ret) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + return makeResult(ctx, impl_##name()); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_1(name, Ret, P0) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + return makeResult(ctx, impl_##name(p0)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_2(name, Ret, P0, P1) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + return makeResult(ctx, impl_##name(p0, p1)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + return makeResult(ctx, impl_##name(p0, p1, p2)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + P11 p11 = getArgument(ctx, argumentCount, arguments, 11); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + P11 p11 = getArgument(ctx, argumentCount, arguments, 11); \ + P12 p12 = getArgument(ctx, argumentCount, arguments, 12); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + P11 p11 = getArgument(ctx, argumentCount, arguments, 11); \ + P12 p12 = getArgument(ctx, argumentCount, arguments, 12); \ + P13 p13 = getArgument(ctx, argumentCount, arguments, 13); \ + return makeResult(ctx, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V0(name) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V1(name, P0) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + impl_##name(p0); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V2(name, P0, P1) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + impl_##name(p0, p1); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V3(name, P0, P1, P2) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + impl_##name(p0, p1, p2); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + impl_##name(p0, p1, p2, p3); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + impl_##name(p0, p1, p2, p3, p4); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + impl_##name(p0, p1, p2, p3, p4, p5); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + P11 p11 = getArgument(ctx, argumentCount, arguments, 11); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + P11 p11 = getArgument(ctx, argumentCount, arguments, 11); \ + P12 p12 = getArgument(ctx, argumentCount, arguments, 12); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + P4 p4 = getArgument(ctx, argumentCount, arguments, 4); \ + P5 p5 = getArgument(ctx, argumentCount, arguments, 5); \ + P6 p6 = getArgument(ctx, argumentCount, arguments, 6); \ + P7 p7 = getArgument(ctx, argumentCount, arguments, 7); \ + P8 p8 = getArgument(ctx, argumentCount, arguments, 8); \ + P9 p9 = getArgument(ctx, argumentCount, arguments, 9); \ + P10 p10 = getArgument(ctx, argumentCount, arguments, 10); \ + P11 p11 = getArgument(ctx, argumentCount, arguments, 11); \ + P12 p12 = getArgument(ctx, argumentCount, arguments, 12); \ + P13 p13 = getArgument(ctx, argumentCount, arguments, 13); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +// Improve: implement properly +#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + printf("Improve: implement KOALA_INTEROP_CTX_3 for jsc"); \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + return makeResult(ctx, impl_##name(nullptr, p0, p1, p2)); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P4) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + printf("Improve: implement KOALA_INTEROP_CTX_4 for jsc"); \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + return makeResult(ctx, impl_##name(nullptr, p0, p1, p2, p3)); \ + } \ + MAKE_JSC_EXPORT(name) + +// Improve: implement properly +#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + printf("Improve: implement KOALA_INTEROP_CTX_V3 for jsc"); \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + impl_##name(nullptr, p0, p1, p2); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + JSValueRef Jsc_##name(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, \ + const JSValueRef arguments[], JSValueRef* exception) \ + { \ + printf("Improve: implement KOALA_INTEROP_CTX_V4 for jsc"); \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(ctx, argumentCount, arguments, 0); \ + P1 p1 = getArgument(ctx, argumentCount, arguments, 1); \ + P2 p2 = getArgument(ctx, argumentCount, arguments, 2); \ + P3 p3 = getArgument(ctx, argumentCount, arguments, 3); \ + impl_##name(nullptr, p0, p1, p2, p3); \ + return makeVoid(ctx); \ + } \ + MAKE_JSC_EXPORT(name) + +#define KOALA_INTEROP_DIRECT_0(name, Ret) KOALA_INTEROP_0(name, Ret) +#define KOALA_INTEROP_DIRECT_1(name, Ret, P0) KOALA_INTEROP_1(name, Ret, P0) +#define KOALA_INTEROP_DIRECT_2(name, Ret, P0, P1) KOALA_INTEROP_2(name, Ret, P0, P1) +#define KOALA_INTEROP_DIRECT_3(name, Ret, P0, P1, P2) KOALA_INTEROP_3(name, Ret, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_4(name, Ret, P0, P1, P2, P3) KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_5(name, Ret, P0, P1, P2, P3, P4) KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_6(name, Ret, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) +#define KOALA_INTEROP_DIRECT_V0(name) KOALA_INTEROP_V0(name) +#define KOALA_INTEROP_DIRECT_V1(name, P0) KOALA_INTEROP_V1(name, P0) +#define KOALA_INTEROP_DIRECT_V2(name, P0, P1) KOALA_INTEROP_V2(name, P0, P1) +#define KOALA_INTEROP_DIRECT_V3(name, P0, P1, P2) KOALA_INTEROP_V3(name, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_V4(name, P0, P1, P2, P3) KOALA_INTEROP_V4(name, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_V5(name, P0, P1, P2, P3, P4) KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_V6(name, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_V7(name, P0, P1, P2, P3, P4, P5, P6) KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) + +#define KOALA_INTEROP_THROW(vmContext, object, ...) \ + do { \ + /* Improve: implement*/ ASSERT(false); \ + return __VA_ARGS__; \ + } while (0) + +#define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \ + do { \ + ASSERT(false); /* Improve: implement*/ \ + return __VA_ARGS__; \ + } while (0) + +#endif // CONVERTORS_JSC_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/napi/convertors-napi.cc b/ets1.2/interop/src/cpp/napi/convertors-napi.cc new file mode 100644 index 0000000000000000000000000000000000000000..63d27e5738a7e6c1d13e3c14e29fc17cccd929b1 --- /dev/null +++ b/ets1.2/interop/src/cpp/napi/convertors-napi.cc @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2022-2023 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. + */ +#include +#include +#include +#include + +#include "interop-logging.h" +#undef KOALA_INTEROP_MODULE +#define KOALA_INTEROP_MODULE InteropNativeModule +#include "convertors-napi.h" + +// Adapter for NAPI_MODULE +#define NODE_API_MODULE_ADAPTER(modname, regfunc) \ + static napi_value __napi_##regfunc(napi_env env, napi_value exports) \ + { \ + return Napi::RegisterModule(env, exports, regfunc); \ + } \ + NAPI_MODULE(modname, __napi_##regfunc) + +napi_valuetype getValueTypeChecked(napi_env env, napi_value value) +{ + napi_valuetype type; + napi_status status = napi_typeof(env, value, &type); + KOALA_NAPI_THROW_IF_FAILED(env, status, napi_undefined); + return type; +} + +bool isTypedArray(napi_env env, napi_value value) +{ + bool result = false; + napi_status status = napi_is_typedarray(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, false); + return result; +} + +KBoolean getBoolean(napi_env env, napi_value value) +{ + if (getValueTypeChecked(env, value) == napi_valuetype::napi_boolean) { + bool result = false; + napi_get_value_bool(env, value, &result); + return static_cast(result); + } + return static_cast(getInt32(env, value) != 0); +} + +KInt getInt32(napi_env env, napi_value value) +{ + if (getValueTypeChecked(env, value) != napi_valuetype::napi_number) { + napi_throw_error(env, nullptr, "Expected Number"); + return 0; + } + int32_t result = false; + napi_get_value_int32(env, value, &result); + return static_cast(result); +} + +KUInt getUInt32(napi_env env, napi_value value) +{ + if (getValueTypeChecked(env, value) != napi_valuetype::napi_number) { + napi_throw_error(env, nullptr, "Expected Number"); + return 0; + } + uint32_t result = false; + napi_get_value_uint32(env, value, &result); + return static_cast(result); +} + +KFloat getFloat32(napi_env env, napi_value value) +{ + if (getValueTypeChecked(env, value) != napi_valuetype::napi_number) { + napi_throw_error(env, nullptr, "Expected Number"); + return 0.0f; + } + double result = false; + napi_get_value_double(env, value, &result); + return static_cast(static_cast(result)); +} + +KDouble getFloat64(napi_env env, napi_value value) +{ + if (getValueTypeChecked(env, value) != napi_valuetype::napi_number) { + napi_throw_error(env, nullptr, "Expected Number"); + return 0.0; + } + double result = false; + napi_get_value_double(env, value, &result); + return static_cast(result); +} + +KStringPtr getString(napi_env env, napi_value value) +{ + KStringPtr result {}; + napi_valuetype valueType = getValueTypeChecked(env, value); + if (valueType == napi_valuetype::napi_null || valueType == napi_valuetype::napi_undefined) { + return result; + } + + if (valueType != napi_valuetype::napi_string) { + napi_throw_error(env, nullptr, "Expected String"); + return result; + } + + size_t length = 0; + napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &length); + if (status != 0) + return result; + result.resize(length); + status = napi_get_value_string_utf8(env, value, result.data(), length + 1, nullptr); + return result; +} + +KNativePointer getPointerSlow(napi_env env, napi_value value) +{ + napi_valuetype valueType = getValueTypeChecked(env, value); + if (valueType == napi_valuetype::napi_external) { + KNativePointer result = nullptr; + napi_status status = napi_get_value_external(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, nullptr); + return result; + } + + if (valueType != napi_valuetype::napi_bigint) { + napi_throw_error(env, nullptr, "cannot be coerced to pointer"); + return nullptr; + } + + bool isWithinRange = true; + uint64_t ptrU64 = 0; + napi_status status = napi_get_value_bigint_uint64(env, value, &ptrU64, &isWithinRange); + KOALA_NAPI_THROW_IF_FAILED(env, status, nullptr); + if (!isWithinRange) { + napi_throw_error(env, nullptr, "cannot be coerced to uint64, value is too large"); + return nullptr; + } + return reinterpret_cast(ptrU64); +} + +KLong getInt64(napi_env env, napi_value value) +{ + if (getValueTypeChecked(env, value) == napi_valuetype::napi_number) { + int64_t result = 0; + if (napi_get_value_int64(env, value, &result) != napi_ok) { + napi_throw_error(env, nullptr, "cannot be coerced to int64"); + return -1; + } + return static_cast(result); + } + if (getValueTypeChecked(env, value) == napi_valuetype::napi_bigint) { + bool isWithinRange = true; + int64_t ptr64 = 0; + if (napi_get_value_bigint_int64(env, value, &ptr64, &isWithinRange) != napi_ok) { + napi_throw_error(env, nullptr, "cannot be coerced to int64"); + return -1; + } + if (!isWithinRange) { + napi_throw_error(env, nullptr, "cannot be coerced to int64, value is too large"); + return -1; + } + return static_cast(ptr64); + } + napi_throw_error(env, nullptr, "cannot be coerced to int64"); + return -1; +} + +KULong getUInt64(napi_env env, napi_value value) +{ + if (getValueTypeChecked(env, value) != napi_valuetype::napi_bigint) { + napi_throw_error(env, nullptr, "cannot be coerced to uint64"); + return -1; + } + + bool isWithinRange = true; + uint64_t ptr64 = 0; + napi_get_value_bigint_uint64(env, value, &ptr64, &isWithinRange); + if (!isWithinRange) { + napi_throw_error(env, nullptr, "cannot be coerced to uint64, value is too large"); + return -1; + } + return static_cast(ptr64); +} + +napi_value makeString(napi_env env, const KStringPtr& value) +{ + napi_value result; + napi_status status; + status = napi_create_string_utf8(env, value.isNull() ? "" : value.data(), value.length(), &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeString(napi_env env, const std::string& value) +{ + napi_value result; + napi_status status; + status = napi_create_string_utf8(env, value.c_str(), value.length(), &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeBoolean(napi_env env, int8_t value) +{ + napi_value result; + napi_status status; + status = napi_get_boolean(env, value != 0, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeInt32(napi_env env, int32_t value) +{ + napi_value result; + napi_status status; + status = napi_create_int32(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeUInt32(napi_env env, uint32_t value) +{ + napi_value result; + napi_status status; + status = napi_create_uint32(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeInt64(napi_env env, int64_t value) +{ + napi_value result; + napi_status status; + status = napi_create_bigint_int64(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeUInt64(napi_env env, uint64_t value) +{ + napi_value result; + napi_status status; + status = napi_create_bigint_uint64(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeFloat32(napi_env env, float value) +{ + napi_value result; + napi_status status; + status = napi_create_double(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeFloat64(napi_env env, double value) +{ + napi_value result; + napi_status status; + status = napi_create_double(env, value, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makePointer(napi_env env, void* value) +{ + napi_value result; + napi_status status; + status = napi_create_bigint_uint64(env, static_cast(reinterpret_cast(value)), &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeVoid(napi_env env) +{ + napi_value result; + napi_status status; + status = napi_get_undefined(env, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +napi_value makeObject(napi_env env, napi_value object) +{ + napi_value result; + napi_status status; + status = napi_create_object(env, &result); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + return result; +} + +#if _MSC_VER >= 1932 // Visual Studio 2022 version 17.2+ +#pragma comment(linker, "/alternatename:__imp___std_init_once_complete=__imp_InitOnceComplete") +#pragma comment(linker, "/alternatename:__imp___std_init_once_begin_initialize=__imp_InitOnceBeginInitialize") +#endif + +Exports* Exports::getInstance() +{ + static Exports* instance = nullptr; + if (instance == nullptr) { + instance = new Exports(); + } + return instance; +} + +std::vector Exports::getModules() +{ + std::vector result; + for (auto it = implementations.begin(); it != implementations.end(); ++it) { + result.push_back(it->first); + } + return result; +} + +void Exports::addMethod(const char* module, const char* name, napi_type_t impl) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + it = implementations.insert(std::make_pair(module, std::vector>())).first; + } + it->second.push_back(std::make_pair(name, impl)); +} + +const std::vector>& Exports::getMethods(const std::string& module) +{ + auto it = implementations.find(module); + if (it == implementations.end()) { + LOGE("Module %s is not registered", module.c_str()); + INTEROP_FATAL("Fatal error"); + } + return it->second; +} + +// +// Callback dispatcher +// +// Improve: Should we get rid of explicit Node_* declrations and hide the naming convention behind the macro +// definitions? + +static napi_ref g_koalaNapiCallbackDispatcher = nullptr; + +// Improve: shall we pass name in globalThis instead of object reference? +napi_value Node_SetCallbackDispatcher(napi_env env, napi_callback_info cbinfo) +{ + fprintf(stderr, "Node_SetCallbackDispatcher!\n"); + + CallbackInfo info(env, cbinfo); + napi_value dispatcher = info[0]; + napi_value result = makeVoid(env); + napi_status status = napi_create_reference(env, dispatcher, 1, &g_koalaNapiCallbackDispatcher); + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + + return result; +} +MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, SetCallbackDispatcher) + +napi_value Node_CleanCallbackDispatcher(napi_env env, napi_callback_info cbinfo) +{ + napi_value result = makeVoid(env); + if (g_koalaNapiCallbackDispatcher) { + napi_status status = napi_delete_reference(env, g_koalaNapiCallbackDispatcher); + g_koalaNapiCallbackDispatcher = nullptr; + KOALA_NAPI_THROW_IF_FAILED(env, status, result); + } + return result; +} +MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, CleanCallbackDispatcher) + +napi_value getKoalaNapiCallbackDispatcher(napi_env env) +{ + if (!g_koalaNapiCallbackDispatcher) { + abort(); + } + napi_value value; + napi_status status = napi_get_reference_value(env, g_koalaNapiCallbackDispatcher, &value); + KOALA_NAPI_THROW_IF_FAILED(env, status, makeVoid(env)); + return value; +} + +// +// Module initialization +// + +using ModuleRegisterCallback = napi_value (*)(napi_env env, napi_value exports); + +/** + * Sets a new callback and returns its previous value. + */ +ModuleRegisterCallback ProvideModuleRegisterCallback(ModuleRegisterCallback value = nullptr) +{ + static const ModuleRegisterCallback DEFAULT_CB = [](napi_env env, napi_value exports) { return exports; }; + static ModuleRegisterCallback curCallback = DEFAULT_CB; + + ModuleRegisterCallback prevCallback = curCallback; + curCallback = value ? value : DEFAULT_CB; + return prevCallback; +} + +static constexpr bool splitModules = true; + +static napi_value InitModule(napi_env env, napi_value exports) +{ + Exports* inst = Exports::getInstance(); + napi_status status; + napi_value target = exports; + for (const auto& module : inst->getModules()) { + if (splitModules) { + status = napi_create_object(env, &target); + KOALA_NAPI_THROW_IF_FAILED(env, status, exports); + status = napi_set_named_property(env, exports, module.c_str(), target); + KOALA_NAPI_THROW_IF_FAILED(env, status, exports); + } + + for (const auto& impl : inst->getMethods(module)) { + napi_value implFunc; + status = napi_create_function(env, impl.first.c_str(), NAPI_AUTO_LENGTH, impl.second, nullptr, &implFunc); + KOALA_NAPI_THROW_IF_FAILED(env, status, exports); + status = napi_set_named_property(env, target, impl.first.c_str(), implFunc); + KOALA_NAPI_THROW_IF_FAILED(env, status, exports); + } + } + return ProvideModuleRegisterCallback()(env, exports); +} + +NAPI_MODULE(INTEROP_LIBRARY_NAME, InitModule) diff --git a/ets1.2/interop/src/cpp/napi/convertors-napi.h b/ets1.2/interop/src/cpp/napi/convertors-napi.h new file mode 100644 index 0000000000000000000000000000000000000000..4e75183815fff691a282bd75c6383cd81d30e58b --- /dev/null +++ b/ets1.2/interop/src/cpp/napi/convertors-napi.h @@ -0,0 +1,1575 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#ifndef _CONVERTORS_NAPI_H_ +#define _CONVERTORS_NAPI_H_ + +#ifdef KOALA_NAPI + +#include +#include +#include + +#ifndef KOALA_NAPI_OHOS +#include +#else +#include +#include +#endif +#include "interop-types.h" +#include "koala-types.h" + +// Improve: switch to more generic convertors eventually. +template +struct InteropTypeConverter { + using InteropType = T; + static T convertFrom(napi_env env, InteropType value) + { + return value; + } + static InteropType convertTo(napi_env env, T value) + { + return value; + } + static void release(napi_env env, InteropType value, T converted) {} +}; + +template +inline typename InteropTypeConverter::InteropType makeResult(napi_env env, Type value) +{ + return InteropTypeConverter::convertTo(env, value); +} + +template +inline Type getArgument(napi_env env, typename InteropTypeConverter::InteropType arg) +{ + return InteropTypeConverter::convertFrom(env, arg); +} + +template +inline void releaseArgument(napi_env env, typename InteropTypeConverter::InteropType arg, Type data) +{ + InteropTypeConverter::release(env, arg, data); +} + +napi_value makeString(napi_env env, KStringPtr value); +napi_value makeString(napi_env env, const std::string& value); +napi_value makeBoolean(napi_env env, KBoolean value); +napi_value makeInt32(napi_env env, int32_t value); +napi_value makeUInt32(napi_env env, uint32_t value); +napi_value makeInt64(napi_env env, int64_t value); +napi_value makeUInt64(napi_env env, uint64_t value); +napi_value makeFloat32(napi_env env, float value); +napi_value makeFloat64(napi_env env, double value); +napi_value makePointer(napi_env env, void* value); +napi_value makeVoid(napi_env env); + +void* getPointerSlow(napi_env env, napi_value value); + +inline void* getPointer(napi_env env, napi_value value) +{ + bool isWithinRange = true; + uint64_t ptrU64 = 0; + napi_status status = napi_get_value_bigint_uint64(env, value, &ptrU64, &isWithinRange); + if (status != 0 || !isWithinRange) + return getPointerSlow(env, value); + else + return reinterpret_cast(ptrU64); +} +void* getSerializerBufferPointer(napi_env env, napi_value value); + +template<> +struct InteropTypeConverter { + using InteropType = napi_value; + static KInteropBuffer convertFrom(napi_env env, InteropType value) + { + KInteropBuffer result {}; + bool isArrayBuffer = false; + napi_is_arraybuffer(env, value, &isArrayBuffer); + if (isArrayBuffer) { + napi_get_arraybuffer_info(env, value, &result.data, reinterpret_cast(&result.length)); + } else { + bool isDataView = false; + napi_is_dataview(env, value, &isDataView); + if (isDataView) { + napi_get_dataview_info( + env, value, reinterpret_cast(&result.length), &result.data, nullptr, nullptr); + } + } + return result; + } + static InteropType convertTo(napi_env env, KInteropBuffer value) + { + KInteropBuffer* copy = new KInteropBuffer(value); + napi_value result; + napi_status status = napi_create_external_arraybuffer( + env, value.data, value.length, + [](napi_env env, void* finalize_data, void* finalize_hint) { + KInteropBuffer* buffer = reinterpret_cast(finalize_hint); + buffer->dispose(buffer->resourceId); + delete buffer; + }, + (void*)copy, &result); + if (status != napi_ok) { + // do smth here + } + return result; + }; + static void release(napi_env env, InteropType value, KInteropBuffer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = napi_value; + static KStringPtr convertFrom(napi_env env, InteropType value) + { + if (value == nullptr) + return KStringPtr(); + KStringPtr result; + size_t length = 0; + napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &length); + if (status != 0) + return result; + result.resize(length); + status = napi_get_value_string_utf8(env, value, result.data(), length + 1, nullptr); + return result; + } + static InteropType convertTo(napi_env env, const KStringPtr& value) + { + napi_value result; + napi_create_string_utf8(env, value.c_str(), value.length(), &result); + return result; + } + static void release(napi_env env, InteropType value, const KStringPtr& converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = napi_value; + static KInteropNumber convertFrom(napi_env env, InteropType interopValue) + { + double value = 0.0; + napi_get_value_double(env, interopValue, &value); + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(napi_env env, KInteropNumber value) + { + napi_value result; + napi_create_double(env, value.asDouble(), &result); + return result; + } + static void release(napi_env env, InteropType value, KInteropNumber converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = napi_value; + static KSerializerBuffer convertFrom(napi_env env, InteropType value) + { + return (KSerializerBuffer)getSerializerBufferPointer( + env, value); // Improve: we are receiving Uint8Array from the native side + } + static InteropType convertTo(napi_env env, KSerializerBuffer value) + { + return makePointer(env, value); + } + static void release(napi_env env, InteropType value, KSerializerBuffer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = napi_value; + static inline KVMObjectHandle convertFrom(napi_env env, InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(napi_env env, KVMObjectHandle value) + { + return reinterpret_cast(value); + } + static inline void release(napi_env env, InteropType value, KVMObjectHandle converted) {} +}; + +inline napi_typedarray_type getNapiType(KInt size) +{ + constexpr auto NUM_1{1}; + constexpr auto NUM_2{2}; + constexpr auto NUM_3{3}; + constexpr auto NUM_4{4}; + switch (size) { + case NUM_1: + return napi_uint8_array; + case NUM_2: + return napi_uint16_array; + case NUM_4: + return napi_uint32_array; + case NUM_8: + return napi_biguint64_array; + default: + break; + } + return napi_uint8_array; +} + +template<> +struct InteropTypeConverter { + using InteropType = napi_value; + static inline KInteropReturnBuffer convertFrom(napi_env env, InteropType value) = delete; + static void disposer(napi_env env, void* data, void* hint) + { + KInteropReturnBuffer* bufferCopy = (KInteropReturnBuffer*)hint; + // todo: Should the dispose signature contain length? It is not common for libc + // and removing it can avoid an extra allocation. + bufferCopy->dispose ? bufferCopy->dispose(bufferCopy->data, bufferCopy->length) : (void)0; + delete bufferCopy; + } + static InteropType convertTo(napi_env env, KInteropReturnBuffer value) + { + napi_value result = nullptr; + napi_value arrayBuffer = nullptr; + auto clone = new KInteropReturnBuffer(value); + napi_create_external_arraybuffer( + env, value.data, value.length * value.elementSize, disposer, clone, &arrayBuffer); + napi_create_typedarray(env, getNapiType(value.elementSize), value.length, arrayBuffer, 0, &result); + return result; + } + static inline void release(napi_env env, InteropType value, const KInteropReturnBuffer& converted) = delete; +}; + +#define KOALA_INTEROP_THROW(vmContext, object, ...) \ + do { \ + napi_env env = (napi_env)vmContext; \ + napi_handle_scope scope = nullptr; \ + napi_open_handle_scope(env, &scope); \ + napi_throw(env, object); \ + napi_close_handle_scope(env, scope); \ + return __VA_ARGS__; \ + } while (0) + +#define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \ + do { \ + napi_env env = (napi_env)vmContext; \ + napi_handle_scope scope = nullptr; \ + napi_open_handle_scope(env, &scope); \ + napi_throw_error(env, nullptr, message); \ + napi_close_handle_scope(env, scope); \ + return __VA_ARGS__; \ + } while (0) + +#define NAPI_ASSERT_INDEX(info, index, result) \ + do { \ + if (static_cast(index) >= info.Length()) { \ + napi_throw_error(info.Env(), nullptr, "No such element"); \ + return result; \ + } \ + } while (0) + +// Helpers from node-addon-api +#define KOALA_NAPI_THROW_IF_FAILED(env, status, ...) \ + if ((status) != napi_ok) { \ + const napi_extended_error_info* errorInfo; \ + napi_get_last_error_info(env, &errorInfo); \ + napi_throw_error(env, nullptr, errorInfo->error_message); \ + return __VA_ARGS__; \ + } +#define KOALA_NAPI_THROW_IF_FAILED_VOID(env, status) \ + if ((status) != napi_ok) { \ + const napi_extended_error_info* errorInfo; \ + napi_get_last_error_info(env, &errorInfo); \ + napi_throw_error(env, nullptr, errorInfo->error_message); \ + return; \ + } + +class CallbackInfo { +public: + CallbackInfo(napi_env env, napi_callback_info info) : _env(env) + { + size_t size = 0; + napi_status status; + status = napi_get_cb_info(env, info, &size, nullptr, nullptr, nullptr); + KOALA_NAPI_THROW_IF_FAILED_VOID(env, status); + if (size > 0) { + args.resize(size); // Improve: statically allocate small array for common case with few arguments passed + status = napi_get_cb_info(env, info, &size, args.data(), nullptr, nullptr); + KOALA_NAPI_THROW_IF_FAILED_VOID(env, status); + } + } + + napi_value operator[](size_t idx) const + { + if (idx >= Length()) { + napi_value result; + napi_get_undefined(_env, &result); + return result; + } + return args[idx]; + } + + napi_env Env() const + { + return _env; + } + + size_t Length() const + { + return args.size(); + } + +private: + napi_env _env; + // napi_callback_info _info; + std::vector args; +}; + +template +inline napi_typedarray_type getNapiType() = delete; + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_float32_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_float64_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_int8_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_uint8_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_int16_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_uint16_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_int32_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_uint32_array; +} + +template<> +inline napi_typedarray_type getNapiType() +{ + return napi_biguint64_array; +} +napi_valuetype getValueTypeChecked(napi_env env, napi_value value); +bool isTypedArray(napi_env env, napi_value value); + +template +inline ElemType* getTypedElements(napi_env env, napi_value value) +{ + napi_valuetype valueType = getValueTypeChecked(env, value); + if (valueType == napi_null) { + return nullptr; + } + if (!isTypedArray(env, value)) { + napi_throw_error(env, nullptr, "Expected TypedArray"); + return nullptr; + } + napi_value arrayBuffer; + void* data = nullptr; + size_t byteLength; + size_t byteOffset; + napi_typedarray_type type; + napi_status status = napi_get_typedarray_info(env, value, &type, &byteLength, &data, &arrayBuffer, &byteOffset); + KOALA_NAPI_THROW_IF_FAILED(env, status, nullptr); + if (type != getNapiType()) { + printf("Array type mismatch. Expected %d got %d\n", getNapiType(), type); + napi_throw_error(env, nullptr, "Array type mismatch"); + return nullptr; + } + return reinterpret_cast(data); +} + +template +inline ElemType* getTypedElements(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, nullptr); + return getTypedElements(info.Env(), info[index]); +} + +inline uint8_t* getUInt8Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline int8_t* getInt8Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline uint16_t* getUInt16Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline int16_t* getInt16Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline uint32_t* getUInt32Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline uint32_t* getUInt32Elements(napi_env env, napi_value value) +{ + return getTypedElements(env, value); +} + +inline int32_t* getInt32Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline float* getFloat32Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline double* getFloat64Elements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline KNativePointer* getPointerElements(const CallbackInfo& info, int index) +{ + return getTypedElements(info, index); +} + +inline void* getSerializerBufferPointer(napi_env env, napi_value value) +{ + return getTypedElements(env, value); +} + +KInt getInt32(napi_env env, napi_value value); +inline int32_t getInt32(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, 0); + return getInt32(info.Env(), info[index]); +} +KUInt getUInt32(napi_env env, napi_value value); +inline uint32_t getUInt32(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, 0); + return getUInt32(info.Env(), info[index]); +} +KFloat getFloat32(napi_env env, napi_value value); +inline float getFloat32(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, 0.0f); + return getFloat32(info.Env(), info[index]); +} +KDouble getFloat64(napi_env env, napi_value value); +inline KDouble getFloat64(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, 0.0); + return getFloat64(info.Env(), info[index]); +} +KStringPtr getString(napi_env env, napi_value value); +inline KStringPtr getString(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, KStringPtr()); + return getString(info.Env(), info[index]); +} +inline void* getPointer(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, nullptr); + return getPointer(info.Env(), info[index]); +} +KULong getUInt64(napi_env env, napi_value value); +inline KULong getUInt64(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, 0); + return getUInt64(info.Env(), info[index]); +} +KLong getInt64(napi_env env, napi_value value); +inline KLong getInt64(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, 0); + return getInt64(info.Env(), info[index]); +} +KBoolean getBoolean(napi_env env, napi_value value); +inline KBoolean getBoolean(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, false); + return getBoolean(info.Env(), info[index]); +} +template +inline Type getArgument(const CallbackInfo& info, int index) = delete; + +template<> +inline KBoolean getArgument(const CallbackInfo& info, int index) +{ + return getBoolean(info, index); +} + +template<> +inline KUInt getArgument(const CallbackInfo& info, int index) +{ + return getUInt32(info, index); +} + +template<> +inline KInt getArgument(const CallbackInfo& info, int index) +{ + return getInt32(info, index); +} + +template<> +inline KInteropNumber getArgument(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, { 0 }); + return getArgument(info.Env(), info[index]); +} + +template<> +inline KSerializerBuffer getArgument(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, nullptr); + return getArgument(info.Env(), info[index]); +} + +template<> +inline KInteropBuffer getArgument(const CallbackInfo& info, int index) +{ + NAPI_ASSERT_INDEX(info, index, {}); + return getArgument((napi_env)info.Env(), (napi_value)info[index]); +} + +template<> +inline KFloat getArgument(const CallbackInfo& info, int index) +{ + return getFloat32(info, index); +} + +template<> +inline KDouble getArgument(const CallbackInfo& info, int index) +{ + return getFloat64(info, index); +} + +template<> +inline KNativePointer getArgument(const CallbackInfo& info, int index) +{ + return getPointer(info, index); +} + +template<> +inline KLong getArgument(const CallbackInfo& info, int index) +{ + return getInt64(info, index); +} + +template<> +inline KULong getArgument(const CallbackInfo& info, int index) +{ + return getUInt64(info, index); +} + +template<> +inline KNativePointerArray getArgument(const CallbackInfo& info, int index) +{ + return getPointerElements(info, index); +} + +template<> +inline uint8_t* getArgument(const CallbackInfo& info, int index) +{ + return getUInt8Elements(info, index); +} + +template<> +inline const uint8_t* getArgument(const CallbackInfo& info, int index) +{ + return getUInt8Elements(info, index); +} + +template<> +inline int8_t* getArgument(const CallbackInfo& info, int index) +{ + return getInt8Elements(info, index); +} + +template<> +inline int16_t* getArgument(const CallbackInfo& info, int index) +{ + return getInt16Elements(info, index); +} + +template<> +inline uint16_t* getArgument(const CallbackInfo& info, int index) +{ + return getUInt16Elements(info, index); +} + +template<> +inline int32_t* getArgument(const CallbackInfo& info, int index) +{ + return getInt32Elements(info, index); +} + +template<> +inline uint32_t* getArgument(const CallbackInfo& info, int index) +{ + return getUInt32Elements(info, index); +} + +template<> +inline float* getArgument(const CallbackInfo& info, int index) +{ + return getFloat32Elements(info, index); +} + +template<> +inline KStringPtr getArgument(const CallbackInfo& info, int index) +{ + return getString(info, index); +} + +inline napi_value makeVoid(const CallbackInfo& info) +{ + return makeVoid(info.Env()); +} + +template +inline napi_value makeResult(const CallbackInfo& info, Type value) = delete; + +template<> +inline napi_value makeResult(const CallbackInfo& info, KBoolean value) +{ + return makeBoolean(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, int32_t value) +{ + return makeInt32(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, uint32_t value) +{ + return makeUInt32(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, int64_t value) +{ + return makeInt64(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, uint64_t value) +{ + return makeUInt64(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, float value) +{ + return makeFloat32(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, double value) +{ + return makeFloat64(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, KNativePointer value) +{ + return makePointer(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, KVMObjectHandle value) +{ + return InteropTypeConverter::convertTo(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, KStringPtr value) +{ + return InteropTypeConverter::convertTo(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, KInteropBuffer value) +{ + return InteropTypeConverter::convertTo(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, KInteropReturnBuffer value) +{ + return InteropTypeConverter::convertTo(info.Env(), value); +} + +template<> +inline napi_value makeResult(const CallbackInfo& info, KInteropNumber value) +{ + return InteropTypeConverter::convertTo(info.Env(), value); +} + +typedef napi_value (*napi_type_t)(napi_env, napi_callback_info); + +class Exports { + std::unordered_map>> implementations; + +public: + static Exports* getInstance(); + + std::vector getModules(); + void addMethod(const char* module, const char* name, napi_type_t impl); + const std::vector>& getMethods(const std::string& module); +}; + +#define QUOTE2(x) #x +#define QUOTE(x) QUOTE2(x) + +#ifdef _MSC_VER +#define MAKE_NODE_EXPORT(module, name) \ + static void __init_##name() \ + { \ + Exports::getInstance()->addMethod(QUOTE(module), "_" #name, Node_##name); \ + } \ + namespace { \ + struct __Init_##name { \ + __Init_##name() \ + { \ + __init_##name(); \ + } \ + } __Init_##name##_v; \ + } +#else +#define MAKE_NODE_EXPORT(module, name) \ + __attribute__((constructor)) static void __init_##name() \ + { \ + Exports::getInstance()->addMethod(QUOTE(module), "_" #name, Node_##name); \ + } +#endif + +#ifndef KOALA_INTEROP_MODULE +#error KOALA_INTEROP_MODULE is undefined +#endif + +#define MAKE_INTEROP_NODE_EXPORT(name) MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_0(name, Ret) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + return makeResult(info, impl_##name()); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_1(name, Ret, P0) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + return makeResult(info, impl_##name(p0)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_2(name, Ret, P0, P1) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + return makeResult(info, impl_##name(p0, p1)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + return makeResult(info, impl_##name(p0, p1, p2)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + return makeResult(info, impl_##name(p0, p1, p2, p3)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + P11 p11 = getArgument(info, 11); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + P11 p11 = getArgument(info, 11); \ + P12 p12 = getArgument(info, 12); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + P11 p11 = getArgument(info, 11); \ + P12 p12 = getArgument(info, 12); \ + P13 p13 = getArgument(info, 13); \ + return makeResult(info, impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V0(name) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + impl_##name(); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V1(name, P0) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + impl_##name(p0); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V2(name, P0, P1) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + impl_##name(p0, p1); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V3(name, P0, P1, P2) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + impl_##name(p0, p1, p2); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + impl_##name(p0, p1, p2, p3); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + impl_##name(p0, p1, p2, p3, p4); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + impl_##name(p0, p1, p2, p3, p4, p5); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(impl_##name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(impl_##name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(impl_##name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + P11 p11 = getArgument(info, 11); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(impl_##name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + P11 p11 = getArgument(info, 11); \ + P12 p12 = getArgument(info, 12); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + P11 p11 = getArgument(info, 11); \ + P12 p12 = getArgument(info, 12); \ + P13 p13 = getArgument(info, 13); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_V15(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + P5 p5 = getArgument(info, 5); \ + P6 p6 = getArgument(info, 6); \ + P7 p7 = getArgument(info, 7); \ + P8 p8 = getArgument(info, 8); \ + P9 p9 = getArgument(info, 9); \ + P10 p10 = getArgument(info, 10); \ + P11 p11 = getArgument(info, 11); \ + P12 p12 = getArgument(info, 12); \ + P13 p13 = getArgument(info, 13); \ + P14 p14 = getArgument(info, 14); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_0(name, Ret) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(impl_##name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + return makeResult(info, impl_##name(ctx)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_1(name, Ret, P0) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(impl_##name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + return makeResult(info, impl_##name(ctx, p0)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + return makeResult(info, impl_##name(ctx, p0, p1)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + return makeResult(info, impl_##name(ctx, p0, p1, p2)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + return makeResult(info, impl_##name(ctx, p0, p1, p2, p3)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_5(name, Ret, P0, P1, P2, P3, P4) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + return makeResult(info, impl_##name(ctx, p0, p1, p2, p3, p4)); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_V0(name) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + impl_##name(ctx); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_V1(name, P0) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + impl_##name(ctx, p0); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_V2(name, P0, P1) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + impl_##name(ctx, p0, p1); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + impl_##name(ctx, p0, p1, p2); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + impl_##name(ctx, p0, p1, p2, p3); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define KOALA_INTEROP_CTX_V5(name, P0, P1, P2, P3, P4) \ + napi_value Node_##name(napi_env env, napi_callback_info cbinfo) \ + { \ + KOALA_MAYBE_LOG(name) \ + CallbackInfo info(env, cbinfo); \ + KVMContext ctx = reinterpret_cast((napi_env)info.Env()); \ + P0 p0 = getArgument(info, 0); \ + P1 p1 = getArgument(info, 1); \ + P2 p2 = getArgument(info, 2); \ + P3 p3 = getArgument(info, 3); \ + P4 p4 = getArgument(info, 4); \ + impl_##name(ctx, p0, p1, p2, p3, p4); \ + return makeVoid(info); \ + } \ + MAKE_NODE_EXPORT(KOALA_INTEROP_MODULE, name) + +#define NODEJS_GET_AND_THROW_LAST_ERROR(env) \ + do { \ + const napi_extended_error_info* error_info; \ + napi_get_last_error_info((env), &error_info); \ + bool is_pending; \ + napi_is_exception_pending((env), &is_pending); \ + /* If an exception is already pending, don't rethrow it */ \ + if (!is_pending) { \ + const char* error_message = \ + error_info->error_message != NULL ? error_info->error_message : "empty error message"; \ + napi_throw_error((env), NULL, error_message); \ + } \ + } while (0) + +#define KOALA_INTEROP_DIRECT_0(name, Ret) KOALA_INTEROP_0(name, Ret) +#define KOALA_INTEROP_DIRECT_1(name, Ret, P0) KOALA_INTEROP_1(name, Ret, P0) +#define KOALA_INTEROP_DIRECT_2(name, Ret, P0, P1) KOALA_INTEROP_2(name, Ret, P0, P1) +#define KOALA_INTEROP_DIRECT_3(name, Ret, P0, P1, P2) KOALA_INTEROP_3(name, Ret, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_4(name, Ret, P0, P1, P2, P3) KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_5(name, Ret, P0, P1, P2, P3, P4) KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_6(name, Ret, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) +#define KOALA_INTEROP_DIRECT_V0(name) KOALA_INTEROP_V0(name) +#define KOALA_INTEROP_DIRECT_V1(name, P0) KOALA_INTEROP_V1(name, P0) +#define KOALA_INTEROP_DIRECT_V2(name, P0, P1) KOALA_INTEROP_V2(name, P0, P1) +#define KOALA_INTEROP_DIRECT_V3(name, P0, P1, P2) KOALA_INTEROP_V3(name, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_V4(name, P0, P1, P2, P3) KOALA_INTEROP_V4(name, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_V5(name, P0, P1, P2, P3, P4) KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_V6(name, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_V7(name, P0, P1, P2, P3, P4, P5, P6) KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) + +napi_value getKoalaNapiCallbackDispatcher(napi_env env); +// Improve: can/shall we cache bridge reference? + +#define KOALA_INTEROP_CALL_VOID(venv, id, length, args) \ + { \ + napi_env env = reinterpret_cast(venv); \ + napi_value bridge = getKoalaNapiCallbackDispatcher(env), global = nullptr, return_val = nullptr; \ + napi_handle_scope scope = nullptr; \ + napi_open_handle_scope(env, &scope); \ + napi_status status = napi_get_global(env, &global); \ + napi_value node_args[3]; \ + napi_create_int32(env, id, &node_args[0]); \ + napi_value buffer = nullptr; \ + napi_create_external_arraybuffer( \ + env, args, length, [](napi_env, void* data, void* hint) {}, nullptr, &buffer); \ + napi_create_typedarray(env, napi_uint8_array, length, buffer, 0, &node_args[1]); \ + napi_create_int32(env, length, &node_args[2]); \ + status = napi_call_function(env, global, bridge, 3, node_args, &return_val); \ + if (status != napi_ok) \ + NODEJS_GET_AND_THROW_LAST_ERROR((env)); \ + napi_close_handle_scope(env, scope); \ + } + +#define KOALA_INTEROP_CALL_INT(venv, id, length, args) \ + { \ + napi_env env = reinterpret_cast(venv); \ + napi_value bridge = getKoalaNapiCallbackDispatcher(env), global = nullptr, return_val = nullptr; \ + napi_handle_scope scope = nullptr; \ + napi_open_handle_scope(env, &scope); \ + napi_status status = napi_get_global(env, &global); \ + napi_value node_args[3]; \ + napi_create_int32(env, id, &node_args[0]); \ + napi_value buffer = nullptr; \ + napi_create_external_arraybuffer( \ + env, args, length, [](napi_env, void* data, void* hint) {}, nullptr, &buffer); \ + napi_create_typedarray(env, napi_uint8_array, length, buffer, 0, &node_args[1]); \ + napi_create_int32(env, length, &node_args[2]); \ + status = napi_call_function(env, global, bridge, 3, node_args, &return_val); \ + if (status != napi_ok) \ + NODEJS_GET_AND_THROW_LAST_ERROR((env)); \ + int result; \ + status = napi_get_value_int32(env, return_val, &result); \ + napi_close_handle_scope(env, scope); \ + return result; \ + } + +#define KOALA_INTEROP_CALL_VOID_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_VOID(venv, id, (argc) * sizeof(int32_t), args) +#define KOALA_INTEROP_CALL_INT_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_INT(venv, id, (argc) * sizeof(int32_t), args) + +#endif // KOALA_NAPI + +#endif // _CONVERTORS_NAPI_H_ diff --git a/ets1.2/interop/src/cpp/napi/win-dynamic-node.cc b/ets1.2/interop/src/cpp/napi/win-dynamic-node.cc new file mode 100644 index 0000000000000000000000000000000000000000..3e8824969104669b401807281786127e3a48e9bb --- /dev/null +++ b/ets1.2/interop/src/cpp/napi/win-dynamic-node.cc @@ -0,0 +1,538 @@ +/* + * Copyright (c) 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. + */ + +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif + +#include + +#include "node_api.h" + +#define NAPI_CDECL __cdecl + +#define NAPI_FUNCTIONS(op) \ + op(napi_module_register) op(napi_create_function) op(napi_set_named_property) op(napi_create_string_utf8) op( \ + napi_add_env_cleanup_hook) op(napi_get_last_error_info) op(napi_get_value_bigint_int64) \ + op(napi_get_value_bigint_uint64) op(napi_create_object) op(napi_get_arraybuffer_info) op( \ + napi_create_bigint_uint64) op(napi_is_typedarray) op(napi_add_finalizer) op(napi_get_typedarray_info) \ + op(napi_set_property) op(napi_get_value_bool) op(napi_coerce_to_string) op(napi_get_value_uint32) op( \ + napi_get_value_int32) op(napi_throw) op(napi_get_cb_info) op(napi_create_error) \ + op(napi_get_value_string_utf8) op(napi_define_properties) op(napi_delete_reference) op( \ + napi_get_reference_value) op(napi_open_handle_scope) op(napi_close_handle_scope) \ + op(napi_open_escapable_handle_scope) op(napi_close_escapable_handle_scope) op( \ + napi_is_exception_pending) op(napi_create_type_error) op(napi_escape_handle) \ + op(napi_get_and_clear_last_exception) op(napi_fatal_error) op(napi_create_double) op( \ + napi_typeof) op(napi_get_property) op(napi_get_named_property) op(napi_create_reference) \ + op(napi_get_global) op(napi_has_property) op(napi_get_undefined) op(napi_get_value_double) \ + op(napi_close_callback_scope) op(napi_async_destroy) op(napi_call_function) \ + op(napi_get_value_external) op(napi_throw_error) op(napi_create_int32) \ + op(napi_create_external_arraybuffer) op(napi_create_typedarray) \ + op(napi_create_string_latin1) op(napi_create_async_work) \ + op(napi_delete_async_work) op(napi_queue_async_work) \ + op(napi_resolve_deferred) op(napi_reject_deferred) \ + op(napi_create_promise) op(napi_create_threadsafe_function) \ + op(napi_acquire_threadsafe_function) op( \ + napi_release_threadsafe_function) \ + op(napi_call_threadsafe_function) op(napi_is_dataview) \ + op(napi_is_arraybuffer) op(napi_get_dataview_info) \ + op(napi_get_value_int64) op(napi_get_boolean) \ + op(napi_create_uint32) \ + op(napi_create_bigint_int64) \ + op(napi_cancel_async_work) + +#define DECL_NAPI_IMPL(fn_name, ...) decltype(&fn_name) p_##fn_name; + +NAPI_FUNCTIONS(DECL_NAPI_IMPL) + +bool LoadNapiFunctions() +{ + static bool isLoaded = false; + if (isLoaded) + return true; + HMODULE nodeModule = GetModuleHandle(NULL); + FARPROC fn_addr = GetProcAddress(nodeModule, "napi_module_register"); + + if (fn_addr == NULL) { + nodeModule = GetModuleHandleA("node.dll"); + if (nodeModule == NULL) + return false; + fn_addr = GetProcAddress(nodeModule, "napi_module_register"); + if (fn_addr == NULL) { + return false; + } + } + bool apiLoadFailed = false; + +#define GET_NAPI_IMPL(fn_name) \ + fn_addr = GetProcAddress(nodeModule, #fn_name); \ + if (fn_addr == NULL) \ + apiLoadFailed = true; \ + p_##fn_name = (decltype(p_##fn_name))fn_addr; + + // Assign the addresses of the needed functions to the "p*" named pointers. + NAPI_FUNCTIONS(GET_NAPI_IMPL); + + // If any required APIs failed to load, return false + if (apiLoadFailed) + return false; + + isLoaded = true; + + return true; +} + +NAPI_EXTERN void NAPI_CDECL napi_module_register(napi_module* mod) +{ + LoadNapiFunctions(); + p_napi_module_register(mod); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info(napi_env env, const napi_extended_error_info** result) +{ + LoadNapiFunctions(); + return p_napi_get_last_error_info(env, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_int64( + napi_env env, napi_value value, int64_t* result, bool* lossless) +{ + LoadNapiFunctions(); + return p_napi_get_value_bigint_int64(env, value, result, lossless); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_uint64( + napi_env env, napi_value value, uint64_t* result, bool* lossless) +{ + LoadNapiFunctions(); + return p_napi_get_value_bigint_uint64(env, value, result, lossless); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_object(env, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info( + napi_env env, napi_value arraybuffer, void** data, size_t* byte_length) +{ + LoadNapiFunctions(); + return p_napi_get_arraybuffer_info(env, arraybuffer, data, byte_length); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_bigint_uint64(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(napi_env env, napi_value value, bool* result) +{ + LoadNapiFunctions(); + return p_napi_is_typedarray(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_add_finalizer(napi_env env, napi_value js_object, void* finalize_data, + napi_finalize finalize_cb, void* finalize_hint, napi_ref* result) +{ + LoadNapiFunctions(); + return p_napi_add_finalizer(env, js_object, finalize_data, finalize_cb, finalize_hint, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env, napi_value typedarray, + napi_typedarray_type* type, size_t* length, void** data, napi_value* arraybuffer, size_t* byte_offset) +{ + LoadNapiFunctions(); + return p_napi_get_typedarray_info(env, typedarray, type, length, data, arraybuffer, byte_offset); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(napi_env env, napi_value object, napi_value key, napi_value value) +{ + LoadNapiFunctions(); + return p_napi_set_property(env, object, key, value); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bool(napi_env env, napi_value value, bool* result) +{ + LoadNapiFunctions(); + return p_napi_get_value_bool(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(napi_env env, napi_value value, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_coerce_to_string(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(napi_env env, napi_value value, int32_t* result) +{ + LoadNapiFunctions(); + return p_napi_get_value_int32(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_cb_info( + napi_env env, napi_callback_info cbinfo, size_t* argc, napi_value* argv, napi_value* this_arg, void** data) +{ + LoadNapiFunctions(); + return p_napi_get_cb_info(env, cbinfo, argc, argv, this_arg, data); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8( + napi_env env, const char* str, size_t length, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_string_utf8(env, str, length, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) +{ + LoadNapiFunctions(); + return p_napi_throw(env, error); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_error(napi_env env, napi_value code, napi_value msg, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_error(env, code, msg, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf8( + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) +{ + LoadNapiFunctions(); + return p_napi_get_value_string_utf8(env, value, buf, bufsize, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_define_properties( + napi_env env, napi_value object, size_t property_count, const napi_property_descriptor* properties) +{ + LoadNapiFunctions(); + return p_napi_define_properties(env, object, property_count, properties); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(napi_env env, napi_ref ref) +{ + LoadNapiFunctions(); + return p_napi_delete_reference(env, ref); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_reference_value(napi_env env, napi_ref ref, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_get_reference_value(env, ref, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_open_handle_scope(napi_env env, napi_handle_scope* result) +{ + LoadNapiFunctions(); + return p_napi_open_handle_scope(env, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_close_handle_scope(napi_env env, napi_handle_scope scope) +{ + LoadNapiFunctions(); + return p_napi_close_handle_scope(env, scope); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope(napi_env env, napi_escapable_handle_scope* result) +{ + return p_napi_open_escapable_handle_scope(env, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope(napi_env env, napi_escapable_handle_scope scope) +{ + LoadNapiFunctions(); + return p_napi_close_escapable_handle_scope(env, scope); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, bool* result) +{ + LoadNapiFunctions(); + return p_napi_is_exception_pending(env, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property( + napi_env env, napi_value object, napi_value key, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_get_property(env, object, key, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, napi_value value, uint32_t* result) +{ + LoadNapiFunctions(); + return p_napi_get_value_uint32(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(napi_env env, napi_value value, napi_valuetype* result) +{ + LoadNapiFunctions(); + return p_napi_typeof(env, value, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_get_and_clear_last_exception(napi_env env, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_get_and_clear_last_exception(env, result); +} +NAPI_EXTERN NAPI_NO_RETURN void NAPI_CDECL napi_fatal_error( + const char* location, size_t location_len, const char* message, size_t message_len) +{ + LoadNapiFunctions(); + p_napi_fatal_error(location, location_len, message, message_len); + // Not reachable, but not represented in type signature. + exit(0); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(napi_env env, napi_value value, void** result) +{ + LoadNapiFunctions(); + return p_napi_get_value_external(env, value, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, double value, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_double(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error( + napi_env env, napi_value code, napi_value msg, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_type_error(env, code, msg, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property( + napi_env env, napi_value object, const char* utf8name, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_get_named_property(env, object, utf8name, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_create_reference( + napi_env env, napi_value value, uint32_t initial_refcount, napi_ref* result) +{ + LoadNapiFunctions(); + return p_napi_create_reference(env, value, initial_refcount, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_escape_handle( + napi_env env, napi_escapable_handle_scope scope, napi_value escapee, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_get_global(env, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(napi_env env, napi_value object, napi_value key, bool* result) +{ + LoadNapiFunctions(); + return p_napi_has_property(env, object, key, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_create_function( + napi_env env, const char* utf8name, size_t length, napi_callback cb, void* data, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_function(env, utf8name, length, cb, data, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_escape_handle( + napi_env env, napi_escapable_handle_scope scope, napi_value escapee, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_escape_handle(env, scope, escapee, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_get_undefined(env, result); +} +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(napi_env env, napi_value value, double* result) +{ + LoadNapiFunctions(); + return p_napi_get_value_double(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_close_callback_scope(napi_env env, napi_callback_scope scope) +{ + LoadNapiFunctions(); + return p_napi_close_callback_scope(env, scope); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_async_destroy(napi_env env, napi_async_context async_context) +{ + LoadNapiFunctions(); + return p_napi_async_destroy(env, async_context); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_call_function( + napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value* argv, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_call_function(env, recv, func, argc, argv, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(napi_env env, const char* code, const char* msg) +{ + LoadNapiFunctions(); + return p_napi_throw_error(env, code, msg); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, int32_t value, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_int32(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_external_arraybuffer(napi_env env, void* external_data, + size_t byte_length, napi_finalize finalize_cb, void* finalize_hint, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_external_arraybuffer(env, external_data, byte_length, finalize_cb, finalize_hint, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_typedarray(napi_env env, napi_typedarray_type type, size_t length, + napi_value array_buffer, size_t byte_offset, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_typedarray(env, type, length, array_buffer, byte_offset, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1( + napi_env env, const char* str, size_t length, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_string_latin1(env, str, length, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_async_work(napi_env env, napi_value async_resource, + napi_value async_resource_name, napi_async_execute_callback execute, napi_async_complete_callback complete, + void* data, napi_async_work* result) +{ + LoadNapiFunctions(); + return p_napi_create_async_work(env, async_resource, async_resource_name, execute, complete, data, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_async_work(napi_env env, napi_async_work work) +{ + LoadNapiFunctions(); + return p_napi_delete_async_work(env, work); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(napi_env env, napi_async_work work) +{ + LoadNapiFunctions(); + return p_napi_queue_async_work(env, work); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(napi_env env, napi_deferred* deferred, napi_value* promise) +{ + LoadNapiFunctions(); + return p_napi_create_promise(env, deferred, promise); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(napi_env env, napi_deferred deferred, napi_value resolution) +{ + LoadNapiFunctions(); + return p_napi_resolve_deferred(env, deferred, resolution); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(napi_env env, napi_deferred deferred, napi_value rejection) +{ + LoadNapiFunctions(); + return p_napi_reject_deferred(env, deferred, rejection); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_threadsafe_function(napi_env env, napi_value func, + napi_value async_resource, napi_value async_resource_name, size_t max_queue_size, size_t initial_thread_count, + void* thread_finalize_data, napi_finalize thread_finalize_cb, void* context, + napi_threadsafe_function_call_js call_js_cb, napi_threadsafe_function* result) +{ + LoadNapiFunctions(); + return p_napi_create_threadsafe_function(env, func, async_resource, async_resource_name, max_queue_size, + initial_thread_count, thread_finalize_data, thread_finalize_cb, context, call_js_cb, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_acquire_threadsafe_function(napi_threadsafe_function func) +{ + LoadNapiFunctions(); + return p_napi_acquire_threadsafe_function(func); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function( + napi_threadsafe_function func, napi_threadsafe_function_release_mode mode) +{ + LoadNapiFunctions(); + return p_napi_release_threadsafe_function(func, mode); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_call_threadsafe_function( + napi_threadsafe_function func, void* data, napi_threadsafe_function_call_mode is_blocking) +{ + LoadNapiFunctions(); + return p_napi_call_threadsafe_function(func, data, is_blocking); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(napi_env env, napi_value value, bool* result) +{ + LoadNapiFunctions(); + return p_napi_is_dataview(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, napi_value value, bool* result) +{ + LoadNapiFunctions(); + return p_napi_is_arraybuffer(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_dataview_info( + napi_env env, napi_value dataview, size_t* bytelength, void** data, napi_value* arraybuffer, size_t* byte_offset) +{ + LoadNapiFunctions(); + return p_napi_get_dataview_info(env, dataview, bytelength, data, arraybuffer, byte_offset); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property( + napi_env env, napi_value object, const char* utf8name, napi_value value) +{ + LoadNapiFunctions(); + return p_napi_set_named_property(env, object, utf8name, value); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(napi_env env, napi_value value, int64_t* result) +{ + LoadNapiFunctions(); + return p_napi_get_value_int64(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, bool value, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_get_boolean(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, uint32_t value, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_uint32(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, int64_t value, napi_value* result) +{ + LoadNapiFunctions(); + return p_napi_create_bigint_int64(env, value, result); +} + +NAPI_EXTERN napi_status NAPI_CDECL napi_cancel_async_work(napi_env env, napi_async_work work) +{ + LoadNapiFunctions(); + return p_napi_cancel_async_work(env, work); +} \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/ohos/hilog/log.h b/ets1.2/interop/src/cpp/ohos/hilog/log.h new file mode 100644 index 0000000000000000000000000000000000000000..385385521a1ccd1beb6edea72afe06bb6b80bd57 --- /dev/null +++ b/ets1.2/interop/src/cpp/ohos/hilog/log.h @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2021-2022 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. + */ + +#ifndef HIVIEWDFX_HILOG_H +#define HIVIEWDFX_HILOG_H +/** + * @addtogroup HiLog + * @{ + * + * @brief Provides logging functions. + * + * For example, you can use these functions to output logs of the specified log type, service domain, log tag, + * and log level. + * + * @syscap SystemCapability.HiviewDFX.HiLog + * + * @since 8 + */ + +/** + * @file log.h + * + * @brief Defines the logging functions of the HiLog module. + * + * Before outputting logs, you must define the service domain, and log tag, use the function with + * the specified log type and level, and specify the privacy identifier.\n + *
  • Service domain: used to identify the subsystem and module of a service. Its value is a hexadecimal + * integer ranging from 0x0 to 0xFFFF. \n + *
  • Log tag: a string used to identify the class, file, or service.
  • \n + *
  • Log level: DEBUG, INFO, WARN, ERROR, and FATAL
  • \n + *
  • Parameter format: a printf format string that starts with a % character, including format specifiers + * and variable parameters.
  • \n + *
  • Privacy identifier: {public} or {private} added between the % character and the format specifier in + * each parameter. Note that each parameter has a privacy identifier. If no privacy identifier is added, + * the parameter is considered to be private.
\n + * + * Sample code:\n + * Defining the service domain and log tag:\n + * #include \n + * #define LOG_DOMAIN 0x0201\n + * #define LOG_TAG "MY_TAG"\n + * Outputting logs:\n + * HILOG_WARN({@link LOG_APP}, "Failed to visit %{private}s, reason:%{public}d.", url, errno);\n + * Output result:\n + * 05-06 15:01:06.870 1051 1051 W 0201/MY_TAG: Failed to visit , reason:503.\n + * + * @since 8 + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Defines the service domain for a log file. + * + * The service domain is used to identify the subsystem and module of a service. Its value is a hexadecimal integer + * ranging from 0x0 to 0xFFFF. If the value is beyond the range, its significant bits are automatically truncated. \n + * + * @since 8 + */ +#ifndef LOG_DOMAIN +#define LOG_DOMAIN 0 +#endif + +/** + * @brief Defines a string constant used to identify the class, file, or service. + * + * @since 8 + */ +#ifndef LOG_TAG +#define LOG_TAG NULL +#endif + +/** + * @brief Enumerates log types. + * + * Currently, LOG_APP is available. \n + * + * @since 8 + */ +typedef enum { + /** Third-party application logs */ + LOG_APP = 0, +} LogType; + +/** + * @brief Enumerates log levels. + * + * You are advised to select log levels based on their respective usage scenarios:\n + *
  • DEBUG: used for debugging and disabled from commercial releases
  • \n + *
  • INFO: used for logging important system running status and steps in key processes
  • \n + *
  • WARN: used for logging unexpected exceptions that have little impact on user experience and can + * automatically recover. Logs at this level are generally output when such exceptions are detected and + * captured.
  • \n + *
  • ERROR: used for logging malfunction that affects user experience and cannot automatically + * recover
  • \n + *
  • FATAL: used for logging major exceptions that have severely affected user experience and should + * not occur.
\n + * + * @since 8 + */ +typedef enum { + /** Debug level to be used by {@link OH_LOG_DEBUG} */ + LOG_DEBUG = 3, + /** Informational level to be used by {@link OH_LOG_INFO} */ + LOG_INFO = 4, + /** Warning level to be used by {@link OH_LOG_WARN} */ + LOG_WARN = 5, + /** Error level to be used by {@link OH_LOG_ERROR} */ + LOG_ERROR = 6, + /** Fatal level to be used by {@link OH_LOG_FATAL} */ + LOG_FATAL = 7, +} LogLevel; + +/** + * @brief Outputs logs. + * + * You can use this function to output logs based on the specified log type, log level, service domain, log tag, + * and variable parameters determined by the format specifier and privacy identifier in the printf format. + * + * @param type Indicates the log type. The type for third-party applications is defined by {@link LOG_APP}. + * @param level Indicates the log level, which can be LOG_DEBUG, LOG_INFO, LOG_WARN, + * LOG_ERROR, and LOG_FATAL. + * @param domain Indicates the service domain of logs. Its value is a hexadecimal integer ranging from 0x0 to 0xFFFF. + * @param tag Indicates the log tag, which is a string used to identify the class, file, or service behavior. + * @param fmt Indicates the format string, which is an enhancement of a printf format string and supports the privacy + * identifier. Specifically, {public} or {private} is added between the % character and the format specifier + * in each parameter. \n + * @param ... Indicates a list of parameters. The number and type of parameters must map onto the format specifiers + * in the format string. + * @return Returns 0 or a larger value if the operation is successful; returns a value smaller + * than 0 otherwise. + * @since 8 + */ +int OH_LOG_Print(LogType type, LogLevel level, unsigned int domain, const char* tag, const char* fmt, ...) + __attribute__((__format__(os_log, 5, 6))); + +/** + * @brief Checks whether logs of the specified service domain, log tag, and log level can be output. + * + * @param domain Indicates the service domain of logs. + * @param tag Indicates the log tag. + * @param level Indicates the log level. + * @return Returns true if the specified logs can be output; returns false otherwise. + * @since 8 + */ +bool OH_LOG_IsLoggable(unsigned int domain, const char* tag, LogLevel level); + +/** + * @brief Outputs debug logs. This is a function-like macro. + * + * Before calling this function, define the log service domain and log tag. Generally, you need to define them at + * the beginning of the source file. \n + * + * @param type Indicates the log type. The type for third-party applications is defined by {@link LOG_APP}. + * @param fmt Indicates the format string, which is an enhancement of a printf format string and supports the + * privacy identifier. Specifically, {public} or {private} is added between the % character and the format specifier + * in each parameter. \n + * @param ... Indicates a list of parameters. The number and type of parameters must map onto the format specifiers + * in the format string. + * @see OH_LOG_Print + * @since 8 + */ +#define OH_LOG_DEBUG(type, ...) ((void)OH_LOG_Print((type), LOG_DEBUG, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +/** + * @brief Outputs informational logs. This is a function-like macro. + * + * Before calling this function, define the log service domain and log tag. Generally, you need to define them + * at the beginning of the source file. \n + * + * @param type Indicates the log type. The type for third-party applications is defined by {@link LOG_APP}. + * @param fmt Indicates the format string, which is an enhancement of a printf format string and supports the privacy + * identifier. Specifically, {public} or {private} is added between the % character and the format specifier in + * each parameter. \n + * @param ... Indicates a list of parameters. The number and type of parameters must map onto the format specifiers + * in the format string. + * @see OH_LOG_Print + * @since 8 + */ +#define OH_LOG_INFO(type, ...) ((void)OH_LOG_Print((type), LOG_INFO, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +/** + * @brief Outputs warning logs. This is a function-like macro. + * + * Before calling this function, define the log service domain and log tag. Generally, you need to define them + * at the beginning of the source file. \n + * + * @param type Indicates the log type. The type for third-party applications is defined by {@link LOG_APP}. + * @param fmt Indicates the format string, which is an enhancement of a printf format string and supports the + * privacy identifier. Specifically, {public} or {private} is added between the % character and the format specifier + * in each parameter. \n + * @param ... Indicates a list of parameters. The number and type of parameters must map onto the format specifiers + * in the format string. + * @see OH_LOG_Print + * @since 8 + */ +#define OH_LOG_WARN(type, ...) ((void)OH_LOG_Print((type), LOG_WARN, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +/** + * @brief Outputs error logs. This is a function-like macro. + * + * Before calling this function, define the log service domain and log tag. Generally, you need to define + * them at the beginning of the source file. \n + * + * @param type Indicates the log type. The type for third-party applications is defined by {@link LOG_APP}. + * @param fmt Indicates the format string, which is an enhancement of a printf format string and supports the privacy + * identifier. Specifically, {public} or {private} is added between the % character and the format specifier in each + * parameter. \n + * @param ... Indicates a list of parameters. The number and type of parameters must map onto the format specifiers + * in the format string. + * @see OH_LOG_Print + * @since 8 + */ +#define OH_LOG_ERROR(type, ...) ((void)OH_LOG_Print((type), LOG_ERROR, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +/** + * @brief Outputs fatal logs. This is a function-like macro. + * + * Before calling this function, define the log service domain and log tag. Generally, you need to define them at + * the beginning of the source file. \n + * + * @param type Indicates the log type. The type for third-party applications is defined by {@link LOG_APP}. + * @param fmt Indicates the format string, which is an enhancement of a printf format string and supports the privacy + * identifier. Specifically, {public} or {private} is added between the % character and the format specifier in + * each parameter. \n + * @param ... Indicates a list of parameters. The number and type of parameters must map onto the format specifiers + * in the format string. + * @see OH_LOG_Print + * @since 8 + */ +#define OH_LOG_FATAL(type, ...) ((void)OH_LOG_Print((type), LOG_FATAL, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) + +/** + * @brief Defines the function pointer type for the user-defined log processing function. + * + * @param type Indicates the log type. The type for third-party applications is defined by {@link LOG_APP}. + * @param level Indicates the log level, which can be LOG_DEBUG, LOG_INFO, LOG_WARN, + * LOG_ERROR, and LOG_FATAL. + * @param domain Indicates the service domain of logs. Its value is a hexadecimal integer ranging from 0x0 to 0xFFFF. + * @param tag Indicates the log tag, which is a string used to identify the class, file, or service behavior. + * @param msg Indicates the log message itself, which is a formatted log string. + * @since 11 + */ +typedef void (*LogCallback)( + const LogType type, const LogLevel level, const unsigned int domain, const char* tag, const char* msg); + +/** + * @brief Set the user-defined log processing function. + * + * After calling this function, the callback function implemented by the user can receive all hilogs of the + * current process. + * Note that it will not change the default behavior of hilog logs of the current process, no matter whether this + * interface is called or not. \n + * + * @param callback Indicates the callback function implemented by the user. If you do not need to process hilog logs, + * you can transfer a null pointer. + * @since 11 + */ +void OH_LOG_SetCallback(LogCallback callback); + +#ifdef __cplusplus +} +#endif +/** @} */ + +#ifdef HILOG_RAWFORMAT +#include "hilog/log_inner.h" +#endif + +#endif // HIVIEWDFX_HILOG_C_H diff --git a/ets1.2/interop/src/cpp/ohos/oh_sk_log.cc b/ets1.2/interop/src/cpp/ohos/oh_sk_log.cc new file mode 100644 index 0000000000000000000000000000000000000000..254feea6b76d8dd56940e09e96cdacf01dc2f38e --- /dev/null +++ b/ets1.2/interop/src/cpp/ohos/oh_sk_log.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#include "oh_sk_log.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "interop-utils.h" + +static const char* KOALAUI_OHOS_LOG_ROOT = "/data/storage/el2/base/files/logs"; + +#define APPLY_LOG_FILE_PATTERN(buf, bufLen, t, ms, pid) \ + interop_sprintf(buf, bufLen, "%s/%d_%d_%d_%lld.pid%d.log", KOALAUI_OHOS_LOG_ROOT, (t).tm_year + 1900, \ + (t).tm_mon + 1, (t).tm_mday, (ms).tv_sec, pid) + +const char* oh_sk_log_type_str(oh_sk_log_type type) +{ + switch (type) { + case Log_Debug: + return "D"; + case Log_Info: + return "I"; + case Log_Warn: + return "W"; + case Log_Error: + return "E"; + case Log_Fatal: + return "F"; + } +} + +void oh_sk_file_log(oh_sk_log_type type, const char* msg, ...) +{ + time_t t = time(nullptr); + struct tm lt = *localtime(&t); + struct timeval ms {}; + gettimeofday(&ms, nullptr); + + static char* path = nullptr; + if (!path) { + size_t len = interop_strlen(KOALAUI_OHOS_LOG_ROOT) + 100; + path = new char[len]; + APPLY_LOG_FILE_PATTERN(path, len, lt, ms, getpid()); + mkdir(KOALAUI_OHOS_LOG_ROOT, ACCESSPERMS); + } + + std::unique_ptr file(fopen(path, "a"), fclose); + if (!file) + return; + + constexpr auto US_IN_MS{1000}; + fprintf(file.get(), "%02d-%02d %02d:%02d:%02d.%03lld %s koala: ", lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, + lt.tm_sec, static_cast(ms.tv_usec / US_IN_MS), oh_sk_log_type_str(type)); + + va_list args; + va_start(args, msg); + vfprintf(file.get(), msg, args); + va_end(args); + + fprintf(file.get(), "\n"); +} diff --git a/ets1.2/interop/src/cpp/ohos/oh_sk_log.h b/ets1.2/interop/src/cpp/ohos/oh_sk_log.h new file mode 100644 index 0000000000000000000000000000000000000000..2ebc650377c63750c96ef6f664b6337fbe902250 --- /dev/null +++ b/ets1.2/interop/src/cpp/ohos/oh_sk_log.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#ifndef OH_SK_LOG_H +#define OH_SK_LOG_H + +#include + +typedef enum { Log_Debug, Log_Info, Log_Warn, Log_Error, Log_Fatal } oh_sk_log_type; + +void oh_sk_file_log(oh_sk_log_type type, const char* msg, ...); +const char* oh_sk_log_type_str(oh_sk_log_type type); + +#ifdef OH_SK_LOG_TO_FILE + +#define OH_SK_LOG_INFO(msg) oh_sk_file_log(oh_sk_log_type::Log_Info, msg) +#define OH_SK_LOG_INFO_A(msg, ...) oh_sk_file_log(oh_sk_log_type::Log_Info, msg, ##__VA_ARGS__) +#define OH_SK_LOG_ERROR(msg) oh_sk_file_log(oh_sk_log_type::Log_Error, msg) +#define OH_SK_LOG_ERROR_A(msg, ...) oh_sk_file_log(oh_sk_log_type::Log_Error, msg, ##__VA_ARGS__) +#define OH_SK_LOG_DEBUG(msg) oh_sk_file_log(oh_sk_log_type::Log_Debug, msg) +#define OH_SK_LOG_DEBUG_A(msg, ...) oh_sk_file_log(oh_sk_log_type::Log_Debug, msg, ##__VA_ARGS__) +#define OH_SK_LOG_WARN(msg) oh_sk_file_log(oh_sk_log_type::Log_Warn, msg) +#define OH_SK_LOG_WARN_A(msg, ...) oh_sk_file_log(oh_sk_log_type::Log_Warn, msg, ##__VA_ARGS__) +#define OH_SK_LOG_FATAL(msg) oh_sk_file_log(oh_sk_log_type::Log_Fatal, msg) +#define OH_SK_LOG_FATAL_A(msg, ...) oh_sk_file_log(oh_sk_log_type::Log_Fatal, msg, ##__VA_ARGS__) + +#else + +#define OH_SK_LOG_INFO(msg) OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Koala", msg) +#define OH_SK_LOG_INFO_A(msg, ...) OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Koala", msg, ##__VA_ARGS__) +#define OH_SK_LOG_ERROR(msg) OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Koala", msg) +#define OH_SK_LOG_ERROR_A(msg, ...) OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Koala", msg, ##__VA_ARGS__) +#define OH_SK_LOG_DEBUG(msg) OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xFF00, "Koala", msg) +#define OH_SK_LOG_DEBUG_A(msg, ...) OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xFF00, "Koala", msg, ##__VA_ARGS__) +#define OH_SK_LOG_WARN(msg) OH_LOG_Print(LOG_APP, LOG_WARN, 0xFF00, "Koala", msg) +#define OH_SK_LOG_WARN_A(msg, ...) OH_LOG_Print(LOG_APP, LOG_WARN, 0xFF00, "Koala", msg, ##__VA_ARGS__) +#define OH_SK_LOG_FATAL(msg) OH_LOG_Print(LOG_APP, LOG_FATAL, 0xFF00, "Koala", msg) +#define OH_SK_LOG_FATAL_A(msg, ...) OH_LOG_Print(LOG_APP, LOG_FATAL, 0xFF00, "Koala", msg, ##__VA_ARGS__) + +#endif + +#endif // OH_SK_LOG_H \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/profiler.h b/ets1.2/interop/src/cpp/profiler.h new file mode 100644 index 0000000000000000000000000000000000000000..a99c8173d117aa44283668937e714f2a2d59cb79 --- /dev/null +++ b/ets1.2/interop/src/cpp/profiler.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#ifndef _KOALA_PROFILER_ +#define _KOALA_PROFILER_ + +#include +#include +#include +#include +#include +#include +#include + +#include "interop-utils.h" + +struct InteropProfilerRecord { + int64_t time; + int64_t count; + InteropProfilerRecord(int64_t time, int64_t count) : time(time), count(count) {} +}; + +class InteropProfiler { +private: + std::unordered_map records; + static InteropProfiler* _instance; + InteropProfiler() {} + +public: + static InteropProfiler* instance() + { + if (!_instance) + _instance = new InteropProfiler(); + return _instance; + } + + void record(const char* name, int64_t ns) + { + auto it = records.find(name); + if (it == records.end()) { + records.insert({ name, InteropProfilerRecord(ns, 1) }); + } else { + it->second.time += ns; + it->second.count++; + } + } + + std::string report() + { + std::vector> elems(records.begin(), records.end()); + std::sort(elems.begin(), elems.end(), + [](const std::pair& a, + const std::pair& b) { return b.second.time < a.second.time; }); + int64_t total = 0; + std::for_each(elems.begin(), elems.end(), + [&total](const std::pair& a) { total += a.second.time; }); + std::string result; + std::for_each( + elems.begin(), elems.end(), [total, &result](const std::pair& a) { + auto ns = a.second.time; + auto count = a.second.count; + char buffer[1024]; + constexpr auto PERCENT_100{100}; + interop_snprintf(buffer, sizeof buffer, "for %s[%lld]: %.01f%% (%lld)\n", a.first.c_str(), + (long long)count, (double)ns / total * PERCENT_100, (long long)ns); + result += buffer; + }); + return result; + } + + void reset() + { + records.clear(); + } +}; + +class InteropMethodCall { +private: + const char* name; + std::chrono::steady_clock::time_point begin; + +public: + InteropMethodCall(const char* name) : name(name) + { + begin = std::chrono::steady_clock::now(); + } + ~InteropMethodCall() + { + auto end = std::chrono::steady_clock::now(); + int64_t ns = std::chrono::duration_cast(end - begin).count(); + InteropProfiler::instance()->record(name, ns); + } +}; + +#endif // _KOALA_PROFILER_ diff --git a/ets1.2/interop/src/cpp/tracer.h b/ets1.2/interop/src/cpp/tracer.h new file mode 100644 index 0000000000000000000000000000000000000000..d8e3e71cff7dde2f0479d187d47bd0b2b98f4725 --- /dev/null +++ b/ets1.2/interop/src/cpp/tracer.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _KOALA_TRACER_ +#define _KOALA_TRACER_ + +#ifdef KOALA_OHOS +#include +#define KOALA_TRACE(msg, str) OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Koala", msg, str) +// Also do +// hdc shell hilog -p off +// hdc shell hilog -Q pidoff +// to see the output. +#define KOALA_TRACE_PUBLIC "%{public}s" +#else +#include +#define KOALA_TRACE(msg, str) fprintf(stderr, "Koala: " msg "\n", str) +#define KOALA_TRACE_PUBLIC "%s" +#endif + +class InteropMethodCall { +private: + const char* name; + +public: + InteropMethodCall(const char* name) : name(name) + { + KOALA_TRACE(">>> " KOALA_TRACE_PUBLIC, name); + } + ~InteropMethodCall() + { + KOALA_TRACE("<<< " KOALA_TRACE_PUBLIC, name); + } +}; + +#endif // _KOALA_TRACER_ \ No newline at end of file diff --git a/ets1.2/interop/src/cpp/types/koala-types.h b/ets1.2/interop/src/cpp/types/koala-types.h new file mode 100644 index 0000000000000000000000000000000000000000..6cb7f2685b9e6ec5528f00ba503f020e408433ca --- /dev/null +++ b/ets1.2/interop/src/cpp/types/koala-types.h @@ -0,0 +1,333 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _KOALA_TYPES_H +#define _KOALA_TYPES_H + +#include +#include +#include +#include +#include + +#include "interop-types.h" +#include "interop-utils.h" + +#ifdef _MSC_VER +#define KOALA_EXECUTE(name, code) \ + static void __init_##name() \ + { \ + code; \ + } \ + namespace { \ + struct __Init_##name { \ + __Init_##name() \ + { \ + __init_##name(); \ + } \ + } __Init_##name##_v; \ + } +#else +#define KOALA_EXECUTE(name, code) \ + __attribute__((constructor)) static void __init_jni_##name() \ + { \ + code; \ + } +#endif + +struct KStringPtrImpl { + KStringPtrImpl(const uint8_t* str) : _value(nullptr), _owned(true) + { + int len = str ? interop_strlen((const char*)str) : 0; + assign((const char*)str, len); + } + KStringPtrImpl(const char* str) : _value(nullptr), _owned(true) + { + int len = str ? interop_strlen(str) : 0; + assign(str, len); + } + KStringPtrImpl(const char* str, int len, bool owned) : _value(nullptr), _owned(owned) + { + assign(str, len); + } + KStringPtrImpl(const uint8_t* str, int len, bool owned) : _value(nullptr), _owned(owned) + { + assign((const char*)str, len); + } + KStringPtrImpl() : _value(nullptr), _length(0), _owned(true) {} + + KStringPtrImpl(const KStringPtrImpl& other) = delete; + KStringPtrImpl& operator=(const KStringPtrImpl& other) = delete; + + KStringPtrImpl(InteropString value) : KStringPtrImpl(value.chars, value.length, true) {} + + KStringPtrImpl(KStringPtrImpl&& other) + { + this->_value = other.release(); + this->_owned = other._owned; + other._owned = false; + this->_length = other._length; + } + + ~KStringPtrImpl() + { + if (_value && _owned) + free(_value); + } + + bool isNull() const + { + return _value == nullptr; + } + const char* c_str() const + { + return _value; + } + char* data() const + { + return _value; + } + int length() const + { + return _length; + } + + void resize(int size) + { + _length = size; + if (!_owned) + return; + // Ignore old content. + if (_value && _owned) + free(_value); + auto memSize{static_cast(std::max(0, length + 1))}; + _value = reinterpret_cast(malloc(memSize)); + if (!_value) { + INTEROP_FATAL("Cannot allocate memory"); + } + _value[length] = 0; + } + + void assign(const char* data) + { + assign(data, data ? interop_strlen(data) : 0); + } + + void assign(const char* data, int length) + { + if (_value && _owned) + free(_value); + if (data) { + if (_owned) { + auto memSize{static_cast(std::max(0, length + 1))}; + _value = reinterpret_cast(malloc(memSize)); + if (!_value) { + INTEROP_FATAL("Cannot allocate memory"); + } + interop_memcpy(_value, length, data, length); + _value[length] = 0; + } else { + _value = const_cast(data); + } + } else { + _value = nullptr; + } + _length = length; + } + +protected: + char* release() + { + char* result = this->_value; + this->_value = nullptr; + return result; + } + +private: + char* _value; + int _length; + bool _owned; +}; + +struct KInteropNumber { + int8_t tag; + union { + int32_t i32; + float f32; + }; + KInteropNumber() + { + this->tag = 0; + this->i32 = 0; + } + KInteropNumber(int32_t value) + { + this->tag = INTEROP_TAG_INT32; + this->i32 = value; + } + KInteropNumber(float value) + { + this->tag = INTEROP_TAG_FLOAT32; + this->f32 = value; + } + KInteropNumber(InteropNumber value) + { + this->tag = value.tag; + this->i32 = value.i32; + } + InteropNumber toCType() + { + InteropNumber result; + result.tag = this->tag; + result.i32 = this->i32; + return result; + } + static inline KInteropNumber fromDouble(double value) + { + KInteropNumber result; + // Improve: boundary check + if (value == std::floor(value)) { + result.tag = INTEROP_TAG_INT32; + result.i32 = static_cast(value); + } else { + result.tag = INTEROP_TAG_FLOAT32; + result.f32 = (float)value; + } + return result; + } + inline double asDouble() + { + if (tag == INTEROP_TAG_INT32) + return (double)i32; + else + return (double)f32; + } + inline int32_t asInt32() + { + if (tag == INTEROP_TAG_INT32) + return i32; + else + return (int32_t)f32; + } +}; + +typedef InteropBoolean KBoolean; +typedef InteropUInt8 KByte; +typedef int16_t KChar; +typedef int16_t KShort; +typedef uint16_t KUShort; +typedef InteropInt32 KInt; +typedef InteropUInt32 KUInt; +typedef InteropInt64 KLong; +typedef InteropUInt64 KULong; +typedef InteropFloat32 KFloat; +typedef InteropFloat64 KDouble; +typedef InteropNativePointer KNativePointer; +typedef KStringPtrImpl KStringPtr; + +typedef KFloat* KFloatArray; +typedef const uint8_t* KStringArray; +typedef KNativePointer* KNativePointerArray; + +struct KSerializerBufferOpaque { + explicit operator KByte*() + { + return reinterpret_cast(this); + } +}; +typedef KSerializerBufferOpaque* KSerializerBuffer; + +struct KInteropBuffer { + KInteropBuffer(KLong len = 0, KNativePointer ptr = nullptr, KInt resId = 0, void (*dis)(KInt) = nullptr) + : length(len), data(ptr), resourceId(resId), dispose(dis) + {} + + /** + * Takes ownership of given InteropBuffer + */ + KInteropBuffer(InteropBuffer value) + { + length = value.length; + data = value.data; + resourceId = value.resource.resourceId; + dispose = value.resource.release; + } + + KLong length; + KNativePointer data; + + KInt resourceId; + void (*dispose)(KInt /* resourceId for now */); +}; + +struct KInteropReturnBuffer { + KInt length; + KNativePointer data; + void (*dispose)(KNativePointer data, KInt length); + KInt elementSize = 1; + + template + static KInteropReturnBuffer from(std::vector const& v, decltype(dispose) dispose) + { + return { (KInt)v.size(), (KNativePointer)v.data(), dispose, (KInt)sizeof(T) }; + } +}; + +typedef _InteropVMContext* KVMContext; + +// BEWARE: this MUST never be used in user code, only in very rare service code. +struct _KVMObject; +typedef _KVMObject* KVMObjectHandle; + +typedef struct KVMDeferred { + KVMDeferred() {} + KVMDeferred(InteropDeferred value) + { + handler = value.handler; + context = value.context; + resolve = reinterpret_cast(value.resolve); + reject = reinterpret_cast(value.reject); + } + + void* handler; + void* context; + void (*resolve)(KVMDeferred* thiz, uint8_t* data, int32_t length); + void (*reject)(KVMDeferred* thiz, const char* message); +} KVMDeferred; + +template +T* ptr(KNativePointer ptr) +{ + return reinterpret_cast(ptr); +} + +template +T& ref(KNativePointer ptr) +{ + return *reinterpret_cast(ptr); +} + +inline KNativePointer nativePtr(void* pointer) +{ + return reinterpret_cast(pointer); +} + +template +KNativePointer fnPtr(void (*pointer)(T*)) +{ + return reinterpret_cast(pointer); +} + +#endif /* _KOALA_TYPES_H */ diff --git a/ets1.2/interop/src/cpp/types/signatures.cc b/ets1.2/interop/src/cpp/types/signatures.cc new file mode 100644 index 0000000000000000000000000000000000000000..76bc6748d53f3dfe63e1d2f58750d6d9aa4f866e --- /dev/null +++ b/ets1.2/interop/src/cpp/types/signatures.cc @@ -0,0 +1,175 @@ +/* + * Copyright (c) 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. + */ + +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif + +#include + +#include "interop-types.h" +#include "signatures.h" + +// For types with the same name on ets and jni +#define KOALA_INTEROP_TYPEDEF(func, lang, CPP_TYPE, SIG_TYPE, CODE_TYPE) \ + if (std::strcmp(func, "sigType") == 0) \ + if (type == (CPP_TYPE)) \ + return SIG_TYPE; \ + if (std::strcmp(func, "codeType") == 0) \ + if (type == (CPP_TYPE)) \ + return CODE_TYPE; + +// For types with distinct names on ets and jni +#define KOALA_INTEROP_TYPEDEF_LS(func, lang, CPP_TYPE, ETS_SIG_TYPE, ETS_CODE_TYPE, JNI_SIG_TYPE, JNI_CODE_TYPE) \ + if (std::strcmp(func, "sigType") == 0 && std::strcmp(lang, "ets") == 0) \ + if (type == (CPP_TYPE)) \ + return ETS_SIG_TYPE; \ + if (std::strcmp(func, "codeType") == 0 && std::strcmp(lang, "ets") == 0) \ + if (type == (CPP_TYPE)) \ + return ETS_CODE_TYPE; \ + if (std::strcmp(func, "sigType") == 0 && std::strcmp(lang, "jni") == 0) \ + if (type == (CPP_TYPE)) \ + return JNI_SIG_TYPE; \ + if (std::strcmp(func, "codeType") == 0 && std::strcmp(lang, "jni") == 0) \ + if (type == (CPP_TYPE)) \ + return JNI_CODE_TYPE; + +#define KOALA_INTEROP_TYPEDEFS(func, lang) \ + KOALA_INTEROP_TYPEDEF(func, lang, "void", "V", "void") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KBoolean", "Z", "boolean") \ + KOALA_INTEROP_TYPEDEF(func, lang, "OH_Boolean", "Z", "boolean") \ + KOALA_INTEROP_TYPEDEF(func, lang, "Ark_Boolean", "Z", "boolean") \ + KOALA_INTEROP_TYPEDEF(func, lang, "int32_t", "I", "int") \ + KOALA_INTEROP_TYPEDEF(func, lang, "uint32_t", "I", "int") \ + KOALA_INTEROP_TYPEDEF(func, lang, "int", "I", "int") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KInt", "I", "int") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KUInt", "I", "int") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KLong", "J", "long") \ + KOALA_INTEROP_TYPEDEF(func, lang, "OH_Int32", "I", "int") \ + KOALA_INTEROP_TYPEDEF(func, lang, "OH_Int64", "J", "long") \ + KOALA_INTEROP_TYPEDEF(func, lang, "Ark_Int32", "I", "int") \ + KOALA_INTEROP_TYPEDEF(func, lang, "Ark_Int64", "J", "long") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KNativePointer", "J", "long") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KSerializerBuffer", "J", "long") \ + KOALA_INTEROP_TYPEDEF(func, lang, "Ark_NativePointer", "J", "long") \ + KOALA_INTEROP_TYPEDEF(func, lang, "OH_NativePointer", "J", "long") \ + KOALA_INTEROP_TYPEDEF(func, lang, "float", "F", "float") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KFloat", "F", "float") \ + KOALA_INTEROP_TYPEDEF(func, lang, "Ark_Float32", "F", "float") \ + KOALA_INTEROP_TYPEDEF(func, lang, "double", "D", "double") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KDouble", "D", "double") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KInteropNumber", "D", "double") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KVMObjectHandle", "Ljava/lang/Object;", "Object") \ + KOALA_INTEROP_TYPEDEF(func, lang, "uint8_t*", "[B", "byte[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KByte*", "[B", "byte[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KInteropBuffer", "[B", "byte[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KShort*", "[S", "short[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KUShort*", "[S", "short[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "int32_t*", "[I", "int[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KInt*", "[I", "int[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KNativePointerArray", "[J", "long[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KInteropReturnBuffer", "[B", "byte[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "float*", "[F", "float[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KFloatArray", "[F", "float[]") \ + KOALA_INTEROP_TYPEDEF(func, lang, "KFloat*", "[F", "float[]") \ + KOALA_INTEROP_TYPEDEF_LS(func, lang, "KStringPtr", "Lstd/core/String;", "String", "Ljava/lang/String;", "String") \ + KOALA_INTEROP_TYPEDEF_LS( \ + func, lang, "KStringArray", "[Lstd/core/String;", "String[]", "[Ljava/lang/String;", "String[]") + +std::string sigType(const std::string& type) +{ +#if KOALA_USE_PANDA_VM + KOALA_INTEROP_TYPEDEFS("sigType", "ets") +#elif KOALA_USE_JAVA_VM + KOALA_INTEROP_TYPEDEFS("sigType", "jni") +#endif + INTEROP_FATAL("Unhandled type: %s\n", type.c_str()); + return type; +} + +std::string codeType(const std::string& type) +{ +#if KOALA_USE_PANDA_VM + KOALA_INTEROP_TYPEDEFS("codeType", "ets") +#elif KOALA_USE_JAVA_VM + KOALA_INTEROP_TYPEDEFS("codeType", "jni") +#endif + INTEROP_FATAL("Unhandled type: %s\n", type.c_str()); + return ""; +} + +std::string convertType(const char* name, const char* koalaType) +{ + std::string result; + size_t current = 0, last = 0; + std::string input(koalaType); + std::vector tokens; + while ((current = input.find('|', last)) != std::string::npos) { + auto token = input.substr(last, current - last); + tokens.push_back(token); + last = current + 1; + } + tokens.push_back(input.substr(last, input.length() - last)); + +#if KOALA_USE_PANDA_VM + + for (int i = 1; i < static_cast(tokens.size()); i++) { + result.append(sigType(tokens[i])); + } + result.append(":"); + result.append(sigType(tokens[0])); + +#elif KOALA_USE_JAVA_VM + + result.append("("); + for (int i = 1; i < static_cast(tokens.size()); i++) { + result.append(sigType(tokens[i])); + } + result.append(")"); + result.append(sigType(tokens[0])); + +#endif + +#ifdef KOALA_BUILD_FOR_SIGNATURES +#ifdef KOALA_USE_PANDA_VM + std::string params; + for (int i = 1; i < static_cast(tokens.size()); i++) { + params.append("arg"); + params.append(std::to_string(i)); + params.append(": "); + params.append(codeType(tokens[i])); + if (i < static_cast(tokens.size() - 1)) + params.append(", "); + } + fprintf(stderr, " static native %s(%s): %s;\n", name, params.c_str(), codeType(tokens[0]).c_str()); +#elif KOALA_USE_JAVA_VM + std::string params; + for (int i = 1; i < static_cast(tokens.size()); i++) { + params.append(codeType(tokens[i])); + params.append(" arg"); + params.append(std::to_string(i)); + if (i < static_cast(tokens.size() - 1)) + params.append(", "); + } + fprintf(stderr, " public static native %s %s(%s);\n", codeType(tokens[0]).c_str(), name, params.c_str()); +#endif +#endif + + return result; +} diff --git a/ets1.2/interop/src/cpp/types/signatures.h b/ets1.2/interop/src/cpp/types/signatures.h new file mode 100644 index 0000000000000000000000000000000000000000..4726766edaa797bc3a5fc83b911f93ced025647e --- /dev/null +++ b/ets1.2/interop/src/cpp/types/signatures.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _SIGNATURES_H +#define _SIGNATURES_H + +#include + +std::string sigType(const std::string& type); +std::string codeType(const std::string& type); +std::string convertType(const char* name, const char* koalaType); + +#endif // _SIGNATURES_H diff --git a/ets1.2/interop/src/cpp/vmloader.cc b/ets1.2/interop/src/cpp/vmloader.cc new file mode 100644 index 0000000000000000000000000000000000000000..e9693e89de647891abd6c0e4e087bb13c6d6c0f6 --- /dev/null +++ b/ets1.2/interop/src/cpp/vmloader.cc @@ -0,0 +1,1171 @@ +/* + * Copyright (c) 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. + */ + +#include +#include +#include +#include +#include + +#include "dynamic-loader.h" +#include "interop-logging.h" +#include "interop-utils.h" +#include "koala-types.h" + +// DO NOT USE KOALA INTEROP MECHANISMS IN THIS FILE! + +#ifdef KOALA_JNI +#include "jni.h" +#endif + +#ifdef KOALA_ETS_NAPI +#include "etsapi.h" +#endif + +#ifdef KOALA_ANI +#include "ani.h" +#endif + +#ifdef KOALA_KOTLIN +#include "kotlin_vmloader_wrapper.h" +#endif + +#if defined(KOALA_LINUX) || defined(KOALA_MACOS) || defined(KOALA_OHOS) +#include "dirent.h" +#include "sys/stat.h" +#endif + +#define OHOS_USER_LIBS "/data/storage/el1/bundle/libs" +#ifdef KOALA_OHOS_ARM32 +#define USE_SYSTEM_ARKVM 1 +#elif KOALA_OHOS_ARM64 +#define USE_SYSTEM_ARKVM 1 +#else +#define USE_SYSTEM_ARKVM 0 +#endif + +#if USE_SYSTEM_ARKVM +#define SYSTEM_ARK_STDLIB_PATH "/system/etc/etsstdlib.abc" +#endif + +#ifndef KOALA_USE_PANDA_VM +#ifdef KOALA_ANI +#define KOALA_USE_PANDA_VM 1 +#endif +#ifdef KOALA_ETS_NAPI +#define KOALA_USE_PANDA_VM 1 +#endif +#endif + +void traverseDir(const std::string& root, std::vector& paths, std::string suffix, + const std::vector& fallbackPaths = {}); + +struct VMLibInfo { + const char* sdkPath; + const char* platform; + const char* lib; +}; + +#ifdef KOALA_JNI +const VMLibInfo javaVMLib = { getenv("JAVA_HOME"), +#if defined(KOALA_LINUX) || defined(KOALA_MACOS) + "lib/server" +#elif KOALA_WINDOWS + "bin/server" +#else +#error "Unknown platform" +#endif + , + "jvm" }; +#endif + +#if defined(KOALA_ETS_NAPI) || defined(KOALA_ANI) +const VMLibInfo pandaVMLib = { +// sdkPath +#if defined(KOALA_OHOS) +#ifdef KOALA_OHOS_ARM32 + "/system/lib" +#elif KOALA_OHOS_ARM64 + "/system/lib64" +#else + OHOS_USER_LIBS +#endif +#else + getenv("PANDA_HOME") +#endif + , + +// platform +#ifdef KOALA_LINUX +#ifdef KOALA_LINUX_ARM64 + "linux_arm64_host_tools/lib" +#else + "linux_host_tools/lib" +#endif +#elif KOALA_MACOS + "macos_host_tools/lib" +#elif KOALA_WINDOWS + "_host_tools/lib" +#elif KOALA_OHOS_ARM64 + "arm64" +#elif KOALA_OHOS_ARM32 + "arm" +#else +#error "Unknown platform" +#endif + , + + // lib + "arkruntime" +}; +#endif + +#ifdef KOALA_KOTLIN +const VMLibInfo kotlinLib = { + .sdkPath = nullptr, + .platform = nullptr, + .lib = "kotlin_koala", +}; +#endif + +struct VMInitArgs { + int version; + int nOptions; + void* options; +}; + +#define JAVA_VM_KIND 1 +#define PANDA_VM_KIND 2 +#define ES2PANDA_KIND 3 +#define PANDA_ANI_VM_KIND 4 +#define KOTLIN_KIND 5 + +struct ForeignVMContext { + void* currentVMContext; + int32_t (*callSync)(void* vmContext, int32_t callback, int8_t* data, int32_t length); +}; + +struct VMEntry { + int vmKind; + void* env; + void* app; + void* create; + void* start; + void* enter; + void* emitEvent; + void* restartWith; + void* loadView; + ForeignVMContext foreignVMContext; + std::string userFilesAbcPaths; +}; + +VMEntry g_vmEntry = {}; + +typedef int (*createVM_t)(void** pVM, void** pEnv, void* vmInitArgs); + +#ifdef KOALA_WINDOWS +#define DLL_EXPORT __declspec(dllexport) +#else +#define DLL_EXPORT __attribute__((visibility("default"))) +#endif + +int loadES2Panda(const char* appClassPath, const char* appLibPath) +{ + fprintf(stderr, "native: es2panda %s\n", appClassPath); + return 0; +} + +#ifdef KOALA_ETS_NAPI +namespace { + +enum PandaLog2MobileLog : int { + UNKNOWN = 0, + DEFAULT, + VERBOSE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL, + SILENT, +}; + +int ArkMobileLog(int id, int level, const char* component, const char* fmt, const char* msg) +{ + switch (level) { + case PandaLog2MobileLog::DEFAULT: + case PandaLog2MobileLog::VERBOSE: + case PandaLog2MobileLog::DEBUG: + case PandaLog2MobileLog::INFO: + case PandaLog2MobileLog::SILENT: + LOGI("ArkRuntime [%" LOG_PUBLIC "s]: %" LOG_PUBLIC "s", component, msg); + break; + case PandaLog2MobileLog::UNKNOWN: + case PandaLog2MobileLog::WARN: + case PandaLog2MobileLog::ERROR: + case PandaLog2MobileLog::FATAL: + default: + LOGE("ArkRuntime [%" LOG_PUBLIC "s]: %" LOG_PUBLIC "s", component, msg); + break; + } + return 0; +} + +} // namespace +#endif + +#ifdef KOALA_ANI + +static void AniMobileLog([[maybe_unused]] FILE* stream, int level, const char* component, const char* msg) +{ + switch (level) { + case ANI_LOGLEVEL_INFO: + case ANI_LOGLEVEL_DEBUG: + LOGI("ArkRuntime [%" LOG_PUBLIC "s]: %" LOG_PUBLIC "s", component, msg); + break; + case ANI_LOGLEVEL_FATAL: + case ANI_LOGLEVEL_ERROR: + case ANI_LOGLEVEL_WARNING: + default: + LOGE("ArkRuntime [%" LOG_PUBLIC "s]: %" LOG_PUBLIC "s", component, msg); + break; + } +} + +static std::string makeClasspath(const std::vector& files) +{ + std::stringstream stream; + for (size_t index = 0, end = files.size(); index < end; ++index) { + if (index > 0) { + stream << ':'; + } + stream << files[index]; + } + return stream.str(); +} + +static std::pair GetBootAndAppPandaFiles( + const VMLibInfo* thisVM, const char* bootFilesPath, const char* userFilesPath) +{ + std::vector bootFiles; +#if USE_SYSTEM_ARKVM + bootFiles.push_back(SYSTEM_ARK_STDLIB_PATH); +#elif defined(KOALA_OHOS) + bootFiles.push_back(std::string(OHOS_USER_LIBS) + "/etsstdlib.abc"); +#elif defined(KOALA_LINUX) || defined(KOALA_MACOS) || defined(KOALA_WINDOWS) + bootFiles.push_back(std::string(thisVM->sdkPath) + "/ets/etsstdlib.abc"); +#endif + +#if defined(KOALA_OHOS) + traverseDir("/system/framework", bootFiles, ".abc", { "etsstdlib_bootabc" }); +#endif + + std::vector userFiles; + traverseDir(userFilesPath, userFiles, ".abc"); + std::sort(userFiles.begin(), userFiles.end()); + + traverseDir(bootFilesPath, bootFiles, ".abc"); + std::sort(bootFiles.begin(), bootFiles.end()); + + if (bootFiles.empty() || userFiles.empty()) + return { "", "" }; + + return { makeClasspath(bootFiles), makeClasspath(userFiles) }; +} + +static std::string GetAOTFiles(const char* appClassPath) +{ + std::vector files; + traverseDir(std::string(appClassPath), files, ".an"); + return makeClasspath(files); +} + +static bool ResetErrorIfExists(ani_env* env) +{ + ani_boolean hasError = ANI_FALSE; + env->ExistUnhandledError(&hasError); + if (hasError == ANI_TRUE) { + env->DescribeError(); + env->ResetError(); + return true; + } + return false; +} + +#endif + +std::string makeLibPath(const char* sdkPath, const char* platform, const char* lib) +{ + std::string result; + constexpr auto RESERVE_SIZE{255}; + result.reserve(RESERVE_SIZE); + if (sdkPath) { + result.append(sdkPath).append("/"); + } + if (platform) { + result.append(platform).append("/"); + } + result.append(libName(lib)); + return result; +} + +extern "C" DLL_EXPORT KInt LoadVirtualMachine(KInt vmKind, const char* bootFilesDir, const char* userFilesDir, + const char* appLibPath, const ForeignVMContext* foreignVMContext) +{ + if (vmKind == ES2PANDA_KIND) { + return loadES2Panda(bootFilesDir, appLibPath); + } + + const VMLibInfo* thisVM = +#ifdef KOALA_JNI + (vmKind == JAVA_VM_KIND) ? &javaVMLib : +#endif +#if defined(KOALA_ETS_NAPI) || defined(KOALA_ANI) + (vmKind == PANDA_VM_KIND || vmKind == PANDA_ANI_VM_KIND) ? &pandaVMLib + : +#endif +#ifdef KOALA_KOTLIN + (vmKind == KOTLIN_KIND) ? &kotlinLib + : +#endif + nullptr; + + if (!thisVM) { + LOGE("Unknown VM kind: %" LOG_PUBLIC "d\n (possibly %" LOG_PUBLIC "s is compiled without expected flags)", + vmKind, __FILE__); + return -1; + } + + LOGI("Starting VM %" LOG_PUBLIC "d with bootFilesDir=%" LOG_PUBLIC "s userFilesDir=%" LOG_PUBLIC + "s native=%" LOG_PUBLIC "s", + vmKind, bootFilesDir, userFilesDir, appLibPath); + + std::string libPath = +#if USE_SYSTEM_ARKVM + std::string(thisVM->sdkPath) + "/" + libName(thisVM->lib) +#elif defined(KOALA_LINUX) || defined(KOALA_MACOS) || defined(KOALA_WINDOWS) + makeLibPath(thisVM->sdkPath, thisVM->platform, thisVM->lib) +#elif defined(KOALA_OHOS) + std::string(OHOS_USER_LIBS) + "/" + libName(thisVM->lib) +#else +#error "Library path not specified for this platform" +#endif + ; + void* handle = loadLibrary(libPath); + if (!handle) { + LOGE("Cannot load library %" LOG_PUBLIC "s: %" LOG_PUBLIC "s\n", libPath.c_str(), libraryError()); + return -1; + } + + void* vm = nullptr; + void* env = nullptr; + int result = 0; + +#ifdef KOALA_JNI + if (vmKind == JAVA_VM_KIND) { + typedef int (*createVM_t)(void** pVM, void** pEnv, void* vmInitArgs); + createVM_t createVM = (createVM_t)findSymbol(handle, "JNI_CreateJavaVM"); + if (!createVM) { + LOGE("Cannot find %" LOG_PUBLIC "s\n", "JNI_CreateJavaVM"); + return -1; + } + JavaVMInitArgs javaVMArgs; + javaVMArgs.version = JNI_VERSION_10; + javaVMArgs.ignoreUnrecognized = false; + std::vector javaVMOptions; + javaVMOptions = { + { (char*)strdup((std::string("-Djava.class.path=") + bootFilesDir).c_str()) }, + { (char*)strdup((std::string("-Djava.library.path=") + appLibPath).c_str()) }, + }; + javaVMArgs.nOptions = javaVMOptions.size(); + javaVMArgs.options = javaVMOptions.data(); + g_vmEntry.vmKind = JAVA_VM_KIND; + result = createVM(&vm, &env, &javaVMArgs); + } +#endif + +#if defined(KOALA_ANI) + if (vmKind == PANDA_ANI_VM_KIND) { + g_vmEntry.vmKind = vmKind; + + uint32_t version = ANI_VERSION_1; + size_t nVMs = 0; + typedef int (*getVMs_t)(void** pVM, size_t bufLen, size_t* nVMs); + typedef int (*createVM_t)(const void* args, uint32_t version, void** pVM); + createVM_t createVM = (createVM_t)findSymbol(handle, "ANI_CreateVM"); + getVMs_t getVMs = (getVMs_t)findSymbol(handle, "ANI_GetCreatedVMs"); + result = getVMs ? getVMs(&vm, 1, &nVMs) : 0; + if (nVMs == 0 && result == 0) { + std::vector pandaVMOptions; + + auto [bootFiles, userFiles] = GetBootAndAppPandaFiles(thisVM, bootFilesDir, userFilesDir); + LOGI("ANI: user abc-files \"%" LOG_PUBLIC "s\" from %" LOG_PUBLIC "s", userFiles.c_str(), userFilesDir); + g_vmEntry.userFilesAbcPaths = std::move(userFiles); + + bootFiles = "--ext:--boot-panda-files=" + bootFiles; + LOGI("ANI boot-panda-files option: \"%" LOG_PUBLIC "s\"", bootFiles.c_str()); + pandaVMOptions.push_back({ bootFiles.c_str(), nullptr }); + + auto aotFiles = GetAOTFiles(bootFilesDir); + if (!aotFiles.empty()) { + LOGI("ANI AOT files: \"%" LOG_PUBLIC "s\"", aotFiles.c_str()); + aotFiles = "--ext:--aot-files=" + aotFiles; + pandaVMOptions.push_back({ aotFiles.c_str(), nullptr }); + } + + pandaVMOptions.push_back({ "--ext:--gc-trigger-type=heap-trigger", nullptr }); + std::string nativeLibraryPathOption = std::string("--ext:--native-library-path=") + appLibPath; + pandaVMOptions.push_back({ nativeLibraryPathOption.c_str(), nullptr }); + pandaVMOptions.push_back({ "--ext:--verification-mode=on-the-fly", nullptr }); + pandaVMOptions.push_back({ "--ext:--compiler-enable-jit=true", nullptr }); + pandaVMOptions.push_back({ "--logger", reinterpret_cast(AniMobileLog) }); + pandaVMOptions.push_back({ "--ext:--enable-an", nullptr }); + ani_options optionsPtr = { pandaVMOptions.size(), pandaVMOptions.data() }; + + result = createVM(&optionsPtr, version, &vm); + } + + if (result == 0) { + ani_vm* vmInstance = (ani_vm*)vm; + ani_env* pEnv = nullptr; + result = vmInstance->GetEnv(version, &pEnv); + env = static_cast(pEnv); + } + } +#endif /* KOALA_ANI */ + +// For now we use ETS API for VM startup and entry. +#if defined(KOALA_ETS_NAPI) + if (vmKind == PANDA_VM_KIND) { + EtsVMInitArgs pandaVMArgs; + pandaVMArgs.version = ETS_NAPI_VERSION_1_0; + std::vector etsVMOptions; + std::vector files; + traverseDir(std::string(bootFilesDir), files, ".abc"); + std::sort(files.begin(), files.end()); + std::vector files_aot; + traverseDir(std::string(bootFilesDir), files_aot, ".an"); + std::sort(files_aot.begin(), files_aot.end()); + etsVMOptions = { +#if USE_SYSTEM_ARKVM + { EtsOptionType::ETS_BOOT_FILE, SYSTEM_ARK_STDLIB_PATH }, +#elif defined(KOALA_OHOS) + { EtsOptionType::ETS_BOOT_FILE, (std::string(OHOS_USER_LIBS) + "/" + "etsstdlib.abc").c_str() }, + +#elif defined(KOALA_LINUX) || defined(KOALA_MACOS) || defined(KOALA_WINDOWS) + { EtsOptionType::ETS_BOOT_FILE, + (char*)strdup((std::string(thisVM->sdkPath) + "/ets/etsstdlib.abc").c_str()) }, +#endif + }; + std::string all_files; + for (const std::string& path : files) { + etsVMOptions.push_back({ EtsOptionType::ETS_BOOT_FILE, (char*)strdup(path.c_str()) }); + if (all_files.size() > 0) + all_files.append(":"); + all_files.append(path); + } + LOGI("Using ETSNAPI: classpath \"%" LOG_PUBLIC "s\" from %" LOG_PUBLIC "s", all_files.c_str(), bootFilesDir); + std::string all_files_aot; + for (const std::string& path : files_aot) { + etsVMOptions.push_back({ EtsOptionType::ETS_AOT_FILE, (char*)strdup(path.c_str()) }); + if (all_files_aot.size() > 0) + all_files_aot.append(":"); + all_files_aot.append(path); + } + LOGI("ETSNAPI classpath (aot) \"%" LOG_PUBLIC "s\" from %" LOG_PUBLIC "s", all_files_aot.c_str(), bootFilesDir); + etsVMOptions.push_back({ EtsOptionType::ETS_GC_TRIGGER_TYPE, "heap-trigger" }); + etsVMOptions.push_back( + { EtsOptionType::ETS_NATIVE_LIBRARY_PATH, (char*)strdup(std::string(appLibPath).c_str()) }); + etsVMOptions.push_back({ EtsOptionType::ETS_VERIFICATION_MODE, "on-the-fly" }); + etsVMOptions.push_back({ EtsOptionType::ETS_JIT, nullptr }); + etsVMOptions.push_back({ EtsOptionType::ETS_MOBILE_LOG, (void*)ArkMobileLog }); + etsVMOptions.push_back({ EtsOptionType::ETS_AOT, nullptr }); + pandaVMArgs.nOptions = etsVMOptions.size(); + pandaVMArgs.options = etsVMOptions.data(); + g_vmEntry.vmKind = vmKind; + + int32_t nVMs = 0; + typedef int (*createVM_t)(void** pVM, void** pEnv, void* vmInitArgs); + typedef int (*getVMs_t)(void** pVM, int32_t bufLen, int32_t* nVMs); + createVM_t createVM = (createVM_t)findSymbol(handle, "ETS_CreateVM"); + getVMs_t getVMs = (getVMs_t)findSymbol(handle, "ETS_GetCreatedVMs"); + result = getVMs ? getVMs(&vm, 1, &nVMs) : 0; + if (nVMs != 0) { + __EtsVM* vmInstance = (__EtsVM*)vm; + EtsEnv* pEnv = nullptr; + vmInstance->GetEnv(&pEnv, ETS_NAPI_VERSION_1_0); + env = static_cast(pEnv); + + } else { + result = createVM(&vm, &env, &pandaVMArgs); + } + } +#endif + +#ifdef KOALA_KOTLIN + if (vmKind == KOTLIN_KIND) { + g_vmEntry.vmKind = vmKind; + (void)vm; + + kotlin_exported_symbols_t kotlin_exported_symbols = + (kotlin_exported_symbols_t)findSymbol(handle, "kotlin_koala_symbols"); + env = kotlin_exported_symbols(); + + set_user_view_factory_t set_user_view_factory = + (set_user_view_factory_t)findSymbol(handle, "set_user_view_factory"); + set_user_view_factory(); + + g_vmEntry.create = findSymbol(handle, "application_create"); + g_vmEntry.start = findSymbol(handle, "application_start"); + g_vmEntry.enter = findSymbol(handle, "application_enter"); + g_vmEntry.emitEvent = findSymbol(handle, "application_emit_event"); + + result = 0; + } +#endif + + if (result != 0) { + LOGE("Error creating a VM of kind %" LOG_PUBLIC "d: %" LOG_PUBLIC "d\n", vmKind, result); + return result; + } + g_vmEntry.env = env; + g_vmEntry.foreignVMContext = *foreignVMContext; + return 0; +} + +struct AppInfo { + const char* className; + const char* createMethodName; + const char* createMethodSig; + const char* startMethodName; + const char* startMethodSig; + const char* enterMethodName; + const char* enterMethodSig; + const char* emitEventMethodName; + const char* emitEventMethodSig; + const char* restartWithMethodName; + const char* restartWithMethodSig; + const char* loadViewMethodName; + const char* loadViewMethodSig; +}; + +#ifdef KOALA_JNI +const AppInfo javaAppInfo = { "org/koalaui/arkoala/Application", "createApplication", + "(Ljava/lang/String;Ljava/lang/String;)Lorg/koalaui/arkoala/Application;", "start", "(JI)J", "enter", "(IIJ)Z", + "emitEvent", "(IIII)Ljava/lang/String;", "UNUSED", "()V" }; +#endif + +#ifdef KOALA_ETS_NAPI +const AppInfo pandaAppInfo = { "arkui/ArkUIEntry/Application", "createApplication", + "Lstd/core/String;Lstd/core/String;ZI:Larkui/ArkUIEntry/Application;", "start", "JI:J", "enter", "IIJ:Z", + "emitEvent", "IIII:Lstd/core/String;", "UNUSED", "I:I" }; +const AppInfo harnessAppInfo = { + "@koalaui/ets-harness/src/EtsHarnessApplication/EtsHarnessApplication", + "createApplication", + "Lstd/core/String;Lstd/core/String;ZI:L@koalaui/ets-harness/src/EtsHarnessApplication/EtsHarnessApplication;", + "start", + "J:J", + "enter", + "IIJ:Z", + "emitEvent", + "IIII:Lstd/core/String;", + "restartWith", + "Lstd/core/String;:V", +}; +#endif +#ifdef KOALA_ANI +const AppInfo harnessAniAppInfo = { "@koalaui.ets-harness.src.EtsHarnessApplication.EtsHarnessApplication", + "createApplication", + "C{std.core.String}C{std.core.String}C{std.core.String}zi:C{@koalaui.ets-harness.src.EtsHarnessApplication." + "EtsHarnessApplication}", + "start", "li:l", "enter", "iil:z", "emitEvent", "iiii:C{std.core.String}", "restartWith", + "C{std.core.String}:", "UNUSED", "i:i" }; +const AppInfo aniAppInfo = { + "arkui.ArkUIEntry.Application", + "createApplication", + "C{std.core.String}C{std.core.String}C{std.core.String}zi:C{arkui.ArkUIEntry.Application}", + "start", + "li:l", + "enter", + "il:z", + "emitEvent", + "iiii:C{std.core.String}", + "UNUSED", + "i:i", + "loadView", + "C{std.core.String}C{std.core.String}:C{std.core.String}", +}; +#endif + +#ifdef KOALA_KOTLIN +const AppInfo kotlinAppInfo = { 0 }; +#endif + +extern "C" DLL_EXPORT KNativePointer StartApplication(const char* appUrl, const char* appParams, int32_t loopIterations) +{ + const auto isTestEnv = std::string(appUrl) == "EtsHarness"; + const AppInfo* appInfo = +#ifdef KOALA_JNI + (g_vmEntry.vmKind == JAVA_VM_KIND) ? &javaAppInfo : +#endif +#if defined(KOALA_ETS_NAPI) + (g_vmEntry.vmKind == PANDA_VM_KIND) ? isTestEnv ? &harnessAppInfo : &pandaAppInfo + : +#endif +#if defined(KOALA_ANI) + (g_vmEntry.vmKind == PANDA_ANI_VM_KIND) ? isTestEnv ? &harnessAniAppInfo : &aniAppInfo + : +#endif +#if defined(KOALA_KOTLIN) + (g_vmEntry.vmKind == KOTLIN_KIND) ? &kotlinAppInfo + : +#endif + nullptr; + + if (!appInfo) { + LOGE("No appInfo provided for VM kind %" LOG_PUBLIC "d (recompile vmloader.cc with the missing flags)\n", + g_vmEntry.vmKind); + return nullptr; + } + + LOGI("Starting application %" LOG_PUBLIC "s with params %" LOG_PUBLIC "s", appUrl, appParams); +#ifdef KOALA_JNI + if (g_vmEntry.vmKind == JAVA_VM_KIND) { + JNIEnv* jEnv = (JNIEnv*)(g_vmEntry.env); + jclass appClass = jEnv->FindClass(appInfo->className); + if (!appClass) { + LOGE("Cannot load main class %s\n", appInfo->className); + return nullptr; + } + jmethodID create = jEnv->GetStaticMethodID(appClass, appInfo->createMethodName, appInfo->createMethodSig); + if (!create) { + LOGE("Cannot find create method %s\n", appInfo->createMethodName); + return nullptr; + } + auto app = jEnv->NewGlobalRef( + jEnv->CallStaticObjectMethod(appClass, create, jEnv->NewStringUTF(appUrl), jEnv->NewStringUTF(appParams))); + g_vmEntry.app = app; + auto start = jEnv->GetMethodID(appClass, appInfo->startMethodName, appInfo->startMethodSig); + if (!start) { + LOGE("Cannot find start method \"%s %s\"\n", appInfo->startMethodName, appInfo->startMethodSig); + return nullptr; + } + g_vmEntry.enter = (void*)(jEnv->GetMethodID(appClass, appInfo->enterMethodName, appInfo->enterMethodSig)); + if (!g_vmEntry.enter) { + LOGE("Cannot find enter method %s\n", appInfo->enterMethodName); + return nullptr; + } + g_vmEntry.emitEvent = + (void*)(jEnv->GetMethodID(appClass, appInfo->emitEventMethodName, appInfo->emitEventMethodSig)); + if (!g_vmEntry.emitEvent) { + LOGE("Cannot find emitEvent method %s\n", appInfo->emitEventMethodName); + return nullptr; + } + return reinterpret_cast(jEnv->CallLongMethod(app, start)); + } +#endif +#if defined(KOALA_ETS_NAPI) + if (g_vmEntry.vmKind == PANDA_VM_KIND) { + EtsEnv* etsEnv = (EtsEnv*)g_vmEntry.env; + ets_class appClass = etsEnv->FindClass(appInfo->className); + if (!appClass) { + LOGE("Cannot load main class %" LOG_PUBLIC "s\n", appInfo->className); + if (etsEnv->ErrorCheck()) { + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + return nullptr; + } + ets_method create = etsEnv->GetStaticp_method(appClass, appInfo->createMethodName, appInfo->createMethodSig); + if (!create) { + LOGE("Cannot find create method %" LOG_PUBLIC "s\n", appInfo->createMethodName); + if (etsEnv->ErrorCheck()) { + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + return nullptr; + } + auto useNativeLog = false; + auto app = etsEnv->NewGlobalRef(etsEnv->CallStaticObjectMethod(appClass, create, etsEnv->NewStringUTF(appUrl), + etsEnv->NewStringUTF(appParams), useNativeLog, g_vmEntry.vmKind)); + if (!app) { + LOGE("createApplication returned null"); + if (etsEnv->ErrorCheck()) { + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + return nullptr; + } + return nullptr; + } + g_vmEntry.app = (void*)app; + auto start = etsEnv->Getp_method(appClass, appInfo->startMethodName, appInfo->startMethodSig); + g_vmEntry.enter = + (void*)(etsEnv->Getp_method(appClass, appInfo->enterMethodName, nullptr /*appInfo->enterMethodSig */)); + if (!g_vmEntry.enter) { + LOGE("Cannot find enter method %" LOG_PUBLIC "s", appInfo->enterMethodName); + if (etsEnv->ErrorCheck()) { + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + return nullptr; + } + if (etsEnv->ErrorCheck()) { + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + return nullptr; + } + g_vmEntry.emitEvent = + (void*)(etsEnv->Getp_method(appClass, appInfo->emitEventMethodName, appInfo->emitEventMethodSig)); + if (!g_vmEntry.emitEvent) { + LOGE("Cannot find enter emitEvent %" LOG_PUBLIC "s", appInfo->emitEventMethodSig); + if (etsEnv->ErrorCheck()) { + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + return nullptr; + } + if (isTestEnv) { + g_vmEntry.restartWith = + (void*)(etsEnv->Getp_method(appClass, appInfo->restartWithMethodName, appInfo->restartWithMethodSig)); + if (!g_vmEntry.restartWith) { + LOGE("Cannot find enter restartWith %" LOG_PUBLIC "s", appInfo->restartWithMethodSig); + if (etsEnv->ErrorCheck()) { + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + return nullptr; + } + } + // Improve: pass app entry point! + return reinterpret_cast( + etsEnv->CallLongMethod((ets_object)(app), start, &g_vmEntry.foreignVMContext)); + } +#endif +#if defined(KOALA_ANI) + if (g_vmEntry.vmKind == PANDA_ANI_VM_KIND) { + auto* env = reinterpret_cast(g_vmEntry.env); + + ani_class appClass {}; + auto status = env->FindClass(appInfo->className, &appClass); + if (status != ANI_OK) { + LOGE("Cannot load main class %" LOG_PUBLIC "s\n", appInfo->className); + ResetErrorIfExists(env); + return nullptr; + } + ani_static_method create {}; + status = env->Class_FindStaticMethod(appClass, appInfo->createMethodName, appInfo->createMethodSig, &create); + if (status != ANI_OK) { + LOGE("Cannot find create method %" LOG_PUBLIC "s\n", appInfo->createMethodName); + ResetErrorIfExists(env); + return nullptr; + } + + ani_boolean useNativeLog = ANI_FALSE; + ani_string appUrlString {}; + status = env->String_NewUTF8(appUrl, interop_strlen(appUrl), &appUrlString); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return nullptr; + } + + ani_string userPandaFilesPathString {}; + status = env->String_NewUTF8( + g_vmEntry.userFilesAbcPaths.c_str(), g_vmEntry.userFilesAbcPaths.size(), &userPandaFilesPathString); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return nullptr; + } + + ani_string appParamsString {}; + status = env->String_NewUTF8(appParams, interop_strlen(appParams), &appParamsString); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return nullptr; + } + + ani_ref appInstance {}; + status = env->Class_CallStaticMethod_Ref(appClass, create, &appInstance, appUrlString, userPandaFilesPathString, + appParamsString, useNativeLog, static_cast(g_vmEntry.vmKind)); + if (status != ANI_OK) { + LOGE("createApplication returned null"); + ResetErrorIfExists(env); + return nullptr; + } + ani_ref app {}; + status = env->GlobalReference_Create(appInstance, &app); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return nullptr; + } + g_vmEntry.app = (void*)app; + + ani_method start {}; + status = env->Class_FindMethod(appClass, appInfo->startMethodName, appInfo->startMethodSig, &start); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return nullptr; + } + ani_method enter {}; + status = env->Class_FindMethod(appClass, appInfo->enterMethodName, nullptr, &enter); + if (status != ANI_OK) { + LOGE("Cannot find `enter` method %" LOG_PUBLIC "s", appInfo->enterMethodName); + ResetErrorIfExists(env); + return nullptr; + } + g_vmEntry.enter = reinterpret_cast(enter); + ani_method emitEvent {}; + status = env->Class_FindMethod(appClass, appInfo->emitEventMethodName, appInfo->emitEventMethodSig, &emitEvent); + if (status != ANI_OK) { + LOGE("Cannot find `emitEvent` method %" LOG_PUBLIC "s", appInfo->emitEventMethodSig); + ResetErrorIfExists(env); + return nullptr; + } + g_vmEntry.emitEvent = reinterpret_cast(emitEvent); + ani_method loadView {}; + status = env->Class_FindMethod(appClass, appInfo->loadViewMethodName, appInfo->loadViewMethodSig, &loadView); + if (status != ANI_OK) { + LOGE("Cannot find `%" LOG_PUBLIC "s` method %" LOG_PUBLIC "s", appInfo->loadViewMethodName, + appInfo->loadViewMethodSig); + ResetErrorIfExists(env); + return nullptr; + } + g_vmEntry.loadView = reinterpret_cast(loadView); + + if (isTestEnv) { + ani_method restartWith {}; + status = env->Class_FindMethod( + appClass, appInfo->restartWithMethodName, appInfo->restartWithMethodSig, &restartWith); + if (status != ANI_OK) { + LOGE("Cannot find `restartWith` method sig=%" LOG_PUBLIC "s", appInfo->restartWithMethodSig); + ResetErrorIfExists(env); + return nullptr; + } + g_vmEntry.restartWith = reinterpret_cast(restartWith); + } + + ani_long ptr = 0; + // Improve: pass app entry point! + status = env->Object_CallMethod_Long(static_cast(appInstance), start, &ptr, + reinterpret_cast(&g_vmEntry.foreignVMContext), loopIterations); + if (status != ANI_OK) { + LOGE("Cannot start application"); + ResetErrorIfExists(env); + return nullptr; + } + return reinterpret_cast(ptr); + } +#endif + +#if defined(KOALA_KOTLIN) + if (g_vmEntry.vmKind == KOTLIN_KIND) { + application_create_t application_create = (application_create_t)g_vmEntry.create; + application_start_t application_start = (application_start_t)g_vmEntry.start; + + bool useNativeLog = false; + kotlin_kref_VMLoaderApplication app = application_create(appUrl, appParams, useNativeLog); + g_vmEntry.app = app.pinned; + + kotlin_KLong root = application_start(app, loopIterations); + return reinterpret_cast(root); + } +#endif + + return nullptr; +} + +extern "C" DLL_EXPORT KBoolean RunApplication(const KInt arg0, const KInt arg1) +{ +#ifdef KOALA_JNI + if (g_vmEntry.vmKind == JAVA_VM_KIND) { + JNIEnv* jEnv = (JNIEnv*)(g_vmEntry.env); + auto result = jEnv->CallBooleanMethod((jobject)(g_vmEntry.app), (jmethodID)(g_vmEntry.enter), (jint)arg0, + (jint)arg1, (int64_t)(intptr_t)(&g_vmEntry.foreignVMContext)); + if (jEnv->ExceptionCheck()) { + jEnv->ExceptionDescribe(); + jEnv->ExceptionClear(); + } + return result; + } +#endif +#if defined(KOALA_ETS_NAPI) + if (g_vmEntry.vmKind == PANDA_VM_KIND) { + EtsEnv* etsEnv = (EtsEnv*)(g_vmEntry.env); + if (!g_vmEntry.enter) { + LOGE("Cannot find enter method"); + return -1; + } + auto result = etsEnv->CallBooleanMethod((ets_object)(g_vmEntry.app), (ets_method)(g_vmEntry.enter), + (ets_int)arg0, (ets_int)arg1, (int64_t)(intptr_t)(&g_vmEntry.foreignVMContext)); + if (etsEnv->ErrorCheck()) { + LOGE("Calling enter() method gave an error"); + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + return result; + } +#endif +#if defined(KOALA_ANI) + if (g_vmEntry.vmKind == PANDA_ANI_VM_KIND) { + ani_env* env = reinterpret_cast(g_vmEntry.env); + if (g_vmEntry.enter == nullptr) { + LOGE("Cannot find enter method"); + return -1; + } + ani_boolean result = ANI_FALSE; + auto status = env->Object_CallMethod_Boolean(reinterpret_cast(g_vmEntry.app), + reinterpret_cast(g_vmEntry.enter), &result, static_cast(arg0), + static_cast(arg1), reinterpret_cast(&g_vmEntry.foreignVMContext)); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return ANI_FALSE; + } + return result; + } +#endif + +#ifdef KOALA_KOTLIN + if (g_vmEntry.vmKind == KOTLIN_KIND) { + kotlin_kref_VMLoaderApplication app = { .pinned = g_vmEntry.app }; + application_enter_t application_enter = (application_enter_t)g_vmEntry.enter; + return application_enter(app) ? 1 : 0; + } +#endif + + return 1; +} + +extern "C" DLL_EXPORT const char* EmitEvent(const KInt type, const KInt target, const KInt arg0, const KInt arg1) +{ +#ifdef KOALA_JNI + if (g_vmEntry.vmKind == JAVA_VM_KIND) { + JNIEnv* jEnv = (JNIEnv*)(g_vmEntry.env); + if (!g_vmEntry.emitEvent) { + LOGE("Cannot find emitEvent method"); + return "-1"; + } + auto rv = (jstring)jEnv->CallObjectMethod((jobject)(g_vmEntry.app), (jmethodID)(g_vmEntry.emitEvent), + (jint)type, (jint)target, (jint)arg0, (jint)arg1); + if (jEnv->ExceptionCheck()) { + jEnv->ExceptionDescribe(); + jEnv->ExceptionClear(); + } + const char* result = jEnv->GetStringUTFChars(rv, 0); + return result; + } +#endif + +#if defined(KOALA_ETS_NAPI) + if (g_vmEntry.vmKind == PANDA_VM_KIND) { + EtsEnv* etsEnv = (EtsEnv*)(g_vmEntry.env); + if (!g_vmEntry.emitEvent) { + LOGE("Cannot find emitEvent method"); + return "-1"; + } + auto rv = (ets_string)etsEnv->CallObjectMethod((ets_object)(g_vmEntry.app), (ets_method)(g_vmEntry.emitEvent), + (ets_int)type, (ets_int)target, (ets_int)arg0, (ets_int)arg1); + if (etsEnv->ErrorCheck()) { + LOGE("Calling emitEvent() method gave an error"); + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + const char* result = etsEnv->GetStringUTFChars(rv, 0); + return result; + } +#endif +#if defined(KOALA_ANI) + if (g_vmEntry.vmKind == PANDA_ANI_VM_KIND) { + ani_env* env = reinterpret_cast(g_vmEntry.env); + if (g_vmEntry.emitEvent == nullptr) { + LOGE("Cannot find emitEvent method"); + return "-1"; + } + ani_ref result {}; + auto status = env->Object_CallMethod_Ref(reinterpret_cast(g_vmEntry.app), + reinterpret_cast(g_vmEntry.emitEvent), &result, static_cast(type), + static_cast(target), static_cast(arg0), static_cast(arg1)); + if (status != ANI_OK) { + LOGE("Calling emitEvent() method gave an error"); + ResetErrorIfExists(env); + return "-1"; + } + + auto str = static_cast(result); + ani_size sz = 0; + status = env->String_GetUTF8Size(str, &sz); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return "-1"; + } + auto buffer = new char[sz + 1]; + ani_size writtenChars = 0; + status = env->String_GetUTF8(str, buffer, sz + 1, &writtenChars); + if (status != ANI_OK || writtenChars != sz) { + delete[] buffer; + ResetErrorIfExists(env); + return "-1"; + } + return buffer; + } +#endif + +#ifdef KOALA_KOTLIN + if (g_vmEntry.vmKind == KOTLIN_KIND) { + kotlin_kref_VMLoaderApplication app = { .pinned = g_vmEntry.app }; + application_emit_event_t application_emit_event = (application_emit_event_t)g_vmEntry.emitEvent; + const char* kotlinString = application_emit_event(app, type, target, arg0, arg1); + + size_t bufferSize = interop_strlen(kotlinString) + 1; + char* result = (char*)malloc(bufferSize); + interop_strcpy(result, bufferSize, kotlinString); + + kotlin_ExportedSymbols* env = reinterpret_cast(g_vmEntry.env); + env->DisposeString(kotlinString); + + return result; + } +#endif + return "-1"; +} + +extern "C" DLL_EXPORT void RestartWith(const char* page) +{ +#ifdef KOALA_JNI + if (g_vmEntry.vmKind == JAVA_VM_KIND) { + JNIEnv* jEnv = (JNIEnv*)(g_vmEntry.env); + if (!g_vmEntry.restartWith) { + LOGE("Cannot find restartWith method"); + return; + } + jEnv->CallVoidMethod((jobject)(g_vmEntry.app), (jmethodID)(g_vmEntry.restartWith), jEnv->NewStringUTF(page)); + if (jEnv->ExceptionCheck()) { + jEnv->ExceptionDescribe(); + jEnv->ExceptionClear(); + } + } +#endif +#if defined(KOALA_ETS_NAPI) + if (g_vmEntry.vmKind == PANDA_VM_KIND) { + EtsEnv* etsEnv = (EtsEnv*)(g_vmEntry.env); + if (!g_vmEntry.restartWith) { + LOGE("Cannot find restartWith method"); + return; + } + etsEnv->CallVoidMethod( + (ets_object)(g_vmEntry.app), (ets_method)(g_vmEntry.restartWith), etsEnv->NewStringUTF(page)); + if (etsEnv->ErrorCheck()) { + LOGE("Calling restartWith() method gave an error"); + etsEnv->ErrorDescribe(); + etsEnv->ErrorClear(); + } + } +#endif +#if defined(KOALA_ANI) + if (g_vmEntry.vmKind == PANDA_ANI_VM_KIND) { + ani_env* env = reinterpret_cast(g_vmEntry.env); + if (!g_vmEntry.restartWith) { + LOGE("Cannot find restartWith method"); + return; + } + ani_string pageString {}; + auto status = env->String_NewUTF8(page, interop_strlen(page), &pageString); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return; + } + status = env->Object_CallMethod_Void(reinterpret_cast(g_vmEntry.app), + reinterpret_cast(g_vmEntry.restartWith), pageString); + if (status != ANI_OK) { + LOGE("Calling restartWith() method gave an error"); + ResetErrorIfExists(env); + } + } +#endif +} + +extern "C" DLL_EXPORT const char* LoadView(const char* className, const char* params) +{ +#if defined(KOALA_ANI) + if (g_vmEntry.vmKind == PANDA_ANI_VM_KIND) { + ani_env* env = reinterpret_cast(g_vmEntry.env); + if (!g_vmEntry.loadView) { + return strdup("Cannot find loadView() method"); + } + ani_string classNameString {}; + auto status = env->String_NewUTF8(className, interop_strlen(className), &classNameString); + if (status != ANI_OK) { + return strdup("Cannot make ANI string"); + } + ani_string paramsString {}; + status = env->String_NewUTF8(params, interop_strlen(params), ¶msString); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return strdup("Cannot make ANI string"); + } + ani_string resultString = nullptr; + status = env->Object_CallMethod_Ref(reinterpret_cast(g_vmEntry.app), + reinterpret_cast(g_vmEntry.loadView), (ani_ref*)&resultString, classNameString, paramsString); + if (status != ANI_OK) { + ResetErrorIfExists(env); + return strdup("Calling laodView() method gave an error"); + } + ani_size resultStringLength = 0; + status = env->String_GetUTF8Size(resultString, &resultStringLength); + char* resultChars = (char*)malloc(resultStringLength); + if (!resultChars) { + return strdup("Cannot allocate memory"); + } + status = env->String_GetUTF8(resultString, resultChars, resultStringLength, &resultStringLength); + return resultChars; + } +#endif + return strdup("Unsupported"); +} + +namespace fs = std::filesystem; + +bool ends_with(std::string str, std::string suffix) +{ + return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +} + +void traverseDir(const std::string& root, std::vector& paths, std::string suffix, + const std::vector& fallbackPaths) +{ +#ifdef KOALA_OHOS_ARM32 + // selinux prohibits any access to "/system/framework" + if (root == "/system/framework") { + for (auto path : fallbackPaths) { + paths.push_back(root + "/" + path + suffix); + } + return; + } +#endif + + if (!fs::exists(root)) { + LOGE("Cannot open dir %" LOG_PUBLIC "s\n", root.c_str()); + return; + } + +#if defined(KOALA_OHOS) + suffix += ".so"; +#endif + + LOGI("Searching in %" LOG_PUBLIC "s\n", root.c_str()); + for (auto& file : fs::recursive_directory_iterator(root)) { + if (ends_with(file.path().string(), suffix) && fs::is_regular_file(file)) { + paths.push_back(file.path().string()); + } + } +} diff --git a/ets1.2/interop/src/cpp/wasm/convertors-wasm.h b/ets1.2/interop/src/cpp/wasm/convertors-wasm.h new file mode 100644 index 0000000000000000000000000000000000000000..5c540ae6c6d45dc24ad36726f315b2086762b14f --- /dev/null +++ b/ets1.2/interop/src/cpp/wasm/convertors-wasm.h @@ -0,0 +1,983 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#ifndef CONVERTORS_WASM_H +#define CONVERTORS_WASM_H + +#include + +#include "koala-types.h" +#define KOALA_INTEROP_EXPORT EMSCRIPTEN_KEEPALIVE extern "C" + +#include "interop-logging.h" + +template +struct InteropTypeConverter { + using InteropType = T; + static T convertFrom(InteropType value) = delete; + static InteropType convertTo(T value) = delete; + static void release(InteropType value, T converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = const uint8_t*; + static KStringPtr convertFrom(InteropType value) + { + if (value == nullptr) + return KStringPtr(); + KStringPtr result; + int len = (value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24)); + return KStringPtr(value + sizeof(int), len, true); + } + static InteropType convertTo(KStringPtr& value) + { + return (InteropType)value.c_str(); + }; +}; + +template<> +struct InteropTypeConverter { + using InteropType = bool; + static KBoolean convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(KBoolean value) + { + return value; + } + static void release(InteropType value, KBoolean converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = int; + static KInt convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(KInt value) + { + return value; + } + static void release(InteropType value, KInt converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = uint32_t; + static KUInt convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(KUInt value) + { + return value; + } + static void release(InteropType value, KUInt converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = uint8_t; + static KByte convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(KByte value) + { + return value; + } + static void release(InteropType value, KByte converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = float; + static KFloat convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(InteropFloat32 value) + { + return value; + } + static void release(InteropType value, KFloat converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = double; + static KDouble convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(InteropFloat64 value) + { + return value; + } + static void release(InteropType value, KDouble converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = void*; + static KNativePointer convertFrom(InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(KNativePointer value) + { + return reinterpret_cast(value); + } + static void release(InteropType value, KNativePointer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = void**; + static KNativePointerArray convertFrom(InteropType value) + { + return reinterpret_cast(value); + } + static InteropType convertTo(KNativePointerArray value) + { + return reinterpret_cast(value); + } + static void release(InteropType value, KNativePointerArray converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = long; + static KLong convertFrom(InteropType value) + { + return value; + } + static InteropType convertTo(KLong value) + { + return value; + } + static void release(InteropType value, KLong converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = uint64_t; + static KULong convertFrom(InteropType value) + { + return static_cast(value); + } + static InteropType convertTo(KULong value) + { + return static_cast(value); + } + static void release(InteropType value, KULong converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = int32_t*; + static KInt* convertFrom(InteropType value) + { + if (!value) + return nullptr; + return value; + } + static InteropType convertTo(KInt* value) = delete; + static void release(InteropType value, KInt* converted) + { + if (value) + delete value; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = float*; + static KFloat* convertFrom(InteropType value) + { + if (!value) + return nullptr; + return value; + } + static InteropType convertTo(KFloat* value) = delete; + static void release(InteropType value, KFloat* converted) + { + if (value) + delete value; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = unsigned char*; + static KByte* convertFrom(InteropType value) + { + if (!value) + return nullptr; + return (KByte*)value; + } + static InteropType convertTo(KByte* value) = delete; + static void release(InteropType value, KByte* converted) + { + if (value) + delete value; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = unsigned short*; + static KUShort* convertFrom(InteropType value) + { + if (!value) + return nullptr; + return (KUShort*)value; + } + static InteropType convertTo(KUShort* value) = delete; + static void release(InteropType value, KUShort* converted) + { + if (value) + delete value; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = short*; + static KShort* convertFrom(InteropType value) + { + if (!value) + return nullptr; + return (KShort*)value; + } + static InteropType convertTo(KShort* value) = delete; + static void release(InteropType value, KShort* converted) + { + if (value) + delete value; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = const unsigned char*; + static KStringArray convertFrom(InteropType value) + { + if (!value) + return nullptr; + return (KStringArray)value; + } + static InteropType convertTo(KStringArray value) = delete; + static void release(InteropType value, KStringArray converted) + { + if (value) + delete value; + } +}; + +template<> +struct InteropTypeConverter { + using InteropType = long; + static KSerializerBuffer convertFrom(InteropType value) + { + return reinterpret_cast(static_cast(value)); + } + static InteropType convertTo(KSerializerBuffer value) = delete; + static void release(InteropType value, KSerializerBuffer converted) {} +}; + +template<> +struct InteropTypeConverter { + using InteropType = double; + static KInteropNumber convertFrom(InteropType value) + { + return KInteropNumber::fromDouble(value); + } + static InteropType convertTo(KInteropNumber value) + { + return value.asDouble(); + } + static void release(InteropType value, KInteropNumber converted) {} +}; + +template +inline Type getArgument(typename InteropTypeConverter::InteropType arg) +{ + return InteropTypeConverter::convertFrom(arg); +} + +template +inline void releaseArgument(typename InteropTypeConverter::InteropType arg, Type& data) +{ + InteropTypeConverter::release(arg, data); +} + +template +inline typename InteropTypeConverter::InteropType makeResult(T value) +{ + return InteropTypeConverter::convertTo(value); +} + +// Improve: Rewrite all others to typed convertors. + +#define KOALA_INTEROP_0(name, Ret) \ + KOALA_INTEROP_EXPORT Ret name() \ + { \ + KOALA_MAYBE_LOG(name) \ + return makeResult(impl_##name()); \ + } + +#define KOALA_INTEROP_1(name, Ret, P0) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + return makeResult(impl_##name(p0)); \ + } + +#define KOALA_INTEROP_2(name, Ret, P0, P1) \ + KOALA_INTEROP_EXPORT Ret name( \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + return makeResult(impl_##name(p0, p1)); \ + } + +#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + return makeResult(impl_##name(p0, p1, p2)); \ + } + +#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + return makeResult(impl_##name(p0, p1, p2, p3)); \ + } + +#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4)); \ + } + +#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5)); \ + } + +#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ + } + +#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ + } + +#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ + } + +#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ + } + +#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ + } + +#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ + } + +#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ + } + +#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + P13 p13 = getArgument(_p13); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ + } + +#define KOALA_INTEROP_V0(name) \ + KOALA_INTEROP_EXPORT void name() \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + return; \ + } + +#define KOALA_INTEROP_V1(name, P0) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + impl_##name(p0); \ + return; \ + } + +#define KOALA_INTEROP_V2(name, P0, P1) \ + KOALA_INTEROP_EXPORT void name( \ + typename InteropTypeConverter::InteropType _p0, typename InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + impl_##name(p0, p1); \ + return; \ + } + +#define KOALA_INTEROP_V3(name, P0, P1, P2) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + impl_##name(p0, p1, p2); \ + return; \ + } + +#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + impl_##name(p0, p1, p2, p3); \ + return; \ + } + +#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + impl_##name(p0, p1, p2, p3, p4); \ + return; \ + } + +#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + impl_##name(p0, p1, p2, p3, p4, p5); \ + return; \ + } + +#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6); \ + return; \ + } + +#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ + return; \ + } + +#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ + return; \ + } + +#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + return; \ + } + +#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + return; \ + } + +#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10, \ + typename InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + return; \ + } + +#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10, \ + typename InteropTypeConverter::InteropType _p11, typename InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + return; \ + } + +#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10, \ + typename InteropTypeConverter::InteropType _p11, typename InteropTypeConverter::InteropType _p12, \ + typename InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + P13 p13 = getArgument(_p13); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + return; \ + } + +#define KOALA_INTEROP_CTX_1(name, Ret, P0) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + return makeResult(impl_##name(nullptr, p0)); \ + } + +#define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \ + KOALA_INTEROP_EXPORT Ret name( \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + return makeResult(impl_##name(nullptr, p0, p1)); \ + } + +#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + return makeResult(impl_##name(nullptr, p0, p1, p2)); \ + } + +#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT Ret name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + return makeResult(impl_##name(nullptr, p0, p1, p2, p3)); \ + } + +#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ + KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + impl_##name(nullptr, p0, p1, p2); \ + } + +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + impl_##name(nullptr, p0, p1, p2, p3); \ + } + +#define KOALA_INTEROP_DIRECT_0(name, Ret) KOALA_INTEROP_0(name, Ret) +#define KOALA_INTEROP_DIRECT_1(name, Ret, P0) KOALA_INTEROP_1(name, Ret, P0) +#define KOALA_INTEROP_DIRECT_2(name, Ret, P0, P1) KOALA_INTEROP_2(name, Ret, P0, P1) +#define KOALA_INTEROP_DIRECT_3(name, Ret, P0, P1, P2) KOALA_INTEROP_3(name, Ret, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_4(name, Ret, P0, P1, P2, P3) KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_5(name, Ret, P0, P1, P2, P3, P4) KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_6(name, Ret, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) +#define KOALA_INTEROP_DIRECT_V0(name) KOALA_INTEROP_V0(name) +#define KOALA_INTEROP_DIRECT_V1(name, P0) KOALA_INTEROP_V1(name, P0) +#define KOALA_INTEROP_DIRECT_V2(name, P0, P1) KOALA_INTEROP_V2(name, P0, P1) +#define KOALA_INTEROP_DIRECT_V3(name, P0, P1, P2) KOALA_INTEROP_V3(name, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_V4(name, P0, P1, P2, P3) KOALA_INTEROP_V4(name, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_V5(name, P0, P1, P2, P3, P4) KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_V6(name, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_V7(name, P0, P1, P2, P3, P4, P5, P6) KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) + +#define KOALA_INTEROP_THROW(vmContext, object, ...) \ + do { \ + ASSERT(false); /* Improve: implement*/ \ + return __VA_ARGS__; \ + } while (0) + +#define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \ + do { \ + ASSERT(false); /* Improve: implement*/ \ + return __VA_ARGS__; \ + } while (0) + +#endif // CONVERTORS_WASM_H \ No newline at end of file diff --git a/ets1.2/interop/src/interop/DeserializerBase.ts b/ets1.2/interop/src/interop/DeserializerBase.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbcd0fdb461f66883de0e8f1306a9a7729cb00dd --- /dev/null +++ b/ets1.2/interop/src/interop/DeserializerBase.ts @@ -0,0 +1,247 @@ +/* + * Copyright (c) 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. + */ +import { CustomTextDecoder, float32, float64, int32, int64 } from '@koalaui/common'; +import { Tags, CallbackResource } from './SerializerBase'; +import { pointer, KUint8ArrayPtr, KSerializerBuffer } from './InteropTypes'; +import { NativeBuffer } from './NativeBuffer'; +import { ResourceHolder } from '../arkts/ResourceManager'; +import { InteropNativeModule } from './InteropNativeModule'; + +export class DeserializerBase { + private position = 0; + private readonly buffer: ArrayBuffer; + private readonly length: int32; + private view: DataView; + private static textDecoder = new CustomTextDecoder(); + private static customDeserializers: CustomDeserializer | undefined = undefined; + + static registerCustomDeserializer(deserializer: CustomDeserializer) { + let current = DeserializerBase.customDeserializers; + if (current == undefined) { + DeserializerBase.customDeserializers = deserializer; + } else { + while (current.next != undefined) { + current = current.next; + } + current.next = deserializer; + } + } + + constructor(buffer: ArrayBuffer | KSerializerBuffer | KUint8ArrayPtr, length: int32) { + if (typeof buffer != 'object') throw new Error('Must be used only with ArrayBuffer'); + if (buffer && 'buffer' in buffer) { + buffer = buffer.buffer as ArrayBuffer; + } + this.buffer = buffer as ArrayBuffer; + this.length = length; + this.view = new DataView(this.buffer); + } + + static get( + factory: (args: Uint8Array, length: int32) => T, + args: Uint8Array, + length: int32 + ): T { + // Improve: Use cache + return factory(args, length); + } + + asBuffer(position?: int32, length?: int32): KSerializerBuffer { + return new Uint8Array(this.buffer, position, length); + } + + asArray(position?: int32, length?: int32): Uint8Array { + return new Uint8Array(this.buffer, position, length); + } + + currentPosition(): int32 { + return this.position; + } + + resetCurrentPosition(): void { + this.position = 0; + } + + private checkCapacity(value: int32) { + if (value > this.length) { + throw new Error(`${value} is less than remaining buffer length`); + } + } + + readInt8(): int32 { + this.checkCapacity(1); + const value = this.view.getInt8(this.position); + this.position += 1; + return value; + } + + readInt32(): int32 { + this.checkCapacity(4); + const value = this.view.getInt32(this.position, true); + this.position += 4; + return value; + } + + readInt64(): int64 { + this.checkCapacity(8); + const value = this.view.getBigInt64(this.position, true); + this.position += 8; + return Number(value); + } + + readPointer(): pointer { + this.checkCapacity(8); + const value = this.view.getBigInt64(this.position, true); + this.position += 8; + return value; + } + + readFloat32(): float32 { + this.checkCapacity(4); + const value = this.view.getFloat32(this.position, true); + this.position += 4; + return value; + } + + readFloat64(): float64 { + this.checkCapacity(8); + const value = this.view.getFloat64(this.position, true); + this.position += 8; + return value; + } + + readBoolean(): boolean { + this.checkCapacity(1); + const value = this.view.getInt8(this.position); + this.position += 1; + return value == 1; + } + + readFunction(): any { + // Improve: not exactly correct. + const id = this.readInt32(); + return id; + } + + readMaterialized(): object { + const ptr = this.readPointer(); + return { ptr: ptr }; + } + + readString(): string { + const length = this.readInt32(); + this.checkCapacity(length); + // read without null-terminated byte + const value = DeserializerBase.textDecoder.decode(this.asArray(this.position, length - 1)); + this.position += length; + return value; + } + + readCustomObject(kind: string): any { + let current = DeserializerBase.customDeserializers; + while (current) { + if (current.supports(kind)) { + return current.deserialize(this, kind); + } + current = current.next; + } + // consume tag + const tag = this.readInt8(); + return undefined; + } + + readNumber(): int32 | undefined { + const tag = this.readInt8(); + switch (tag) { + case Tags.UNDEFINED: + return undefined; + case Tags.INT32: + return this.readInt32(); + case Tags.FLOAT32: + return this.readFloat32(); + default: + throw new Error(`Unknown number tag: ${tag}`); + break; + } + } + + readCallbackResource(): CallbackResource { + return { + resourceId: this.readInt32(), + hold: this.readPointer(), + release: this.readPointer(), + }; + } + readObject(): any { + const resource = this.readCallbackResource(); + return ResourceHolder.instance().get(resource.resourceId); + } + + static lengthUnitFromInt(unit: int32): string { + let suffix: string; + switch (unit) { + case 0: + suffix = 'px'; + break; + case 1: + suffix = 'vp'; + break; + case 3: + suffix = '%'; + break; + case 4: + suffix = 'lpx'; + break; + default: + suffix = ''; + } + return suffix; + } + readBuffer(): ArrayBuffer { + const resource = this.readCallbackResource(); + const data = this.readPointer(); + const length = this.readInt64(); + return InteropNativeModule._MaterializeBuffer( + data, + BigInt(length), + resource.resourceId, + resource.hold, + resource.release + ); + } +} + +export abstract class CustomDeserializer { + protected constructor(protected supported: Array) {} + + supports(kind: string): boolean { + return this.supported.includes(kind); + } + + abstract deserialize(serializer: DeserializerBase, kind: string): any; + + next: CustomDeserializer | undefined = undefined; +} + +class DateDeserializer extends CustomDeserializer { + constructor() { + super(['Date']); + } + + deserialize(serializer: DeserializerBase, kind: string): any { + return new Date(serializer.readString()); + } +} +DeserializerBase.registerCustomDeserializer(new DateDeserializer()); diff --git a/ets1.2/interop/src/interop/Finalizable.ts b/ets1.2/interop/src/interop/Finalizable.ts new file mode 100644 index 0000000000000000000000000000000000000000..21b7aa2f849efa8f2547640b2336dad94d76729b --- /dev/null +++ b/ets1.2/interop/src/interop/Finalizable.ts @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { Wrapper, nullptr } from './Wrapper'; +import { finalizerRegister, finalizerUnregister, Thunk } from '@koalaui/common'; +import { InteropNativeModule } from './InteropNativeModule'; +import { pointer } from './InteropTypes'; + +export class NativeThunk implements Thunk { + finalizer: pointer; + obj: pointer; + name: string | undefined; + + constructor(obj: pointer, finalizer: pointer, name?: string) { + this.finalizer = finalizer; + this.obj = obj; + this.name = name; + } + + clean() { + if (this.obj != nullptr) { + this.destroyNative(this.obj, this.finalizer); + } + this.obj = nullptr; + } + + destroyNative(ptr: pointer, finalizer: pointer): void { + InteropNativeModule._InvokeFinalizer(ptr, finalizer); + } +} + +/** + * Class with the custom finalizer, usually used to release a native peer. + * Do not use directly, only via subclasses. + */ +export class Finalizable extends Wrapper { + finalizer: pointer; + cleaner?: NativeThunk = undefined; + managed: boolean; + constructor(ptr: pointer, finalizer: pointer, managed: boolean = true) { + super(ptr); + this.finalizer = finalizer; + this.managed = managed; + const handle = this.createHandle(); + + if (this.managed) { + // Improve: reenable exception. + if (this.ptr == nullptr) return; // throw new Error("Can't have nullptr ptr ${}") + if (this.finalizer == nullptr) throw new Error('Managed finalizer is 0'); + + const thunk = this.makeNativeThunk(ptr, finalizer, handle); + finalizerRegister(this, thunk); + this.cleaner = thunk; + } + } + + createHandle(): string | undefined { + return undefined; + } + + makeNativeThunk(ptr: pointer, finalizer: pointer, handle: string | undefined): NativeThunk { + return new NativeThunk(ptr, finalizer, handle); + } + + close() { + if (this.ptr == nullptr) { + throw new Error(`Closing a closed object: ` + this.toString()); + } else if (this.cleaner == null) { + throw new Error(`No thunk assigned to ` + this.toString()); + } else { + finalizerUnregister(this); + this.cleaner.clean(); + this.cleaner = undefined; + this.ptr = nullptr; + } + } + + release(): pointer { + finalizerUnregister(this); + if (this.cleaner) this.cleaner.obj = nullptr; + let result = this.ptr; + this.ptr = nullptr; + return result; + } + + resetPeer(pointer: pointer) { + if (this.managed) throw new Error('Can only reset peer for an unmanaged object'); + this.ptr = pointer; + } + + use(body: (value: Finalizable) => R): R { + let result = body(this); + this.close(); + return result; + } +} diff --git a/ets1.2/interop/src/interop/InteropNativeModule.ts b/ets1.2/interop/src/interop/InteropNativeModule.ts new file mode 100644 index 0000000000000000000000000000000000000000..e55056a644f4f5dd25daaba8143d164091fef769 --- /dev/null +++ b/ets1.2/interop/src/interop/InteropNativeModule.ts @@ -0,0 +1,166 @@ +/* + * Copyright (c) 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. + */ + +import { int32, int64 } from '@koalaui/common'; +import { KPointer, KSerializerBuffer, KStringPtr, KUint8ArrayPtr } from './InteropTypes'; +import { loadNativeModuleLibrary } from './loadLibraries'; + +export class InteropNativeModule { + public static _SetCallbackDispatcher(dispatcher: (id: int32, args: Uint8Array, length: int32) => int32): void { + throw 'method not loaded'; + } + public static _CleanCallbackDispatcher(): void { + throw 'method not loaded'; + } + + public static _GetGroupedLog(index: int32): KPointer { + throw 'method not loaded'; + } + public static _StartGroupedLog(index: int32): void { + throw 'method not loaded'; + } + public static _StopGroupedLog(index: int32): void { + throw 'method not loaded'; + } + public static _AppendGroupedLog(index: int32, message: string): void { + throw 'method not loaded'; + } + public static _PrintGroupedLog(index: int32): void { + throw 'method not loaded'; + } + public static _GetStringFinalizer(): KPointer { + throw 'method not loaded'; + } + public static _IncrementNumber(value: number): number { + throw 'method not loaded'; + } + public static _InvokeFinalizer(ptr1: KPointer, ptr2: KPointer): void { + throw 'method not loaded'; + } + public static _GetPtrVectorElement(ptr1: KPointer, arg: int32): KPointer { + throw 'method not loaded'; + } + public static _StringLength(ptr1: KPointer): int32 { + throw 'method not loaded'; + } + public static _StringData(ptr1: KPointer, array: KUint8ArrayPtr, arrayLength: int32): void { + throw 'method not loaded'; + } + public static _StringMake(str1: KStringPtr): KPointer { + throw 'method not loaded'; + } + public static _GetPtrVectorSize(ptr1: KPointer): int32 { + throw 'method not loaded'; + } + public static _ManagedStringWrite(str1: string, array: Uint8Array, arrayLength: int32, arg: int32): int32 { + throw 'method not loaded'; + } + public static _NativeLog(str1: string): void { + throw 'method not loaded'; + } + public static _Utf8ToString(data: KSerializerBuffer, offset: int32, length: int32): string { + throw 'method not loaded'; + } + public static _StdStringToString(cstring: KPointer): string { + throw 'method not loaded'; + } + public static _CheckCallbackEvent(buffer: KSerializerBuffer, bufferLength: int32): int32 { + throw 'method not loaded'; + } + public static _HoldCallbackResource(resourceId: int32): void { + throw 'method not loaded'; + } + public static _ReleaseCallbackResource(resourceId: int32): void { + throw 'method not loaded'; + } + public static _CallCallback(apiKind: int32, callbackKind: int32, args: KSerializerBuffer, argsSize: int32): void { + throw 'method not loaded'; + } + public static _CallCallbackSync( + apiKind: int32, + callbackKind: int32, + args: KSerializerBuffer, + argsSize: int32 + ): void { + throw 'method not loaded'; + } + public static _CallCallbackResourceHolder(holder: KPointer, resourceId: int32): void { + throw 'method not loaded'; + } + public static _CallCallbackResourceReleaser(releaser: KPointer, resourceId: int32): void { + throw 'method not loaded'; + } + public static _CallbackAwait(pipeline: KPointer): Object { + throw 'method not loaded'; + } + public static _UnblockCallbackWait(pipeline: KPointer): void { + throw 'method not loaded'; + } + public static _MaterializeBuffer( + data: KPointer, + length: bigint, + resourceId: int32, + hold: KPointer, + release: KPointer + ): ArrayBuffer { + throw 'method not loaded'; + } + public static _GetNativeBufferPointer(data: ArrayBuffer): KPointer { + throw 'method not loaded'; + } + + public static _LoadVirtualMachine(arg0: int32, arg1: string, arg2: string, arg3: string): int32 { + throw 'method not loaded'; + } + public static _RunApplication(arg0: int32, arg1: int32): number { + throw 'method not loaded'; + } + public static _StartApplication(appUrl: string, appParams: string): KPointer { + throw 'method not loaded'; + } + public static _EmitEvent(eventType: int32, target: int32, arg0: int32, arg1: int32): string { + throw 'method not loaded'; + } + public static _CallForeignVM( + foreignContext: KPointer, + kind: int32, + args: KSerializerBuffer, + argsSize: int32 + ): int32 { + throw 'method not loaded'; + } + public static _SetForeignVMContext(context: KPointer): void { + throw 'method not loaded'; + } + public static _Malloc(length: int64): KPointer { + throw 'method not loaded'; + } + public static _GetMallocFinalizer(): KPointer { + throw 'method not loaded'; + } + public static _ReadByte(data: KPointer, index: int32, length: bigint): int32 { + throw 'method not loaded'; + } + public static _WriteByte(data: KPointer, index: int32, length: bigint, value: int32): void { + throw 'method not loaded'; + } + public static _CopyArray(data: KPointer, length: int64, args: KUint8ArrayPtr): void { + throw 'method not loaded'; + } +} + +export function loadInteropNativeModule() { + loadNativeModuleLibrary('InteropNativeModule', InteropNativeModule); +} diff --git a/ets1.2/interop/src/interop/InteropOps.ts b/ets1.2/interop/src/interop/InteropOps.ts new file mode 100644 index 0000000000000000000000000000000000000000..831a9f6eb8390bb509a9fd46a0ff99c7d053b956 --- /dev/null +++ b/ets1.2/interop/src/interop/InteropOps.ts @@ -0,0 +1,88 @@ +/* + * Copyright (c) 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. + */ + +import { int32 } from '@koalaui/common'; +import { withStringResult } from './Platform'; +import { KInt, KStringPtr, KUint8ArrayPtr, pointer } from './InteropTypes'; + +export type CallbackType = (args: Uint8Array, length: int32) => int32; + +class CallbackRecord { + constructor( + public readonly callback: CallbackType, + public readonly autoDisposable: boolean + ) {} +} + +class CallbackRegistry { + static INSTANCE = new CallbackRegistry(); + + private callbacks = new Map(); + private id = 1024; + + constructor() { + this.callbacks.set( + 0, + new CallbackRecord((args: Uint8Array, length: int32): int32 => { + console.log(`Callback 0 called with args = ${args} and length = ${length}`); + throw new Error(`Null callback called`); + }, false) + ); + } + + wrap(callback: CallbackType, autoDisposable: boolean): int32 { + const id = this.id++; + this.callbacks.set(id, new CallbackRecord(callback, autoDisposable)); + return id; + } + + wrapSystem(id: number, callback: CallbackType, autoDisposable: boolean): int32 { + this.callbacks.set(id, new CallbackRecord(callback, autoDisposable)); + return id; + } + + call(id: int32, args: Uint8Array, length: int32): int32 { + const record = this.callbacks.get(id); + if (!record) { + console.log(`Callback ${id} is not known`); + // throw new Error(`Disposed or unwrapped callback called (id = ${id})`) + return 0; // Improve: + } + if (record.autoDisposable) { + this.dispose(id); + } + return record.callback(args, length); + } + + dispose(id: int32) { + this.callbacks.delete(id); + } +} + +export function wrapCallback(callback: CallbackType, autoDisposable: boolean = true): int32 { + return CallbackRegistry.INSTANCE.wrap(callback, autoDisposable); +} + +export function wrapSystemCallback(id: number, callback: CallbackType): int32 { + return CallbackRegistry.INSTANCE.wrapSystem(id, callback, false); +} + +export function disposeCallback(id: int32) { + CallbackRegistry.INSTANCE.dispose(id); +} + +export function callCallback(id: int32, args: Uint8Array, length: int32): int32 { + return CallbackRegistry.INSTANCE.call(id, args, length); +} diff --git a/ets1.2/interop/src/interop/InteropTypes.ts b/ets1.2/interop/src/interop/InteropTypes.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7451d28baf8cce6c2df6f18fe703aeed6173a39 --- /dev/null +++ b/ets1.2/interop/src/interop/InteropTypes.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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. + */ +import { int32, int64, float32, float64 } from '@koalaui/common'; + +export type KStringPtr = int32 | string | null; +export type KStringArrayPtr = int32 | Uint8Array | null; +export type KInt32ArrayPtr = int32 | Int32Array | null; +export type KFloat32ArrayPtr = int32 | Float32Array | null; +export type KUint8ArrayPtr = int32 | Uint8Array | null; +export type KInt = int32; +export type KUInt = int32; +export type KLong = int64; +export type KFloat = float32; +export type KDouble = float64; +export type KBoolean = int32; +export type KPointer = number | bigint; +export type pointer = KPointer; +export type KNativePointer = KPointer; +export type KInteropReturnBuffer = Uint8Array; +export type KSerializerBuffer = KUint8ArrayPtr; diff --git a/ets1.2/interop/src/interop/MaterializedBase.ts b/ets1.2/interop/src/interop/MaterializedBase.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa8d81b7f1b607c937ba77af9f3191744c3029f6 --- /dev/null +++ b/ets1.2/interop/src/interop/MaterializedBase.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 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. + */ + +import { Finalizable } from './Finalizable'; + +export interface MaterializedBase { + getPeer(): Finalizable | undefined; +} diff --git a/ets1.2/interop/src/interop/NativeBuffer.ts b/ets1.2/interop/src/interop/NativeBuffer.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f53534e247994e4a5ee9a929b98b6112e8557aa --- /dev/null +++ b/ets1.2/interop/src/interop/NativeBuffer.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 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. + */ + +import { pointer } from './InteropTypes'; +import { int32, int64 } from '@koalaui/common'; +import { InteropNativeModule } from './InteropNativeModule'; +import { Finalizable } from './Finalizable'; + +// stub wrapper for KInteropBuffer +// export type NativeBuffer = ArrayBuffer + +export class NativeBuffer { + public data: pointer; + public length: int64; + protected finalizable: Finalizable; + + constructor(length: int64); + constructor(data: pointer, length: int64, destroy: pointer); + constructor(dataOrLength: pointer | int64, length_?: int64, destroy_?: pointer) { + let data: pointer; + let length: int64; + let destroy: pointer; + if (length_ === undefined) { + length = dataOrLength as int64; + data = InteropNativeModule._Malloc(length); + destroy = InteropNativeModule._GetMallocFinalizer(); + } else { + data = dataOrLength as pointer; + length = length_ as int64; + destroy = destroy_ as pointer; + } + this.data = data; + this.length = length; + this.finalizable = new Finalizable(data, destroy); + } + + public readByte(index: int64): int32 { + return InteropNativeModule._ReadByte(this.data, index, BigInt(this.length)); + } + + public writeByte(index: int64, value: int32): void { + InteropNativeModule._WriteByte(this.data, index, BigInt(this.length), value); + } +} diff --git a/ets1.2/interop/src/interop/NativeString.ts b/ets1.2/interop/src/interop/NativeString.ts new file mode 100644 index 0000000000000000000000000000000000000000..04ce1bbeb4ba6856916214237d451b47041cdf0b --- /dev/null +++ b/ets1.2/interop/src/interop/NativeString.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { Finalizable } from './Finalizable'; +import { InteropNativeModule } from './InteropNativeModule'; +import { pointer } from './InteropTypes'; + +export class NativeString extends Finalizable { + constructor(ptr: pointer) { + super(ptr, InteropNativeModule._GetStringFinalizer()); + } + static Make(value: string): NativeString { + return new NativeString(InteropNativeModule._StringMake(value)); + } + toString(): string { + return InteropNativeModule._StdStringToString(this.ptr); + } +} diff --git a/ets1.2/interop/src/interop/Platform.ts b/ets1.2/interop/src/interop/Platform.ts new file mode 100644 index 0000000000000000000000000000000000000000..68a4d5226874c7007ac433aecaeca1361f3dcd76 --- /dev/null +++ b/ets1.2/interop/src/interop/Platform.ts @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { int32 } from '@koalaui/common'; +import { isNullPtr, nullptr, Wrapper } from './Wrapper'; +import { decodeToString } from '#common/wrappers/arrays'; +import { setCallbackRegistry } from '#common/wrappers/Callback'; +import { KPointer } from './InteropTypes'; + +export abstract class NativeStringBase extends Wrapper { + constructor(ptr: KPointer) { + super(ptr); + } + + protected abstract bytesLength(): int32; + protected abstract getData(data: Uint8Array): void; + + toString(): string { + let length = this.bytesLength(); + let data = new Uint8Array(length); + this.getData(data); + return decodeToString(data); + } + + abstract close(): void; +} + +export abstract class ArrayDecoder { + abstract getArraySize(blob: KPointer): int32; + abstract disposeArray(blob: KPointer): void; + abstract getArrayElement(blob: KPointer, index: int32): T; + + decode(blob: KPointer): Array { + const size = this.getArraySize(blob); + const result = new Array(size); + for (let index = 0; index < size; index++) { + result[index] = this.getArrayElement(blob, index); + } + this.disposeArray(blob); + return result; + } +} + +// Improve: the semicolons after methods in these interfaces are to +// workaround ArkTS compiler parser bug +export interface CallbackRegistry { + registerCallback(callback: any, obj: any): KPointer; +} + +export interface PlatformDefinedData { + nativeString(ptr: KPointer): NativeStringBase; + nativeStringArrayDecoder(): ArrayDecoder; + callbackRegistry(): CallbackRegistry | undefined; +} + +let platformData: PlatformDefinedData | undefined = undefined; + +export function providePlatformDefinedData(platformDataParam: PlatformDefinedData) { + platformData = platformDataParam; + let registry = platformDataParam.callbackRegistry(); + if (registry) setCallbackRegistry(registry); +} + +export function withStringResult(ptr: KPointer): string | undefined { + if (isNullPtr(ptr)) return undefined; + let managedString = platformData!.nativeString(ptr); + let result = managedString?.toString(); + managedString?.close(); + return result; +} + +export function withStringArrayResult(ptr: KPointer): Array { + if (ptr == nullptr) return new Array(); + let managedStringArray = platformData!.nativeStringArrayDecoder().decode(ptr); + return managedStringArray.map((nativeString: NativeStringBase) => nativeString.toString()); +} diff --git a/ets1.2/interop/src/interop/SerializerBase.ts b/ets1.2/interop/src/interop/SerializerBase.ts new file mode 100644 index 0000000000000000000000000000000000000000..8361d723a5dc8a042b68625af477f428a52b6a16 --- /dev/null +++ b/ets1.2/interop/src/interop/SerializerBase.ts @@ -0,0 +1,349 @@ +/* + * Copyright (c) 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. + */ +import { float32, float64, int32, int64 } from '@koalaui/common'; +import { pointer, KPointer, KSerializerBuffer } from './InteropTypes'; +import { wrapCallback } from './InteropOps'; +import { InteropNativeModule } from './InteropNativeModule'; +import { ResourceHolder, ResourceId } from '../arkts/ResourceManager'; +import { MaterializedBase } from './MaterializedBase'; +import { nullptr } from './Wrapper'; +import { NativeBuffer } from './NativeBuffer'; + +// imports required interfaces (now generation is disabled) +// import { Resource } from "@arkoala/arkui" +/** + * Value representing possible JS runtime object type. + * Must be synced with "enum RuntimeType" in C++. + */ +export enum RuntimeType { + UNEXPECTED = -1, + NUMBER = 1, + STRING = 2, + OBJECT = 3, + BOOLEAN = 4, + UNDEFINED = 5, + BIGINT = 6, + FUNCTION = 7, + SYMBOL = 8, + MATERIALIZED = 9, +} + +/** + * Value representing object type in serialized data. + * Must be synced with "enum Tags" in C++. + */ +export enum Tags { + UNDEFINED = 101, + INT32 = 102, + FLOAT32 = 103, + STRING = 104, + LENGTH = 105, + RESOURCE = 106, + OBJECT = 107, +} + +export function runtimeType(value: any): int32 { + let type = typeof value; + if (type == 'number') return RuntimeType.NUMBER; + if (type == 'string') return RuntimeType.STRING; + if (type == 'undefined') return RuntimeType.UNDEFINED; + if (type == 'object') return RuntimeType.OBJECT; + if (type == 'boolean') return RuntimeType.BOOLEAN; + if (type == 'bigint') return RuntimeType.BIGINT; + if (type == 'function') return RuntimeType.FUNCTION; + if (type == 'symbol') return RuntimeType.SYMBOL; + + throw new Error(`bug: ${value} is ${type}`); +} + +// Poor man's instanceof, fails on subclasses +export function isInstanceOf(className: string, value: object | undefined): boolean { + return value?.constructor.name === className; +} + +export function registerCallback(value: object | undefined): int32 { + return wrapCallback((args: Uint8Array, length: int32) => { + // Improve: deserialize the callback arguments and call the callback + return 42; + }); +} + +export function toPeerPtr(value: object): KPointer { + if (value.hasOwnProperty('peer')) return unsafeCast(value).getPeer()?.ptr ?? nullptr; + else throw new Error('Value is not a MaterializedBase instance'); +} + +export interface CallbackResource { + resourceId: int32; + hold: pointer; + release: pointer; +} + +/* Serialization extension point */ +export abstract class CustomSerializer { + constructor(protected supported: Array) {} + supports(kind: string): boolean { + return this.supported.includes(kind); + } + abstract serialize(serializer: SerializerBase, value: any, kind: string): void; + next: CustomSerializer | undefined = undefined; +} + +export class SerializerBase { + private position = 0; + private buffer: ArrayBuffer; + private view: DataView; + + private static pool: SerializerBase[] = [ + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + new SerializerBase(), + ]; + private static poolTop = 0; + + static hold(): SerializerBase { + if (this.poolTop === this.pool.length) { + throw new Error('Pool empty! Release one of taken serializers'); + } + return SerializerBase.pool[this.poolTop++]; + } + + private static customSerializers: CustomSerializer | undefined = undefined; + static registerCustomSerializer(serializer: CustomSerializer) { + if (SerializerBase.customSerializers == undefined) { + SerializerBase.customSerializers = serializer; + } else { + let current = SerializerBase.customSerializers; + while (current.next != undefined) { + current = current.next; + } + current.next = serializer; + } + } + constructor() { + this.buffer = new ArrayBuffer(96); + this.view = new DataView(this.buffer); + } + public release() { + this.releaseResources(); + this.position = 0; + if (this !== SerializerBase.pool[SerializerBase.poolTop - 1]) { + throw new Error('Serializers should be release in LIFO order'); + } + SerializerBase.poolTop -= 1; + } + asBuffer(): KSerializerBuffer { + return new Uint8Array(this.buffer); + } + length(): int32 { + return this.position; + } + getByte(offset: int32): int32 { + return this.view.getUint8(offset) as int32; + } + toArray(): Uint8Array { + return new Uint8Array(this.buffer.slice(0, this.currentPosition())); + } + currentPosition(): int32 { + return this.position; + } + + private checkCapacity(value: int32) { + if (value < 1) { + throw new Error(`${value} is less than 1`); + } + let buffSize = this.buffer.byteLength; + if (this.position > buffSize - value) { + const minSize = this.position + value; + const resizedSize = Math.max(minSize, Math.round((3 * buffSize) / 2)); + let resizedBuffer = new ArrayBuffer(resizedSize); + // Improve: can we grow without new? + // Improve: check the status of ArrayBuffer.transfer function implementation in STS + new Uint8Array(resizedBuffer).set(new Uint8Array(this.buffer)); + this.buffer = resizedBuffer; + this.view = new DataView(resizedBuffer); + } + } + private heldResources: ResourceId[] = []; + holdAndWriteCallback( + callback: object, + hold: KPointer = 0, + release: KPointer = 0, + call: KPointer = 0, + callSync: KPointer = 0 + ): ResourceId { + const resourceId = ResourceHolder.instance().registerAndHold(callback); + this.heldResources.push(resourceId); + this.writeInt32(resourceId); + this.writePointer(hold); + this.writePointer(release); + this.writePointer(call); + this.writePointer(callSync); + return resourceId; + } + holdAndWriteCallbackForPromiseVoid( + hold: KPointer = 0, + release: KPointer = 0, + call: KPointer = 0, + callSync = 0 + ): [Promise, ResourceId] { + let resourceId: ResourceId = 0; + const promise = new Promise((resolve, reject) => { + const callback = (err: string[] | undefined) => { + if (err !== undefined) reject(err); + else resolve(); + }; + resourceId = this.holdAndWriteCallback(callback, hold, release, call, callSync); + }); + return [promise, resourceId]; + } + holdAndWriteCallbackForPromise( + hold: KPointer = 0, + release: KPointer = 0, + call: KPointer = 0 + ): [Promise, ResourceId] { + let resourceId: ResourceId = 0; + const promise = new Promise((resolve, reject) => { + const callback = (value: T | undefined, err: string[] | undefined) => { + if (err !== undefined) reject(err); + else resolve(value!); + }; + resourceId = this.holdAndWriteCallback(callback, hold, release, call); + }); + return [promise, resourceId]; + } + writeCallbackResource(resource: CallbackResource) { + this.writeInt32(resource.resourceId); + this.writePointer(resource.hold); + this.writePointer(resource.release); + } + holdAndWriteObject(obj: any, hold: KPointer = 0, release: KPointer = 0): ResourceId { + const resourceId = ResourceHolder.instance().registerAndHold(obj); + this.heldResources.push(resourceId); + this.writeInt32(resourceId); + this.writePointer(hold); + this.writePointer(release); + return resourceId; + } + private releaseResources() { + for (const resourceId of this.heldResources) InteropNativeModule._ReleaseCallbackResource(resourceId); + // Improve: think about effective array clearing/pushing + this.heldResources = []; + } + writeCustomObject(kind: string, value: any) { + let current = SerializerBase.customSerializers; + while (current) { + if (current.supports(kind)) { + current.serialize(this, value, kind); + return; + } + current = current.next; + } + console.log(`Unsupported custom serialization for ${kind}, write undefined`); + this.writeInt8(Tags.UNDEFINED); + } + writeNumber(value: number | undefined) { + this.checkCapacity(5); + if (value == undefined) { + this.view.setInt8(this.position, Tags.UNDEFINED); + this.position++; + return; + } + if (value == Math.round(value)) { + this.view.setInt8(this.position, Tags.INT32); + this.view.setInt32(this.position + 1, value, true); + this.position += 5; + return; + } + this.view.setInt8(this.position, Tags.FLOAT32); + this.view.setFloat32(this.position + 1, value, true); + this.position += 5; + } + writeInt8(value: int32) { + this.checkCapacity(1); + this.view.setInt8(this.position, value); + this.position += 1; + } + writeInt32(value: int32) { + this.checkCapacity(4); + this.view.setInt32(this.position, value, true); + this.position += 4; + } + writeInt64(value: int64) { + this.checkCapacity(8); + this.view.setBigInt64(this.position, BigInt(value), true); + this.position += 8; + } + writePointer(value: pointer) { + this.checkCapacity(8); + this.view.setBigInt64(this.position, BigInt(value ?? 0), true); + this.position += 8; + } + writeFloat32(value: float32) { + this.checkCapacity(4); + this.view.setFloat32(this.position, value, true); + this.position += 4; + } + writeFloat64(value: float64) { + this.checkCapacity(8); + this.view.setFloat64(this.position, value, true); + this.position += 8; + } + writeBoolean(value: boolean | undefined) { + this.checkCapacity(1); + this.view.setInt8(this.position, value == undefined ? RuntimeType.UNDEFINED : +value); + this.position++; + } + writeFunction(value: object | undefined) { + this.writeInt32(registerCallback(value)); + } + writeString(value: string) { + this.checkCapacity(4 + value.length * 4); // length, data + let encodedLength = InteropNativeModule._ManagedStringWrite( + value, + new Uint8Array(this.view.buffer, 0), + this.view.buffer.byteLength, + this.position + 4 + ); + this.view.setInt32(this.position, encodedLength, true); + this.position += encodedLength + 4; + } + writeBuffer(buffer: ArrayBuffer) { + this.holdAndWriteObject(buffer); + const ptr = InteropNativeModule._GetNativeBufferPointer(buffer); + this.writePointer(ptr); + this.writeInt64(buffer.byteLength); + } +} + +class DateSerializer extends CustomSerializer { + constructor() { + super(['Date']); + } + + serialize(serializer: SerializerBase, value: object, kind: string): void { + serializer.writeString((value as Date).toISOString()); + } +} +SerializerBase.registerCustomSerializer(new DateSerializer()); + +export function unsafeCast(value: unknown) { + return value as unknown as T; +} diff --git a/ets1.2/interop/src/interop/Wrapper.ts b/ets1.2/interop/src/interop/Wrapper.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b0b51c51009f9b81f14dc50ed513fedba3c8932 --- /dev/null +++ b/ets1.2/interop/src/interop/Wrapper.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { ptrToString, nullptr, isSamePtr } from '#common/wrappers/Wrapper'; +import { className } from '@koalaui/common'; +import { KPointer } from './InteropTypes'; + +export { isNullPtr, nullptr, ptrToBits, bitsToPtr, isSamePtr, ptrToString } from '#common/wrappers/Wrapper'; + +/** + * An object holding reference to the native pointer. + */ +export class Wrapper { + ptr: KPointer; + constructor(ptr: KPointer) { + if (ptr == null) throw new Error(`Init <${className(this)}> with null native peer`); + this.ptr = ptr; + } + toString(): string { + return `[native object <${className(this)}> at ${ptrToString(this.ptr)}]`; + } +} + +export function getPtr(value: Wrapper | undefined): KPointer { + return value?.ptr ?? nullptr; +} + +export function ptrEqual(a: Wrapper | undefined, b: Wrapper | undefined): boolean { + if (a === b) return true; + if (a == undefined || b == undefined) return false; + return isSamePtr(a.ptr, b.ptr); +} diff --git a/ets1.2/interop/src/interop/arrays.ts b/ets1.2/interop/src/interop/arrays.ts new file mode 100644 index 0000000000000000000000000000000000000000..d13273391883247151d255349d3efd01ee2dfc87 --- /dev/null +++ b/ets1.2/interop/src/interop/arrays.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +import { int32 } from '@koalaui/common'; + +export enum Access { + READ = 1, // 1 << 0, + WRITE = 2, // 1 << 1, + READWRITE = 3, // READ | WRITE +} +export function isRead(access: Access) { + return access & Access.READ; +} +export function isWrite(access: Access) { + return access & Access.WRITE; +} + +export type Exec = (pointer: P) => R; +export type ExecWithLength = (pointer: P, length: int32) => R; + +export type TypedArray = + | Uint8Array + | Int8Array + | Uint16Array + | Int16Array + | Uint32Array + | Int32Array + | Float32Array + | Float64Array; + +export type PtrArray = Uint32Array | BigUint64Array; diff --git a/ets1.2/interop/src/interop/buffer.ts b/ets1.2/interop/src/interop/buffer.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ca4e36ee368cdf0c160692a9dc43c7ee5868bcb --- /dev/null +++ b/ets1.2/interop/src/interop/buffer.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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. + */ + +import { int32 } from '@koalaui/common'; + +// Improve: can be removed if passing ArrayBuffer type through interop is possible +export class KBuffer { + private readonly _buffer: Uint8Array; + public get buffer(): ArrayBuffer { + return this._buffer; + } + public get length(): int32 { + return this._buffer.length; + } + + constructor(length: int32) { + this._buffer = new Uint8Array(length); + } + + set(index: int32, value: int32): void { + this._buffer[index] = value; + } + + get(index: int32): int32 { + return this._buffer[index]; + } +} diff --git a/ets1.2/interop/src/interop/events.ts b/ets1.2/interop/src/interop/events.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f1096066d24ced94686f9b94ec47ee602ad52f1 --- /dev/null +++ b/ets1.2/interop/src/interop/events.ts @@ -0,0 +1,91 @@ +/* + * 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. + */ + +import { int32 } from '@koalaui/common'; +import { DeserializerBase } from './DeserializerBase'; +import { InteropNativeModule } from './InteropNativeModule'; +import { ResourceHolder } from '../arkts/ResourceManager'; +import { wrapSystemCallback } from './InteropOps'; +import { KSerializerBuffer } from './InteropTypes'; + +const API_KIND_MAX = 100; +const apiEventHandlers: (EventHandler | undefined)[] = new Array(API_KIND_MAX).fill(undefined); +export type EventHandler = (deserializer: DeserializerBase) => void; +export function registerApiEventHandler(apiKind: int32, handler: EventHandler) { + if (apiKind < 0 || apiKind > API_KIND_MAX) { + throw new Error(`Maximum api kind is ${API_KIND_MAX}, received ${apiKind}`); + } + if (apiEventHandlers[apiKind] !== undefined) { + throw new Error(`Callback caller for api kind ${apiKind} already was set`); + } + apiEventHandlers[apiKind] = handler; +} +export function handleApiEvent(apiKind: int32, deserializer: DeserializerBase) { + if (apiKind < 0 || apiKind > API_KIND_MAX) { + throw new Error(`Maximum api kind is ${API_KIND_MAX}, received ${apiKind}`); + } + if (apiEventHandlers[apiKind] === undefined) { + throw new Error(`Callback caller for api kind ${apiKind} was not set`); + } + apiEventHandlers[apiKind]!(deserializer); +} +export function wrapSystemApiHandlerCallback() { + wrapSystemCallback(1, (buffer: KSerializerBuffer, len: int32) => { + const deserializer = new DeserializerBase(buffer, len); + const apiKind = deserializer.readInt32(); + handleApiEvent(apiKind, deserializer); + return 0; + }); +} +export function checkEvents(): void { + while (checkSingleEvent()) {} +} + +enum CallbackEventKind { + Event_CallCallback = 0, + Event_HoldManagedResource = 1, + Event_ReleaseManagedResource = 2, +} + +const bufferSize = 8 * 1024; +const buffer = new Uint8Array(bufferSize); +const deserializer = new DeserializerBase(buffer.buffer, bufferSize); +function checkSingleEvent(): boolean { + deserializer.resetCurrentPosition(); + let result = InteropNativeModule._CheckCallbackEvent(buffer, bufferSize); + if (result == 0) return false; + + const eventKind = deserializer.readInt32() as CallbackEventKind; + switch (eventKind) { + case CallbackEventKind.Event_CallCallback: { + const apiKind = deserializer.readInt32(); + handleApiEvent(apiKind, deserializer); + return true; + } + case CallbackEventKind.Event_HoldManagedResource: { + const resourceId = deserializer.readInt32() + ResourceHolder.instance().hold(resourceId) + return true; + } + case CallbackEventKind.Event_ReleaseManagedResource: { + const resourceId = deserializer.readInt32() + ResourceHolder.instance().release(resourceId) + return true; + } + default: { + throw new Error(`Unknown callback event kind ${eventKind}`) + } + } +} diff --git a/ets1.2/interop/src/interop/index.ts b/ets1.2/interop/src/interop/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..00f3330e88d5b446919243646db949ffdb386827 --- /dev/null +++ b/ets1.2/interop/src/interop/index.ts @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { + withFloat32Array, + withFloat64Array, + withInt16Array, + withInt32Array, + withInt8Array, + withUint16Array, + withUint32Array, + withUint8Array, + wasmHeap as wasmHeapArrayBuffer, +} from '#common/wrappers/arrays'; + +export { registerCallback, setCallbackRegistry } from '#common/wrappers/Callback'; + +export { Access, Exec } from './arrays'; +export { Finalizable, NativeThunk } from './Finalizable'; +export { nullable } from './nullable'; +export { getPtr, isNullPtr, nullptr, ptrEqual, Wrapper, ptrToBits, bitsToPtr } from './Wrapper'; + +export { + decodeToString, + encodeToData, + withString, + withStringArray, + withPtrArray, + fromPtrArray, + toPtrArray, +} from '#common/wrappers/arrays'; + +export const withFloatArray = withFloat32Array; +export const withByteArray = withUint8Array; +export const withIntArray = withInt32Array; + +export const wasmHeap = wasmHeapArrayBuffer; + +export { + withFloat32Array, + withFloat64Array, + withInt8Array, + withInt16Array, + withInt32Array, + withUint8Array, + withUint16Array, + withUint32Array, +}; + +export * from './Platform'; +export * from './InteropTypes'; + +export * from './InteropOps'; +export * from './NativeString'; +export * from './buffer'; +export * from '../arkts/ResourceManager'; +export * from './NativeBuffer'; +export { InteropNativeModule, loadInteropNativeModule } from './InteropNativeModule'; +export { + SerializerBase, + RuntimeType, + Tags, + runtimeType, + CallbackResource, + unsafeCast, + isInstanceOf, + toPeerPtr, +} from './SerializerBase'; +export { DeserializerBase } from './DeserializerBase'; +export * from './events'; +export { loadNativeModuleLibrary, loadNativeLibrary, registerNativeModuleLibraryName } from './loadLibraries'; +export * from './MaterializedBase'; diff --git a/ets1.2/interop/src/interop/java/CallbackRecord.java b/ets1.2/interop/src/interop/java/CallbackRecord.java new file mode 100644 index 0000000000000000000000000000000000000000..2292705a6c5707f76e068a8e26481f12eef2fb1d --- /dev/null +++ b/ets1.2/interop/src/interop/java/CallbackRecord.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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. + */ +package org.koalaui.interop; + +class CallbackRecord { + public CallbackType callback; + public boolean autoDisposable; + + public CallbackRecord(CallbackType callback, boolean autoDisposable) { + this.callback = callback; + this.autoDisposable = autoDisposable; + } +} diff --git a/ets1.2/interop/src/interop/java/CallbackRegistry.java b/ets1.2/interop/src/interop/java/CallbackRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..2fb731539602a5fc07d25a2eaa72c73154e45fef --- /dev/null +++ b/ets1.2/interop/src/interop/java/CallbackRegistry.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 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. + */ +package org.koalaui.interop; + +import java.util.Arrays; +import java.util.HashMap; + +class CallbackRegistry { + + private static HashMap callbacks = new HashMap(); + private static Integer id = 0; + + static { + CallbackRegistry.callbacks.put(id, new CallbackRecord( + new CallbackType() { + @Override + public int apply(byte[] args, int length) { + System.out.printf("Callback 0 called with args = %s and length = %d\n", Arrays.toString(args), length); + throw new Error("Null callback called"); + } + }, false) + ); + CallbackRegistry.id++; + } + + private CallbackRegistry() { + + } + + public static Integer wrap(CallbackType callback) { + Integer callbackId = CallbackRegistry.id++; + CallbackRegistry.callbacks.put(callbackId, new CallbackRecord(callback, true)); + return callbackId; + } + + public static Integer wrap(CallbackType callback, boolean autoDisposable) { + Integer callbackId = CallbackRegistry.id++; + CallbackRegistry.callbacks.put(callbackId, new CallbackRecord(callback, autoDisposable)); + return callbackId; + } + + public static int call(Integer id, byte[] args, int length) { + if (!CallbackRegistry.callbacks.containsKey(id)) { + System.out.printf("Callback %d is not known\n", id); + throw new Error(String.format("Disposed or unwrapped callback called (id = %d)", id)); + } + CallbackRecord record = CallbackRegistry.callbacks.get(id); + if (record.autoDisposable) { + CallbackRegistry.dispose(id); + } + return record.callback.apply(args, length); + } + + public static void dispose(Integer id) { + CallbackRegistry.callbacks.remove(id); + } +} diff --git a/ets1.2/interop/src/interop/java/CallbackTests.java b/ets1.2/interop/src/interop/java/CallbackTests.java new file mode 100644 index 0000000000000000000000000000000000000000..22cf1fbe6c0fdae09969c9d3c315ed590bcbafe4 --- /dev/null +++ b/ets1.2/interop/src/interop/java/CallbackTests.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 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. + */ +package org.koalaui.interop; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.util.function.Function; + +import org.koalaui.arkoala.NativeModule; + +public class CallbackTests { + // Improve: where tests will be located? + + public class TestUtils { + // Improve: where test utils will be located? + public static void assertEquals(String name, T expected, T actual) { + if (!expected.equals(actual)) { + System.out.printf("TEST %s FAIL:\n EXPECTED \"%s\"\n ACTUAL \"%s\"\n", name, expected.toString(), actual.toString()); + } else { + System.out.printf("TEST %s PASS\n", name); + } + } + + public static void assertThrows(String name, Function fn) { + boolean caught = false; + try { + fn.apply(null); + } catch (Throwable e) { + caught = true; + } + if (!caught) { + System.out.printf("TEST %s FAIL:\n No exception thrown\n", name); + } else { + System.out.printf("TEST %s PASS\n", name); + } + } + } + + public static void checkCallback() { + Integer id1 = CallbackRegistry.wrap(new CallbackType() { + @Override + public int apply(byte[] args, int length) { + return 2024; + } + }); + Integer id2 = CallbackRegistry.wrap(new CallbackType() { + @Override + public int apply(byte[] args, int length) { + return 2025; + } + }); + + TestUtils.assertEquals("Call callback 1", 2024, CallbackRegistry.call(id1, new byte[] {}, 0)); + TestUtils.assertEquals("Call callback 2", 2025, CallbackRegistry.call(id2, new byte[] {}, 0)); + TestUtils.assertThrows("Call disposed callback 1", new Function() { + @Override + public Integer apply(Void v) { + return CallbackRegistry.call(id1, new byte[] { }, 0); + } + }); + TestUtils.assertThrows("Call callback 0", new Function() { + @Override + public Integer apply(Void v) { + return CallbackRegistry.call(0, new byte[] { 2, 4, 6, 8 }, 4); + } + }); + } + + public static void checkNativeCallback() { + Integer id1 = CallbackRegistry.wrap(new CallbackType() { + @Override + public int apply(byte[] args, int length) { + return 123456; + } + }); + TestUtils.assertEquals("NativeCallback without args", 123456, NativeModule._TestCallIntNoArgs(id1)); + TestUtils.assertThrows("NativeCallback without args called again", new Function() { + @Override + public Integer apply(Void v) { + return CallbackRegistry.call(id1, new byte[] { }, 0); + } + }); + TestUtils.assertThrows("NativeCallback without args called again from native", new Function() { + @Override + public Integer apply(Void v) { + return NativeModule._TestCallIntNoArgs(id1); + } + }); + + Integer id2 = CallbackRegistry.wrap(new CallbackType() { + @Override + public int apply(byte[] args, int length) { + ByteBuffer buffer = ByteBuffer.wrap(args); + buffer.order(ByteOrder.LITTLE_ENDIAN); + IntBuffer intBuffer = buffer.asIntBuffer(); + int sum = 0; + for (int i = 0; i < length / 4; i++) { + sum += intBuffer.get(i); + } + return sum; + } + }); + int[] arr2 = new int[] { 100, 200, 300, -1000 }; + TestUtils.assertEquals("NativeCallback Int32Array sum", -400, NativeModule._TestCallIntIntArraySum(id2, arr2, arr2.length)); + + Integer id3 = CallbackRegistry.wrap(new CallbackType() { + @Override + public int apply(byte[] args, int length) { + ByteBuffer buffer = ByteBuffer.wrap(args); + buffer.order(ByteOrder.LITTLE_ENDIAN); + IntBuffer intBuffer = buffer.asIntBuffer(); + for (int i = 1; i < length / 4; i++) { + intBuffer.put(i, intBuffer.get(i) + intBuffer.get(i - 1)); + } + return 0; + } + }); + int[] arr3 = new int[] { 100, 200, 300, -1000 }; + NativeModule._TestCallVoidIntArrayPrefixSum(id3, arr3, arr3.length); + TestUtils.assertEquals("NativeCallback Int32Array PrefixSum [0]", 100, arr3[0]); + TestUtils.assertEquals("NativeCallback Int32Array PrefixSum [1]", 300, arr3[1]); + TestUtils.assertEquals("NativeCallback Int32Array PrefixSum [2]", 600, arr3[2]); + TestUtils.assertEquals("NativeCallback Int32Array PrefixSum [3]", -400, arr3[3]); + + long start = System.currentTimeMillis(); + Integer id4 = CallbackRegistry.wrap(new CallbackType() { + @Override + public int apply(byte[] args, int length) { + ByteBuffer buffer = ByteBuffer.wrap(args); + buffer.order(ByteOrder.LITTLE_ENDIAN); + IntBuffer intBuffer = buffer.asIntBuffer(); + intBuffer.put(1, intBuffer.get(1) + 1); + if (intBuffer.get(0) + intBuffer.get(1) < intBuffer.get(2)) { + return NativeModule._TestCallIntRecursiveCallback(id3 + 1, args, args.length); + } + return 1; + } + }, false); + TestUtils.assertEquals("NativeCallback prepare recursive callback test", id4, id3 + 1); + int depth = 500; + int count = 100; + for (int i = 0; i < count; i++) { + int length = 12; + byte[] args = new byte[length]; + IntBuffer args32 = ByteBuffer.wrap(args).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); + args32.put(2, depth); + NativeModule._TestCallIntRecursiveCallback(id4, args, args.length); + if (i == 0) { + TestUtils.assertEquals("NativeCallback Recursive [0]", (depth + 1) / 2, args32.get(0)); + TestUtils.assertEquals("NativeCallback Recursive [1]", depth / 2, args32.get(1)); + } + } + long passed = System.currentTimeMillis() - start; + System.out.println("recursive native callback: " + String.valueOf(passed) + "ms for " + depth * count + " callbacks, " + Math.round((double)passed / (depth * count) * 1000000) + "ms per 1M callbacks"); + + Integer id5 = CallbackRegistry.wrap(new CallbackType() { + @Override + public int apply(byte[] args, int length) { + int sum = 0; + for (int i = 0; i < length; i++) { + sum += args[i]; + } + return sum; + } + }, false); + NativeModule._TestCallIntMemory(id5, 1000); + } +} diff --git a/ets1.2/interop/src/interop/java/CallbackType.java b/ets1.2/interop/src/interop/java/CallbackType.java new file mode 100644 index 0000000000000000000000000000000000000000..952cd3d399a7fddc441ca5bef9d755ee3231a24b --- /dev/null +++ b/ets1.2/interop/src/interop/java/CallbackType.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 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. + */ +package org.koalaui.interop; + +public interface CallbackType { + public int apply(byte[] args, int length); +} diff --git a/ets1.2/interop/src/interop/loadLibraries.ts b/ets1.2/interop/src/interop/loadLibraries.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c6a3efbab2c8de20eff0701cf637d2655e39486 --- /dev/null +++ b/ets1.2/interop/src/interop/loadLibraries.ts @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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. + */ +import * as os from 'os'; + +const nativeModuleLibraries: Map = new Map(); + +export function loadNativeLibrary(name: string): Record { + const isHZVM = !!(globalThis as any).requireNapi; + let nameWithoutSuffix = name.endsWith('.node') ? name.slice(0, name.length - 5) : name; + let candidates: string[] = [ + name, + `${nameWithoutSuffix}.node`, + `${nameWithoutSuffix}_${os.arch()}.node`, + `${nameWithoutSuffix}_${os.platform()}_${os.arch()}.node`, + ]; + const errors: { candidate: string; command: string; error: any }[] = []; + if (!isHZVM) + try { + candidates.push(eval(`require.resolve(${JSON.stringify(nameWithoutSuffix + '.node')})`)); + } catch (e) { + errors.push({ candidate: `${nameWithoutSuffix}.node`, command: `resolve(...)`, error: e }); + } + + for (const candidate of candidates) { + try { + if (isHZVM) return (globalThis as any).requireNapi(candidate, true); + else return eval(`let exports = {}; process.dlopen({ exports }, ${JSON.stringify(candidate)}, 2); exports`); + } catch (e) { + errors.push({ candidate: candidate, command: `dlopen`, error: e }); + } + } + errors.forEach((e, i) => { + console.error( + `Error ${i} of ${errors.length} command: ${e.command}, candidate: ${e.candidate}, message: ${e.error}` + ); + }); + throw new Error(`Failed to load native library ${name}. dlopen candidates: ${candidates.join(':')}`); +} + +export function registerNativeModuleLibraryName(nativeModule: string, libraryName: string) { + nativeModuleLibraries.set(nativeModule, libraryName); +} + +export function loadNativeModuleLibrary(moduleName: string, module?: object) { + if (!module) throw new Error(' argument is required and optional only for compatibility with ArkTS'); + const library = loadNativeLibrary(nativeModuleLibraries.get(moduleName) ?? moduleName); + if (!library || !library[moduleName]) { + console.error(`Failed to load library for module ${moduleName}`); + return; + } + Object.assign(module, library[moduleName]); +} diff --git a/ets1.2/interop/src/interop/nullable.ts b/ets1.2/interop/src/interop/nullable.ts new file mode 100644 index 0000000000000000000000000000000000000000..34b2b0a630f0b5565e69f0a99ded1aa93e34197f --- /dev/null +++ b/ets1.2/interop/src/interop/nullable.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { isNullPtr } from './Wrapper'; +import { KPointer } from './InteropTypes'; + +export function nullable(value: KPointer, body: (arg: KPointer) => T | undefined): T | undefined { + if (isNullPtr(value)) { + return undefined; + } else { + return body(value); + } +} diff --git a/ets1.2/interop/src/napi/wrappers/Callback.ts b/ets1.2/interop/src/napi/wrappers/Callback.ts new file mode 100644 index 0000000000000000000000000000000000000000..a05fc22db115e912f98f62fb3b63bc58a4c47929 --- /dev/null +++ b/ets1.2/interop/src/napi/wrappers/Callback.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { KPointer } from '../../interop/InteropTypes'; +import { CallbackRegistry } from '../../interop/Platform'; + +export function registerCallback(callback: any, obj: any = null): KPointer { + return theRegistry!.registerCallback(callback, obj); +} + +let theRegistry: CallbackRegistry | undefined = undefined; + +export function setCallbackRegistry(registry: CallbackRegistry) { + theRegistry = registry; +} diff --git a/ets1.2/interop/src/napi/wrappers/Wrapper.ts b/ets1.2/interop/src/napi/wrappers/Wrapper.ts new file mode 100644 index 0000000000000000000000000000000000000000..743b8308c97abd8ad006680e1e98a39728770f66 --- /dev/null +++ b/ets1.2/interop/src/napi/wrappers/Wrapper.ts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { int32 } from '@koalaui/common'; +import { KPointer } from '../../interop/InteropTypes'; + +export const nullptr = BigInt(0); + +export function isNullPtr(value: KPointer): boolean { + return value === nullptr; +} + +export function ptrToString(ptr: KPointer) { + return `0x${ptr!.toString(16).padStart(8, '0')}`; +} + +export function isSamePtr(a: KPointer, b: KPointer) { + return a === b; +} + +// Improve: rethink me +export function ptrToBits(ptr: KPointer): Uint32Array | null { + let result = new Uint32Array(2); + let ptrBigInt = ptr as bigint; + result[0] = Number(ptrBigInt & BigInt(0xffffffff)); + result[1] = Number((ptrBigInt >> BigInt(32)) & BigInt(0xffffffff)); + return result; +} + +export function bitsToPtr(array: Int32Array, offset: int32): KPointer { + let ptrBigInt: bigint = BigInt(array[offset + 1]) & BigInt(0xffffffff); + ptrBigInt = (ptrBigInt << BigInt(32)) | (BigInt(array[offset]) & BigInt(0xffffffff)); + return ptrBigInt; +} diff --git a/ets1.2/interop/src/napi/wrappers/arrays.ts b/ets1.2/interop/src/napi/wrappers/arrays.ts new file mode 100644 index 0000000000000000000000000000000000000000..295048e9a46977d0791608c076725539a4c8f9fa --- /dev/null +++ b/ets1.2/interop/src/napi/wrappers/arrays.ts @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { CustomTextDecoder, CustomTextEncoder } from '@koalaui/common'; +import { Access, Exec, ExecWithLength, PtrArray, TypedArray } from '../../interop/arrays'; +import { nullptr } from './Wrapper'; +import { Wrapper } from '../../interop/Wrapper'; +import { KPointer, KStringArrayPtr } from '../../interop'; + +const encoder = new CustomTextEncoder(); +const decoder = new CustomTextDecoder(); + +export function decodeToString(array: Uint8Array): string { + return decoder.decode(array); +} + +export function encodeToData(string: string): Uint8Array { + return encoder.encode(string, false); +} + +export function withString(data: string | undefined, exec: Exec): R { + return exec(data === undefined ? null : data); +} + +export function withStringArray(strings: Array | undefined, exec: Exec): R { + if (strings === undefined || strings.length === 0) { + return exec(null); + } + + let array = encoder.encodeArray(strings); + return exec(array); +} + +function withArray(data: C | undefined, exec: ExecWithLength): R { + return exec(data ?? null, data?.length ?? 0); +} + +export function withPtrArray(data: BigUint64Array, access: Access, exec: ExecWithLength) { + return exec(data ?? null, data?.length ?? 0); // Improve: rethink +} + +export function toPtrArray(data: Array | undefined): BigUint64Array { + if (data == undefined || data.length === 0) { + return new BigUint64Array(0); + } + const array = new BigUint64Array(data.length); + for (let i = 0; i < data.length; i++) { + let item = data[i]; + array[i] = item != undefined ? (item.ptr as bigint) : nullptr; + } + return array; +} + +export function fromPtrArray(array: PtrArray, factory: (ptr: KPointer) => T): Array { + if (array.length === 0) { + return new Array(0); + } + const result = new Array(array.length); + for (let i = 0; i < array.length; i++) { + let ptr = array[i]; + if (ptr == nullptr) { + result[i] = undefined; + } else { + result[i] = factory(ptr); + } + } + return result; +} + +export function withUint8Array( + data: Uint8Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function withInt8Array( + data: Int8Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function withUint16Array( + data: Uint16Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function withInt16Array( + data: Int16Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function withUint32Array( + data: Uint32Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function withInt32Array( + data: Int32Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function withFloat32Array( + data: Float32Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function withFloat64Array( + data: Float64Array | undefined, + access: Access, + exec: ExecWithLength +) { + return withArray(data, exec); +} +export function wasmHeap(): ArrayBuffer { + throw new Error('Unused'); +} diff --git a/ets1.2/interop/src/wasm/wrappers/Callback.ts b/ets1.2/interop/src/wasm/wrappers/Callback.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b8ea480274433ae8e9f5583e9c8f9cbc9f961de --- /dev/null +++ b/ets1.2/interop/src/wasm/wrappers/Callback.ts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { KPointer } from '../../interop/InteropTypes'; +import { CallbackRegistry } from '../../interop/Platform'; + +class CallbackInfo { + cb: any; + recv: any; + constructor(callback: any, obj: any = null) { + this.cb = callback; + this.recv = obj; + } +} + +const GLOBAL_SCOPE = new (class CallbackScope { + static readonly CB_NULL = new CallbackInfo(() => { + throw new Error('attempted to call a callback at NULL'); + }, null); + static readonly CB_UNDEFINED = new CallbackInfo(() => { + throw new Error('attempted to call an uninitialized callback'); + }, null); + static readonly CB_NULL_ID = 0; + nextId: number; + callbackMap: Map | null; + + constructor() { + this.nextId = 1; + this.callbackMap = new Map(); + this.callbackMap.set(CallbackScope.CB_NULL_ID, CallbackScope.CB_NULL); + } + + addCallback(cb: any, obj: any): number { + let id = this.nextId++; + this.callbackMap?.set(id, new CallbackInfo(cb, obj)); + return id; + } + + getCallback(id: number): CallbackInfo { + return this.callbackMap?.get(id) || CallbackScope.CB_UNDEFINED; + } + + deleteCallback(id: number): void { + if (id > CallbackScope.CB_NULL_ID) { + this.callbackMap?.delete(id); + } + } + + release(): void { + this.callbackMap = null; + } +})(); + +function callCallback(callbackId: number): any { + let CallbackInfo = GLOBAL_SCOPE.getCallback(callbackId); + try { + let cb = CallbackInfo.cb; + if (CallbackInfo.recv !== null) { + cb = cb.bind(CallbackInfo.recv); + } + return cb(); + } catch (e) { + console.error(e); + } +} + +export function registerCallback(callback: any, obj: any = null): KPointer { + return GLOBAL_SCOPE.addCallback(callback, obj); +} + +function releaseCallback(callbackId: number): void { + return GLOBAL_SCOPE.deleteCallback(callbackId); +} + +declare namespace globalThis { + function callCallback(callbackId: number): any; + function releaseCallback(callbackId: number): any; +} + +globalThis.callCallback = callCallback; +globalThis.releaseCallback = releaseCallback; + +export function setCallbackRegistry(_ignoredRegistry: CallbackRegistry) { + // On WASM we don't need registry in current implementation. +} diff --git a/ets1.2/interop/src/wasm/wrappers/Wrapper.ts b/ets1.2/interop/src/wasm/wrappers/Wrapper.ts new file mode 100644 index 0000000000000000000000000000000000000000..066e4c77fa58af7c82ead33e0a8d9a2603c1bc8f --- /dev/null +++ b/ets1.2/interop/src/wasm/wrappers/Wrapper.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { int32 } from '@koalaui/common'; +import { KPointer } from '../../interop/InteropTypes'; + +export const nullptr: number = 0; + +export function isNullPtr(value: KPointer): boolean { + return value == nullptr; +} + +export function ptrToString(ptr: KPointer) { + if (ptr === 0) return '0x0'; + + const hex = (ptr as number).toString(16).padStart(8, '0'); + return `0x${hex}`; +} + +export function isSamePtr(a: KPointer, b: KPointer) { + return a === b; +} + +export function ptrToBits(ptr: KPointer): Uint32Array { + let result = new Uint32Array(2); + result[0] = ptr as int32; + return result; +} + +export function bitsToPtr(array: Int32Array, offset: int32): KPointer { + return array[offset]; +} diff --git a/ets1.2/interop/src/wasm/wrappers/arrays.ts b/ets1.2/interop/src/wasm/wrappers/arrays.ts new file mode 100644 index 0000000000000000000000000000000000000000..074fceabbbd27173dd2cf5596b21f3d925138c86 --- /dev/null +++ b/ets1.2/interop/src/wasm/wrappers/arrays.ts @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { CustomTextEncoder, CustomTextDecoder, int32 } from '@koalaui/common'; + +import { KPointer } from '../../interop/InteropTypes'; +import { Wrapper } from '../../interop/Wrapper'; +import { Access, isRead, isWrite, Exec, TypedArray, ExecWithLength } from '../../interop/arrays'; + +const encoder = new CustomTextEncoder(); +const decoder = new CustomTextDecoder(); + +export function decodeToString(array: Uint8Array): string { + return decoder.decode(array); +} + +export function encodeToData(string: string): Uint8Array { + return encoder.encode(string, false); +} + +type Heap = { readonly buffer: ArrayBuffer }; + +// Improve: actually memory allocation primitives are defined for a specific intance instance, +// refactor me +declare const _heaps: { + HEAP8(): Heap; + HEAP16(): Heap; + HEAP32(): Heap; + HEAPU8(): Heap; + HEAPU16(): Heap; + HEAPU32(): Heap; + HEAPF32(): Heap; + HEAPF64(): Heap; +}; +declare function _malloc(size: number): number; +declare function _free(ptr: number): void; + +const nullptr: number = 0; + +// with string as array of utf8 data headed by length +export function withString(data: string | undefined, exec: Exec): R { + if (data === undefined) return exec(nullptr); + + let array = encoder.encode(data, true); + return withUint8Array(array, Access.READ, exec); +} + +export function withStringArray(strings: Array | undefined, exec: Exec): R { + if (strings === undefined || strings.length === 0) { + return exec(nullptr); + } + + let array = encoder.encodeArray(strings); + return withUint8Array(array, Access.READ, exec); +} + +function withArray( + data: C | undefined, + access: Access, + exec: ExecWithLength, + bytesPerElement: int32, + ctor: (ptr: number, length: number) => C +): R { + if (data === undefined || data.length === 0) { + return exec(nullptr, 0); + } + + let ptr = _malloc(data.length * bytesPerElement); + let wasmArray = ctor(ptr, data.length); + + if (isRead(access)) { + wasmArray.set(data); + } + + let result = exec(ptr, data.length); + + if (isWrite(access)) { + data.set(wasmArray); + } + + _free(ptr); + + return result; +} + +export function withPtrArray(data: Uint32Array, access: Access, exec: ExecWithLength) { + return withArray( + data as Uint32Array, + access, + exec, + Uint32Array.BYTES_PER_ELEMENT, + (ptr: number, length: number) => { + return new Uint32Array(_heaps.HEAPU8().buffer, ptr, length); + } + ); +} + +export function toPtrArray(data: Array | undefined): Uint32Array { + if (data === undefined || data.length === 0) { + return new Uint32Array(0); + } + const array = new Uint32Array(data.length); + for (let i = 0; i < data.length; i++) { + array[i] = data[i]?.ptr as number; + } + return array; +} + +export function fromPtrArray( + array: Uint32Array, + factory: (ptr: KPointer) => T +): Array { + const result = new Array(array.length); + for (let i = 0; i < array.length; i++) { + let v = array[i]; + if (v == 0) { + result[i] = undefined; + } else { + result[i] = factory(v); + } + } + return result; +} + +export function withUint8Array(data: Uint8Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Uint8Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Uint8Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} +export function withInt8Array(data: Int8Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Int8Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Int8Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} +export function withUint16Array(data: Uint16Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Uint16Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Uint16Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} +export function withInt16Array(data: Int16Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Int16Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Int16Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} +export function withUint32Array(data: Uint32Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Uint32Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Uint32Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} +export function withInt32Array(data: Int32Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Int32Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Int32Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} +export function withFloat32Array(data: Float32Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Float32Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Float32Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} +export function withFloat64Array(data: Float64Array | undefined, access: Access, exec: ExecWithLength) { + return withArray(data, access, exec, Float64Array.BYTES_PER_ELEMENT, (ptr: number, length: number) => { + return new Float64Array(_heaps.HEAPU8().buffer, ptr, length); + }); +} + +export function wasmHeap(): ArrayBuffer { + return _heaps.HEAP32().buffer; +} diff --git a/ets1.2/interop/tsconfig.json b/ets1.2/interop/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..afe382db7f7d696313ad5fe54bbff58bc7f6f71a --- /dev/null +++ b/ets1.2/interop/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2017", + "lib": ["ESNext", "ESNext.WeakRef"], + "moduleResolution": "node", + "composite": true, + "incremental": true, + "declarationMap": true, + "sourceMap": true, + "declaration": true, + "noEmitOnError": true, + "strict": true, + "skipLibCheck": true, + "removeComments": false, + "outDir": "build/lib", + "module": "CommonJS", // Improve: maybe migrate to ESM? + "rootDirs": ["src"], + "baseUrl": ".", + "types": ["node"], + "paths": { + "@koalaui/common": ["../incremental/common/src"], + "#common/wrappers/*": ["./src/napi/wrappers/*", "./src/wasm/wrappers/*"] + } + }, + "include": ["src/interop/**/*", "src/napi/**/*", "src/wasm/**/*", "src/arkts/ResourceManager.ts"], + "references": [ + { "path": "../incremental/compat" }, + { "path": "../incremental/common" } + ] +} diff --git a/ets1.2/interop/ui2abcconfig.json b/ets1.2/interop/ui2abcconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..68085b0e5019f82fd95f7aebd18de264fbbebb45 --- /dev/null +++ b/ets1.2/interop/ui2abcconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "package": "@koalaui/interop", + "outDir": "./build/abc", + "baseUrl": "./src/arkts", + "paths": { + "@koalaui/compat": ["../../../incremental/compat/src/arkts"], + "@koalaui/common": ["../../../incremental/common/src"] + } + }, + "include": ["./src/arkts/*.ts"] +} diff --git a/ets1.2/koala_integration.gni b/ets1.2/koala_integration.gni new file mode 100644 index 0000000000000000000000000000000000000000..5295f7960ab84780c8fb9f9becf0289ae5ee6c52 --- /dev/null +++ b/ets1.2/koala_integration.gni @@ -0,0 +1,25 @@ +# Copyright (c) 2025 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. + +koala_mr = { + root_path = "//developtools/ace_ets2bundle/ets1.2" + scripts_path = "$root_path/gn/script" + imports_prefix = "$root_path/gn/import" + libarkts_path = "$root_path/libarkts" + interop_path = "$root_path/interop" + is_rri = false +} + +node_version = "v16.20.2" +host_arch = "${host_os}-${host_cpu}" +koala_node_path = rebase_path("//prebuilts/build-tools/common/nodejs/node-${node_version}-${host_arch}/bin") diff --git a/ets1.2/libarkts/.clang-format b/ets1.2/libarkts/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..35740da59029fdf79b010223eca5b755f7e5af06 --- /dev/null +++ b/ets1.2/libarkts/.clang-format @@ -0,0 +1,107 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakAfterJavaFieldAnnotations: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +ReflowComments: true +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^"(base|core|elements|rendering|adapter|dsl|frameworks|resource|accessibility|bridge)/' + Priority: 3 + - Regex: '<*>' + Priority: 1 + - Regex: '.*' + Priority: 2 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 39 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 80 +PointerAlignment: Left +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/ets1.2/libarkts/.gitignore b/ets1.2/libarkts/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9e0adcc107c697a23bb04d98c015bc82025fc040 --- /dev/null +++ b/ets1.2/libarkts/.gitignore @@ -0,0 +1 @@ +/generated/ diff --git a/ets1.2/libarkts/.mocharc.json b/ets1.2/libarkts/.mocharc.json new file mode 100644 index 0000000000000000000000000000000000000000..35222a70dbc455d94ac0d57251be08cf39638af2 --- /dev/null +++ b/ets1.2/libarkts/.mocharc.json @@ -0,0 +1,11 @@ +{ + "ui": "tdd", + "spec": "./test/arkts-api/**/*.test.ts", + "extension": [ + "ts" + ], + "require": [ + "../../incremental/test-utils/scripts/register" + ], + "timeout": 20000 +} diff --git a/ets1.2/libarkts/.prettierrc b/ets1.2/libarkts/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..0ac1c22344baf59186eae700aea827a7a367830b --- /dev/null +++ b/ets1.2/libarkts/.prettierrc @@ -0,0 +1,8 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 4, + "trailingComma": "es5", + "bracketSpacing": true, + "printWidth": 120 +} \ No newline at end of file diff --git a/ets1.2/libarkts/BUILD.gn b/ets1.2/libarkts/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e7e7c8f3daf25954e7e639a523ebb9146b97d588 --- /dev/null +++ b/ets1.2/libarkts/BUILD.gn @@ -0,0 +1,308 @@ +# Copyright (c) 2025 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. + +if (!defined(koala_mr)) { + # OHOS build tree workaround + import("../../../koala_integration.gni") +} +if (!koala_mr.is_rri) { + import("//build/ohos.gni") +} +import("${koala_mr.imports_prefix}/npm.gni") + +ws_node_modules_dir = koala_mr.ui2abc_path + "/node_modules" + +if (koala_mr.is_rri) { + npm_cmd("panda_sdk_reinstall") { + project_path = rebase_path(".") + run_tasks = [ + "panda:sdk:reinstall" + ] + deps = [ + ":libarkts_install" + ] + } +} else { + + # Use from OHOS-SDK build (//build/ohos/sdk/ohos_sdk_description_std.json) + + ohos_copy("libarkts-sdk") { + deps = [ ":libarkts_sdk_copy" ] + sources = [ rebase_path("$target_gen_dir") ] + outputs = [ target_out_dir + "/$target_name" ] + module_source_dir = target_out_dir + "/$target_name" + module_install_name = "" + subsystem_name = "arkui" + part_name = "ace_engine" + } + +} + + +if (current_toolchain == host_toolchain) { + npm_cmd("regenerate") { + assert(current_toolchain == host_toolchain, "must be executed with host_toolchain") + if (koala_mr.is_rri) { + deps = [ + ":libarkts_install", + ":panda_sdk_reinstall" + ] + } else { + deps = [ + "${koala_mr.ui2abc_path}:ui2abc_install_all(${host_toolchain})", + "${koala_mr.ui2abc_path}:ui2abc_panda_sdk" + ] + } + project_path = rebase_path(".") + run_tasks = [ + "regenerate" + ] + } + + npm_install("libarkts_install") { + project_path = rebase_path(".") + } +} + +shared_library("es2panda_lib") { + if (!koala_mr.is_rri) { + external_deps = [ "ets_frontend:ets2panda" ] + } + + sources = [ + "${koala_mr.libarkts_path}/native/src/common.cc", + "${koala_mr.libarkts_path}/native/src/bridges.cc", + + "${koala_mr.interop_path}/src/cpp/napi/convertors-napi.cc", + "${koala_mr.interop_path}/src/cpp/callback-resource.cc", + "${koala_mr.interop_path}/src/cpp/interop-logging.cc", + "${koala_mr.interop_path}/src/cpp/common-interop.cc" + ] + + include_dirs = [ + "${koala_mr.es2panda_path}/public", + "${koala_mr.es2panda_path}", + "${koala_mr.libarkts_path}/native/src", + "${koala_mr.root_path}/interop/src/cpp", + "${koala_mr.root_path}/interop/src/cpp/napi", + "${koala_mr.root_path}/interop/src/cpp/types", + "$ws_node_modules_dir/node-api-headers/include", + "$ws_node_modules_dir/node-addon-api" + ] + + defines = [ + "KOALA_INTEROP_MODULE=NativeModule", + "INTEROP_LIBRARY_NAME=es2panda", + "KOALA_USE_NODE_VM", + "KOALA_NAPI" + ] + + deps = [ + ":regenerate_and_copy", + ] + #sources += get_target_outputs(deps[1]) // FIXME: cannot find target + sources += [ "$target_out_dir/generated/native/bridges.cc" ] + + if (!koala_mr.is_rri) { + deps += [ "${koala_mr.ui2abc_path}:ui2abc_install($host_toolchain)" ] + configs -= [ "//build/config/compiler:compiler" ] + } + + if (is_mac) { + cflags_cc = [ + "-std=c++17", + "-Wall", + "-Werror", + "-Wno-unused-variable", + "-fPIC", + ] + + ldflags = [ + "-fPIC", + "-Wl,-undefined,dynamic_lookup", + "-fuse-ld=lld", + "-Wl,--icf=all", + "-Wl,--color-diagnostics", + "-m64" + ] + defines += [ "KOALA_MACOS" ] + output_extension = "node" + } + + if (is_linux) { + cflags_cc = [ + "-std=c++17", + "-Wall", + "-Werror", + "-Wno-unused-command-line-argument", + "-Wno-unused-variable", + "-fPIC", + ] + + ldflags = [ + "-Wl,--allow-shlib-undefined", + "-Wl,--fatal-warnings", + "-Wl,--build-id=md5", + "-fPIC", + "-Wl,-z,noexecstack", + "-Wl,-z,now", + "-Wl,-z,relro", + + # "-Wl,-z,defs", # must no use this option + "-Wl,--as-needed", + "-fuse-ld=lld", + "-Wl,--icf=all", + "-Wl,--color-diagnostics", + "-m64", + ] + defines += [ "KOALA_LINUX" ] + output_extension = "node" + } else if (current_os == "mingw") { + cflags_cc = [ + "-std=c++17", + "-Wall", + "-Werror", + "-Wno-unused-variable", + "-Wno-unused-command-line-argument", + "-fPIC", + "-Wno-error=deprecated-copy", + "-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang", + "-ftrivial-auto-var-init=zero", + "-fcolor-diagnostics", + "-fmerge-all-constants", + "-Xclang", + "-mllvm", + "-Xclang", + "-instcombine-lower-dbg-declare=0", + "-no-canonical-prefixes", + "-fuse-ld=lld", + "-fno-stack-protector", + "-fno-strict-aliasing", + "-Wno-builtin-macro-redefined", + "-fms-extensions", + "-static", + "-rtlib=compiler-rt", + "-stdlib=libc++", + "-lunwind", + "-lpthread", + "-Qunused-arguments", + "-target", + "x86_64-pc-windows-gnu", + "-D__CUSTOM_SECURITY_LIBRARY", + ] + + ldflags = [ + "-Wl,--fatal-warnings", + "-fPIC", + "-Wl,--as-needed", + "-fuse-ld=lld", + "-Wl,--icf=all", + "-m64", + "-static", + "-rtlib=compiler-rt", + "-stdlib=libc++", + "-std=c++17", + "-lunwind", + "-lpthread", + "-Qunused-arguments", + "-target", + "x86_64-pc-windows-gnu", + ] + output_extension = "dll" + defines += [ "KOALA_WINDOWS" ] + sources += [ "${koala_mr.interop_path}/src/cpp/napi/win-dynamic-node.cc" ] + } +} + +action("es2panda_lib_copy") { + script = "gn/command/copy.py" + if (defined(build_ohos_sdk) && build_ohos_sdk) { + deps = [ + ":es2panda_lib" + ] + from_path = root_out_dir + } else { + deps = [ + ":es2panda_lib(${host_toolchain})" + ] + if (host_toolchain != current_toolchain) { + toolchain_parts = string_split(host_toolchain, ":") + from_path = "$root_out_dir/${toolchain_parts[1]}" + } else { + from_path = root_out_dir + } + } + + # inputs = [ + # "$from_path/libes2panda_lib.node" + # ] + outputs = [ + "$target_out_dir/es2panda.node" + ] + args = [ + "--from-path", rebase_path(from_path), + "--to-path", rebase_path("."), + "--current-os", current_os, + "--current-cpu", current_cpu + ] +} + +# The generated bridges.cc doesn't exist at configure step and +# should be linked with a target that creates it. As outputs cannot +# point outside target_out_dir - make a copy target. +copy("regenerate_and_copy") { + sources = [ "${koala_mr.libarkts_path}/generated/native/bridges.cc", ] + outputs = [ "$target_out_dir/generated/native/bridges.cc", ] + deps = [ ":regenerate(${host_toolchain})", ] +} +# for //developtools/ace_ets2bundle + +npm_cmd("libarkts_compile") { + deps = [ + "${koala_mr.interop_path}:interop_install(${host_toolchain})", + "${koala_mr.incremental_path}:incremental_install(${host_toolchain})", + ":regenerate(${host_toolchain})" + ] + outputs = [ + "$target_out_dir/libarkts.js" + ] + project_path = rebase_path(".") + run_tasks = [ "compile:koala:interop", "compile:js" ] +} + +group("es2panda") { + deps = [ + ":es2panda_lib_copy", + ":libarkts_compile(${host_toolchain})" + ] +} + +group("libarkts") { + deps = [ + ":es2panda_lib", + ":libarkts_compile(${host_toolchain})" + ] +} + +action("libarkts_sdk_copy") { + script = "../gn/command/copy_libs.py" + args = [ + "--source_path", rebase_path(get_path_info(".", "abspath")), + "--output_path", rebase_path("$target_gen_dir"), + "--root_out_dir", rebase_path(root_out_dir), + ] + outputs = [ "$target_gen_dir" ] + deps = [ + "${koala_mr.ui2abc_path}:ui2abc" + ] +} diff --git a/ets1.2/libarkts/arktsconfig-direct.json b/ets1.2/libarkts/arktsconfig-direct.json new file mode 100644 index 0000000000000000000000000000000000000000..4c082ac14e93efcbc680bfeb4c2d13f8bc82041e --- /dev/null +++ b/ets1.2/libarkts/arktsconfig-direct.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "outDir": "./build/abc", + "baseUrl": ".", + "paths": { + "@koalaui/compat": [ "../../incremental/compat/src/arkts" ], + "#platform": [ "../../incremental/compat/src/arkts" ], + "@koalaui/common": [ "../../incremental/common/src" ], + "@koalaui/runtime": [ "../../incremental/runtime/ets" ], + "@koalaui/runtime/annotations": [ "../../incremental/runtime/annotations" ] + }, + "plugins": [ + { + "transform": "../memo-plugin-ng", + "state": "checked", + "name": "memo" + } + ] + } +} diff --git a/ets1.2/libarkts/arktsconfig.json b/ets1.2/libarkts/arktsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..3ece19cfd09431daf8d0f38608dd54b419b04b58 --- /dev/null +++ b/ets1.2/libarkts/arktsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "package": "test", + "outDir": "./build/abc", + "baseUrl": ".", + "plugins": [ + { + "transform": "./lib/plugins/printer-plugin.js", + "state": "parsed", + "name": "printer" + }, + { + "transform": "./lib/plugins/printer-plugin.js", + "state": "checked", + "name": "printer" + }, + { + "transform": "./lib/plugins/printer-plugin.js", + "state": "checked", + "name": "printer2" + } + ] + }, + "include": ["./plugins/input/main.ets", "./plugins/input/library.ets"] +} diff --git a/ets1.2/libarkts/generator/options.json5 b/ets1.2/libarkts/generator/options.json5 new file mode 100644 index 0000000000000000000000000000000000000000..64c3be9d43a87bcced135325fcc0739358b96780 --- /dev/null +++ b/ets1.2/libarkts/generator/options.json5 @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2025 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. + */ + +{ + "irHack": [ + "AnnotationUsage", + "ETSFunctionType", + "ETSUnionType", + "ETSNullType", + "ETSUndefinedType", + ], + "ignore": { + "full": [ + "es2panda_Config", + "es2panda_ExternalSource", + "es2panda_OverloadInfo", + "es2panda_GlobalContext", + + // Duplicates of types in ir namespace + // They will be removed in the fututre. + 'es2panda_Signature', + 'es2panda_CheckerContext', + 'es2panda_Type', + 'es2panda_TypeRelation', + 'es2panda_GlobalTypesHolder', + 'es2panda_Variable', + 'es2panda_Scope', + 'es2panda_Path', + 'es2panda_ResolveResult', + 'es2panda_RecordTable', + 'es2panda_BoundContext', + 'es2panda_ImportPathManager', + 'es2panda_Options', + 'es2panda_AstNode', + 'es2panda_Program', + 'es2panda_ArkTsConfig', + 'es2panda_FunctionSignature', + + 'NodeTransformer', + 'NodeTraverser', + 'AstNodeForEachFunction', + 'ClassBuilder', + 'ClassInitializerBuilder', + 'MethodBuilder', + 'NodePredicate', + 'PropertyProcessor', + 'PropertyTraverser', + + 'checker.*', + 'varbinder.*', + 'parser.*', + 'util.*', + 'gen.*', + 'es2panda.*', + 'ast_verifier.*', + + 'parser.Program!', + 'es2panda.ArkTsConfig!', + // Do not support node type + //'varbinder.FunctionDecl!', + //'varbinder.InterfaceDecl!', + // MemberExpression has checker.ETSFunctionType ExtensionAccessorTypeConst(es2panda_Context context); + //'checker.ETSFunctionType!', + //'ir.ETSFunctionType', + + 'ir.Annotated', + 'ir.AnnotationAllowed', + 'ir.Typed', + 'ir.VectorIterationGuard', + + 'VoidPtr', + ], + "partial": [ + { + interface: "es2panda_Impl", + methods: [ + "LogSyntaxError", "LogWarning", "LogTypeError", // wrong idl + "DestroyContext", // cleanup arena (Improve: move this cleanup to another method) + + // Handwritten bridges + "AstNodeRebind", + "ConfigGetOptions", + "CreateCacheContextFromFile", + "CreateContextFromFile", + "CreateContextFromString", + "CreateContextGenerateAbcForExternalSourceFiles", + "CreateDiagnosticInfo", + "CreateDiagnosticKind", + "CreateGlobalContext", + "CreateSuggestionInfo", + "DestroyGlobalContext", + "SourcePositionCol", + "ExternalSourceName", + "ExternalSourcePrograms", + "GenerateTsDeclarationsFromContext", + "LogDiagnostic", + ], + }, + { + interface: "MethodDefinition", + methods: [ + "GetOverloadInfo", // return type is wrong + ] + }, + { + interface: "Decl", // handwritten bridge + methods: [ + "Node" + ] + }, + { + interface: "ETSParser", // handwritten bridge + methods: [ + "BuildImportDeclaration", + "CreateExpression", + "GetGlobalProgramAbsName", + "GetImportPathManager", + ] + }, + { + interface: "Program", // handwritten bridge + methods: [ + "DirectExternalSources", + "ExternalSources", + ] + }, + { + interface: "Scope", // handwritten bridge + methods: [ + "SetParent", + ] + }, + { + interface: "Signature", // handwritten bridge + methods: [ + "Function", + ] + }, + { + interface: "TSInterfaceBody", // handwritten bridge + methods: [ + "BodyPtr", + ] + }, + { + interface: "AnnotationDeclaration", + methods: [ + "PropertiesPtrConst" // interfaces create-to-param matching + ] + }, + { + interface: "NumberLiteral", + methods: [ + "SetInt", + "SetLong", + "SetDouble", + "SetFloat" + ] + }, + { + interface: "AnnotationUsage", + methods: [ + "PropertiesPtrConst" // interfaces create-to-param matching + ] + }, + { + interface: "TSInterfaceBody", + methods: [ + "BodyPtr" // interfaces create-to-param matching + ] + }, + { + interface: "Signature", + methods: [ + "ProtectionFlagConst" // u8 + ] + }, + { + interface: "ETSReExportDeclaration", + methods: [ + "Create", // sequence + "Update", // sequence + "GetUserPathsConst" // sequence + ] + }, + { + interface: "CharLiteral", + methods: [ + "Create1", // KShort, + "Update1", // KShort + "CharConst", // KShort + ] + }, + { + interface: "ForUpdateStatement", + methods: [ + "Update" // forbidden naming + ] + }, + { + interface: "CallExpression", + methods: [ + "Update" // differs from handwritten + ] + }, + { + interface: "TryStatement", + methods: [ + "AddFinalizerInsertion" // idl missing const + ] + }, + { + interface: "MemberExpression", + methods: [ + "SetExtensionAccessorType" // ETSFunction type ambiguity + ] + }, + { + interface: "ArkTsConfig", + methods: [ + "EntriesConst", + "FilesConst", + "Parse", + ] + }, + ] + }, + nonNullable: [ + { + name: "ScriptFunction", + methods: [ + { + name: "SetIdent", + types: ["id"] + } + ] + }, + { + name: "ArrowFunctionExpression", + methods: [ + { + name: "Function", + types: ["returnType"] + }, + { + name: "FunctionConst", + types: ["returnType"] + }, + ] + }, + { + name : "FunctionDeclaration", + methods: [ + { + name: "FunctionConst", + types: ["returnType"] + } + ] + }, + { + name: "CallExpression", + methods: [ + { + name: "CalleeConst", + types: ["returnType"] + } + ] + }, + { + name : "ExpressionStatement", + methods: [ + { + name: "GetExpressionConst", + types: ["returnType"] + } + ] + }, + { + name: "IfStatement", + methods: [ + { + name: "TestConst", + types: ["returnType"] + }, + { + name: "ConsequentConst", + types: ["returnType"] + } + ] + }, + { + name: "MemberExpression", + methods: [ + { + name: "ObjectConst", + types: ["returnType"] + }, + { + name: "PropertyConst", + types: ["returnType"] + } + ] + }, + { + name: "ETSParameterExpression", + methods: [ + { + name: "IdentConst", + types: ["returnType"] + } + ] + }, + { + name: "VariableDeclarator", + methods: [ + { + name: "IdConst", + types: ["returnType"] + } + ] + }, + { + name: "ClassElement", + methods: [ + { + name: "IdConst", + types: ["returnType"] + } + ] + }, + { + name: "MethodDefinition", + methods: [ + { + name: "Function", + types: ["returnType"] + }, + { + name: "FunctionConst", + types: ["returnType"] + }, + ] + }, + { + name: "ETSFunctionType", + methods: [ + { + name: "ReturnTypeConst", + types: ["returnType"] + } + ] + }, + { + name: "TSTypeAliasDeclaration", + methods: [ + { + name: "TypeAnnotationConst", + types: ["returnType"] + } + ] + }, + { + name: "Program", + methods: [ + { + name: "Ast", + types: ["returnType"] + } + ] + }, + { + name: "ClassDeclaration", + methods: [ + { + name: "Definition", + types: ["returnType"] + } + ] + }, + ], + fragments: [ + { + interface: "MethodDefinition", + methods: [ + { + name: "setChildrenParentPtr", + definition: "extension_MethodDefinitionSetChildrenParentPtr", + }, + { + name: "onUpdate", + definition: "extension_MethodDefinitionOnUpdate", + }, + ] + }, + { + interface: "ETSModule", + methods: [ + { + name: "getNamespaceFlag", + definition: "extension_ETSModuleGetNamespaceFlag", + } + ] + }, + { + interface: "ScriptFunction", + methods: [ + { + name: "getSignaturePointer", + definition: "extension_ScriptFunctionGetSignaturePointer", + }, + { + name: "setSignaturePointer", + definition: "extension_ScriptFunctionSetSignaturePointer", + }, + { + name: "getParamsCasted", + definition: "extension_ScriptFunctionGetParamsCasted", + }, + { + name: "getPreferredReturnTypePointer", + definition: "extension_ScriptFunctionGetPreferredReturnTypePointer", + }, + { + name: "setPreferredReturnTypePointer", + definition: "extension_ScriptFunctionSetPreferredReturnTypePointer", + }, + ] + }, + { + interface: "ClassDefinition", + methods: [ + { + name: "setBody", + definition: "extension_ClassDefinitionSetBody", + }, + ] + }, + { + interface: "Expression", + methods: [ + { + name: "getPreferredTypePointer", + definition: "extension_ExpressionGetPreferredTypePointer", + }, + { + name: "setPreferredTypePointer", + definition: "extension_ExpressionSetPreferredTypePointer", + }, + ] + }, + { + interface: "Program", + methods: [ + { + name: "getAstCasted", + definition: "extension_ProgramGetAstCasted", + }, + { + name: "getExternalSources", + definition: "extension_ProgramGetExternalSources", + }, + ], + }, + { + interface: "es2panda_SourcePosition", + methods: [ + { + name: "getLine", + definition: "extension_SourcePositionGetLine", + }, + { + name: "getCol", + definition: "extension_SourcePositionGetCol", + }, + { + name: "getIndex", + definition: "extension_SourcePositionGetIndex", + }, + { + name: "toString", + definition: "extension_SourcePositionToString", + }, + ], + }, + { + interface: "NumberLiteral", + methods: [ + { + name: "value", + definition: "extension_NumberLiteralValue", + }, + ], + }, + { + interface: "ETSFunctionType", + methods: [ + { + name: "getParamsCasted", + definition: "extension_ETSFunctionTypeGetParamsCasted", + }, + ], + }, + ], + parameters: [ + { + interface: "ArrowFunctionExpression", + parameters: [ + { + name: "annotations", + }, + ], + }, + { + interface: "CallExpression", + parameters: [ + { + name: "trailingBlock", + }, + ], + }, + { + interface: "ClassDeclaration", + parameters: [ + { + name: "modifierFlags", + }, + ], + }, + { + interface: "ClassDefinition", + parameters: [ + { + name: "annotations", + }, + ], + }, + { + interface: "ClassProperty", + parameters: [ + { + name: "annotations", + }, + ], + }, + { + interface: "ETSFunctionType", + parameters: [ + { + name: "annotations", + }, + ], + }, + { + interface: "ETSParameterExpression", + parameters: [ + { + name: "annotations", + }, + ], + }, + { + interface: "ETSUnionType", + parameters: [ + { + name: "annotations", + }, + ], + }, + { + interface: "MethodDefinition", + parameters: [ + { + name: "overloads", + }, + ], + }, + { + interface: "ScriptFunction", + parameters: [ + { + name: "ident", + setter: "setIdent", + getter: "id", + }, + { + name: "annotations", + }, + ], + }, + { + interface: "TSInterfaceDeclaration", + parameters: [ + { + name: "modifierFlags", + }, + ], + }, + { + interface: "TSTypeAliasDeclaration", + parameters: [ + { + name: "annotations", + }, + { + name: "modifierFlags", + }, + ], + }, + { + interface: "VariableDeclaration", + parameters: [ + { + name: "annotations", + }, + ], + }, + ], +} diff --git a/ets1.2/libarkts/gn/command/copy.py b/ets1.2/libarkts/gn/command/copy.py new file mode 100755 index 0000000000000000000000000000000000000000..54ac0975bbe1f9893d174e575cd4a8acabc641e3 --- /dev/null +++ b/ets1.2/libarkts/gn/command/copy.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2025 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. + +import argparse +import os +import shutil +import subprocess +import sys + +def library_ext(os_name, cpu_name): + if (os_name == 'mingw' and cpu_name == 'x86_64'): + return 'dll' + return 'node' + +def copy_files(source_path, dest_path, is_file=False): + try: + if is_file: + os.makedirs(os.path.dirname(dest_path), exist_ok=True) + shutil.copy(source_path, dest_path) + else: + shutil.copytree(source_path, dest_path, dirs_exist_ok=True, + symlinks=True) + except Exception as err: + raise Exception("Copy files failed. Error: " + str(err)) from err + + +def run_cmd(cmd, execution_path=None): + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=execution_path) + stdout, stderr = proc.communicate(timeout=1000) + if proc.returncode != 0: + raise Exception(stdout.decode() + stderr.decode()) + + + +def copy_output(options): + library_extention = library_ext(options.current_os, options.current_cpu) + + from_path = options.from_path + to_path = options.to_path + + copy_files(os.path.join(from_path, f'libes2panda_lib.{library_extention}'), + os.path.join(to_path, 'build/native/build/es2panda.node'), True) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--from-path', help='path to output') + parser.add_argument('--to-path', help='path to root out') + parser.add_argument('--current-os', help='current OS') + parser.add_argument('--current-cpu', help='current CPU') + + options = parser.parse_args() + return options + + +def main(): + options = parse_args() + copy_output(options) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/ets1.2/libarkts/native/meson.build b/ets1.2/libarkts/native/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..72955d62027a4a2659f9fe875361cb7b9d28d8c9 --- /dev/null +++ b/ets1.2/libarkts/native/meson.build @@ -0,0 +1,128 @@ +# Copyright (c) 2025 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. + +project( + 'es2panda_interop', + 'cpp', + version: '1.0', + default_options: [ + 'cpp_std=c++17', + 'buildtype=release', + ], +) +is_cross = get_option('cross_compile') + +sources = [ + './src/common.cc', + './src/memoryTracker.cc', + './src/bridges.cc', + '../generated/native/bridges.cc', + get_option('interop_src_dir') / 'common-interop.cc', + get_option('interop_src_dir') / 'callback-resource.cc', + get_option('interop_src_dir') / 'interop-logging.cc', + get_option('interop_src_dir') / 'napi' / 'convertors-napi.cc', +] + +cflags = [ + '-DKOALA_INTEROP_MODULE=NativeModule', + '-DINTEROP_LIBRARY_NAME=' + get_option('lib_name'), + '-DKOALA_USE_NODE_VM', + '-DKOALA_NAPI', +] + +if (host_machine.system() == 'windows') + cflags += ['-DKOALA_WINDOWS'] + # apply node.exe symbol loading hook + sources += [ + get_option('interop_src_dir') / 'napi/win-dynamic-node.cc' + ] +else + cflags += ['-DKOALA_LINUX'] +endif + +arch = target_machine.cpu() + +oses = { 'darwin': 'macos' } # rename meson default names to convenient ones +archs = { 'x86_64': 'x64', 'aarch64': 'arm64', 'armv7-a': 'arm32', 'wasm32': 'wasm' } + +os = target_machine.system() +os = oses.get(os, os) +arch = target_machine.cpu() +arch = archs.get(arch, arch) + +cflags_cross = [] +cflags_host = [] +suffix_host = '_' + os + '_' + arch +suffix_cross = '' + +if get_option('cross_compile') +if arch == 'arm64' +cflags_cross = ['--target=x86_64-linux-gnu'] +suffix_cross = '_' + os + '_x64' +endif +if arch == 'x64' +cflags_cross = ['--target=aarch64-linux-gnu'] +suffix_cross = '_' + os + '_arm64' +endif +endif + +shared_library( + get_option('lib_name') + suffix_host, + sources, + override_options: [ + 'b_lundef=false', + ], + install: true, + name_prefix: '', + name_suffix: 'node', + include_directories: [ + './src/', + get_option('panda_sdk_dir') / 'ohos_arm64/include/tools/es2panda/public', + get_option('panda_sdk_dir') / 'ohos_arm64/include/tools/es2panda', + get_option('interop_src_dir'), + get_option('interop_src_dir') / 'types', + get_option('interop_src_dir') / 'napi', + get_option('node_modules_dir') / 'node-api-headers/include', + get_option('node_modules_dir') / 'node-addon-api', + ], + cpp_args: cflags + cflags_host, + link_args: [cflags_host], + dependencies: [] +) + +if is_cross + # sudo apt install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu + shared_library( + get_option('lib_name') + suffix_cross, + sources, + override_options: [ + 'b_lundef=false', + ], + install: true, + name_prefix: '', + name_suffix: 'node', + include_directories: [ + './src/', + get_option('panda_sdk_dir') / 'ohos_arm64/include/tools/es2panda/public', + get_option('panda_sdk_dir') / 'ohos_arm64/include/tools/es2panda', + get_option('interop_src_dir'), + get_option('interop_src_dir') / 'types', + get_option('interop_src_dir') / 'napi', + get_option('node_modules_dir') / 'node-api-headers/include', + get_option('node_modules_dir') / 'node-addon-api', + ], + cpp_args: cflags + cflags_cross, + link_args: [cflags_cross], + dependencies: [] + ) +endif \ No newline at end of file diff --git a/ets1.2/libarkts/native/meson_options.txt b/ets1.2/libarkts/native/meson_options.txt new file mode 100644 index 0000000000000000000000000000000000000000..a59bde5ec5ec79c49d5033c733eb3cf5acbd70e1 --- /dev/null +++ b/ets1.2/libarkts/native/meson_options.txt @@ -0,0 +1,43 @@ +# Copyright (c) 2025 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. + +option( + 'node_modules_dir', + type : 'string', + value : '../../node_modules/', + description : 'path to node_modules' +) +option( + 'interop_src_dir', + type : 'string', + value : '../../../interop/src/cpp/', + description : 'path to koala interop cpp files' +) +option( + 'panda_sdk_dir', + type : 'string', + value : '../../../incremental/tools/panda/node_modules/@panda/sdk/', + description : 'path to panda sdk' +) +option( + 'lib_name', + type : 'string', + value : 'es2panda', + description : 'name of shared library' +) +option( + 'cross_compile', + type : 'boolean', + value : false, + description : 'whether to build binaries for all architectures or just for current' +) \ No newline at end of file diff --git a/ets1.2/libarkts/native/mingw.cross b/ets1.2/libarkts/native/mingw.cross new file mode 100644 index 0000000000000000000000000000000000000000..61007dbc506ba1fdfdd2805b666f92c2fed071f4 --- /dev/null +++ b/ets1.2/libarkts/native/mingw.cross @@ -0,0 +1,27 @@ +# Copyright (c) 2025 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. + +[binaries] +c = 'x86_64-w64-mingw32-gcc' +cpp = 'x86_64-w64-mingw32-g++' +ar = 'x86_64-w64-mingw32-ar' +windres = 'x86_64-w64-mingw32-windres' +strip = 'x86_64-w64-mingw32-strip' +exe_wrapper = 'wine64' + +[host_machine] +system = 'windows' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + diff --git a/ets1.2/libarkts/native/src/bridges.cc b/ets1.2/libarkts/native/src/bridges.cc new file mode 100644 index 0000000000000000000000000000000000000000..d19ed1a8843237c464fb7475a5d512279d2cee85 --- /dev/null +++ b/ets1.2/libarkts/native/src/bridges.cc @@ -0,0 +1,555 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#include +#include +#include + +#include "common.h" + +/** XXX: If you add or remove methods that exist in C API, + * please change generator/options.json5 accordingly. + */ + +KNativePointer impl_AstNodeRebind(KNativePointer contextPtr, KNativePointer nodePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto node = reinterpret_cast(nodePtr); + GetImpl()->AstNodeRebind(context, node); + return nullptr; +} +KOALA_INTEROP_2(AstNodeRebind, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_AnnotationAllowedAnnotations( + KNativePointer contextPtr, KNativePointer nodePtr, KNativePointer returnLen) +{ + auto context = reinterpret_cast(contextPtr); + auto node = reinterpret_cast(nodePtr); + std::size_t params_len = 0; + auto annotations = GetImpl()->AnnotationAllowedAnnotations(context, node, ¶ms_len); + return StageArena::cloneVector(annotations, params_len); +} +KOALA_INTEROP_3(AnnotationAllowedAnnotations, KNativePointer, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_AnnotationAllowedAnnotationsConst( + KNativePointer contextPtr, KNativePointer nodePtr, KNativePointer returnLen) +{ + auto context = reinterpret_cast(contextPtr); + auto node = reinterpret_cast(nodePtr); + std::size_t params_len = 0; + auto annotations = GetImpl()->AnnotationAllowedAnnotationsConst(context, node, ¶ms_len); + return StageArena::cloneVector(annotations, params_len); +} +KOALA_INTEROP_3(AnnotationAllowedAnnotationsConst, KNativePointer, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_VariableDeclaration(KNativePointer contextPtr, KNativePointer variablePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto variable = reinterpret_cast(variablePtr); + + return GetImpl()->VariableDeclaration(context, variable); +} +KOALA_INTEROP_2(VariableDeclaration, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_DeclNode(KNativePointer contextPtr, KNativePointer declPtr) +{ + auto context = reinterpret_cast(contextPtr); + auto decl = reinterpret_cast(declPtr); + + return GetImpl()->DeclNode(context, decl); +} +KOALA_INTEROP_2(DeclNode, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_ScopeSetParent(KNativePointer contextPtr, KNativePointer nodePtr, KNativePointer parentPtr) +{ + auto context = reinterpret_cast(contextPtr); + auto node = reinterpret_cast(nodePtr); + auto parent = reinterpret_cast(parentPtr); + GetImpl()->ScopeSetParent(context, node, parent); + return node; +} +KOALA_INTEROP_3(ScopeSetParent, KNativePointer, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_ETSParserCreateExpression(KNativePointer contextPtr, KStringPtr& sourceCodePtr, KInt flagsT) +{ + auto context = reinterpret_cast(contextPtr); + auto flags = static_cast(flagsT); + + return GetImpl()->ETSParserCreateExpression(context, getStringCopy(sourceCodePtr), flags); +} +KOALA_INTEROP_3(ETSParserCreateExpression, KNativePointer, KNativePointer, KStringPtr, KInt) + +KNativePointer impl_CreateContextFromString(KNativePointer configPtr, KStringPtr& sourcePtr, KStringPtr& filenamePtr) +{ + auto config = reinterpret_cast(configPtr); + return GetImpl()->CreateContextFromString(config, sourcePtr.data(), filenamePtr.data()); +} +KOALA_INTEROP_3(CreateContextFromString, KNativePointer, KNativePointer, KStringPtr, KStringPtr) + +KNativePointer impl_CreateContextFromFile(KNativePointer configPtr, KStringPtr& filenamePtr) +{ + auto config = reinterpret_cast(configPtr); + return GetImpl()->CreateContextFromFile(config, getStringCopy(filenamePtr)); +} +KOALA_INTEROP_2(CreateContextFromFile, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_SignatureFunction(KNativePointer context, KNativePointer classInstance) +{ + const auto _context = reinterpret_cast(context); + const auto _classInstance = reinterpret_cast(classInstance); + const auto result = GetImpl()->SignatureFunction(_context, _classInstance); + return result; +} +KOALA_INTEROP_2(SignatureFunction, KNativePointer, KNativePointer, KNativePointer) + +static KNativePointer impl_ProgramExternalSources(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto&& instance = reinterpret_cast(instancePtr); + std::size_t source_len = 0; + auto external_sources = GetImpl()->ProgramExternalSources(context, instance, &source_len); + return StageArena::cloneVector(external_sources, source_len); +} +KOALA_INTEROP_2(ProgramExternalSources, KNativePointer, KNativePointer, KNativePointer); + +static KNativePointer impl_ProgramDirectExternalSources(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto&& instance = reinterpret_cast(instancePtr); + std::size_t sourceLen = 0; + auto externalSources = GetImpl()->ProgramDirectExternalSources(context, instance, &sourceLen); + return new std::vector(externalSources, externalSources + sourceLen); +} +KOALA_INTEROP_2(ProgramDirectExternalSources, KNativePointer, KNativePointer, KNativePointer); + +static KNativePointer impl_ProgramSourceFilePath(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto&& instance = reinterpret_cast(instancePtr); + auto&& result = GetImpl()->ProgramSourceFilePathConst(context, instance); + return StageArena::strdup(result); +} +KOALA_INTEROP_2(ProgramSourceFilePath, KNativePointer, KNativePointer, KNativePointer); + +static KNativePointer impl_ExternalSourceName(KNativePointer instance) +{ + auto&& _instance_ = reinterpret_cast(instance); + auto&& result = GetImpl()->ExternalSourceName(_instance_); + return StageArena::strdup(result); +} +KOALA_INTEROP_1(ExternalSourceName, KNativePointer, KNativePointer); + +static KNativePointer impl_ExternalSourcePrograms(KNativePointer instance) +{ + auto&& _instance_ = reinterpret_cast(instance); + std::size_t program_len = 0; + auto programs = GetImpl()->ExternalSourcePrograms(_instance_, &program_len); + return StageArena::cloneVector(programs, program_len); +} +KOALA_INTEROP_1(ExternalSourcePrograms, KNativePointer, KNativePointer); + +KNativePointer impl_ETSParserBuildImportDeclaration(KNativePointer context, KInt importKinds, + KNativePointerArray specifiers, KUInt specifiersSequenceLength, KNativePointer source, KNativePointer program, + KInt importFlag) +{ + const auto _context = reinterpret_cast(context); + const auto _kinds = static_cast(importKinds); + const auto _specifiers = reinterpret_cast(specifiers); + const auto _specifiersSequenceLength = static_cast(specifiersSequenceLength); + const auto _source = reinterpret_cast(source); + const auto _program = reinterpret_cast(program); + const auto _importFlag = static_cast(importFlag); + + return GetImpl()->ETSParserBuildImportDeclaration( + _context, _kinds, _specifiers, _specifiersSequenceLength, _source, _program, _importFlag); +} +KOALA_INTEROP_7(ETSParserBuildImportDeclaration, KNativePointer, KNativePointer, KInt, KNativePointerArray, KUInt, + KNativePointer, KNativePointer, KInt) + +KNativePointer impl_ETSParserGetImportPathManager(KNativePointer contextPtr) +{ + auto context = reinterpret_cast(contextPtr); + return GetImpl()->ETSParserGetImportPathManager(context); +} +KOALA_INTEROP_1(ETSParserGetImportPathManager, KNativePointer, KNativePointer); + +KInt impl_SourcePositionCol(KNativePointer context, KNativePointer instance) +{ + auto&& _context_ = reinterpret_cast(context); + auto&& _instance_ = reinterpret_cast(instance); + return GetImpl()->SourcePositionCol(_context_, _instance_); +} +KOALA_INTEROP_2(SourcePositionCol, KInt, KNativePointer, KNativePointer); + +KNativePointer impl_ConfigGetOptions(KNativePointer config) +{ + const auto _config = reinterpret_cast(config); + auto result = GetImpl()->ConfigGetOptions(_config); + return (void*)result; +} +KOALA_INTEROP_1(ConfigGetOptions, KNativePointer, KNativePointer) + +KNativePointer impl_OptionsArkTsConfig(KNativePointer context, KNativePointer options) +{ + const auto _context = reinterpret_cast(context); + const auto _options = reinterpret_cast(options); + auto result = GetImpl()->OptionsUtilArkTSConfigConst(_context, _options); + return (void*)result; +} +KOALA_INTEROP_2(OptionsArkTsConfig, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_CreateCacheContextFromFile( + KNativePointer configPtr, KStringPtr& source_file_namePtr, KNativePointer globalContextPtr, KBoolean isExternal) +{ + auto config = reinterpret_cast(configPtr); + auto globalContext = reinterpret_cast(globalContextPtr); + return GetImpl()->CreateCacheContextFromFile(config, getStringCopy(source_file_namePtr), globalContext, isExternal); +} +KOALA_INTEROP_4(CreateCacheContextFromFile, KNativePointer, KNativePointer, KStringPtr, KNativePointer, KBoolean) + +KNativePointer impl_CreateGlobalContext( + KNativePointer configPtr, KStringArray externalFileListPtr, KUInt fileNum, KBoolean LspUsage) +{ + auto config = reinterpret_cast(configPtr); + const int headerLen = 4; + const char** files = StageArena::allocArray(fileNum); + uint8_t* filesPtr = (uint8_t*)externalFileListPtr; + std::size_t position = headerLen; + std::size_t strLen; + for (std::size_t i = 0; i < static_cast(fileNum); ++i) { + strLen = unpackUInt(filesPtr + position); + position += headerLen; + files[i] = StageArena::strdup(std::string(reinterpret_cast(filesPtr + position), strLen).c_str()); + position += strLen; + } + return GetImpl()->CreateGlobalContext(config, files, fileNum, LspUsage); +} +KOALA_INTEROP_4(CreateGlobalContext, KNativePointer, KNativePointer, KStringArray, KUInt, KBoolean) + +void impl_DestroyGlobalContext(KNativePointer globalContextPtr) +{ + auto globalContext = reinterpret_cast(globalContextPtr); + GetImpl()->DestroyGlobalContext(globalContext); +} +KOALA_INTEROP_V1(DestroyGlobalContext, KNativePointer) + +// All these "Checker_" bridges are related to checker namespace in es2panda, so work with them carefully +// Checker.Type does reset on recheck, so modifying them makes no sence +// It seems that compiler does not provide API to convert Checker.Type to ir.Type +KNativePointer impl_Checker_CreateOpaqueTypeNode(KNativePointer context, KNativePointer type) +{ + auto _context = reinterpret_cast(context); + auto _type = reinterpret_cast(type); + return GetImpl()->CreateOpaqueTypeNode(_context, _type); +} +KOALA_INTEROP_2(Checker_CreateOpaqueTypeNode, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_Checker_ScriptFunctionSignature(KNativePointer context, KNativePointer node) +{ + auto _context = reinterpret_cast(context); + auto _node = reinterpret_cast(node); + return GetImpl()->ScriptFunctionSignature(_context, _node); +} +KOALA_INTEROP_2(Checker_ScriptFunctionSignature, KNativePointer, KNativePointer, KNativePointer) + +void impl_Checker_ScriptFunctionSetSignature(KNativePointer context, KNativePointer node, KNativePointer signature) +{ + auto _context = reinterpret_cast(context); + auto _node = reinterpret_cast(node); + auto _signature = reinterpret_cast(signature); + GetImpl()->ScriptFunctionSetSignature(_context, _node, _signature); + return; +} +KOALA_INTEROP_V3(Checker_ScriptFunctionSetSignature, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_Checker_SignatureReturnType(KNativePointer context, KNativePointer signature) +{ + auto _context = reinterpret_cast(context); + auto _signature = reinterpret_cast(signature); + return GetImpl()->SignatureReturnType(_context, _signature); +} +KOALA_INTEROP_2(Checker_SignatureReturnType, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_Checker_ScriptFunctionGetPreferredReturnType(KNativePointer context, KNativePointer node) +{ + auto _context = reinterpret_cast(context); + auto _node = reinterpret_cast(node); + return GetImpl()->ScriptFunctionGetPreferredReturnType(_context, _node); +} +KOALA_INTEROP_2(Checker_ScriptFunctionGetPreferredReturnType, KNativePointer, KNativePointer, KNativePointer) + +void impl_Checker_ScriptFunctionSetPreferredReturnType(KNativePointer context, KNativePointer node, KNativePointer type) +{ + auto _context = reinterpret_cast(context); + auto _node = reinterpret_cast(node); + auto _type = reinterpret_cast(type); + GetImpl()->ScriptFunctionSetPreferredReturnType(_context, _node, _type); + return; +} +KOALA_INTEROP_V3(Checker_ScriptFunctionSetPreferredReturnType, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_Checker_ExpressionGetPreferredType(KNativePointer context, KNativePointer node) +{ + auto _context = reinterpret_cast(context); + auto _node = reinterpret_cast(node); + return GetImpl()->ExpressionPreferredTypeConst(_context, _node); +} +KOALA_INTEROP_2(Checker_ExpressionGetPreferredType, KNativePointer, KNativePointer, KNativePointer) + +void impl_Checker_ExpressionSetPreferredType(KNativePointer context, KNativePointer node, KNativePointer type) +{ + auto _context = reinterpret_cast(context); + auto _node = reinterpret_cast(node); + auto _type = reinterpret_cast(type); + GetImpl()->ExpressionSetPreferredType(_context, _node, _type); + return; +} +KOALA_INTEROP_V3(Checker_ExpressionSetPreferredType, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_Checker_TypeToString(KNativePointer context, KNativePointer type) +{ + auto _context = reinterpret_cast(context); + auto _type = reinterpret_cast(type); + auto result = GetImpl()->TypeToStringConst(_context, _type); + return StageArena::strdup(result); +} +KOALA_INTEROP_2(Checker_TypeToString, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_Checker_TypeClone(KNativePointer context, KNativePointer type) +{ + auto _context = reinterpret_cast(context); + auto _type = reinterpret_cast(type); + return GetImpl()->TypeClone(_context, _type); +} +KOALA_INTEROP_2(Checker_TypeClone, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_Checker_TypeNodeGetType(KNativePointer context, KNativePointer astNode) +{ + auto _context = reinterpret_cast(context); + auto _astNode = reinterpret_cast(astNode); + return GetImpl()->TypeNodeGetType(_context, _astNode); +} +KOALA_INTEROP_2(Checker_TypeNodeGetType, KNativePointer, KNativePointer, KNativePointer) + +// From koala-wrapper +// Improve: check if some code should be generated + +std::set globalStructInfo; +#ifdef _GLIBCXX_HAS_GTHREADS +std::mutex g_structMutex; +#endif + +void impl_InsertGlobalStructInfo(KNativePointer contextPtr, KStringPtr& instancePtr) +{ +#ifdef _GLIBCXX_HAS_GTHREADS + std::lock_guard lock(g_structMutex); +#endif + globalStructInfo.insert(getStringCopy(instancePtr)); + return; +} +KOALA_INTEROP_V2(InsertGlobalStructInfo, KNativePointer, KStringPtr); + +KBoolean impl_HasGlobalStructInfo(KNativePointer contextPtr, KStringPtr& instancePtr) +{ +#ifdef _GLIBCXX_HAS_GTHREADS + std::lock_guard lock(g_structMutex); +#endif + return globalStructInfo.count(getStringCopy(instancePtr)); +} +KOALA_INTEROP_2(HasGlobalStructInfo, KBoolean, KNativePointer, KStringPtr); + +KNativePointer impl_ClassVariableDeclaration(KNativePointer context, KNativePointer classInstance) +{ + const auto _context = reinterpret_cast(context); + const auto _classInstance = reinterpret_cast(classInstance); + auto _typedTsType = GetImpl()->TypedTsType(_context, _classInstance); + if (_typedTsType == nullptr) { + return nullptr; + } + const auto _instanceType = reinterpret_cast(_typedTsType); + auto _typeVar = GetImpl()->TypeVariable(_context, _instanceType); + if (_typeVar == nullptr) { + return nullptr; + } + const auto result = reinterpret_cast(GetImpl()->VariableDeclaration(_context, _typeVar)); + const auto declNode = GetImpl()->DeclNode(_context, result); + return declNode; +} +KOALA_INTEROP_2(ClassVariableDeclaration, KNativePointer, KNativePointer, KNativePointer) + +KNativePointer impl_TSInterfaceBodyBodyPtr(KNativePointer context, KNativePointer receiver) +{ + const auto _context = reinterpret_cast(context); + const auto _receiver = reinterpret_cast(receiver); + std::size_t length; + auto result = GetImpl()->TSInterfaceBodyBodyPtr(_context, _receiver, &length); + return StageArena::cloneVector(result, length); +} +KOALA_INTEROP_2(TSInterfaceBodyBodyPtr, KNativePointer, KNativePointer, KNativePointer); + +KNativePointer impl_AnnotationDeclarationPropertiesPtrConst(KNativePointer context, KNativePointer receiver) +{ + const auto _context = reinterpret_cast(context); + const auto _receiver = reinterpret_cast(receiver); + std::size_t length; + auto result = GetImpl()->AnnotationDeclarationPropertiesPtrConst(_context, _receiver, &length); + return StageArena::cloneVector(result, length); +} +KOALA_INTEROP_2(AnnotationDeclarationPropertiesPtrConst, KNativePointer, KNativePointer, KNativePointer); + +KNativePointer impl_ETSParserGetGlobalProgramAbsName(KNativePointer contextPtr) +{ + auto context = reinterpret_cast(contextPtr); + auto result = GetImpl()->ETSParserGetGlobalProgramAbsName(context); + return new std::string(result); +} +KOALA_INTEROP_1(ETSParserGetGlobalProgramAbsName, KNativePointer, KNativePointer) + +KNativePointer impl_CreateDiagnosticKind(KNativePointer context, KStringPtr& message, KInt type) +{ + const auto _context = reinterpret_cast(context); + const auto _message = getStringCopy(message); + const auto _type = static_cast(type); + return const_cast(GetImpl()->CreateDiagnosticKind(_context, _message, _type)); +} +KOALA_INTEROP_3(CreateDiagnosticKind, KNativePointer, KNativePointer, KStringPtr, KInt) + +KNativePointer impl_CreateDiagnosticInfo( + KNativePointer context, KNativePointer kind, KStringArray argsPtr, KInt argc, KNativePointer pos) +{ + const auto _context = reinterpret_cast(context); + const auto _kind = reinterpret_cast(kind); + const auto _pos = reinterpret_cast(pos); + const std::size_t headerLen = 4; + const char** _args = new const char*[argc]; + std::size_t position = headerLen; + std::size_t strLen; + for (std::size_t i = 0; i < static_cast(argc); ++i) { + strLen = unpackUInt(argsPtr + position); + position += headerLen; + _args[i] = strdup(std::string(reinterpret_cast(argsPtr + position), strLen).c_str()); + position += strLen; + } + return GetImpl()->CreateDiagnosticInfo(_context, _kind, _args, argc, _pos); +} +KOALA_INTEROP_5( + CreateDiagnosticInfo, KNativePointer, KNativePointer, KNativePointer, KStringArray, KInt, KNativePointer) + +KNativePointer impl_CreateSuggestionInfo(KNativePointer context, KNativePointer kind, KStringArray argsPtr, KInt argc, + KStringPtr& substitutionCode, KStringPtr& title, KNativePointer range) +{ + const auto _context = reinterpret_cast(context); + const auto _kind = reinterpret_cast(kind); + const auto _title = getStringCopy(title); + const auto _range = reinterpret_cast(range); + const std::size_t headerLen = 4; + const char** _args = new const char*[argc]; + std::size_t position = headerLen; + std::size_t strLen; + for (std::size_t i = 0; i < static_cast(argc); ++i) { + strLen = unpackUInt(argsPtr + position); + position += headerLen; + _args[i] = strdup(std::string(reinterpret_cast(argsPtr + position), strLen).c_str()); + position += strLen; + } + const auto _substitutionCode = getStringCopy(substitutionCode); + return GetImpl()->CreateSuggestionInfo(_context, _kind, _args, argc, _substitutionCode, _title, _range); +} +KOALA_INTEROP_7(CreateSuggestionInfo, KNativePointer, KNativePointer, KNativePointer, KStringArray, KInt, KStringPtr, + KStringPtr, KNativePointer) + +void impl_LogDiagnostic( + KNativePointer context, KNativePointer kind, KStringArray argvPtr, KInt argc, KNativePointer pos) +{ + auto&& _context_ = reinterpret_cast(context); + auto&& _kind_ = reinterpret_cast(kind); + auto&& _pos_ = reinterpret_cast(pos); + const std::size_t headerLen = 4; + const char** argv = new const char*[argc]; + std::size_t position = headerLen; + std::size_t strLen; + for (std::size_t i = 0; i < static_cast(argc); ++i) { + strLen = unpackUInt(argvPtr + position); + position += headerLen; + argv[i] = strdup(std::string(reinterpret_cast(argvPtr + position), strLen).c_str()); + position += strLen; + } + GetImpl()->LogDiagnostic(_context_, _kind_, argv, argc, _pos_); +} +KOALA_INTEROP_V5(LogDiagnostic, KNativePointer, KNativePointer, KStringArray, KInt, KNativePointer) + +KNativePointer impl_AnnotationUsageIrPropertiesPtrConst(KNativePointer context, KNativePointer receiver) +{ + const auto _context = reinterpret_cast(context); + const auto _receiver = reinterpret_cast(receiver); + std::size_t length; + auto result = GetImpl()->AnnotationUsageIrPropertiesPtrConst(_context, _receiver, &length); + return StageArena::cloneVector(result, length); +} +KOALA_INTEROP_2(AnnotationUsageIrPropertiesPtrConst, KNativePointer, KNativePointer, KNativePointer); + +KInt impl_GenerateTsDeclarationsFromContext(KNativePointer contextPtr, KStringPtr& outputDeclEts, KStringPtr& outputEts, + KBoolean exportAll, KBoolean isolated, KStringPtr& recordFile, KBoolean genAnnotations) +{ + auto context = reinterpret_cast(contextPtr); + return GetImpl()->GenerateTsDeclarationsFromContext( + context, outputDeclEts.data(), outputEts.data(), exportAll, isolated, recordFile.data(), genAnnotations); +} +KOALA_INTEROP_7(GenerateTsDeclarationsFromContext, KInt, KNativePointer, KStringPtr, KStringPtr, KBoolean, KBoolean, + KStringPtr, KBoolean) + +// Improve: simplify +KNativePointer impl_CreateContextGenerateAbcForExternalSourceFiles( + KNativePointer configPtr, KInt fileNamesCount, KStringArray fileNames) +{ + auto config = reinterpret_cast(configPtr); + const std::size_t headerLen = 4; + const char** argv = new const char*[static_cast(fileNamesCount)]; + std::size_t position = headerLen; + std::size_t strLen; + for (std::size_t i = 0; i < static_cast(fileNamesCount); ++i) { + strLen = unpackUInt(fileNames + position); + position += headerLen; + argv[i] = strdup(std::string(reinterpret_cast(fileNames + position), strLen).c_str()); + position += strLen; + } + return GetImpl()->CreateContextGenerateAbcForExternalSourceFiles(config, fileNamesCount, argv); +} +KOALA_INTEROP_3(CreateContextGenerateAbcForExternalSourceFiles, KNativePointer, KNativePointer, KInt, KStringArray) + +KInt impl_GetCompilationMode(KNativePointer configPtr) +{ + auto _config = reinterpret_cast(configPtr); + auto _options = const_cast(GetImpl()->ConfigGetOptions(_config)); + return GetImpl()->OptionsUtilGetCompilationModeConst(nullptr, _options); +} +KOALA_INTEROP_1(GetCompilationMode, KInt, KNativePointer) + +KNativePointer impl_CreateTypeNodeFromTsType(KNativePointer context, KNativePointer nodePtr) +{ + const auto _context = reinterpret_cast(context); + const auto _nodePtr = reinterpret_cast(nodePtr); + auto _tsType = GetImpl()->TypedTsType(_context, _nodePtr); + if (_tsType == nullptr) { + _tsType = GetImpl()->ExpressionTsType(_context, _nodePtr); + } + if (_tsType == nullptr) { + return nullptr; + } + const auto _nodeTsType = reinterpret_cast(_tsType); + auto _typeAnnotation = GetImpl()->CreateOpaqueTypeNode(_context, _nodeTsType); + return _typeAnnotation; +} +KOALA_INTEROP_2(CreateTypeNodeFromTsType, KNativePointer, KNativePointer, KNativePointer) \ No newline at end of file diff --git a/ets1.2/libarkts/native/src/common.cc b/ets1.2/libarkts/native/src/common.cc new file mode 100644 index 0000000000000000000000000000000000000000..116fb46126e3fec770a52f3c3d1db3f244bcebe5 --- /dev/null +++ b/ets1.2/libarkts/native/src/common.cc @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "interop-types.h" + +using std::string, std::cout, std::endl, std::vector; + +es2panda_Impl* es2pandaImplementation = nullptr; +static thread_local StageArena currentArena; + +StageArena* StageArena::instance() +{ + return ¤tArena; +} + +void StageArena::add(void* pointer) +{ + if (pointer) + allocated.push_back(pointer); +} + +void StageArena::cleanup() +{ + if (totalSize > 0 && false) + printf("cleanup %d objects %d bytes\n", (int)allocated.size(), (int)totalSize); + for (auto it : allocated) { + free(it); + } + totalSize = 0; + allocated.clear(); +} + +StageArena::StageArena() +{ + totalSize = 0; +} + +StageArena::~StageArena() +{ + cleanup(); +} + +char* StageArena::strdup(const char* string) +{ + auto* arena = StageArena::instance(); + auto size = strlen(string) + 1; + char* memory = (char*)arena->alloc(size); + interop_memcpy(memory, size, string, size); + return memory; +} + +void* StageArena::alloc(size_t size) +{ + void* result = malloc(size); + if (!result) { + INTEROP_FATAL("Cannot allocate memory"); + } + totalSize += size; + add(result); + return result; +} + +#ifdef KOALA_WINDOWS +#include +#define PLUGIN_DIR "windows_host_tools" +#define LIB_PREFIX "lib" +#define LIB_SUFFIX ".dll" +#endif + +#if defined(KOALA_LINUX) || defined(KOALA_MACOS) +#include + +#ifdef __x86_64__ +#define PLUGIN_DIR "linux_host_tools" +#else +#define PLUGIN_DIR "linux_arm64_host_tools" +#endif + +#define LIB_PREFIX "lib" +#define LIB_SUFFIX ".so" +#endif + +const char* DEFAULT_SDK_PATH = "../../../incremental/tools/panda/node_modules/@panda/sdk"; +const char* NAME = LIB_PREFIX "es2panda-public" LIB_SUFFIX; + +const char* LIB_ES2PANDA_PUBLIC = LIB_PREFIX "es2panda_public" LIB_SUFFIX; +const char* IS_UI_FLAG = "IS_UI_FLAG"; +const char* NOT_UI_FLAG = "NOT_UI_FLAG"; +const string MODULE_SUFFIX = ".d.ets"; +const string ARKUI = "arkui"; + +#ifdef KOALA_WINDOWS +const char* SEPARATOR = "\\"; +#else +const char* SEPARATOR = "/"; +#endif +const char* LIB_DIR = "lib"; + +static std::string ES2PANDA_LIB_PATH = ""; + +std::string joinPath(vector& paths) +{ + std::string res; + for (std::size_t i = 0; i < paths.size(); ++i) { + if (i == 0) { + res = paths[i]; + } else { + res += SEPARATOR + paths[i]; + } + } + return res; +} + +void impl_SetUpSoPath(KStringPtr& soPath) +{ + ES2PANDA_LIB_PATH = std::string(soPath.c_str()); +} +KOALA_INTEROP_V1(SetUpSoPath, KStringPtr); + +// Improve: simplify this +void* FindLibrary() +{ + void* res = nullptr; + std::vector pathArray; + + // find by SetUpSoPath + if (!ES2PANDA_LIB_PATH.empty()) { + pathArray = { ES2PANDA_LIB_PATH, LIB_DIR, LIB_ES2PANDA_PUBLIC }; + res = loadLibrary(joinPath(pathArray)); + if (res) { + return res; + } + } + + // find by set PANDA_SDK_PATH + char* envValue = getenv("PANDA_SDK_PATH"); + if (envValue) { + pathArray = { envValue, PLUGIN_DIR, LIB_DIR, NAME }; + res = loadLibrary(joinPath(pathArray)); + if (res) { + return res; + } + } + + // find by set LD_LIBRARY_PATH + pathArray = { LIB_ES2PANDA_PUBLIC }; + res = loadLibrary(joinPath(pathArray)); + if (res) { + return res; + } + + // find by DEFAULT_SDK_PATH + pathArray = { DEFAULT_SDK_PATH, PLUGIN_DIR, LIB_DIR, NAME }; + res = loadLibrary(joinPath(pathArray)); + if (res) { + return res; + } + + return nullptr; +} + +es2panda_Impl* GetImplSlow() +{ + if (es2pandaImplementation) { + return es2pandaImplementation; + } + auto library = FindLibrary(); + if (!library) { + printf("No library (es2panda_lib.cc)"); + abort(); + } + auto symbol = findSymbol(library, "es2panda_GetImpl"); + if (!symbol) { + printf("no entry point"); + abort(); + } + es2pandaImplementation = reinterpret_cast(symbol)(ES2PANDA_LIB_VERSION); + return es2pandaImplementation; +} + +string getString(KStringPtr ptr) +{ + return ptr.data(); +} + +char* getStringCopy(KStringPtr& ptr) +{ + return StageArena::strdup(ptr.c_str() ? ptr.c_str() : ""); +} + +KNativePointer impl_CreateConfig(KInt argc, KStringArray argvPtr) +{ + const std::size_t headerLen = 4; + + const char** argv = StageArena::allocArray(argc); + std::size_t position = headerLen; + std::size_t strLen; + for (std::size_t i = 0; i < static_cast(argc); ++i) { + strLen = unpackUInt(argvPtr + position); + position += headerLen; + argv[i] = StageArena::strdup(std::string(reinterpret_cast(argvPtr + position), strLen).c_str()); + position += strLen; + } + return GetImpl()->CreateConfig(argc, argv); +} +KOALA_INTEROP_2(CreateConfig, KNativePointer, KInt, KStringArray) + +KNativePointer impl_DestroyConfig(KNativePointer configPtr) +{ + auto config = reinterpret_cast(configPtr); + GetImpl()->DestroyConfig(config); + return nullptr; +} +KOALA_INTEROP_1(DestroyConfig, KNativePointer, KNativePointer) + +void impl_DestroyContext(KNativePointer contextPtr) +{ + auto context = reinterpret_cast(contextPtr); + GetImpl()->DestroyContext(context); + StageArena::instance()->cleanup(); +} +KOALA_INTEROP_V1(DestroyContext, KNativePointer) + +KNativePointer impl_UpdateCallExpression(KNativePointer contextPtr, KNativePointer nodePtr, KNativePointer calleePtr, + KNativePointerArray argumentsPtr, KInt argumentsLen, KNativePointer typeParamsPtr, KBoolean optionalT, + KBoolean trailingCommaT) +{ + auto node = reinterpret_cast(nodePtr); + auto context = reinterpret_cast(contextPtr); + auto callee = reinterpret_cast(calleePtr); + auto arguments = reinterpret_cast(argumentsPtr); + auto typeParams = reinterpret_cast(typeParamsPtr); + auto optional = static_cast(optionalT); + auto trailingComma = static_cast(trailingCommaT); + + auto nn = + GetImpl()->CreateCallExpression(context, callee, arguments, argumentsLen, typeParams, optional, trailingComma); + GetImpl()->AstNodeSetOriginalNode(context, nn, node); + return nn; +} +KOALA_INTEROP_8(UpdateCallExpression, KNativePointer, KNativePointer, KNativePointer, KNativePointer, + KNativePointerArray, KInt, KNativePointer, KBoolean, KBoolean) + +KInt impl_IdentifierIdentifierFlags(KNativePointer contextPtr, KNativePointer nodePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto node = reinterpret_cast(nodePtr); + + return (GetImpl()->IdentifierIsOptionalConst(context, node) ? (1 << 0) : 0) | + (GetImpl()->IdentifierIsReferenceConst(context, node) ? (1 << 1) : 0) | + (GetImpl()->IdentifierIsTdzConst(context, node) ? (1 << 2) : 0); +} +KOALA_INTEROP_2(IdentifierIdentifierFlags, KInt, KNativePointer, KNativePointer) + +void impl_ClassDefinitionSetBody( + KNativePointer context, KNativePointer receiver, KNativePointerArray body, KUInt bodyLength) +{ + const auto _context = reinterpret_cast(context); + const auto _receiver = reinterpret_cast(receiver); + const auto _body = reinterpret_cast(body); + const auto _bodyLength = static_cast(bodyLength); + GetImpl()->ClassDefinitionClearBody(_context, _receiver); + for (size_t i = 0; i < _bodyLength; i++) { + GetImpl()->ClassDefinitionEmplaceBody(_context, _receiver, _body[i]); + } +} +KOALA_INTEROP_V4(ClassDefinitionSetBody, KNativePointer, KNativePointer, KNativePointerArray, KUInt) + +/* +Improve: NOT FROM API (shouldn't be there) +----------------------------------------------------------------------------------------------------------------------------- +*/ + +es2panda_AstNode* cachedParentNode; +es2panda_Context* cachedContext; + +static void changeParent(es2panda_AstNode* child) +{ + GetImpl()->AstNodeSetParent(cachedContext, child, cachedParentNode); +} + +static void SetRightParent(es2panda_AstNode* node, void* arg) +{ + es2panda_Context* ctx = static_cast(arg); + cachedContext = ctx; + cachedParentNode = node; + + GetImpl()->AstNodeIterateConst(ctx, node, changeParent); +} + +KNativePointer impl_AstNodeUpdateAll(KNativePointer contextPtr, KNativePointer programPtr) +{ + auto context = reinterpret_cast(contextPtr); + auto program = reinterpret_cast(programPtr); + + GetImpl()->AstNodeForEach(program, SetRightParent, context); + return program; +} +KOALA_INTEROP_2(AstNodeUpdateAll, KNativePointer, KNativePointer, KNativePointer) + +void impl_AstNodeSetChildrenParentPtr(KNativePointer contextPtr, KNativePointer nodePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto node = reinterpret_cast(nodePtr); + cachedParentNode = node; + + GetImpl()->AstNodeIterateConst(context, node, changeParent); +} +KOALA_INTEROP_V2(AstNodeSetChildrenParentPtr, KNativePointer, KNativePointer) + +void impl_AstNodeOnUpdate(KNativePointer context, KNativePointer newNode, KNativePointer replacedNode) +{ + auto _context = reinterpret_cast(context); + auto _newNode = reinterpret_cast(newNode); + auto _replacedNode = reinterpret_cast(replacedNode); + + // Assign original + auto _original = GetImpl()->AstNodeOriginalNodeConst(_context, _replacedNode); + if (!_original) { + _original = _replacedNode; + } + GetImpl()->AstNodeSetOriginalNode(_context, _newNode, _original); + + // Assign new node parent + auto _parent = GetImpl()->AstNodeParent(_context, _replacedNode); + if (_parent) { + GetImpl()->AstNodeSetParent(_context, _newNode, _parent); + } + + // Redirect children parent pointer to this node + impl_AstNodeSetChildrenParentPtr(context, newNode); +} +KOALA_INTEROP_V3(AstNodeOnUpdate, KNativePointer, KNativePointer, KNativePointer) + +static thread_local std::vector cachedChildren; + +static void visitChild(es2panda_AstNode* node) +{ + cachedChildren.emplace_back(node); +} + +KNativePointer impl_AstNodeChildren(KNativePointer contextPtr, KNativePointer nodePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto node = reinterpret_cast(nodePtr); + cachedContext = context; + cachedChildren.clear(); + + GetImpl()->AstNodeIterateConst(context, node, visitChild); + return StageArena::clone(cachedChildren); +} +KOALA_INTEROP_2(AstNodeChildren, KNativePointer, KNativePointer, KNativePointer); + +struct Pattern { + es2panda_Context* context; + std::string key; + std::string value; + es2panda_Impl* impl; + + Pattern(es2panda_Context* context, const std::string& part) : context(context), impl(GetImpl()) + { + std::istringstream stream(part); + std::getline(stream, key, '='); + std::getline(stream, value, '='); + } + bool match(es2panda_AstNode* node) + { + if (key == "type") { + auto type = impl->AstNodeTypeConst(context, node); + switch (type) { + case Es2pandaAstNodeType::AST_NODE_TYPE_METHOD_DEFINITION: + case Es2pandaAstNodeType::AST_NODE_TYPE_SCRIPT_FUNCTION: + + return value == "method"; + case Es2pandaAstNodeType::AST_NODE_TYPE_STRUCT_DECLARATION: + return value == "struct"; + default: + return false; + } + } + if (key == "annotation") { + std::size_t length = 0; + Es2pandaAstNodeType type = impl->AstNodeTypeConst(context, node); + es2panda_AstNode** result = nullptr; + switch (type) { + case Es2pandaAstNodeType::AST_NODE_TYPE_METHOD_DEFINITION: { + auto function = impl->MethodDefinitionFunction(context, node); + result = impl->FunctionDeclarationAnnotations(context, function, &length); + break; + } + case Es2pandaAstNodeType::AST_NODE_TYPE_FUNCTION_DECLARATION: + result = impl->FunctionDeclarationAnnotations(context, node, &length); + break; + case AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION: { + auto function = impl->ArrowFunctionExpressionFunction(context, node); + result = impl->FunctionDeclarationAnnotations(context, function, &length); + break; + } + case Es2pandaAstNodeType::AST_NODE_TYPE_CLASS_PROPERTY: + result = impl->ClassPropertyAnnotations(context, node, &length); + break; + default: + return false; + } + bool found = false; + for (std::size_t i = 0; i < length && result; i++) { + es2panda_AstNode* ident = impl->AnnotationUsageIrGetBaseNameConst(context, result[i]); + const char* name = impl->IdentifierNameConst(context, ident); + found |= matchWildcard(value, name); + } + return found; + } + return false; + } + + bool matchWildcard(const std::string& pattern, const char* valueArg) + { + if (pattern.find('*') == std::string::npos) { + return pattern == valueArg; + } + regex_t regex; + regmatch_t match[1]; + regcomp(®ex, pattern.c_str(), REG_NEWLINE); + return regexec(®ex, valueArg, 1, match, 0) != REG_NOMATCH; + } +}; + +struct Matcher { + es2panda_Context* context; + const char* query; + std::vector patterns; + es2panda_Impl* impl; + Matcher(es2panda_Context* context, const char* query) : context(context), query(query), impl(GetImpl()) + { + std::istringstream stream(query); + std::string item; + while (std::getline(stream, item, ';')) { + patterns.emplace_back(Pattern(context, item)); + } + } + bool match(es2panda_AstNode* node) + { + bool result = true; + for (auto pattern : patterns) { + result &= pattern.match(node); + } + return result; + } +}; + +KNativePointer impl_FilterNodes(KNativePointer context, KNativePointer node, const KStringPtr& filters) +{ + auto _node = reinterpret_cast(node); + auto _context = reinterpret_cast(context); + const char* _filters = filters.c_str(); + std::vector result; + es2panda_Impl* impl = GetImpl(); + Matcher matcher(_context, _filters); + std::vector queue; + queue.push_back(_node); + while (queue.size() > 0) { + auto* current = queue.back(); + queue.pop_back(); + if (matcher.match(current)) { + result.push_back(current); + } else { + impl->AstNodeIterateConst(_context, current, visitChild); + // We want to retain match order, so add children in reverse order. + for (auto it = cachedChildren.rbegin(); it != cachedChildren.rend(); ++it) { + queue.push_back(*it); + } + cachedChildren.clear(); + } + } + return StageArena::cloneVector(result.data(), result.size()); +} +KOALA_INTEROP_3(FilterNodes, KNativePointer, KNativePointer, KNativePointer, KStringPtr) + +/* +----------------------------------------------------------------------------------------------------------------------------- +*/ + +// From koala-wrapper +// Improve: check if some code should be generated + +void impl_MemInitialize() +{ + GetImpl()->MemInitialize(); +} +KOALA_INTEROP_V0(MemInitialize) + +void impl_MemFinalize() +{ + GetImpl()->MemFinalize(); +} +KOALA_INTEROP_V0(MemFinalize) + +static bool isUIHeaderFile(es2panda_Context* context, es2panda_Program* program) +{ + auto result = GetImpl()->ProgramFileNameWithExtensionConst(context, program); + string fileNameWithExtension(result); + result = GetImpl()->ProgramModuleNameConst(context, program); + string moduleName(result); + + return fileNameWithExtension.length() >= MODULE_SUFFIX.length() && + fileNameWithExtension.substr(fileNameWithExtension.length() - MODULE_SUFFIX.length()) == MODULE_SUFFIX && + moduleName.find(ARKUI) != std::string::npos; +} + +KBoolean impl_ProgramCanSkipPhases(KNativePointer context, KNativePointer program) +{ + KStringPtr isUiFlag(IS_UI_FLAG); + KStringPtr notUiFlag(NOT_UI_FLAG); + const auto _context = reinterpret_cast(context); + const auto _program = reinterpret_cast(program); + if (isUIHeaderFile(_context, _program)) { + return false; + } + std::size_t sourceLen; + const auto externalSources = + reinterpret_cast(GetImpl()->ProgramExternalSources(_context, _program, &sourceLen)); + for (std::size_t i = 0; i < sourceLen; ++i) { + std::size_t programLen; + auto programs = GetImpl()->ExternalSourcePrograms(externalSources[i], &programLen); + for (std::size_t j = 0; j < programLen; ++j) { + if (isUIHeaderFile(_context, programs[j])) { + return false; + } + } + } + return true; +} +KOALA_INTEROP_2(ProgramCanSkipPhases, KBoolean, KNativePointer, KNativePointer) + +KNativePointer impl_AstNodeProgram(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto _context = reinterpret_cast(contextPtr); + auto _receiver = reinterpret_cast(instancePtr); + + if (GetImpl()->AstNodeIsProgramConst(_context, _receiver)) { + return GetImpl()->ETSModuleProgram(_context, _receiver); + } + return impl_AstNodeProgram(_context, GetImpl()->AstNodeParent(_context, _receiver)); +} +KOALA_INTEROP_2(AstNodeProgram, KNativePointer, KNativePointer, KNativePointer) diff --git a/ets1.2/libarkts/native/src/common.h b/ets1.2/libarkts/native/src/common.h new file mode 100644 index 0000000000000000000000000000000000000000..f2eeeb0e786a117b34eecc2da6e72c96bc98ad90 --- /dev/null +++ b/ets1.2/libarkts/native/src/common.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025 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. + */ + +#ifndef COMMON_H +#define COMMON_H + +/* + * Copyright (c) 2022-2023 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. + */ + +#include +#include +#include + +#include "common-interop.h" +#include "dynamic-loader.h" +#include "es2panda_lib.h" +#include "interop-utils.h" +#include "stdexcept" + +using std::string, std::cout, std::endl, std::vector; + +extern es2panda_Impl* es2pandaImplementation; + +es2panda_Impl* GetImplSlow(); +inline es2panda_Impl* GetImpl() +{ + if (es2pandaImplementation) { + return es2pandaImplementation; + } + return GetImplSlow(); +} + +string getString(KStringPtr ptr); + +char* getStringCopy(KStringPtr& ptr); + +inline KUInt unpackUInt(const KByte* bytes) +{ + const KUInt BYTE_0 = 0; + const KUInt BYTE_1 = 1; + const KUInt BYTE_2 = 2; + const KUInt BYTE_3 = 3; + + const KUInt BYTE_1_SHIFT = 8; + const KUInt BYTE_2_SHIFT = 16; + const KUInt BYTE_3_SHIFT = 24; + return (bytes[BYTE_0] | (bytes[BYTE_1] << BYTE_1_SHIFT) | (bytes[BYTE_2] << BYTE_2_SHIFT) | + (bytes[BYTE_3] << BYTE_3_SHIFT)); +} + +es2panda_ContextState intToState(KInt state); + +class StageArena { + std::vector allocated; + size_t totalSize; + +public: + StageArena(); + ~StageArena(); + static StageArena* instance(); + template + static T* alloc() + { + auto* arena = StageArena::instance(); + void* memory = arena->alloc(sizeof(T)); + return new (memory) T(); + } + template + static T* alloc(T1 arg1) + { + auto* arena = StageArena::instance(); + void* memory = arena->alloc(sizeof(T)); + return new (memory) T(std::forward(arg1)); + } + template + static T* alloc(T1 arg1, T2 arg2) + { + auto* arena = StageArena::instance(); + void* memory = arena->alloc(sizeof(T)); + return new (memory) T(arg1, arg2); + } + template + static T* allocArray(size_t count) + { + auto* arena = StageArena::instance(); + // align? + void* memory = arena->alloc(sizeof(T) * count); + return new (memory) T(); + } + template + static T* clone(const T& arg) + { + auto* arena = StageArena::instance(); + void* memory = arena->alloc(sizeof(T)); + return new (memory) T(arg); + } + template + static std::vector* cloneVector(const T* arg, size_t count) + { + return alloc, const T*, const T*>(arg, arg + count); + } + void* alloc(size_t size); + static char* strdup(const char* original); + void add(void* pointer); + void cleanup(); +}; + +#endif // COMMON_H \ No newline at end of file diff --git a/ets1.2/libarkts/native/src/memoryTracker.cc b/ets1.2/libarkts/native/src/memoryTracker.cc new file mode 100644 index 0000000000000000000000000000000000000000..024a056c664ae7dee00227b8ff6815ced07b4d31 --- /dev/null +++ b/ets1.2/libarkts/native/src/memoryTracker.cc @@ -0,0 +1,171 @@ +/** + * Copyright (c) 2025 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. + */ + +#include "memoryTracker.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#elif defined(__APPLE__) +#include +#include +#elif defined(__linux__) +#include +#include +#endif + +constexpr const char* UNIT_K = "kB"; +constexpr size_t BYTES_PER_KB = 1024; +constexpr const char* MEMORY_STATUS_FILE = "/proc/self/status"; +const std::regex VM_RSS_REGEX( + R"#(VmRSS:\s*(\d+)\s*([kKmMgG]?B))#", std::regex_constants::ECMAScript | std::regex_constants::icase); +const std::regex VM_SIZE_REGEX( + R"#(VmSize:\s*(\d+)\s*([kKmMgG]?B))#", std::regex_constants::ECMAScript | std::regex_constants::icase); + +constexpr int MATCH_GROUP_VALUE = 1; +constexpr int MATCH_GROUP_UNIT = 2; +constexpr int MATCH_GROUP_SIZE = 3; + +#if defined(_WIN32) +MemoryStats GetMemoryStats() +{ + MemoryStats stats = { 0, 0, 0, 0, 0 }; + PROCESS_MEMORY_COUNTERS_EX pmc; + if (GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast(&pmc), sizeof(pmc))) { + stats.currentRss = pmc.WorkingSetSize; + stats.peakRss = pmc.PeakWorkingSetSize; + stats.currentVss = pmc.PrivateUsage; // 私有内存使用量 + stats.pageFaultsMinor = pmc.PageFaultCount; + // Windows API不直接提供主缺页错误计数 + stats.pageFaultsMajor = 0; + } + return stats; +} + +#elif defined(__APPLE__) +MemoryStats GetMemoryStats() +{ + MemoryStats stats = { 0, 0, 0, 0, 0 }; + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) == 0) { + stats.currentRss = 0; // macOS需要专用API获取当前内存 + stats.peakRss = ru.ru_maxrss; // macOS返回字节 + stats.pageFaultsMinor = ru.ru_minflt; + stats.pageFaultsMajor = ru.ru_majflt; + + // 获取当前内存使用 (macOS专用API) + task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; + if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t)&info, &count) == KERN_SUCCESS) { + stats.currentRss = info.resident_size; // 物理内存使用量 + stats.currentVss = info.virtual_size; // 虚拟内存总量 + } + } + return stats; +} + +#elif defined(__linux__) +MemoryStats GetMemoryStats() +{ + MemoryStats stats = { 0, 0, 0, 0, 0 }; + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) == 0) { + stats.peakRss = static_cast(ru.ru_maxrss) * BYTES_PER_KB; // KB -> 字节 + stats.pageFaultsMinor = ru.ru_minflt; + stats.pageFaultsMajor = ru.ru_majflt; + } + std::ifstream statusFile(MEMORY_STATUS_FILE); + if (!statusFile) { + return stats; + } + std::string line; + std::smatch matches; + while (std::getline(statusFile, line)) { + if (std::regex_match(line, matches, VM_RSS_REGEX) && matches.size() >= MATCH_GROUP_SIZE) { + stats.currentRss = std::stoull(matches[MATCH_GROUP_VALUE].str()); + std::string unit = matches[MATCH_GROUP_UNIT].str(); + if (unit == UNIT_K) { + stats.currentRss *= BYTES_PER_KB; + } + } else if (std::regex_match(line, matches, VM_SIZE_REGEX) && matches.size() >= MATCH_GROUP_SIZE) { + stats.currentVss = std::stoull(matches[MATCH_GROUP_VALUE].str()); + std::string unit = matches[MATCH_GROUP_UNIT].str(); + if (unit == UNIT_K) { + stats.currentVss *= BYTES_PER_KB; + } + } + } + return stats; +} +#endif + +void MemoryTracker::Reset() +{ + baseline = GetMemoryStats(); +} + +MemoryStats MemoryTracker::GetDelta() +{ + MemoryStats current = GetMemoryStats(); + MemoryStats delta = { current.currentRss - baseline.currentRss, current.peakRss - baseline.peakRss, + current.currentVss - baseline.currentVss, current.pageFaultsMinor - baseline.pageFaultsMinor, + current.pageFaultsMajor - baseline.pageFaultsMajor }; + return delta; +} + +template +MemoryStats MemoryTracker::MeasureMemory(Func&& func) +{ + Reset(); + auto preStats = GetMemoryStats(); + func(); + auto postStats = GetMemoryStats(); + + return { postStats.currentRss - preStats.currentRss, postStats.peakRss - preStats.peakRss, + postStats.currentVss - preStats.currentVss, postStats.pageFaultsMinor - preStats.pageFaultsMinor, + postStats.pageFaultsMajor - preStats.pageFaultsMajor }; +} + +void MemoryTracker::Report(MemoryStats stats) +{ + auto formatBytes = [](size_t bytes) -> std::string { + const double kb = BYTES_PER_KB; + const double mb = kb * BYTES_PER_KB; + const double gb = mb * BYTES_PER_KB; + + if (bytes > gb) + return std::to_string(bytes / gb) + " GB"; + if (bytes > mb) + return std::to_string(bytes / mb) + " MB"; + if (bytes > kb) + return std::to_string(bytes / kb) + " KB"; + return std::to_string(bytes) + " B"; + }; + + std::cout << "Current RSS: " << formatBytes(stats.currentRss) << "\n"; + std::cout << "Peak RSS : " << formatBytes(stats.peakRss) << "\n"; + std::cout << "VSS : " << formatBytes(stats.currentVss) << "\n"; + std::cout << "FaultsMinor: " << stats.pageFaultsMinor << "\n"; + std::cout << "FaultsMajor: " << stats.pageFaultsMajor << "\n"; + return; +} \ No newline at end of file diff --git a/ets1.2/libarkts/native/src/memoryTracker.h b/ets1.2/libarkts/native/src/memoryTracker.h new file mode 100644 index 0000000000000000000000000000000000000000..3747160f586addccb4b4fb543d609fae75e35493 --- /dev/null +++ b/ets1.2/libarkts/native/src/memoryTracker.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2025 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. + */ + +#ifndef KOALA_MEMORY_TRACKER +#define KOALA_MEMORY_TRACKER + +#include +#include + +// 内存统计结构体 +struct MemoryStats { + size_t currentRss = 0; // 当前驻留集大小 (字节) + size_t peakRss = 0; // 峰值驻留集大小 (字节) + size_t currentVss = 0; // 当前虚拟内存大小 (字节) + size_t pageFaultsMinor = 0; // 小页错误次数 + size_t pageFaultsMajor = 0; // 大页错误次数 +}; + +class MemoryTracker { +public: + MemoryTracker() + { + Reset(); + } + + void Reset(); + MemoryStats GetDelta(); + + template + MemoryStats MeasureMemory(Func&& func); + + void Report(MemoryStats stats); + +private: + MemoryStats baseline; +}; + +MemoryStats GetMemoryStats(); + +#endif diff --git a/ets1.2/libarkts/package.json b/ets1.2/libarkts/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f391b800caa97f81a0445105bd26ae396c75eb99 --- /dev/null +++ b/ets1.2/libarkts/package.json @@ -0,0 +1,86 @@ +{ + "name": "@koalaui/libarkts", + "version": "1.7.10+devel", + "bin": "./lib/es2panda", + "typesVersions": { + "*": { + "./compat/*": [ + "./lib/types/wrapper-compat/index.d.ts" + ], + "*": [ + "./lib/types/src/index.d.ts" + ] + } + }, + "exports": { + ".": "./lib/libarkts.js", + "./compat": "./lib/libarkts-compat.js", + "./plugins/*": "./lib/plugins/*.js" + }, + "files": [ + "./lib/**/*", + "./build/**/*", + "./plugins/build/src/**/*" + ], + "config": { + "panda_sdk_path": "../../incremental/tools/panda/node_modules/@panda/sdk", + "panda_sdk_version": "next" + }, + "dependencies": { + "@koalaui/ets-tsc": "4.9.5-r6", + "@koalaui/build-common": "1.7.10+devel", + "@koalaui/compat": "1.7.10+devel", + "@koalaui/common": "1.7.10+devel", + "@koalaui/harness": "1.7.10+devel", + "@koalaui/interop": "1.7.10+devel", + "@koalaui/fast-arktsc": "1.7.10+devel", + "@idlizer/arktscgen": "2.1.10-arktscgen-4", + "mocha": "^9.2.2", + "node-addon-api": "8.0.0", + "node-api-headers": "0.0.5", + "commander": "10.0.1" + }, + "devDependencies": { + "rollup": "^4.13.0", + "@rollup/plugin-commonjs": "^26.0.1", + "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "rimraf": "^6.0.1" + }, + "scripts": { + "clean": "rimraf generated build native/build* ./.rollup.cache tsconfig.tsbuildinfo lib", + "clean:plugins": "rimraf plugins/build", + "compile:koala:interop": "npm run --prefix ../../interop compile", + "compile:meson": "cd native && meson setup build && meson compile -C build", + "compile:meson:mingw": "cd native && meson setup --cross-file ./mingw.cross mingw_build && meson compile -C mingw_build", + "crosscompile:meson": "cd native && CXX=clang++ meson setup -D cross_compile=true build && CXX=clang++ meson compile -C build", + "copy:.node": "mkdir -p ./build/native/build && cp ./native/build/es2panda_*.node ./build/native/build", + "compile:native": "npm run compile:koala:interop && npm run compile:meson && npm run copy:.node", + "crosscompile:native": "npm run compile:koala:interop && npm run crosscompile:meson && npm run copy:.node", + "compile": "npm run regenerate && npm run compile:native && npm run compile:js", + "compile:release": "npm run crosscompile:native && npm run compile:js", + "compile:js": "rm -rf lib/ && rollup -c rollup.lib.mjs && rollup -c rollup.es2panda.mjs", + "compile:plugins": "rollup -c ./rollup.printer-plugin.mjs", + "direct": "fast-arktsc --config arktsconfig.json --compiler ../../incremental/tools/panda/arkts/ui2abc --link-name ./build/abc/main.abc && ninja -f build/abc/build.ninja", + "simultaneous": "mkdir -p build/abc && bash ../../incremental/tools/panda/arkts/ui2abc --simultaneous --arktsconfig arktsconfig.json --output ./build/abc/main.abc:./build/abc/library.abc plugins/input/main.ets:plugins/input/library.ets", + "run": "npm run compile && npm run compile:plugins && npm run simultaneous", + "run:memo": "npm run compile && npm run compile:plugins && npm run compile --prefix ../memo-plugin-ng && npm run memo", + "run:abc": "$npm_package_config_panda_sdk_path/linux_host_tools/bin/ark --load-runtimes=ets --boot-panda-files=$npm_package_config_panda_sdk_path/ets/etsstdlib.abc ./main.abc main.ETSGLOBAL::main", + "mocha": "PANDA_SDK_PATH=${PANDA_SDK_PATH:=$npm_package_config_panda_sdk_path} TS_NODE_PROJECT=./test/tsconfig.json mocha -r tsconfig-paths/register --reporter-option maxDiffSize=0", + "test:light": "npm run mocha", + "test": "npm run compile:native && npm run test:light", + "test:golden": "npm run compile:native && TEST_GOLDEN=1 npm run test:light", + "compile:playground": "cd playground && meson setup build && meson compile -C build", + "run:playground": "npm run compile:playground && mkdir -p build && ./playground/build/playground _ --extension ets --stdlib ../../incremental/tools/panda/node_modules/@panda/sdk/ets/stdlib --output build/playground.abc ./playground/src/main.ets", + "panda:sdk:clean": "cd ../../incremental/tools/panda && rimraf node_modules", + "panda:sdk:install": "cd ../../incremental/tools/panda && echo \"Installing panda sdk $npm_package_config_panda_sdk_version\" && PANDA_SDK_VERSION=$npm_package_config_panda_sdk_version npm run panda:sdk:install", + "panda:sdk:reinstall": "npm run panda:sdk:clean && npm run panda:sdk:install", + "regenerate:current": "rimraf -rf ./generated && npm run compile -C ../../../arktscgen && node ../../../arktscgen --panda-sdk-path $npm_package_config_panda_sdk_path --output-dir ../ --options-file ./generator/options.json5 --no-initialize --debug", + "regenerate": "rimraf -rf ./generated && arktscgen --panda-sdk-path ${PANDA_SDK_PATH:=$npm_package_config_panda_sdk_path} --output-dir ../ --options-file ./generator/options.json5 --no-initialize", + "reinstall:regenerate": "npm run panda:sdk:reinstall && npm run regenerate && git diff --shortstat", + "format:src:ts": "npx prettier --config .prettierrc --write \"./src/**/*.ts\"", + "format:generated:ts": "npx prettier --config .prettierrc --write \"./generated/**/*.ts\"", + "format:ts": "npm run format:src:ts && npm run format:generated:ts" + } +} diff --git a/ets1.2/libarkts/playground/src/playground.cc b/ets1.2/libarkts/playground/src/playground.cc new file mode 100644 index 0000000000000000000000000000000000000000..d142c008133ad14d5d18105bb23e57d70086ae5e --- /dev/null +++ b/ets1.2/libarkts/playground/src/playground.cc @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2025 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. + */ + +#include +#include +#include + +#include "public/es2panda_lib.h" +#include "util.h" + +// NOLINTBEGIN +static std::string prefix = "returns_"; + +static std::string source = R"( +class C { +} + +interface I { + x: int +} + +class Test { + static returns_void() { + } + + static returns_int() { + return 1 + } + + static returns_arrow() { + return () => {} + } + + static returns_C() { + return new C() + } + + static returns_I() { + return { x: 1 } as I + } + + static returns_union(cond: boolean) { + if (cond) { + return 1 + } else { + return "hello" + } + } +} +)"; + +static es2panda_Impl* impl = nullptr; +static es2panda_Config* config = nullptr; +static es2panda_Context* context = nullptr; + +static int countFound = 0; +static int countApplied = 0; + +void setScriptFunctionReturnType(es2panda_AstNode* node, [[maybe_unused]] void* arg) +{ + if (impl->IsScriptFunction(node)) { + es2panda_AstNode* id = impl->ScriptFunctionId(context, node); + if (!id) { + return; + } + if (std::string(impl->IdentifierNameConst(context, id)).substr(0, prefix.length()) != prefix) { + return; + } + countFound++; + es2panda_Signature* signature = impl->ScriptFunctionSignature(context, node); + if (!signature) { + return; + } + es2panda_Type* returnType = impl->SignatureReturnType(context, signature); + if (!returnType) { + return; + } + es2panda_AstNode* returnTypeAnnotation = impl->CreateOpaqueTypeNode(context, returnType); + if (!returnTypeAnnotation) { + return; + } + impl->ScriptFunctionSetReturnTypeAnnotation(context, node, returnTypeAnnotation); + countApplied++; + } +} + +int main(int argc, char** argv) +{ + if (argc < MIN_ARGC) { + return INVALID_ARGC_ERROR_CODE; + } + + if (GetImpl() == nullptr) { + return NULLPTR_IMPL_ERROR_CODE; + } + impl = GetImpl(); + + const char** args = const_cast(&(argv[1])); + config = impl->CreateConfig(argc - 1, args); + context = impl->CreateContextFromString(config, source.data(), argv[argc - 1]); + if (context == nullptr) { + return NULLPTR_CONTEXT_ERROR_CODE; + } + + impl->ProceedToState(context, ES2PANDA_STATE_CHECKED); + CheckForErrors("CHECKED", context); + if (impl->ContextState(context) == ES2PANDA_STATE_ERROR) { + return PROCEED_ERROR_CODE; + } + + auto* program = impl->ContextProgram(context); + es2panda_AstNode* ast = impl->ProgramAst(context, program); + + impl->AstNodeForEach(ast, setScriptFunctionReturnType, nullptr); + if (countFound == 0) { + return TEST_ERROR_CODE; + } + if (countFound != countApplied) { + return TEST_ERROR_CODE; + } + + impl->AstNodeRecheck(context, ast); + CheckForErrors("RECHECKED", context); + if (impl->ContextState(context) == ES2PANDA_STATE_ERROR) { + return PROCEED_ERROR_CODE; + } + + impl->ProceedToState(context, ES2PANDA_STATE_BIN_GENERATED); + CheckForErrors("BIN", context); + if (impl->ContextState(context) == ES2PANDA_STATE_ERROR) { + return PROCEED_ERROR_CODE; + } + + impl->DestroyContext(context); + impl->DestroyConfig(config); + + return 0; +} + +// NOLINTEND \ No newline at end of file diff --git a/ets1.2/libarkts/playground/src/util.h b/ets1.2/libarkts/playground/src/util.h new file mode 100644 index 0000000000000000000000000000000000000000..26f331cdc1d34347d7a6bcbe444ea16ff8e68bf7 --- /dev/null +++ b/ets1.2/libarkts/playground/src/util.h @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2025 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. + */ + +#ifndef ES2PANDA_TEST_UNIT_PLUGIN_UTIL_H +#define ES2PANDA_TEST_UNIT_PLUGIN_UTIL_H + +#include +#include +#include +#include +#include + +#include "dynamic-loader.h" +#include "public/es2panda_lib.h" + +constexpr int MIN_ARGC = 3; + +// error code number +constexpr int NULLPTR_IMPL_ERROR_CODE = 2; +constexpr int PROCEED_ERROR_CODE = 3; +constexpr int TEST_ERROR_CODE = 4; +constexpr int INVALID_ARGC_ERROR_CODE = 5; +constexpr int NULLPTR_CONTEXT_ERROR_CODE = 6; + +extern es2panda_Impl* g_implPtr; + +es2panda_Impl* GetImplSlow(); +inline es2panda_Impl* GetImpl() +{ + if (g_implPtr) { + return g_implPtr; + } + return GetImplSlow(); +} + +struct ProccedToStatePluginTestData { + int argc; + char** argv; + es2panda_Impl** impl; + std::map>> testFunctions; + bool fromSource; + std::string source; + es2panda_ContextState exitAfterState = ES2PANDA_STATE_ERROR; +}; + +void CheckForErrors(const std::string& stateName, es2panda_Context* context); +bool IsAssertCall(es2panda_AstNode* ast); +es2panda_AstNode* CreateAssertStatement(es2panda_Context* context, es2panda_AstNode* test, es2panda_AstNode* second); +es2panda_AstNode* AssertStatementTest(es2panda_Context* context, es2panda_AstNode* classInstance); +int RunAllStagesWithTestFunction(ProccedToStatePluginTestData& data); + +es2panda_AstNode* CreateIdentifierFromString(es2panda_Context* context, const std::string_view& name); + +void AppendStatementToProgram(es2panda_Context* context, es2panda_AstNode* program, es2panda_AstNode* newStatement); + +void PrependStatementToProgram(es2panda_Context* context, es2panda_AstNode* program, es2panda_AstNode* newStatement); + +int Test(es2panda_Context* context, es2panda_Impl* impl, int stage, + const std::function& handle); + +#endif diff --git a/ets1.2/libarkts/plugins/input/direct.ets b/ets1.2/libarkts/plugins/input/direct.ets new file mode 100644 index 0000000000000000000000000000000000000000..b51286dbbd777886f910d1274831c1f0aba8774d --- /dev/null +++ b/ets1.2/libarkts/plugins/input/direct.ets @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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. + */ + +import { __memo_context_type, __memo_id_type } from "@koalaui/runtime" + +@Retention({policy: "SOURCE"}) +@interface memo { } + +class A { + +} + +class Memo { + @memo static memo_method(): int { + return 1 + } + + @memo static memo_call(): int { + @memo const f = (): int => { + return 2 + } + return f() + } +} diff --git a/ets1.2/libarkts/plugins/input/export.ets b/ets1.2/libarkts/plugins/input/export.ets new file mode 100644 index 0000000000000000000000000000000000000000..77e954c91731fbabddeac5c3c122e9799c8752ef --- /dev/null +++ b/ets1.2/libarkts/plugins/input/export.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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. + */ + +export function foo() { + console.log("Hello, world!") +} + +export const TEST: double = 2.718281828459045; diff --git a/ets1.2/libarkts/plugins/input/f.ets b/ets1.2/libarkts/plugins/input/f.ets new file mode 100644 index 0000000000000000000000000000000000000000..6904403bc5aa43fb340076f9de3c18d885ec081b --- /dev/null +++ b/ets1.2/libarkts/plugins/input/f.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 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. + */ + +export function f() { + console.log("Hello, world!") +} diff --git a/ets1.2/libarkts/plugins/input/library.ets b/ets1.2/libarkts/plugins/input/library.ets new file mode 100644 index 0000000000000000000000000000000000000000..6a90478cce3064de4ad1521dde0bedfeb7da1083 --- /dev/null +++ b/ets1.2/libarkts/plugins/input/library.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 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. + */ + +export function testFunction(): string { + return "yes" +} +export function anotherFunction(): string { + return "no" +} + diff --git a/ets1.2/libarkts/plugins/input/main.ets b/ets1.2/libarkts/plugins/input/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..4846a65a957ef52a657ca7c743d4b86341481788 --- /dev/null +++ b/ets1.2/libarkts/plugins/input/main.ets @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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. + */ + +enum X { + A = 17 +} + +namespace Y { + function foo() { + } +} + +function foo(value: int): void { + switch (X.fromValue(value)) { + case X.A: + console.log("A") + break + default: + console.log("default") + + } +} + diff --git a/ets1.2/libarkts/plugins/input/no-import-no-struct.ets b/ets1.2/libarkts/plugins/input/no-import-no-struct.ets new file mode 100644 index 0000000000000000000000000000000000000000..c1e39867ade1d3df4af5aada138eef6acb3d317c --- /dev/null +++ b/ets1.2/libarkts/plugins/input/no-import-no-struct.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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. + */ + +@interface Component{} + +@interface BuilderLambda { + value: string +} + +@Component +class MyComponent { + @BuilderLambda("instantiateImpl") + static $_instantiate(factory: () => MyComponent): MyComponent { + const instance = factory() + return instance + } + + static instantiateImpl(builder: (instance: MyComponent)=>void, factory: () => MyComponent): void { + const instance = factory() + builder(instance) + } + + width(value: number): MyComponent { return this } + build() {} +} + + +@Component +class AnotherComponent { + + build() { + MyComponent() + .width(17.0) + } +} diff --git a/ets1.2/libarkts/plugins/input/one_recursive.ts b/ets1.2/libarkts/plugins/input/one_recursive.ts new file mode 100644 index 0000000000000000000000000000000000000000..baf5bae595d84d887b36395aa290c248b6b56f12 --- /dev/null +++ b/ets1.2/libarkts/plugins/input/one_recursive.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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. + */ + +import { Two } from "./two_recursive" + +export interface One { + two(): Two { + throw new Error("") + } +} + diff --git a/ets1.2/libarkts/plugins/input/two_recursive.ts b/ets1.2/libarkts/plugins/input/two_recursive.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3e6de586b443924412f819e9b630276dfd3fbb5 --- /dev/null +++ b/ets1.2/libarkts/plugins/input/two_recursive.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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. + */ + +import { One } from "./one_recursive" + +export interface Two { + one(): One { + throw new Error("") + } +} + diff --git a/ets1.2/libarkts/plugins/input/variable.ets b/ets1.2/libarkts/plugins/input/variable.ets new file mode 100644 index 0000000000000000000000000000000000000000..289ef6ec995e13b4fa383a9634cf896b2529ce58 --- /dev/null +++ b/ets1.2/libarkts/plugins/input/variable.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + +export const X: number = 1.2345; diff --git a/ets1.2/libarkts/plugins/src/print-visitor.ts b/ets1.2/libarkts/plugins/src/print-visitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..11a2e4104d6c9477dd58efd42ea6797734ed7c3c --- /dev/null +++ b/ets1.2/libarkts/plugins/src/print-visitor.ts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from '@koalaui/libarkts'; + +export class PrintVisitor extends arkts.AbstractVisitor { + private result = ''; + + private printNode(node: arkts.AstNode) { + return `${' '.repeat(4 * this.indentation)}${arkts.asString(node)}`; + } + + visitor(node: arkts.AstNode): arkts.AstNode { + console.log(this.printNode(node)); + return this.visitEachChild(node); + } +} diff --git a/ets1.2/libarkts/plugins/src/printer-plugin.ts b/ets1.2/libarkts/plugins/src/printer-plugin.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3ce5e18be11690067f1ca1708f289cfff7fd595 --- /dev/null +++ b/ets1.2/libarkts/plugins/src/printer-plugin.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import * as arkts from '@koalaui/libarkts'; +import { PrintVisitor } from './print-visitor'; + +export interface TransformerOptions { + trace?: boolean; +} + +export function printerTransformer(userPluginOptions?: TransformerOptions) { + return (program: arkts.Program) => { + return new PrintVisitor().visitor(program.ast); + }; +} + +export function init(parsedJson?: Object, checkedJson?: Object) { + let pluginContext = new arkts.PluginContextImpl(); + const parsedHooks = new arkts.DumpingHooks(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, 'printer'); + const checkedHooks = new arkts.DumpingHooks(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, 'printer'); + return { + name: 'printer', + parsed(hooks: arkts.RunTransformerHooks = parsedHooks) { + console.log('[printer-plugin] Run parsed state plugin'); + const transform = printerTransformer(parsedJson); + const prog = arkts.arktsGlobal.compilerContext!.program; + const state = arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED; + try { + arkts.runTransformer(prog, state, transform, pluginContext, hooks); + } catch (e) { + console.trace(e); + throw e; + } + }, + checked(hooks: arkts.RunTransformerHooks = checkedHooks) { + console.log('[printer-plugin] Run checked state plugin'); + const transform = printerTransformer(checkedJson); + const prog = arkts.arktsGlobal.compilerContext!.program; + const state = arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED; + try { + arkts.runTransformer(prog, state, transform, pluginContext, hooks); + arkts.recheckSubtree(prog.ast); + } catch (e) { + console.trace(e); + throw e; + } + }, + }; +} diff --git a/ets1.2/libarkts/plugins/tsconfig.json b/ets1.2/libarkts/plugins/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..2336e67754f08e5aa65c9f893a4737409b71c1dd --- /dev/null +++ b/ets1.2/libarkts/plugins/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@koalaui/build-common/tsconfig.json", + "compilerOptions": { + "rootDir": ".", + "baseUrl": ".", + "outDir": "./build", + "module": "CommonJS" + }, + "include": [ + "./src/printer-plugin.ts", + "./src/print-visitor.ts", + ] +} diff --git a/ets1.2/libarkts/rollup-lib.mjs b/ets1.2/libarkts/rollup-lib.mjs new file mode 100644 index 0000000000000000000000000000000000000000..6a17260d346d00d94e9d81e459a73524bf199738 --- /dev/null +++ b/ets1.2/libarkts/rollup-lib.mjs @@ -0,0 +1,82 @@ +/* + * Copyright (c) 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. + */ +import nodeResolve from "@rollup/plugin-node-resolve"; +import typescript from "@rollup/plugin-typescript"; +import commonjs from '@rollup/plugin-commonjs' + +const ENABLE_SOURCE_MAPS = false // Enable for debugging + +/** @type {import("rollup").RollupOptions} */ +export default makeConfig() + +function makeConfig(input, output) { + return { + input: { + 'libarkts': "./src/index.ts" + }, + output: { + dir: "lib", + format: "commonjs", + plugins: [ + // terser() + ], + manualChunks: { + 'libarkts-common': ["./src/index.ts"], + // Improve: maybe split scripts into smaller chunks + // 'libarkts-api': ["./src/arkts-api/index.ts"], + // 'libarkts-generated': ["./src/generated/index.ts"], + }, + banner: APACHE_LICENSE_HEADER(), + sourcemap: ENABLE_SOURCE_MAPS + }, + plugins: [ + commonjs(), + typescript({ + outputToFilesystem: false, + outDir: "lib", + module: "esnext", + sourceMap: ENABLE_SOURCE_MAPS, + declaration: true, + declarationMap: false, + declarationDir: "lib/types", + composite: false, + }), + nodeResolve({ + extensions: [".js", ".mjs", ".cjs", ".ts", ".cts", ".mts"] + }) + ], + } +} + +function APACHE_LICENSE_HEADER() { + return ` +/** +* @license +* Copyright (c) ${new Date().getUTCFullYear()} 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. +*/ + +` +} diff --git a/ets1.2/libarkts/rollup.es2panda.mjs b/ets1.2/libarkts/rollup.es2panda.mjs new file mode 100644 index 0000000000000000000000000000000000000000..bbcc959915ea0bd0ebfae4ff34d21dad0b249c26 --- /dev/null +++ b/ets1.2/libarkts/rollup.es2panda.mjs @@ -0,0 +1,68 @@ +/* + * Copyright (c) 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. + */ +import nodeResolve from "@rollup/plugin-node-resolve"; +import typescript from "@rollup/plugin-typescript"; +import commonjs from '@rollup/plugin-commonjs' + +/** @type {import("rollup").RollupOptions} */ +export default { + input: "./src-host/es2panda.ts", + output: { + file: "./lib/es2panda.js", + format: "commonjs", + banner: [ + "#!/usr/bin/env node", + APACHE_LICENSE_HEADER() + ].join("\n"), + }, + external: ["@koalaui/libarkts"], + plugins: [ + commonjs(), + typescript({ + outputToFilesystem: false, + module: "esnext", + sourceMap: false, + declarationMap: false, + declaration: false, + composite: false, + tsconfig: "./tsconfig.host.json" + }), + nodeResolve({ + extensions: [".js", ".mjs", ".cjs", ".ts", ".cts", ".mts"], + preferBuiltins: true, + }) + ], +} + +function APACHE_LICENSE_HEADER() { + return ` +/** +* @license +* Copyright (c) ${new Date().getUTCFullYear()} 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. +*/ + +` +} diff --git a/ets1.2/libarkts/rollup.printer-plugin.mjs b/ets1.2/libarkts/rollup.printer-plugin.mjs new file mode 100644 index 0000000000000000000000000000000000000000..fc5779c87606020bf8ff7a4abd50a404393881d7 --- /dev/null +++ b/ets1.2/libarkts/rollup.printer-plugin.mjs @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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. + */ +import nodeResolve from "@rollup/plugin-node-resolve"; +import typescript from "@rollup/plugin-typescript"; +import commonjs from '@rollup/plugin-commonjs' + +/** @type {import("rollup").RollupOptions} */ +export default { + input: "./plugins/src/printer-plugin.ts", + output: { + file: "./lib/plugins/printer-plugin.js", + format: "commonjs", + banner: [ + "#!/usr/bin/env node", + APACHE_LICENSE_HEADER() + ].join("\n"), + }, + external: ["@koalaui/libarkts"], + plugins: [ + commonjs(), + typescript({ + outputToFilesystem: false, + module: "esnext", + sourceMap: false, + declarationMap: false, + declaration: false, + composite: false, + tsconfig: "./tsconfig.plugin.json" + }), + nodeResolve({ + extensions: [".js", ".mjs", ".cjs", ".ts", ".cts", ".mts"] + }) + ], +} + +function APACHE_LICENSE_HEADER() { + return ` +/** +* @license +* Copyright (c) ${new Date().getUTCFullYear()} 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. +*/ + +` +} diff --git a/ets1.2/libarkts/src-host/es2panda.ts b/ets1.2/libarkts/src-host/es2panda.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7440f0d281dfea58305693ec34b80ee2ba3999c --- /dev/null +++ b/ets1.2/libarkts/src-host/es2panda.ts @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { + checkSDK, + arktsGlobal as global, + findStdlib, + DumpingHooks, + listPrograms, + initVisitsTable, + PluginContextImpl, +} from '@koalaui/libarkts'; +import { PluginEntry, PluginInitializer } from '@koalaui/libarkts'; +import { Command } from 'commander'; +import { throwError } from '@koalaui/libarkts'; +import { Es2pandaContextState } from '@koalaui/libarkts'; +import { Tracer, traceGlobal, Options, Config, Context, proceedToState, dumpArkTsConfigInfo } from '@koalaui/libarkts'; + +interface CommandLineOptions { + files: string[]; + configPath: string; + outputs: string[]; + dumpAst: boolean; + simultaneous: boolean; + profileMemory: boolean; + trace: boolean; +} + +function readResponseFile(arg: string | undefined): string | undefined { + if (!arg) { + return undefined; + } + if (!arg.startsWith('@')) { + return arg; + } + return fs.readFileSync(arg.slice(1), 'utf-8'); +} + +function parseCommandLineArgs(): CommandLineOptions { + const commander = new Command() + .argument('[file]', 'Path to files to be compiled') + .option('--file, ', 'Path to file to be compiled (deprecated)') + .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') + .option('--simultaneous', 'Use "simultaneous" mode of compilation') + .option('--profile-memory', 'Profile memory usage') + .option('--trace', 'Trace plugin compilation') + .parse(process.argv); + + const cliOptions = commander.opts(); + const cliArgs = commander.args; + const fileArg = readResponseFile(cliOptions.file ?? cliArgs[0]); + if (!fileArg) { + reportErrorAndExit(`Either --file option or file argument is required`); + } + const files = fileArg + .split(/[ :]/g) + .map((it) => (it.startsWith("'") ? it.slice(1, -1) : it)) + .map((it: string) => path.resolve(it)); + const configPath = path.resolve(cliOptions.arktsconfig); + const outputArg = cliOptions.output; + const outputs = outputArg.split(':').map((it: string) => path.resolve(it)); + files.forEach((it: string) => { + if (!fs.existsSync(it)) { + reportErrorAndExit(`File path doesn't exist: ${it}`); + } + }); + if (!fs.existsSync(configPath)) { + reportErrorAndExit(`Arktsconfig path doesn't exist: ${configPath}`); + } + + const dumpAst = cliOptions.dumpPluginAst ?? false; + const simultaneous = cliOptions.simultaneous ?? false; + const profileMemory = cliOptions.profileMemory ?? false; + const trace = cliOptions.trace ?? false; + + return { files, configPath, outputs, dumpAst, simultaneous, profileMemory, trace }; +} + +function insertPlugin(pluginEntry: PluginEntry, state: Es2pandaContextState, dumpAst: boolean) { + const pluginName = `${pluginEntry.name}-${Es2pandaContextState[state].substring(`ES2PANDA_STATE_`.length).toLowerCase()}`; + global.profiler.curPlugin = pluginName; + global.profiler.transformStarted(); + + const hooks = new DumpingHooks(state, pluginName, dumpAst); + const pluginContext = new PluginContextImpl(); + + if (false) { + pluginContext.setProjectConfig({ + bundleName: 'bundle', + moduleName: 'module', + cachePath: './dist', + dependentModuleList: [], + appResource: '', + rawFileResource: '', + buildLoaderJson: '', + hspResourcesMap: false, + compileHar: false, + byteCodeHar: false, + uiTransformOptimization: false, + resetBundleName: true, + allowEmptyBundleName: true, + moduleType: 'module', + moduleRootPath: '.', + aceModuleJsonPath: './module.json', + ignoreError: false, + projectPath: '.', + projectRootPath: '.', + integratedHsp: false, + frameworkMode: 'yes', + }); + } + + if (state == Es2pandaContextState.ES2PANDA_STATE_PARSED) { + pluginEntry.parsed?.call(pluginContext, hooks); + } + + if (state == Es2pandaContextState.ES2PANDA_STATE_CHECKED) { + pluginEntry.checked?.call(pluginContext, hooks); + } + + global.profiler.transformEnded(state, pluginName); + global.profiler.curPlugin = ''; +} + +// Improve: move to profiler +function dumpMemoryProfilerInfo(str: string) { + console.log(str, process.memoryUsage().rss); +} + +function dumpCompilationInfo(simultaneous: boolean) { + traceGlobal(() => { + const programs = listPrograms(global.compilerContext!.program); + if (simultaneous) { + const programsForCodegeneration = programs.filter((it) => it.isGenAbcForExternal); + traceGlobal(() => `Programs for codegeneration : ${programsForCodegeneration.length}`); + traceGlobal( + () => `External programs passed to plugins: ${programs.length - programsForCodegeneration.length - 1}` + ); + } else { + traceGlobal(() => `Programs for codegeneration : 1`); + traceGlobal(() => `External programs passed to plugins: ${programs.length - 1}`); + } + }); +} + +function createContextAdapter(filePaths: string[]): Context { + return Context.createFromFile(filePaths[0]); +} + +function invoke( + configPath: string, + filePaths: string[], + outputPath: string, + pluginsByState: Map, + dumpAst: boolean, + profileMemory: boolean, + trace: boolean, + simultaneous: boolean, + createContext: (fileNames: string[]) => Context +): void { + const stdlib = findStdlib(); + const cmd = ['--arktsconfig', configPath, '--extension', 'ets', '--stdlib', stdlib, '--output', outputPath]; + if (simultaneous) { + cmd.push('--simultaneous'); + } + cmd.push(filePaths[0]); + + fs.mkdirSync(path.dirname(outputPath), { recursive: true }); + if (trace) { + Tracer.startGlobalTracing(path.dirname(outputPath)); + } + Tracer.pushContext('es2panda'); + + initVisitsTable(); + + const compilerConfig = Config.create(['_', ...cmd]); + global.config = compilerConfig.peer; + if (!global.configIsInitialized()) throw new Error(`Wrong config: path=${configPath}`); + + const compilerContext = createContext(filePaths); + global.compilerContext = compilerContext; + global.isContextGenerateAbcForExternalSourceFiles = simultaneous; + + const options = Options.createOptions(new Config(global.config)); + global.arktsconfig = options.getArkTsConfig(); + dumpArkTsConfigInfo(global.arktsconfig); + + if (profileMemory) dumpMemoryProfilerInfo('Memory usage before proceed to parsed:'); + proceedToState(Es2pandaContextState.ES2PANDA_STATE_PARSED); + if (profileMemory) dumpMemoryProfilerInfo('Memory usage after proceed to parsed:'); + + pluginsByState.get(Es2pandaContextState.ES2PANDA_STATE_PARSED)?.forEach((plugin) => { + if (profileMemory) dumpMemoryProfilerInfo(`Memory usage before ${plugin.name}-parsed:`); + insertPlugin(plugin, Es2pandaContextState.ES2PANDA_STATE_PARSED, dumpAst); + if (profileMemory) dumpMemoryProfilerInfo(`Memory usage after ${plugin.name}-parsed:`); + }); + + dumpCompilationInfo(simultaneous); + + if (profileMemory) dumpMemoryProfilerInfo('Memory usage before proceed to checked:'); + proceedToState(Es2pandaContextState.ES2PANDA_STATE_CHECKED); + if (profileMemory) dumpMemoryProfilerInfo('Memory usage after proceed to checked:'); + + pluginsByState.get(Es2pandaContextState.ES2PANDA_STATE_CHECKED)?.forEach((plugin) => { + if (profileMemory) dumpMemoryProfilerInfo(`Memory usage before ${plugin.name}-checked:`); + insertPlugin(plugin, Es2pandaContextState.ES2PANDA_STATE_CHECKED, dumpAst); + if (profileMemory) dumpMemoryProfilerInfo(`Memory usage after ${plugin.name}-checked:`); + }); + + if (profileMemory) dumpMemoryProfilerInfo('Memory usage before proceed to asm:'); + proceedToState(Es2pandaContextState.ES2PANDA_STATE_ASM_GENERATED); + if (profileMemory) dumpMemoryProfilerInfo('Memory usage after proceed to asm:'); + + if (profileMemory) dumpMemoryProfilerInfo('Memory usage before proceed to bin:'); + proceedToState(Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED); + if (profileMemory) dumpMemoryProfilerInfo('Memory usage after proceed to bin:'); + + global.profiler.compilationEnded(); + global.profiler.report(); + global.profiler.reportToFile(true); + + compilerContext.destroy(); + compilerConfig.destroy(); + + Tracer.popContext(); + if (trace) { + Tracer.stopGlobalTracing(); + } +} + +function loadPlugin(configDir: string, transform: string) { + /** Improve: read and pass plugin options */ + const plugin = + transform.startsWith('.') || transform.startsWith('/') ? path.resolve(configDir, transform) : transform; + const pluginEntry = require(plugin); + if (!pluginEntry.init) { + throw new Error(`init is not specified in plugin ${transform}`); + } + if (typeof pluginEntry.init !== 'function') { + throw new Error(`init is not a function in plugin ${transform}`); + } + return pluginEntry.init; +} + +function stateFromString(stateName: string): Es2pandaContextState { + switch (stateName) { + case 'parsed': + return Es2pandaContextState.ES2PANDA_STATE_PARSED; + case 'checked': + return Es2pandaContextState.ES2PANDA_STATE_CHECKED; + default: + throw new Error(`Invalid state name: ${stateName}`); + } +} + +function readAndSortPlugins(configDir: string, plugins: { transform: string; state: string }[]) { + const pluginsByState = new Map(); + const pluginInitializers = new Map(); + const pluginParsedStageOptions = new Map(); + const pluginCheckedStageOptions = new Map(); + + plugins.forEach((it) => { + const transform = it.transform; + if (!transform) { + throwError(`arktsconfig plugins objects should specify transform`); + } + const state = stateFromString(it.state); + if (!pluginInitializers.has(it.transform)) { + pluginInitializers.set(it.transform, loadPlugin(configDir, it.transform)); + } + if (!pluginsByState.has(state)) { + pluginsByState.set(state, []); + } + if (state == Es2pandaContextState.ES2PANDA_STATE_PARSED) { + pluginParsedStageOptions.set(it.transform, it); + } + if (state == Es2pandaContextState.ES2PANDA_STATE_CHECKED) { + pluginCheckedStageOptions.set(it.transform, it); + } + }); + + pluginInitializers.forEach((pluginInit, pluginTransform) => { + const parsedJson = pluginParsedStageOptions.get(pluginTransform); + const checkedJson = pluginCheckedStageOptions.get(pluginTransform); + const plugin = pluginInit(parsedJson, checkedJson); + if (parsedJson && plugin.parsed) { + pluginsByState.get(Es2pandaContextState.ES2PANDA_STATE_PARSED)?.push(plugin); + } + if (checkedJson && plugin.checked) { + pluginsByState.get(Es2pandaContextState.ES2PANDA_STATE_CHECKED)?.push(plugin); + } + }); + + return pluginsByState; +} + +export function main() { + checkSDK(); + const { files, configPath, outputs, dumpAst, simultaneous, profileMemory, trace } = parseCommandLineArgs(); + if (!simultaneous && files.length != outputs.length) { + reportErrorAndExit('Different length of inputs and outputs'); + } + 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); + + if (simultaneous) { + invoke( + configPath, + files, + outputs[0], + pluginsByState, + dumpAst, + profileMemory, + trace, + simultaneous, + Context.createContextGenerateAbcForExternalSourceFiles + ); + } else { + for (var i = 0; i < files.length; i++) { + invoke( + configPath, + [files[i]], + outputs[i], + pluginsByState, + dumpAst, + profileMemory, + trace, + simultaneous, + createContextAdapter + ); + } + } +} + +function reportErrorAndExit(message: string): never { + console.error(message); + process.exit(1); +} + +main(); diff --git a/ets1.2/libarkts/src/Es2pandaNativeModule.ts b/ets1.2/libarkts/src/Es2pandaNativeModule.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe1d80615e83a3e5b7df4b96d4a6c704efed1468 --- /dev/null +++ b/ets1.2/libarkts/src/Es2pandaNativeModule.ts @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { + KNativePointer as KPtr, + KInt, + KBoolean, + KNativePointer, + registerNativeModuleLibraryName, + loadNativeModuleLibrary, + KDouble, + KUInt, + KStringArrayPtr, + KStringPtr, +} from '@koalaui/interop'; +import { + Es2pandaNativeModule as GeneratedEs2pandaNativeModule, + KNativePointerArray, +} from '../generated/Es2pandaNativeModule'; +import * as path from 'path'; +import * as fs from 'fs'; +import { Es2pandaPluginDiagnosticType } from '../generated/Es2pandaEnums'; + +// Improve: this type should be in interop +export type KPtrArray = BigUint64Array; + +export class Es2pandaNativeModule { + _AnnotationAllowedAnnotations(context: KPtr, node: KPtr, returnLen: KPtr): KPtr { + throw new Error('Not implemented'); + } + _AstNodeRebind(context: KPtr, node: KPtr): void { + throw new Error('Not implemented'); + } + _ContextState(context: KPtr): KInt { + throw new Error('Not implemented'); + } + _AstNodeChildren(context: KPtr, node: KPtr): KPtr { + throw new Error('Not implemented'); + } + _AstNodeDumpModifiers(context: KPtr, node: KPtr): KPtr { + throw new Error('Not implemented'); + } + _CreateConfig(argc: number, argv: string[]): KPtr { + throw new Error('Not implemented'); + } + _DestroyConfig(peer: KNativePointer): void { + throw new Error('Not implemented'); + } + _CreateContextFromString(config: KPtr, source: String, filename: String): KPtr { + throw new Error('Not implemented'); + } + _CreateContextFromFile(config: KPtr, filename: String): KPtr { + throw new Error('Not implemented'); + } + _CreateCacheContextFromFile( + config: KNativePointer, + sourceFileName: String, + globalContext: KNativePointer, + isExternal: KBoolean + ): KNativePointer { + throw new Error('Not implemented'); + } + _InsertGlobalStructInfo(context: KNativePointer, str: String): void { + throw new Error('Not implemented'); + } + _HasGlobalStructInfo(context: KNativePointer, str: String): KBoolean { + throw new Error('Not implemented'); + } + _CreateGlobalContext( + config: KNativePointer, + externalFileList: KStringArrayPtr, + fileNum: KUInt, + lspUsage: KBoolean + ): KNativePointer { + throw new Error('Not implemented'); + } + _DestroyGlobalContext(context: KNativePointer): void { + throw new Error('Not implemented'); + } + _DestroyContext(context: KPtr): void { + throw new Error('Not implemented'); + } + _ProceedToState(context: KPtr, state: number): void { + throw new Error('Not implemented'); + } + _CheckerStartChecker(context: KPtr): KBoolean { + throw new Error('Not implemented'); + } + _AstNodeVariableConst(context: KPtr, ast: KPtr): KPtr { + throw new Error('Not implemented'); + } + _CreateNumberLiteral(context: KPtr, value: KDouble): KPtr { + throw new Error('Not implemented'); + } + _AstNodeSetChildrenParentPtr(context: KPtr, node: KPtr): void { + throw new Error('Not implemented'); + } + _AstNodeOnUpdate(context: KPtr, newNode: KPtr, replacedNode: KPtr): void { + throw new Error('Not implemented'); + } + _AstNodeUpdateAll(context: KPtr, node: KPtr): void { + throw new Error('Not implemented'); + } + _VariableDeclaration(context: KPtr, variable: KPtr): KPtr { + throw new Error('Not implemented'); + } + _DeclNode(context: KPtr, decl: KPtr): KPtr { + throw new Error('Not implemented'); + } + _ProgramSourceFilePath(context: KNativePointer, instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _ProgramExternalSources(context: KNativePointer, instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _ProgramDirectExternalSources(context: KNativePointer, instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _ExternalSourceName(instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _ExternalSourcePrograms(instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _ETSParserBuildImportDeclaration( + context: KNativePointer, + importKinds: KInt, + specifiers: KNativePointerArray, + specifiersSequenceLength: KUInt, + source: KNativePointer, + program: KNativePointer, + flags: KInt + ): KNativePointer { + throw new Error('Not implemented'); + } + _ImportPathManagerResolvePathConst( + context: KNativePointer, + importPathManager: KNativePointer, + currentModulePath: String, + importPath: String, + sourcePosition: KNativePointer + ): KNativePointer { + throw new Error('Not implemented'); + } + _ETSParserGetImportPathManager(context: KNativePointer): KPtr { + throw new Error('Not implemented'); + } + _SourcePositionCol(context: KNativePointer, instance: KNativePointer): KUInt { + throw new Error('Not implemented'); + } + _ConfigGetOptions(config: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _OptionsArkTsConfig(context: KNativePointer, options: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_CreateOpaqueTypeNode(context: KNativePointer, type: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_ScriptFunctionSignature(context: KNativePointer, node: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_ScriptFunctionSetSignature( + context: KNativePointer, + node: KNativePointer, + signature: KNativePointer + ): void { + throw new Error('Not implemented'); + } + _Checker_SignatureReturnType(context: KNativePointer, signature: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_ScriptFunctionGetPreferredReturnType(context: KNativePointer, node: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_ScriptFunctionSetPreferredReturnType( + context: KNativePointer, + node: KNativePointer, + type: KNativePointer + ): void { + throw new Error('Not implemented'); + } + _Checker_ExpressionGetPreferredType(context: KNativePointer, node: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_ExpressionSetPreferredType(context: KNativePointer, node: KNativePointer, type: KNativePointer): void { + throw new Error('Not implemented'); + } + _Checker_TypeToString(context: KNativePointer, type: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_TypeClone(context: KNativePointer, type: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _Checker_TypeNodeGetType(context: KNativePointer, node: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _ScriptFunctionSetParams( + context: KNativePointer, + receiver: KNativePointer, + paramsList: BigUint64Array, + paramsListLength: KUInt + ): void { + throw new Error('Not implemented'); + } + _ClassDefinitionSetBody( + context: KNativePointer, + receiver: KNativePointer, + body: BigUint64Array, + bodyLength: KUInt + ): void { + throw new Error('Not implemented'); + } + _FilterNodes(context: KNativePointer, root: KNativePointer, filters: KStringPtr): KNativePointer { + throw new Error('Not implemented'); + } + + // From koala-wrapper + _ClassVariableDeclaration(context: KNativePointer, classInstance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _ETSParserGetGlobalProgramAbsName(context: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _CreateDiagnosticKind( + context: KNativePointer, + message: string, + type: Es2pandaPluginDiagnosticType + ): KNativePointer { + throw new Error('Not implemented'); + } + _CreateDiagnosticInfo( + context: KNativePointer, + kind: KNativePointer, + args: string[], + argc: number, + pos: KNativePointer + ): KNativePointer { + throw new Error('Not implemented'); + } + _CreateSuggestionInfo( + context: KNativePointer, + kind: KNativePointer, + args: string[], + argc: number, + substitutionCode: string, + title: string, + range: KNativePointer + ): KNativePointer { + throw new Error('Not implemented'); + } + _LogDiagnostic( + context: KNativePointer, + kind: KNativePointer, + argv: string[], + argc: number, + pos: KNativePointer + ): void { + throw new Error('Not implemented'); + } + _SetUpSoPath(soPath: string): void { + throw new Error('Not implemented'); + } + _MemInitialize(): void { + throw new Error('Not implemented'); + } + _MemFinalize(): void { + throw new Error('Not implemented'); + } + _ProgramCanSkipPhases(context: KNativePointer, program: KNativePointer): boolean { + throw new Error('Not implemented'); + } + _GenerateTsDeclarationsFromContext( + config: KPtr, + outputDeclEts: String, + outputEts: String, + exportAll: KBoolean, + isolated: KBoolean, + recordFile: String, + genAnnotations: KBoolean + ): KPtr { + throw new Error('Not implemented'); + } + _AstNodeProgram(context: KNativePointer, instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _CreateContextGenerateAbcForExternalSourceFiles(config: KPtr, fileCount: KInt, filenames: string[]): KPtr { + throw new Error('Not implemented'); + } + + _GetCompilationMode(config: KNativePointer): KInt { + throw new Error('Not implemented'); + } + + _CreateTypeNodeFromTsType(context: KNativePointer, classInstance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + + _MemoryTrackerReset(context: KNativePointer): void { + throw new Error('Not implemented'); + } + + _MemoryTrackerGetDelta(context: KNativePointer): void { + throw new Error('Not implemented'); + } + + _MemoryTrackerPrintCurrent(context: KNativePointer): void { + throw new Error('Not implemented'); + } +} + +export function findNativeModule(): string { + const candidates = [path.resolve(__dirname, '../native/build'), path.resolve(__dirname, '../build/native/build')]; + let result = undefined; + candidates.forEach((path) => { + if (fs.existsSync(path)) { + result = path; + return; + } + }); + if (result) return path.join(result, 'es2panda'); + throw new Error('Cannot find native module'); +} + +export function initEs2panda(): Es2pandaNativeModule { + registerNativeModuleLibraryName('NativeModule', findNativeModule()); + const instance = new Es2pandaNativeModule(); + loadNativeModuleLibrary('NativeModule', instance); + return instance; +} + +export function initGeneratedEs2panda(): GeneratedEs2pandaNativeModule { + registerNativeModuleLibraryName('NativeModule', findNativeModule()); + const instance = new GeneratedEs2pandaNativeModule(); + // registerNativeModule("InteropNativeModule", NativeModule) + loadNativeModuleLibrary('NativeModule', instance); + return instance; +} diff --git a/ets1.2/libarkts/src/InteropNativeModule.ts b/ets1.2/libarkts/src/InteropNativeModule.ts new file mode 100644 index 0000000000000000000000000000000000000000..8181b2727ac52cab4bd23efd513614d78718fc2e --- /dev/null +++ b/ets1.2/libarkts/src/InteropNativeModule.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { + KNativePointer as KPtr, + KInt, + registerNativeModuleLibraryName, + loadNativeModuleLibrary, +} from '@koalaui/interop'; +import { findNativeModule } from './Es2pandaNativeModule'; + +export class InteropNativeModule { + _StringLength(ptr: KPtr): KInt { + throw new Error('Not implemented'); + } + _StringData(ptr: KPtr, buffer: KPtr, length: KInt): void { + throw new Error('Not implemented'); + } + _GetStringFinalizer(): KPtr { + throw new Error('Not implemented'); + } + _RawUtf8ToString(ptr: KPtr): string { + throw new Error('Not implemented'); + } + _InvokeFinalizer(ptr: KPtr, finalizer: KPtr): void { + throw new Error('Not implemented'); + } + _GetPtrVector(ptr: KPtr): BigUint64Array { + throw new Error('Not implemented'); + } + _GetPtrVectorSize(ptr: KPtr): KInt { + throw new Error('Not implemented'); + } + _GetPtrVectorElement(ptr: KPtr, index: KInt): KPtr { + throw new Error('Not implemented'); + } +} + +export function initInterop(): InteropNativeModule { + registerNativeModuleLibraryName('InteropNativeModule', findNativeModule()); + const instance = new InteropNativeModule(); + loadNativeModuleLibrary('InteropNativeModule', instance); + return instance; +} diff --git a/ets1.2/libarkts/src/arkts-api/AbstractVisitor.ts b/ets1.2/libarkts/src/arkts-api/AbstractVisitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..d179c0dd4e6f714378321e29694d12e5ca7be197 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/AbstractVisitor.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { AstNode } from './peers/AstNode'; +import { visitEachChild } from './visitor'; +import { Program } from '../../generated'; + +export interface VisitorOptions { + program?: Program; +} + +export abstract class AbstractVisitor { + public program?: Program; + + constructor(options?: VisitorOptions) { + this.program = options?.program; + } + + indentation = 0; + + withIndentation(exec: () => T): T { + this.indentation++; + const result = exec(); + this.indentation--; + return result; + } + + process(node: AstNode, options?: object): AstNode { + return this.visitor(node, options); + } + + abstract visitor(node: AstNode, options?: object): AstNode; + + visitEachChild(node: AstNode, options?: object): AstNode { + return this.withIndentation((): AstNode => visitEachChild(node, (it): AstNode => this.visitor(it, options))); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/ImportStorage.ts b/ets1.2/libarkts/src/arkts-api/ImportStorage.ts new file mode 100644 index 0000000000000000000000000000000000000000..063ba48e5ec69c82f93a75759e8a95125295c4d5 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/ImportStorage.ts @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { ETSModule, ImportDeclaration, isETSImportDeclaration, Program, Statement } from '../../generated'; +import { passNode, passNodeArray, unpackNonNullableNode } from './utilities/private'; +import { global } from './static/global'; +import { Es2pandaImportFlags, Es2pandaImportKinds } from '../../generated/Es2pandaEnums'; +import { factory } from './factory/nodeFactory'; + +export class ImportStorage { + // Improve: migrate to wrappers instead of pointers + private imports: Set = new Set(); + private importSources: Set = new Set(); + + constructor( + private program: Program, + private isParserState: boolean + ) { + for (const statement of program.ast.statements) { + if (isETSImportDeclaration(statement)) { + this.imports.add(statement.peer); + if (!isParserState) { + // Improve: is source non nullable? + this.importSources.add(statement.source?.str); + } + } + } + } + + update(): void { + // Save current statements + const statements = this.program.ast.statements; + + // Update parser information + const newStatements: Statement[] = []; + for (const statement of statements) { + if (isETSImportDeclaration(statement) && !this.imports.has(statement.peer)) { + if (!this.isParserState && !this.importSources.has(statement.source?.str)) { + console.warn('Attempt to insert import from new source after parsed state:'); + console.warn(statement.dumpSrc()); + } + + const importDeclaration = unpackNonNullableNode( + // Note: this call is important, we cannot just pass "statement" to "InsertETSImportDeclarationAndParse" + global.es2panda._ETSParserBuildImportDeclaration( + global.context, + Es2pandaImportKinds.IMPORT_KINDS_ALL, // Improve: do we use IMPORT_KINDS_TYPES? + passNodeArray(statement.specifiers), + statement.specifiers.length, + passNode(statement.source), + this.program.peer, + Es2pandaImportFlags.IMPORT_FLAGS_NONE // Improve: where to get it? + ) + ); + global.generatedEs2panda._InsertETSImportDeclarationAndParse( + global.context, + this.program.peer, + importDeclaration.peer + ); + newStatements.push(importDeclaration); + } else { + newStatements.push(statement); + } + } + + // Drop import statements generated by compiler in the beginning of the ETSModule + const module = this.program.ast as ETSModule; + this.program.setAst( + factory.updateETSModule(module, newStatements, module.ident, module.getNamespaceFlag(), module.program) + ); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/ProgramProvider.ts b/ets1.2/libarkts/src/arkts-api/ProgramProvider.ts new file mode 100644 index 0000000000000000000000000000000000000000..0140c5e39c1edc1fada7db78a7eaf58e2966e8d5 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/ProgramProvider.ts @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { defaultFilter, listPrograms } from './plugins'; +import { Program } from '../../generated'; + +export class ProgramProvider { + // Improve: migrate to wrappers instead of pointers + seenPrograms: Set = new Set(); + queue: Program[] = []; + + constructor( + private mainProgram: Program, + private readonly filter: (name: string) => boolean = defaultFilter + ) { + this.seenPrograms.add(mainProgram.peer); + this.queue = [mainProgram]; + } + + updateQueue(): void { + const listed = listPrograms(this.mainProgram, this.filter); + for (const program of listed) { + if (!this.seenPrograms.has(program.peer)) { + this.seenPrograms.add(program.peer); + this.queue.push(program); + } + } + } + + next(): Program | undefined { + if (this.queue.length === 0) { + this.updateQueue(); + if (this.queue.length === 0) { + // console.log("PROGRAMS:", this.seenPrograms.size) + return undefined; + } + } + return this.queue.shift(); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/class-by-peer.ts b/ets1.2/libarkts/src/arkts-api/class-by-peer.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb436570abe948f24279b1874375a65175f39ca9 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/class-by-peer.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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. + */ + +import { Es2pandaAstNodeType } from '../../generated/Es2pandaEnums'; +import { throwError } from '../utils'; +import { global } from './static/global'; +import { KNativePointer } from '@koalaui/interop'; +import { AstNode } from './peers/AstNode'; +import { NodeCache } from './node-cache'; + +export const nodeByType = new Map AstNode>([]); + +export function nodeFrom(peer: KNativePointer, typeHint?: Es2pandaAstNodeType): T { + const fromCache = NodeCache.get(peer); + if (fromCache) { + return fromCache; + } + const type = typeHint ?? global.generatedEs2panda._AstNodeTypeConst(global.context, peer); + const create = nodeByType.get(type) ?? throwError(`unknown node type: ${type}`); + return create(peer) as T; +} diff --git a/ets1.2/libarkts/src/arkts-api/factory/nodeFactory.ts b/ets1.2/libarkts/src/arkts-api/factory/nodeFactory.ts new file mode 100644 index 0000000000000000000000000000000000000000..28bb407a0b2b9f8c7728e36ebc738d3172d582aa --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/factory/nodeFactory.ts @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { + BlockStatement, + CallExpression, + ClassDefinition, + ClassProperty, + ClassStaticBlock, + ETSImportDeclaration, + ETSModule, + ETSStructDeclaration, + ETSTuple, + ETSTypeReferencePart, + Identifier, + MemberExpression, + ObjectExpression, + TryStatement, + TSTypeParameter, + VariableDeclarator, +} from '../../../generated'; +import { factory as generatedFactory } from '../../../generated/factory'; +import { + createScriptFunction, + inplaceUpdateScriptFunction, + updateScriptFunction, +} from '../node-utilities/ScriptFunction'; +import { inplaceUpdateCallExpression, updateCallExpression } from '../node-utilities/CallExpression'; +import { createNumberLiteral, updateNumberLiteral } from '../node-utilities/NumberLiteral'; +import { updateMemberExpression } from '../node-utilities/MemberExpression'; +import { createETSParameterExpression, updateETSParameterExpression } from '../node-utilities/ETSParameterExpression'; +import { updateTSTypeParameter } from '../node-utilities/TSTypeParameter'; +import { updateETSTypeReferencePart } from '../node-utilities/TSTypeReferencePart'; +import { updateETSImportDeclaration } from '../node-utilities/ETSImportDeclaration'; +import { updateVariableDeclarator } from '../node-utilities/VariableDeclarator'; +import { createClassDefinition, updateClassDefinition } from '../node-utilities/ClassDefinition'; +import { updateETSStructDeclaration } from '../node-utilities/ETSStructDeclaration'; +import { updateClassProperty } from '../node-utilities/ClassProperty'; +import { createETSFunctionType, updateETSFunctionType } from '../node-utilities/ETSFunctionType'; +import { createMethodDefinition, updateMethodDefinition } from '../node-utilities/MethodDefinition'; +import { createTSInterfaceDeclaration, updateTSInterfaceDeclaration } from '../node-utilities/TSInterfaceDeclaration'; +import { updateTryStatement } from '../node-utilities/TryStatement'; +import { createAssignmentExpression, updateAssignmentExpression } from '../node-utilities/AssignmentExpression'; +import { createObjectExpression, updateObjectExpression } from '../node-utilities/ObjectExpression'; +import { updateETSTuple } from '../node-utilities/ETSTuple'; +import { createArrayExpression, updateArrayExpression } from '../node-utilities/ArrayExpression'; +import { updateBlockStatement } from '../node-utilities/BlockStatement'; +import { updateETSModule } from '../node-utilities/ETSModule'; +import { createOpaqueTypeNode } from '../node-utilities/OpaqueTypeNode'; + +export const factory = { + ...generatedFactory, + + createIdentifier: Identifier.create2Identifier, + updateIdentifier: Identifier.update2Identifier, + + createETSModule: ETSModule.create1ETSModule, + updateETSModule, + + createCallExpression: CallExpression.createCallExpression, + updateCallExpression, + inplaceUpdateCallExpression, + + createMemberExpression: MemberExpression.createMemberExpression, + updateMemberExpression, + + createScriptFunction, + updateScriptFunction, + inplaceUpdateScriptFunction, + + createNumberLiteral, + updateNumberLiteral, + + createETSParameterExpression, + updateETSParameterExpression, + + createTypeParameter: TSTypeParameter.create1TSTypeParameter, + updateTypeParameter: updateTSTypeParameter, + + createETSTypeReferencePart: ETSTypeReferencePart.createETSTypeReferencePart, + updateETSTypeReferencePart, + + createETSImportDeclaration: ETSImportDeclaration.createETSImportDeclaration, + updateETSImportDeclaration, + + createVariableDeclarator: VariableDeclarator.create1VariableDeclarator, + updateVariableDeclarator, + + createETSStructDeclaration: ETSStructDeclaration.createETSStructDeclaration, + updateETSStructDeclaration, + + createClassDefinition, + updateClassDefinition, + update3ClassDefinition: ClassDefinition.update3ClassDefinition, + + createClassProperty: ClassProperty.createClassProperty, + updateClassProperty, + + createETSFunctionType, + updateETSFunctionType, + + createMethodDefinition, + updateMethodDefinition, + + createInterfaceDeclaration: createTSInterfaceDeclaration, + updateInterfaceDeclaration: updateTSInterfaceDeclaration, + + createTryStatement: TryStatement.createTryStatement, + updateTryStatement, + + createAssignmentExpression, + updateAssignmentExpression, + + createObjectExpression, + updateObjectExpression, + + createETSTuple: ETSTuple.create2ETSTuple, + updateETSTuple, + + createArrayExpression, + updateArrayExpression, + + createBlockStatement: BlockStatement.createBlockStatement, + updateBlockStatement, + + updateInterfaceBody: generatedFactory.updateTSInterfaceBody, + + createClassStaticBlock: ClassStaticBlock.createClassStaticBlock, + updateClassStaticBlock: ClassStaticBlock.updateClassStaticBlock, + + createOpaqueTypeNode, +}; diff --git a/ets1.2/libarkts/src/arkts-api/index.ts b/ets1.2/libarkts/src/arkts-api/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7cb78e424c2972c895817d885934a1d5f8824c7 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/index.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +export * from '../../generated/Es2pandaEnums'; +export * from '../../generated'; + +export * from './utilities/performance'; +export * from './utilities/private'; +export * from './utilities/public'; +export * from './factory/nodeFactory'; +export * from './visitor'; +export * from './AbstractVisitor'; +export * from './plugins'; +export * from './ImportStorage'; +export * from './ProgramProvider'; + +export * from './peers/AstNode'; +export * from './peers/Config'; +export * from './peers/Context'; +export { GlobalContext } from './peers/Context'; +export * from './peers/ExternalSource'; +export * from './peers/Options'; +export * from './peers/DiagnosticKind'; +export * from './node-utilities/ArkTsConfig'; +export * from './node-utilities/Program'; +export * from './peers/ImportPathManager'; +export * from './static/globalUtils'; +export { global as arktsGlobal } from './static/global'; +export * from './wrapper-compat'; diff --git a/ets1.2/libarkts/src/arkts-api/node-cache.ts b/ets1.2/libarkts/src/arkts-api/node-cache.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6305a3b756893d018e84874ebcfb02e5971f3f1 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-cache.ts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { AstNode } from './peers/AstNode'; + +export class NodeCache { + private static cache = new Map(); + + static cached(pointer: KNativePointer, factory: (pointer: KNativePointer) => AstNode): T { + const cached = NodeCache.cache.get(pointer); + if (cached !== undefined) { + return cached as T; + } + const node = factory(pointer); + NodeCache.addToCache(pointer, node); + return node as T; + } + + static get(pointer: KNativePointer): T | undefined { + return NodeCache.cache.get(pointer) as T | undefined; + } + + public static addToCache(pointer: KNativePointer, node: AstNode): void { + NodeCache.cache.set(pointer, node); + } + + public static clear(): void { + NodeCache.cache.clear(); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ArkTsConfig.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ArkTsConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a4620801d8f6a5493b9d387f6b17817527d0add --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ArkTsConfig.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 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. + */ + +import { ArkTsConfig } from '../../../generated'; +import { traceGlobal } from '../../tracer'; + +export function dumpArkTsConfigInfo(arkTsConfig: ArkTsConfig) { + traceGlobal(() => `ArkTsConfig info:`); + traceGlobal(() => `\tBaseUrl: ${arkTsConfig.baseUrl}`); + traceGlobal(() => `\tConfigPath: ${arkTsConfig.configPath}`); + traceGlobal(() => `\tOutDir: ${arkTsConfig.outDir}`); + traceGlobal(() => `\tPackage: ${arkTsConfig.package}`); + traceGlobal(() => `\tRootDir: ${arkTsConfig.rootDir}`); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ArrayExpression.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ArrayExpression.ts new file mode 100644 index 0000000000000000000000000000000000000000..c25ade899b6a0a1480eb81d5475deb3cc829c451 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ArrayExpression.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 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. + */ + +import { Es2pandaAstNodeType } from '../../../generated/Es2pandaEnums'; +import { ArrayExpression, Expression } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function createArrayExpression(elements: readonly Expression[]): ArrayExpression { + return ArrayExpression.create1ArrayExpression(Es2pandaAstNodeType.AST_NODE_TYPE_ARRAY_EXPRESSION, elements, false); +} + +export function updateArrayExpression(original: ArrayExpression, elements: readonly Expression[]): ArrayExpression { + if (isSameNativeObject(original.elements, elements)) { + return original; + } + return updateNodeByNode(createArrayExpression(elements), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/AssignmentExpression.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/AssignmentExpression.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d54e7773a64fe2fea1e74a23e6bbba6d645fa98 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/AssignmentExpression.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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. + */ + +import { AssignmentExpression, Expression } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { Es2pandaAstNodeType, Es2pandaTokenType } from '../../../generated/Es2pandaEnums'; + +export function createAssignmentExpression( + left: Expression | undefined, + right: Expression | undefined, + assignmentOperator: Es2pandaTokenType +): AssignmentExpression { + return AssignmentExpression.create1AssignmentExpression( + Es2pandaAstNodeType.AST_NODE_TYPE_ASSIGNMENT_EXPRESSION, + left, + right, + assignmentOperator + ); +} + +export function updateAssignmentExpression( + original: AssignmentExpression, + left: Expression | undefined, + right: Expression | undefined, + assignmentOperator: Es2pandaTokenType +): AssignmentExpression { + if ( + isSameNativeObject(left, original.left) && + isSameNativeObject(right, original.right) && + isSameNativeObject(assignmentOperator, original.operatorType) + ) { + return original; + } + return updateNodeByNode(createAssignmentExpression(left, right, assignmentOperator), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/BlockStatement.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/BlockStatement.ts new file mode 100644 index 0000000000000000000000000000000000000000..43cc1847d6955a18fbd91fbd4afeb9f2d5009a72 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/BlockStatement.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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. + */ + +import { BlockStatement, Statement } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateBlockStatement(original: BlockStatement, statements: readonly Statement[]): BlockStatement { + if (isSameNativeObject(statements, original.statements)) { + return original; + } + return updateNodeByNode(BlockStatement.createBlockStatement(statements), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/CallExpression.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/CallExpression.ts new file mode 100644 index 0000000000000000000000000000000000000000..eec68992be165b06d4e177f0e2e8941d9b02491f --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/CallExpression.ts @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 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. + */ + +import { BlockStatement, CallExpression, Expression, TSTypeParameterInstantiation } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateCallExpression( + original: CallExpression, + callee: Expression | undefined, + _arguments: readonly Expression[], + typeParams: TSTypeParameterInstantiation | undefined, + optional_arg: boolean = false, + trailingComma: boolean = false, + trailingBlock: BlockStatement | undefined = undefined +): CallExpression { + if ( + isSameNativeObject(callee, original.callee) && + isSameNativeObject(_arguments, original.arguments) && + isSameNativeObject(typeParams, original.typeParams) && + isSameNativeObject(optional_arg, original.isOptional) && + isSameNativeObject(trailingComma, original.hasTrailingComma) && + isSameNativeObject(trailingBlock, original.trailingBlock) + ) { + return original; + } + return updateNodeByNode( + CallExpression.createCallExpression(callee, _arguments, typeParams, optional_arg, trailingComma, trailingBlock), + original + ); +} + +export function inplaceUpdateCallExpression( + original: CallExpression, + callee: Expression | undefined, + _arguments: readonly Expression[], + typeParams: TSTypeParameterInstantiation | undefined, + optional_arg: boolean = false, + trailingComma: boolean = false, + trailingBlock: BlockStatement | undefined = undefined +) { + if ( + !isSameNativeObject(optional_arg, original.isOptional) || + !isSameNativeObject(trailingComma, original.hasTrailingComma) + ) { + // unlikely + console.log(`Did not managed to update call expression ${callee?.dumpSrc()} inplace!`); + const result = CallExpression.createCallExpression( + callee, + _arguments, + typeParams, + optional_arg, + trailingComma, + trailingBlock + ); + result.onUpdate(original); + return result; + } + original.setCallee(callee); + original.setArguments(_arguments); + original.setTypeParams(typeParams); + original.setTrailingBlock(trailingBlock); + return original; +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ClassDefinition.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ClassDefinition.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c5861846e34f79cf4812348b1e05c235208d59f --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ClassDefinition.ts @@ -0,0 +1,102 @@ +/* + * Copyright (c) 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. + */ + +import { + AnnotationUsage, + ClassDefinition, + Expression, + Identifier, + MethodDefinition, + TSClassImplements, + TSTypeParameterDeclaration, + TSTypeParameterInstantiation, +} from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { AstNode } from '../peers/AstNode'; +import { + Es2pandaClassDefinitionModifiers, + Es2pandaLanguage, + Es2pandaModifierFlags, +} from '../../../generated/Es2pandaEnums'; + +export function createClassDefinition( + ident: Identifier | undefined, + typeParams: TSTypeParameterDeclaration | undefined, + superTypeParams: TSTypeParameterInstantiation | undefined, + _implements: readonly TSClassImplements[], + ctor: MethodDefinition | undefined, + superClass: Expression | undefined, + body: readonly AstNode[], + modifiers: Es2pandaClassDefinitionModifiers, + flags: Es2pandaModifierFlags, + annotations?: readonly AnnotationUsage[] +): ClassDefinition { + return ClassDefinition.create3ClassDefinition( + ident, + typeParams, + superTypeParams, + _implements, + ctor, + superClass, + body, + modifiers, + flags, + Es2pandaLanguage.LANGUAGE_ETS, + annotations + ); +} + +export function updateClassDefinition( + original: ClassDefinition, + ident: Identifier | undefined, + typeParams: TSTypeParameterDeclaration | undefined, + superTypeParams: TSTypeParameterInstantiation | undefined, + _implements: readonly TSClassImplements[], + ctor: MethodDefinition | undefined, + superClass: Expression | undefined, + body: readonly AstNode[], + modifiers: Es2pandaClassDefinitionModifiers, + flags: Es2pandaModifierFlags, + annotations?: readonly AnnotationUsage[] +): ClassDefinition { + if ( + isSameNativeObject(ident, original.ident) && + isSameNativeObject(typeParams, original.typeParams) && + isSameNativeObject(superTypeParams, original.superTypeParams) && + isSameNativeObject(_implements, original.implements) && + isSameNativeObject(ctor, original.ctor) && + isSameNativeObject(superClass, original.super) && + isSameNativeObject(body, original.body) && + isSameNativeObject(modifiers, original.modifiers) && + isSameNativeObject(flags, original.modifierFlags) && + isSameNativeObject(annotations, original.annotations) + ) { + return original; + } + return ClassDefinition.update3ClassDefinition( + original, + ident, + typeParams, + superTypeParams, + _implements, + ctor, + superClass, + body, + modifiers, + flags, + Es2pandaLanguage.LANGUAGE_ETS, + annotations + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ClassProperty.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ClassProperty.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6177cf344ca27b6fb9520c2d9e25f46e47150dd --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ClassProperty.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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. + */ + +import { AnnotationUsage, ClassProperty, Expression, TypeNode } from '../../../generated'; +import { Es2pandaModifierFlags } from '../../../generated/Es2pandaEnums'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateClassProperty( + original: ClassProperty, + key: Expression | undefined, + value: Expression | undefined, + typeAnnotation: TypeNode | undefined, + modifiers: Es2pandaModifierFlags, + isComputed: boolean, + annotations?: readonly AnnotationUsage[] +): ClassProperty { + if ( + isSameNativeObject(key, original.key) && + isSameNativeObject(value, original.value) && + isSameNativeObject(typeAnnotation, original.typeAnnotation) && + isSameNativeObject(modifiers, original.modifierFlags) && + isSameNativeObject(isComputed, original.isComputed) && + isSameNativeObject(annotations, original.annotations) + ) { + return original; + } + return updateNodeByNode( + ClassProperty.createClassProperty(key, value, typeAnnotation, modifiers, isComputed, annotations), + original + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ETSFunctionType.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSFunctionType.ts new file mode 100644 index 0000000000000000000000000000000000000000..e284429480b13fd9ed31a3cd4328b486cb57e170 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSFunctionType.ts @@ -0,0 +1,65 @@ +/* + * Copyright (c) 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. + */ + +import { + AnnotationUsage, + ETSFunctionType, + Expression, + FunctionSignature, + TSTypeParameterDeclaration, + TypeNode, +} from '../../../generated'; +import { Es2pandaScriptFunctionFlags } from '../../../generated/Es2pandaEnums'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function createETSFunctionType( + typeParams: TSTypeParameterDeclaration | undefined, + params: readonly Expression[], + returnTypeAnnotation: TypeNode | undefined, + hasReceiver: boolean, + funcFlags: Es2pandaScriptFunctionFlags, + annotations?: readonly AnnotationUsage[] +): ETSFunctionType { + return ETSFunctionType.createETSFunctionType( + FunctionSignature.createFunctionSignature(typeParams, params, returnTypeAnnotation, hasReceiver), + funcFlags, + annotations + ); +} + +export function updateETSFunctionType( + original: ETSFunctionType, + typeParams: TSTypeParameterDeclaration | undefined, + params: readonly Expression[], + returnTypeAnnotation: TypeNode | undefined, + hasReceiver: boolean, + funcFlags: Es2pandaScriptFunctionFlags, + annotations?: readonly AnnotationUsage[] +): ETSFunctionType { + if ( + isSameNativeObject(typeParams, original.typeParams) && + isSameNativeObject(params, original.params) && + isSameNativeObject(returnTypeAnnotation, original.returnType) && + isSameNativeObject(funcFlags, original.flags) && + isSameNativeObject(annotations, original.annotations) + ) { + return original; + } + return updateNodeByNode( + createETSFunctionType(typeParams, params, returnTypeAnnotation, hasReceiver, funcFlags, annotations), + original + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ETSImportDeclaration.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSImportDeclaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbeba9c1882ef64925ee5dcedb19998831f90f51 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSImportDeclaration.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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. + */ + +import { ETSImportDeclaration, StringLiteral } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { AstNode } from '../peers/AstNode'; +import { Es2pandaImportKinds } from '../../../generated/Es2pandaEnums'; + +export function updateETSImportDeclaration( + original: ETSImportDeclaration, + source: StringLiteral | undefined, + specifiers: readonly AstNode[], + importKind: Es2pandaImportKinds +): ETSImportDeclaration { + if ( + isSameNativeObject(source, original.source) && + isSameNativeObject(specifiers, original.specifiers) + /* no getter for importKind */ + ) { + /* Improve: probably should set importMetadata, but no getter provided yet */ + return original; + } + return updateNodeByNode(ETSImportDeclaration.createETSImportDeclaration(source, specifiers, importKind), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ETSModule.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSModule.ts new file mode 100644 index 0000000000000000000000000000000000000000..0142903d31df59276983cc55978b81de30c1137a --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSModule.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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. + */ + +import { ETSModule, Identifier, Program, Statement } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { Es2pandaLanguage, Es2pandaModuleFlag } from '../../../generated/Es2pandaEnums'; + +export function updateETSModule( + original: ETSModule, + statementList: readonly Statement[], + ident: Identifier | undefined, + flag: Es2pandaModuleFlag, + program?: Program +) { + if ( + isSameNativeObject(statementList, original.statements) && + isSameNativeObject(ident, original.ident) && + isSameNativeObject(flag, original.getNamespaceFlag()) && + isSameNativeObject(program, original.program) + ) { + return original; + } + return updateNodeByNode( + ETSModule.create1ETSModule(statementList, ident, flag, Es2pandaLanguage.LANGUAGE_ETS, program), + original + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ETSParameterExpression.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSParameterExpression.ts new file mode 100644 index 0000000000000000000000000000000000000000..22a4d2444363c71ee877fed5a85b4f37de7ac0e4 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSParameterExpression.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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. + */ + +import { AnnotatedExpression, AnnotationUsage, ETSParameterExpression, Expression, TypeNode } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function createETSParameterExpression( + identOrSpread: AnnotatedExpression | undefined, + isOptional: boolean, + initExpr?: Expression, + annotations?: readonly AnnotationUsage[] +): ETSParameterExpression { + const res = ETSParameterExpression.createETSParameterExpression(identOrSpread, isOptional, annotations); + if (initExpr) { + res.setInitializer(initExpr); + } + return res; +} + +export function updateETSParameterExpression( + original: ETSParameterExpression, + identOrSpread: AnnotatedExpression | undefined, + isOptional: boolean, + initExpr?: Expression, + annotations?: readonly AnnotationUsage[] +): ETSParameterExpression { + if ( + (isSameNativeObject(identOrSpread, original.ident) || + isSameNativeObject(identOrSpread, original.restParameter)) && + isSameNativeObject(isOptional, original.isOptional) && + isSameNativeObject(initExpr, original.initializer) && + isSameNativeObject(annotations, original.annotations) + ) { + return original; + } + return updateNodeByNode(createETSParameterExpression(identOrSpread, isOptional, initExpr, annotations), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ETSStructDeclaration.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSStructDeclaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..0c764fc83c8c8fe5bb102869039339c382cf0259 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSStructDeclaration.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 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. + */ + +import { ClassDefinition, ETSStructDeclaration } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateETSStructDeclaration( + original: ETSStructDeclaration, + def?: ClassDefinition +): ETSStructDeclaration { + if (isSameNativeObject(def, original.definition)) { + return original; + } + return updateNodeByNode(ETSStructDeclaration.createETSStructDeclaration(def), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ETSTuple.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSTuple.ts new file mode 100644 index 0000000000000000000000000000000000000000..9a5090ce6b5a51c50fd00bfeb805281db65ddf39 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ETSTuple.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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. + */ + +import { ETSTuple, TypeNode } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateETSTuple(original: ETSTuple, typeList: readonly TypeNode[]): ETSTuple { + if (isSameNativeObject(typeList, original.tupleTypeAnnotationsList)) { + return original; + } + return updateNodeByNode(ETSTuple.create2ETSTuple(typeList), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/MemberExpression.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/MemberExpression.ts new file mode 100644 index 0000000000000000000000000000000000000000..88cd9b8d062ae62c879e7ca612e5c8a792ac78dc --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/MemberExpression.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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. + */ + +import { Expression, MemberExpression } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { Es2pandaMemberExpressionKind } from '../../../generated/Es2pandaEnums'; + +export function updateMemberExpression( + original: MemberExpression, + object_arg: Expression | undefined, + property: Expression | undefined, + kind: Es2pandaMemberExpressionKind, + computed: boolean, + optional_arg: boolean +): MemberExpression { + if ( + isSameNativeObject(object_arg, original.object) && + isSameNativeObject(property, original.property) && + isSameNativeObject(kind, original.kind) && + isSameNativeObject(computed, original.isComputed) && + isSameNativeObject(optional_arg, original.isOptional) + ) { + return original; + } + return updateNodeByNode( + MemberExpression.createMemberExpression(object_arg, property, kind, computed, optional_arg), + original + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/MethodDefinition.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/MethodDefinition.ts new file mode 100644 index 0000000000000000000000000000000000000000..8aaa406261e6bc227b90d040c9f1206300b7d511 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/MethodDefinition.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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. + */ + +import { Expression, MethodDefinition } from '../../../generated'; +import { Es2pandaMethodDefinitionKind, Es2pandaModifierFlags } from '../../../generated/Es2pandaEnums'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function createMethodDefinition( + kind: Es2pandaMethodDefinitionKind, + key: Expression | undefined, + value: Expression | undefined, + modifiers: Es2pandaModifierFlags, + isComputed: boolean, + overloads?: readonly MethodDefinition[] +): MethodDefinition { + return MethodDefinition.createMethodDefinition(kind, key, value, modifiers, isComputed, overloads); +} + +export function updateMethodDefinition( + original: MethodDefinition, + kind: Es2pandaMethodDefinitionKind, + key: Expression | undefined, + value: Expression | undefined, + modifiers: Es2pandaModifierFlags, + isComputed: boolean, + overloads?: readonly MethodDefinition[] +): MethodDefinition { + if ( + isSameNativeObject(kind, original.kind) && + isSameNativeObject(key, original.key) && + isSameNativeObject(value, original.value) && + isSameNativeObject(modifiers, original.modifierFlags) && + isSameNativeObject(isComputed, original.isComputed) && + isSameNativeObject(overloads, original.overloads) + ) { + return original; + } + return updateNodeByNode(createMethodDefinition(kind, key, value, modifiers, isComputed, overloads), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/NumberLiteral.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/NumberLiteral.ts new file mode 100644 index 0000000000000000000000000000000000000000..147f0106a6b99b13671847a05890042d62aeab2a --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/NumberLiteral.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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. + */ + +import { global } from '../static/global'; +import { NumberLiteral } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { Es2pandaAstNodeType } from '../../../generated/Es2pandaEnums'; + +export function createNumberLiteral(value: number): NumberLiteral { + return new NumberLiteral( + global.es2panda._CreateNumberLiteral(global.context, value), + Es2pandaAstNodeType.AST_NODE_TYPE_NUMBER_LITERAL + ); +} + +export function updateNumberLiteral(original: NumberLiteral, value: number): NumberLiteral { + if (isSameNativeObject(value.toString(), original.str)) { + return original; + } + return updateNodeByNode(createNumberLiteral(value), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ObjectExpression.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ObjectExpression.ts new file mode 100644 index 0000000000000000000000000000000000000000..242058803beda77e840e1ef8cbcfea76cbc7c920 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ObjectExpression.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { ObjectExpression, Expression } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { Es2pandaAstNodeType } from '../../../generated/Es2pandaEnums'; + +export function createObjectExpression( + properties: readonly Expression[], + preferredReturnType?: KNativePointer +): ObjectExpression { + const result = ObjectExpression.createObjectExpression( + Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, + properties, + false // Improve: provide trailingComma value from native module through ObjectExpression? + ); + if (preferredReturnType) { + result.setPreferredTypePointer(preferredReturnType); + } + return result; +} + +export function updateObjectExpression( + original: ObjectExpression, + properties: readonly Expression[], + preferredReturnType?: KNativePointer +): ObjectExpression { + if ( + isSameNativeObject(properties, original.properties) && + preferredReturnType == original.getPreferredTypePointer() + ) { + return original; + } + return updateNodeByNode(createObjectExpression(properties, preferredReturnType), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/OpaqueTypeNode.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/OpaqueTypeNode.ts new file mode 100644 index 0000000000000000000000000000000000000000..da6b13b392b33e659dae17ef96d0dbdff91ea440 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/OpaqueTypeNode.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { global } from '../static/global'; +import { OpaqueTypeNode } from '../../../generated'; +import { Es2pandaAstNodeType } from '../../../generated/Es2pandaEnums'; + +export function createOpaqueTypeNode(typePointer: KNativePointer): OpaqueTypeNode { + return new OpaqueTypeNode( + global.es2panda._Checker_CreateOpaqueTypeNode(global.context, typePointer), + Es2pandaAstNodeType.AST_NODE_TYPE_OPAQUE_TYPE_NODE + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/Program.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/Program.ts new file mode 100644 index 0000000000000000000000000000000000000000..f812f695ed93848a886a31069fe6f3bd7f4c539a --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/Program.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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. + */ + +import { Program } from '../../../generated'; +import { traceGlobal } from '../../tracer'; + +export function dumpProgramInfo(program: Program) { + traceGlobal(() => `Program info:`); + traceGlobal(() => `\tAbsoluteName: ${program.absoluteName}`); + traceGlobal(() => `\tFileName: ${program.fileName}`); + traceGlobal(() => `\tFileNameWithExtension: ${program.fileNameWithExtension}`); + traceGlobal(() => `\tModuleName: ${program.moduleName}`); + traceGlobal(() => `\tModulePrefix: ${program.modulePrefix}`); + traceGlobal(() => `\tRelativeFilePath: ${program.relativeFilePath}`); + traceGlobal(() => `\tResolvedFilePath: ${program.resolvedFilePath}`); + traceGlobal(() => `\tSourceFileFolder: ${program.sourceFileFolder}`); + traceGlobal(() => `\tSourceFilePath: ${program.sourceFilePath}`); +} + +export function dumpProgramSrcFormatted(program: Program, recursive: boolean, withLines: boolean = true) { + const lines = program.ast.dumpSrc(); + console.log(`// file: ${program.absoluteName}`); + if (withLines) { + console.log( + lines + .split('\n') + .map((it, index) => `${`${index + 1}`.padStart(4)} |${it}`) + .join('\n') + ); + } else { + console.log(lines); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/ScriptFunction.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/ScriptFunction.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4682750d516c23286532f61bda3116461b9404b --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/ScriptFunction.ts @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025 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. + */ + +import { + AnnotationUsage, + Expression, + FunctionSignature, + Identifier, + ScriptFunction, + TSTypeParameterDeclaration, + TypeNode, +} from '../../../generated'; +import { AstNode } from '../peers/AstNode'; +import { Es2pandaLanguage, Es2pandaModifierFlags, Es2pandaScriptFunctionFlags } from '../../../generated/Es2pandaEnums'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { KNativePointer } from '@koalaui/interop'; + +export function createScriptFunction( + databody: AstNode | undefined, + typeParams: TSTypeParameterDeclaration | undefined, + params: readonly Expression[], + returnTypeAnnotation: TypeNode | undefined, + hasReceiver: boolean, + datafuncFlags: Es2pandaScriptFunctionFlags, + dataflags: Es2pandaModifierFlags, + ident: Identifier | undefined, + annotations: readonly AnnotationUsage[] | undefined, + signaturePointer?: KNativePointer, + preferredReturnTypePointer?: KNativePointer +) { + const res = ScriptFunction.create1ScriptFunction( + databody, + FunctionSignature.createFunctionSignature(typeParams, params, returnTypeAnnotation, hasReceiver), + datafuncFlags, + dataflags, + Es2pandaLanguage.LANGUAGE_ETS, + ident, + annotations + ); + if (signaturePointer) { + res.setSignaturePointer(signaturePointer); + } + if (preferredReturnTypePointer) { + res.setPreferredReturnTypePointer(preferredReturnTypePointer); + } + return res; +} + +export function updateScriptFunction( + original: ScriptFunction, + databody: AstNode | undefined, + typeParams: TSTypeParameterDeclaration | undefined, + params: readonly Expression[], + returnTypeAnnotation: TypeNode | undefined, + hasReceiver: boolean, + datafuncFlags: Es2pandaScriptFunctionFlags, + dataflags: Es2pandaModifierFlags, + ident: Identifier | undefined, + annotations: readonly AnnotationUsage[] | undefined, + signaturePointer?: KNativePointer, + preferredReturnTypePointer?: KNativePointer +) { + if ( + isSameNativeObject(databody, original.body) && + isSameNativeObject(typeParams, original.typeParams) && + isSameNativeObject(params, original.params) && + isSameNativeObject(returnTypeAnnotation, original.returnTypeAnnotation) && + isSameNativeObject(hasReceiver, original.hasReceiver) && + isSameNativeObject(datafuncFlags, original.flags) && + isSameNativeObject(dataflags, original.modifierFlags) && + isSameNativeObject(ident, original.id) && + isSameNativeObject(annotations, original.annotations) && + signaturePointer == original.getSignaturePointer() && + preferredReturnTypePointer == original.getPreferredReturnTypePointer() + ) { + return original; + } + return updateNodeByNode( + createScriptFunction( + databody, + typeParams, + params, + returnTypeAnnotation, + hasReceiver, + datafuncFlags, + dataflags, + ident, + annotations, + signaturePointer, + preferredReturnTypePointer + ), + original + ); +} + +export function inplaceUpdateScriptFunction( + original: ScriptFunction, + databody: AstNode | undefined, + typeParams: TSTypeParameterDeclaration | undefined, + params: readonly Expression[], + returnTypeAnnotation: TypeNode | undefined, + hasReceiver: boolean, + datafuncFlags: Es2pandaScriptFunctionFlags, + dataflags: Es2pandaModifierFlags, + ident: Identifier | undefined, + annotations: readonly AnnotationUsage[] | undefined, + signaturePointer?: KNativePointer, + preferredReturnTypePointer?: KNativePointer +) { + if ( + !isSameNativeObject(typeParams, original.typeParams) || + !isSameNativeObject(hasReceiver, original.hasReceiver) || + !isSameNativeObject(datafuncFlags, original.flags) + ) { + // unlikely + console.log(`Did not managed to update script function ${ident?.name} inplace!`); + const result = createScriptFunction( + databody, + typeParams, + params, + returnTypeAnnotation, + hasReceiver, + datafuncFlags, + dataflags, + ident, + annotations, + signaturePointer, + preferredReturnTypePointer + ); + result.onUpdate(original); + return result; + } + original.setBody(databody); + original.setParams(params); + original.setReturnTypeAnnotation(returnTypeAnnotation); + original.modifierFlags = dataflags; + if (ident) original.setIdent(ident); + if (annotations) original.setAnnotations(annotations); + if (signaturePointer) original.setSignaturePointer(signaturePointer); + if (preferredReturnTypePointer) original.setPreferredReturnTypePointer(preferredReturnTypePointer); + return original; +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/TSInterfaceDeclaration.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/TSInterfaceDeclaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb0d5c686bb965c29ceb9bdc32016893f3737e92 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/TSInterfaceDeclaration.ts @@ -0,0 +1,68 @@ +/* + * Copyright (c) 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. + */ + +import { TSInterfaceDeclaration, TSInterfaceHeritage } from '../../../generated'; +import { Es2pandaLanguage, Es2pandaModifierFlags } from '../../../generated/Es2pandaEnums'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; +import { AstNode } from '../peers/AstNode'; + +export function createTSInterfaceDeclaration( + _extends: readonly TSInterfaceHeritage[], + id: AstNode | undefined, + typeParams: AstNode | undefined, + body: AstNode | undefined, + isStatic: boolean, + isExternal: boolean, + modifierFlags?: Es2pandaModifierFlags +): TSInterfaceDeclaration { + return TSInterfaceDeclaration.create1TSInterfaceDeclaration( + _extends, + id, + typeParams, + body, + isStatic, + isExternal, + Es2pandaLanguage.LANGUAGE_ETS, + modifierFlags + ); +} + +export function updateTSInterfaceDeclaration( + original: TSInterfaceDeclaration, + _extends: readonly TSInterfaceHeritage[], + id: AstNode | undefined, + typeParams: AstNode | undefined, + body: AstNode | undefined, + isStatic: boolean, + isExternal: boolean, + modifierFlags?: Es2pandaModifierFlags +): TSInterfaceDeclaration { + if ( + isSameNativeObject(_extends, original.extends) && + isSameNativeObject(id, original.id) && + isSameNativeObject(typeParams, original.typeParams) && + isSameNativeObject(body, original.body) && + isSameNativeObject(isStatic, original.isStatic) && + isSameNativeObject(isExternal, original.isFromExternal) && + isSameNativeObject(modifierFlags, original.modifierFlags) + ) { + return original; + } + return updateNodeByNode( + createTSInterfaceDeclaration(_extends, id, typeParams, body, isStatic, isExternal, modifierFlags), + original + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/TSTypeParameter.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/TSTypeParameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea3737498be0df13ef05f60b3d5f621b68c0b754 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/TSTypeParameter.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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. + */ + +import { Identifier, TSTypeParameter, TypeNode } from '../../../generated'; +import { Es2pandaModifierFlags } from '../../../generated/Es2pandaEnums'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateTSTypeParameter( + original: TSTypeParameter, + name: Identifier | undefined, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + flags: Es2pandaModifierFlags +): TSTypeParameter { + if ( + isSameNativeObject(name, original.name) && + isSameNativeObject(constraint, original.constraint) && + isSameNativeObject(defaultType, original.defaultType) && + isSameNativeObject(flags, original.modifierFlags) + ) { + return original; + } + return updateNodeByNode(TSTypeParameter.create1TSTypeParameter(name, constraint, defaultType, flags), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/TSTypeReferencePart.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/TSTypeReferencePart.ts new file mode 100644 index 0000000000000000000000000000000000000000..ebd0a84ce2c13e736d084c84795705bf99c2947b --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/TSTypeReferencePart.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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. + */ + +import { ETSTypeReferencePart, Expression, TSTypeParameterInstantiation } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateETSTypeReferencePart( + original: ETSTypeReferencePart, + name?: Expression, + typeParams?: TSTypeParameterInstantiation, + prev?: ETSTypeReferencePart +): ETSTypeReferencePart { + if ( + isSameNativeObject(name, original.name) && + isSameNativeObject(typeParams, original.typeParams) && + isSameNativeObject(prev, original.previous) + ) { + return original; + } + return updateNodeByNode(ETSTypeReferencePart.createETSTypeReferencePart(name, typeParams, prev), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/TryStatement.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/TryStatement.ts new file mode 100644 index 0000000000000000000000000000000000000000..23add784536f48cf68e584e7b65ab871cca46459 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/TryStatement.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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. + */ + +import { BlockStatement, CatchClause, LabelPair, Statement, TryStatement } from '../../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateTryStatement( + original: TryStatement, + block: BlockStatement | undefined, + catchClauses: readonly CatchClause[], + finalizer: BlockStatement | undefined, + finalizerInsertionsLabelPair: readonly LabelPair[], + finalizerInsertionsStatement: readonly Statement[] +): TryStatement { + if ( + isSameNativeObject(block, original.block) && + isSameNativeObject(catchClauses, original.catchClauses) && + isSameNativeObject(finalizer, original.finallyBlock) + ) { + return original; + } + return updateNodeByNode( + TryStatement.createTryStatement( + block, + catchClauses, + finalizer, + finalizerInsertionsLabelPair, + finalizerInsertionsStatement + ), + original + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/node-utilities/VariableDeclarator.ts b/ets1.2/libarkts/src/arkts-api/node-utilities/VariableDeclarator.ts new file mode 100644 index 0000000000000000000000000000000000000000..d31bb5d9349aa3943800fac765ac4c19628c848a --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/node-utilities/VariableDeclarator.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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. + */ + +import { Expression, VariableDeclarator } from '../../../generated'; +import { Es2pandaVariableDeclaratorFlag } from '../../../generated/Es2pandaEnums'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { updateNodeByNode } from '../utilities/private'; + +export function updateVariableDeclarator( + original: VariableDeclarator, + flag: Es2pandaVariableDeclaratorFlag, + ident?: Expression, + init?: Expression +): VariableDeclarator { + if ( + isSameNativeObject(flag, original.flag) && + isSameNativeObject(ident, original.id) && + isSameNativeObject(init, original.init) + ) { + return original; + } + return updateNodeByNode(VariableDeclarator.create1VariableDeclarator(flag, ident, init), original); +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/ArktsObject.ts b/ets1.2/libarkts/src/arkts-api/peers/ArktsObject.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5f3982ebd01ffc0b8127a0c4e97f299c0fc7659 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/ArktsObject.ts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 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. + */ + +import { KNativePointer } from '@koalaui/interop'; + +export abstract class ArktsObject { + protected constructor(peer: KNativePointer) { + this.peer = peer; + } + + peer: KNativePointer; + + public onUpdate(node: ArktsObject) {} +} + +export function isSameNativeObject( + first: T | readonly T[], + second: T | readonly T[] +): boolean { + if (Array.isArray(first) && Array.isArray(second)) { + if (first.length !== second.length) { + return false; + } + for (let i = 0; i < first.length; i++) { + if (!isSameNativeObject(first[i], second[i])) { + return false; + } + } + return true; + } + if (first instanceof ArktsObject && second instanceof ArktsObject) { + return first?.peer === second?.peer; + } + return first === second; +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/AstNode.ts b/ets1.2/libarkts/src/arkts-api/peers/AstNode.ts new file mode 100644 index 0000000000000000000000000000000000000000..350d9b51e5d4ff3f28461df703117794174e2a6d --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/AstNode.ts @@ -0,0 +1,197 @@ +/* + * Copyright (c) 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. + */ + +import { isNullPtr, KInt, KNativePointer, nullptr } from '@koalaui/interop'; +import { global } from '../static/global'; +import { allFlags, unpackNode, unpackNodeArray, unpackNonNullableNode, unpackString } from '../utilities/private'; +import { throwError } from '../../utils'; +import { Es2pandaAstNodeType, Es2pandaModifierFlags } from '../../../generated/Es2pandaEnums'; +import { ArktsObject } from './ArktsObject'; +import { SourcePosition } from '../../../generated/peers/SourcePosition'; +import { NodeCache } from '../node-cache'; + +export abstract class AstNode extends ArktsObject { + public readonly astNodeType: Es2pandaAstNodeType; + + protected constructor(peer: KNativePointer, astNodeType: Es2pandaAstNodeType) { + global.profiler.nodeCreated(); + if (isNullPtr(peer)) { + throwError(`attempted to create AstNode from nullptr`); + } + super(peer); + this.astNodeType = astNodeType; + NodeCache.addToCache(peer, this); + } + + public get originalPeer(): KNativePointer { + const result = global.generatedEs2panda._AstNodeOriginalNodeConst(global.context, this.peer); + if (result === nullptr) { + this.originalPeer = this.peer; + return this.peer; + } + return result; + } + + public set originalPeer(peer: KNativePointer) { + global.generatedEs2panda._AstNodeSetOriginalNode(global.context, this.peer, peer); + } + + public get original(): this { + return unpackNonNullableNode(this.originalPeer); + } + + public getChildren(): readonly AstNode[] { + return unpackNodeArray(global.es2panda._AstNodeChildren(global.context, this.peer)); + } + + public getSubtree(): readonly AstNode[] { + return this.getChildren().reduce( + (prev: readonly AstNode[], curr) => { + return prev.concat(curr.getSubtree()); + }, + [this] + ); + } + + public updateModifiers(modifierFlags: KInt | undefined): this { + global.generatedEs2panda._AstNodeClearModifier(global.context, this.peer, allFlags); + global.generatedEs2panda._AstNodeAddModifier( + global.context, + this.peer, + modifierFlags ?? Es2pandaModifierFlags.MODIFIER_FLAGS_NONE + ); + return this; + } + + public dump(indentation: number = 0): string { + const children = this.getChildren().map((it) => it.dump(indentation + 1)); + const msg = `${indentation}_` + ` ` + this.dumpMessage(); + return '> ' + ' '.repeat(4 * indentation) + msg + '\n' + children.join(''); + } + + protected dumpMessage(): string { + return ``; + } + + public dumpJson(): string { + return unpackString(global.generatedEs2panda._AstNodeDumpJSONConst(global.context, this.peer)); + } + + public dumpSrc(): string { + return unpackString(global.generatedEs2panda._AstNodeDumpEtsSrcConst(global.context, this.peer)); + } + + public dumpModifiers(): string { + return unpackString(global.es2panda._AstNodeDumpModifiers(global.context, this.peer)); + } + + // public clone(): this { + // return unpackNonNullableNode(global.generatedEs2panda._AstNodeClone(global.context, this.peer, this.parent.peer)); + // } + + // public get parent(): AstNode { + // const parent = global.generatedEs2panda._AstNodeParent(global.context, this.peer) + // if (parent === nullptr) { + // throwError(`no parent`) + // } + // return unpackNonNullableNode(parent) + // } + + // public set parent(node: AstNode) { + // global.generatedEs2panda._AstNodeSetParent(global.context, this.peer, node.peer) + // } + + public clone(): this { + const clonedNode = unpackNonNullableNode( + global.generatedEs2panda._AstNodeClone(global.context, this.peer, this.parent?.peer ?? nullptr) + ); + clonedNode.parent = undefined; + return clonedNode as this; + } + + public get parent(): AstNode | undefined { + const parent = global.generatedEs2panda._AstNodeParent(global.context, this.peer); + return unpackNode(parent); + } + + public set parent(node: AstNode | undefined) { + global.generatedEs2panda._AstNodeSetParent(global.context, this.peer, node?.peer ?? nullptr); + } + + public get modifierFlags(): Es2pandaModifierFlags { + return global.generatedEs2panda._AstNodeModifiers(global.context, this.peer); + } + + public set modifierFlags(flags: KInt | undefined) { + global.generatedEs2panda._AstNodeClearModifier(global.context, this.peer, allFlags); + global.generatedEs2panda._AstNodeAddModifier( + global.context, + this.peer, + flags ?? Es2pandaModifierFlags.MODIFIER_FLAGS_NONE + ); + } + + /** @deprecated Use {@link modifierFlags} instead */ + public get modifiers(): KInt { + return this.modifierFlags; + } + + /** @deprecated Use {@link modifierFlags} instead */ + public set modifiers(flags: KInt | undefined) { + this.modifierFlags = flags; + } + + public setChildrenParentPtr(): void { + if (this.peer === nullptr) { + throwError('setChildrenParentPtr called on NULLPTR'); + } + global.es2panda._AstNodeSetChildrenParentPtr(global.context, this.peer); + } + + public override onUpdate(original: AstNode): void { + // Improve: Update modifiers only for specific AST nodes in the generated factory code + this.modifierFlags = original.modifierFlags; + + global.es2panda._AstNodeOnUpdate(global.context, this.peer, original.peer); + } + + public get isExport(): boolean { + return global.generatedEs2panda._AstNodeIsExportedConst(global.context, this.peer); + } + + public get isDefaultExport(): boolean { + return global.generatedEs2panda._AstNodeIsDefaultExportedConst(global.context, this.peer); + } + + public get isStatic(): boolean { + return global.generatedEs2panda._AstNodeIsStaticConst(global.context, this.peer); + } + + public get startPosition(): SourcePosition { + return new SourcePosition(global.generatedEs2panda._AstNodeStartConst(global.context, this.peer)); + } + + public set startPosition(start: SourcePosition) { + global.generatedEs2panda._AstNodeSetStart(global.context, this.peer, start.peer); + } + + public get endPosition(): SourcePosition { + return new SourcePosition(global.generatedEs2panda._AstNodeEndConst(global.context, this.peer)); + } + + public set endPosition(end: SourcePosition) { + global.generatedEs2panda._AstNodeSetEnd(global.context, this.peer, end.peer); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/Config.ts b/ets1.2/libarkts/src/arkts-api/peers/Config.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e3b5906b8bbb8f0edbd6e546c7fe2eb135e4e9d --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/Config.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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. + */ + +import { ArktsObject } from './ArktsObject'; +import { global } from '../static/global'; +import { passStringArray } from '../utilities/private'; +import { KNativePointer, nullptr } from '@koalaui/interop'; +import { Es2pandaCompilationMode } from '../../../generated/Es2pandaEnums'; + +export class Config extends ArktsObject { + constructor(peer: KNativePointer) { + super(peer); + // Improve: wait for getter from api + this.path = ``; + } + + static create(input: readonly string[]): Config { + return new Config(global.es2panda._CreateConfig(input.length, passStringArray(input))); + } + + static createDefault(): Config { + if (global.configIsInitialized()) { + console.warn(`Config already initialized`); + return new Config(global.config); + } + return new Config( + global.es2panda._CreateConfig( + 4, + passStringArray(['', '--arktsconfig', './arktsconfig.json', global.filePath]) + ) + ); + } + + destroy() { + if (this.peer != nullptr) { + global.es2panda._DestroyConfig(this.peer); + this.peer = nullptr; + } + } + + get compilationMode(): Es2pandaCompilationMode { + return global.es2panda._GetCompilationMode(this.peer); + } + + readonly path: string; +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/Context.ts b/ets1.2/libarkts/src/arkts-api/peers/Context.ts new file mode 100644 index 0000000000000000000000000000000000000000..bfc06643e735de2a0109468e2e038f5b0c5ca148 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/Context.ts @@ -0,0 +1,123 @@ +/* + * Copyright (c) 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. + */ + +import { ArktsObject } from './ArktsObject'; +import { Program } from '../../../generated'; +import { global } from '../static/global'; +import { passString, passStringArray } from '../utilities/private'; +import { KNativePointer, nullptr, KBoolean } from '@koalaui/interop'; +import { Config } from './Config'; +import { filterSource, throwError } from '../../utils'; +import { AstNode } from './AstNode'; + +export class Context extends ArktsObject { + constructor(peer: KNativePointer) { + super(peer); + } + + static createFromString(source: string): Context { + if (!global.configIsInitialized()) { + throw new Error(`Config not initialized`); + } + return new Context( + global.es2panda._CreateContextFromString(global.config, passString(source), passString(global.filePath)) + ); + } + + /** @deprecated Use {@link createCacheFromFile} instead */ + static createCacheContextFromFile( + configPtr: KNativePointer, + fileName: string, + globalContextPtr: KNativePointer, + isExternal: KBoolean + ): Context { + return new Context( + global.es2panda._CreateCacheContextFromFile(configPtr, passString(fileName), globalContextPtr, isExternal) + ); + } + + static createFromFile(filePath: string): Context { + return new Context(global.es2panda._CreateContextFromFile(global.config, passString(filePath))); + } + + static createCacheFromFile(filePath: string, config: Config, globalContext: GlobalContext, isExternal: boolean) { + return new Context( + global.es2panda._CreateCacheContextFromFile( + config.peer, + passString(filePath), + globalContext.peer, + isExternal + ) + ); + } + + static createContextGenerateAbcForExternalSourceFiles(filenames: string[]): Context { + if (!global.configIsInitialized()) { + throwError(`Config not initialized`); + } + return new Context( + global.es2panda._CreateContextGenerateAbcForExternalSourceFiles( + global.config, + filenames.length, + passStringArray(filenames) + ) + ); + } + + destroy() { + if (this.peer != nullptr) { + global.es2panda._DestroyContext(this.peer); + this.peer = nullptr; + } + } + + /** @deprecated */ + static destroyAndRecreate(ast: AstNode): Context { + console.log('[TS WRAPPER] DESTROY AND RECREATE'); + const source = filterSource(ast.dumpSrc()); + global.es2panda._DestroyContext(global.context); + global.compilerContext = Context.createFromString(source) as any; // Improve: commonize Context + + return new Context(global.context); + } + + get program(): Program { + return new Program(global.generatedEs2panda._ContextProgram(this.peer)); + } +} + +export class GlobalContext extends ArktsObject { + static create(config: Config, externalFileList: string[]): GlobalContext { + return new GlobalContext( + global.es2panda._CreateGlobalContext( + config.peer, + passStringArray(externalFileList), + externalFileList.length, + false + ) + ); + } + + constructor(peer: KNativePointer) { + super(peer); + } + + destroy() { + if (this.peer != nullptr) { + global.es2panda._DestroyGlobalContext(this.peer); + this.peer = nullptr; + } + } +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/DiagnosticKind.ts b/ets1.2/libarkts/src/arkts-api/peers/DiagnosticKind.ts new file mode 100644 index 0000000000000000000000000000000000000000..f07f50f6a10837d07c2f3f437e5d9146c3c14567 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/DiagnosticKind.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { ArktsObject } from './ArktsObject'; + +export class DiagnosticKind extends ArktsObject { + constructor(peer: KNativePointer) { + super(peer); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/ExternalSource.ts b/ets1.2/libarkts/src/arkts-api/peers/ExternalSource.ts new file mode 100644 index 0000000000000000000000000000000000000000..d597bdaa95708a70e52b9bc602cf6c6a88500fae --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/ExternalSource.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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. + */ + +import { global } from '../static/global'; +import { acceptNativeObjectArrayResult, unpackString } from '../utilities/private'; +import { KNativePointer, nullptr } from '@koalaui/interop'; +import { Program } from '../../../generated'; +import { ArktsObject } from './ArktsObject'; + +export class ExternalSource extends ArktsObject { + constructor(peer: KNativePointer) { + super(peer); + } + + getName(): string { + return unpackString(global.es2panda._ExternalSourceName(this.peer)); + } + + get programs(): Program[] { + return acceptNativeObjectArrayResult( + global.es2panda._ExternalSourcePrograms(this.peer), + (instance: KNativePointer) => new Program(instance) + ); + } + + static instantiate(peer: KNativePointer) { + return new ExternalSource(peer); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/ImportPathManager.ts b/ets1.2/libarkts/src/arkts-api/peers/ImportPathManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7801eeee0526c822b75888bae71de2a1925273b --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/ImportPathManager.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 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. + */ + +import { ArktsObject } from './ArktsObject'; +import { global } from '../static/global'; +import { KNativePointer } from '@koalaui/interop'; + +export class ImportPathManager extends ArktsObject { + constructor(peer: KNativePointer) { + super(peer); + } + + static create(): ImportPathManager { + return new ImportPathManager(global.es2panda._ETSParserGetImportPathManager(global.context)); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/peers/Options.ts b/ets1.2/libarkts/src/arkts-api/peers/Options.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5f628492613fb83913e6a02987a65dcd9ea9662 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/peers/Options.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { ArktsObject } from './ArktsObject'; +import { global } from '../static/global'; +import { Config } from './Config'; +import { ArkTsConfig } from '../../../generated'; + +export class Options extends ArktsObject { + constructor(peer: KNativePointer) { + super(peer); + } + + static createOptions(config: Config) { + return new Options(global.es2panda._ConfigGetOptions(config.peer)); + } + + getArkTsConfig(): ArkTsConfig { + return new ArkTsConfig(global.es2panda._OptionsArkTsConfig(global.context, this.peer)); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/plugins.ts b/ets1.2/libarkts/src/arkts-api/plugins.ts new file mode 100644 index 0000000000000000000000000000000000000000..3afcc8c6fa61d490f18f9e7b331e5f4e0f92eb49 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/plugins.ts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 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. + */ + +import { Es2pandaContextState } from '../../generated/Es2pandaEnums'; +import { ETSModule, Program } from '../../generated'; +import { ExternalSource } from './peers/ExternalSource'; +import { KNativePointer, nullptr } from '@koalaui/interop'; +import { global } from './static/global'; +import { RunTransformerHooks } from '../plugin-utils'; + +export interface CompilationOptions { + readonly isProgramForCodegeneration: boolean; + readonly state: Es2pandaContextState; +} + +export interface DependentModuleConfig { + packageName: string; + moduleName: string; + moduleType: string; + modulePath: string; + sourceRoots: string[]; + entryFile: string; + language: string; + declFilesPath?: string; + dependencies?: string[]; +} + +export interface ProjectConfig { + bundleName: string; + moduleName: string; + cachePath: string; + dependentModuleList: DependentModuleConfig[]; + appResource: string; + rawFileResource: string; + buildLoaderJson: string; + hspResourcesMap: boolean; + compileHar: boolean; + byteCodeHar: boolean; + uiTransformOptimization: boolean; + resetBundleName: boolean; + allowEmptyBundleName: boolean; + moduleType: string; + moduleRootPath: string; + aceModuleJsonPath: string; + ignoreError: boolean; + projectPath: string; + projectRootPath: string; + integratedHsp: boolean; + frameworkMode?: string; +} + +export interface PluginContext { + setParameter(name: string, value: V): void; + parameter(name: string): V | undefined; +} + +export class PluginContextImpl implements PluginContext { + map = new Map(); + + private ast: ETSModule | undefined = undefined; + private projectConfig: ProjectConfig | undefined = undefined; + + parameter(name: string): V | undefined { + return this.map.get(name) as V | undefined; + } + setParameter(name: string, value: V): void { + this.map.set(name, value as object); + } + getContextPtr(): KNativePointer { + return global.compilerContext?.peer ?? nullptr; + } + public setProjectConfig(projectConfig: ProjectConfig): void { + this.projectConfig = projectConfig; + } + + public getProjectConfig(): ProjectConfig | undefined { + return this.projectConfig; + } + /** + * @deprecated + */ + public setArkTSAst(ast: ETSModule): void { + this.ast = ast; + } + + /** + * @deprecated + */ + public getArkTSAst(): ETSModule | undefined { + return this.ast; + } +} + +export type ProgramTransformer = ( + program: Program, + compilationOptions: CompilationOptions, + context: PluginContext +) => void; + +export function defaultFilter(name: string): boolean { + if (name.startsWith('std.')) return false; + if (name.startsWith('escompat')) return false; + return true; +} + +export function listPrograms(program: Program, filter: (name: string) => boolean = defaultFilter): Program[] { + return [ + program, + ...program.getExternalSources().flatMap((it: ExternalSource): Program[] => { + if (filter(it.getName())) { + return it.programs; + } + return []; + }), + ]; +} + +export interface PluginEntry { + name?: string; + parsed?: (hooks?: RunTransformerHooks) => void; + checked?: (hooks?: RunTransformerHooks) => void; + clean?: (hooks?: RunTransformerHooks) => void; +} + +export type PluginInitializer = (parsedJson?: object, checkedJson?: object) => PluginEntry; diff --git a/ets1.2/libarkts/src/arkts-api/static/global.ts b/ets1.2/libarkts/src/arkts-api/static/global.ts new file mode 100644 index 0000000000000000000000000000000000000000..a39b36a5716e188719349b91def00be96b512223 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/static/global.ts @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { throwError } from '../../utils'; +import { KNativePointer, nullptr } from '@koalaui/interop'; +import { initEs2panda, Es2pandaNativeModule, initGeneratedEs2panda } from '../../Es2pandaNativeModule'; +import { Es2pandaNativeModule as GeneratedEs2pandaNativeModule } from '../../../generated/Es2pandaNativeModule'; +import { initInterop, InteropNativeModule } from '../../InteropNativeModule'; +import { Context } from '../peers/Context'; +import { Profiler } from './profiler'; +import { ArkTsConfig } from '../../../generated'; +import { Config } from '../peers/Config'; + +export class UpdateTracker { + stack: boolean[] = []; + + push() { + this.stack.push(false); + } + + update() { + this.stack[this.stack.length - 1] = true; + } + + check() { + return this.stack.pop(); + } +} + +export class global { + public static filePath: string = './plugins/input/main.ets'; + + public static arktsconfig?: ArkTsConfig; + public static configObj?: Config; + + private static _config?: KNativePointer; + public static set config(config: KNativePointer) { + global._config = config; + global.configObj = new Config(global._config); + } + public static get config(): KNativePointer { + return global._config ?? throwError('Global.config not initialized'); + } + public static configIsInitialized(): boolean { + return global._config !== undefined && global._config !== nullptr; + } + public static resetConfig(): void { + global._config = undefined; + global.configObj = undefined; + } + + // Improve: rename to contextPeer + public static get context(): KNativePointer { + return global.compilerContext?.peer ?? throwError('Global.context not initialized'); + } + + // Improve: rename to context when the pointer valued one is eliminated + public static compilerContext: Context | undefined; + public static isContextGenerateAbcForExternalSourceFiles: boolean = false; + + private static _es2panda: Es2pandaNativeModule | undefined = undefined; + public static get es2panda(): Es2pandaNativeModule { + if (this._es2panda === undefined) { + this._es2panda = initEs2panda(); + } + return this._es2panda; + } + + private static _generatedEs2panda: GeneratedEs2pandaNativeModule | undefined = undefined; + public static get generatedEs2panda(): GeneratedEs2pandaNativeModule { + if (this._generatedEs2panda === undefined) { + this._generatedEs2panda = initGeneratedEs2panda(); + } + return this._generatedEs2panda; + } + + private static _interop: InteropNativeModule | undefined = undefined; + public static get interop(): InteropNativeModule { + if (this._interop === undefined) this._interop = initInterop(); + return this._interop; + } + + public static profiler = new Profiler(); + + // Check node type values during node creation + public static validatePeerTypes = false; + + public static clearContext(): void { + global.compilerContext = undefined; + } + + // Keep track of update info to optimize performance + public static updateTracker: UpdateTracker = new UpdateTracker(); +} diff --git a/ets1.2/libarkts/src/arkts-api/static/globalUtils.ts b/ets1.2/libarkts/src/arkts-api/static/globalUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ab8559f2ab43e5ab8f3dddda983695c728d05b3 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/static/globalUtils.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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. + */ + +import { KNativePointer } from '@koalaui/interop'; +import { Context } from '../peers/Context'; +import { global } from './global'; +import { NodeCache } from '../node-cache'; + +export function getOrUpdateGlobalContext(peer: KNativePointer): Context { + if (!global.compilerContext || global.context !== peer) { + NodeCache.clear(); + global.compilerContext = new Context(peer); + } + return global.compilerContext; +} diff --git a/ets1.2/libarkts/src/arkts-api/static/profiler.ts b/ets1.2/libarkts/src/arkts-api/static/profiler.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b4191258264482d9b1697349110e00c8455a21c --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/static/profiler.ts @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import { Es2pandaContextState } from '../../../generated/Es2pandaEnums'; +import { global } from './global'; + +const PERFORMANCE_DATA_DIR = './performance-results/'; + +interface PluginData { + transformTime: number; + transformTimeDeps: number; + visitedNodes: number; + createdNodes: number; + contextState?: Es2pandaContextState; +} + +function emptyPluginData(contextState?: Es2pandaContextState): PluginData { + return { + transformTime: 0, + transformTimeDeps: 0, + visitedNodes: 0, + createdNodes: 0, + contextState: contextState, + }; +} + +interface PerformanceData { + filePath: string; + + visitedNodes: number; + createdNodes: number; + proceedTime: number; + totalTime: number; + + pluginsByName: Record; +} + +interface PerformanceDataFile { + data: PerformanceData[]; + summary?: PerformanceData; +} + +function parseFile(performanceFile: string): PerformanceDataFile | undefined { + if (!fs.existsSync(performanceFile)) return undefined; + + const data = fs.readFileSync(path.resolve(performanceFile)).toString(); + if (!data.length) return undefined; + return JSON.parse(data) as PerformanceDataFile; +} + +export class Profiler implements PerformanceData { + filePath: string = ''; + visitedNodes: number = 0; + createdNodes: number = 0; + proceedTime: number = 0; + totalTime: number = 0; + pluginsByName: Record = {}; + + curPlugin: string = ''; + curContextState?: Es2pandaContextState; + + private getPluginData(pluginName: string, contextState?: Es2pandaContextState): PluginData { + if (!(pluginName in this.pluginsByName)) { + this.pluginsByName[pluginName] = emptyPluginData(contextState); + } + return this.pluginsByName[pluginName]; + } + + disableReport = false; + + nodeCreated() { + this.createdNodes++; + if (this.curPlugin) this.getPluginData(this.curPlugin, this.curContextState).createdNodes++; + } + + nodeVisited() { + this.visitedNodes++; + if (this.curPlugin) this.getPluginData(this.curPlugin, this.curContextState).visitedNodes++; + } + + private transformStartTime = 0; + transformStarted(): void { + this.transformStartTime = Date.now(); + } + private transformDepStartTime = 0; + transformDepStarted(): void { + this.transformDepStartTime = Date.now(); + } + + transformEnded(state: Es2pandaContextState, pluginName: string): void { + const transformEndTime = Date.now(); + const consumedTime = transformEndTime - this.transformStartTime; + this.getPluginData(pluginName, state).transformTime += consumedTime; + } + + transformDepEnded(state: Es2pandaContextState, pluginName: string): void { + const transformEndTime = Date.now(); + const consumedTime = transformEndTime - this.transformDepStartTime; + this.getPluginData(pluginName, state).transformTimeDeps += consumedTime; + } + + proceededToState(consumedTime: number) { + this.proceedTime += consumedTime; + } + + private compilationStartTime = 0; + compilationStarted(filePath: string) { + this.filePath = filePath; + + this.visitedNodes = 0; + this.createdNodes = 0; + this.proceedTime = 0; + this.totalTime = 0; + this.pluginsByName = {}; + + this.curPlugin = ''; + this.compilationStartTime = Date.now(); + } + + compilationEnded() { + const consumedTime: number = Date.now() - this.compilationStartTime; + this.totalTime = consumedTime; + } + + report() { + Object.entries(this.pluginsByName).forEach((data, key) => { + console.log(data[0], 'totalTransformTime =', data[1].transformTime, 'ms'); + console.log(data[0], 'totalDepsTransformTime =', data[1].transformTimeDeps, 'ms'); + }); + } + + reportToFile(withSummary: boolean = false) { + if (this.disableReport) return; + const outDir = path.resolve(global.arktsconfig!.outDir, PERFORMANCE_DATA_DIR); + fs.mkdirSync(outDir, { recursive: true }); + const outFilePath = path.resolve(outDir, path.basename(this.filePath)) + '.json'; + + const data: PerformanceDataFile = { data: [this as PerformanceData] }; + if (!fs.existsSync(outFilePath)) { + fs.writeFileSync(outFilePath, JSON.stringify(data)); + } else { + const savedData: PerformanceDataFile | undefined = parseFile(outFilePath) ?? data; + savedData.data.push(this as PerformanceData); + + if (withSummary) { + const summary: PerformanceData = { + filePath: this.filePath, + visitedNodes: savedData.data.map((it) => it.visitedNodes).reduce((sum, it) => sum + it), + createdNodes: savedData.data.map((it) => it.createdNodes).reduce((sum, it) => sum + it), + proceedTime: savedData.data.map((it) => it.proceedTime).reduce((sum, it) => sum + it), + totalTime: savedData.data.map((it) => it.totalTime).reduce((sum, it) => sum + it), + pluginsByName: {}, + }; + const pluginNames = new Set(savedData.data.flatMap((it) => Object.keys(it.pluginsByName))); + for (const pluginName of pluginNames) { + const sumTransformTime = savedData.data + .map((it) => it.pluginsByName) + .filter((it) => !!it[pluginName]) + .map((it) => it[pluginName].transformTime) + .reduce((sum, it) => sum + it); + const sumTransformTimeDeps = savedData.data + .map((it) => it.pluginsByName) + .filter((it) => !!it[pluginName]) + .map((it) => it[pluginName].transformTimeDeps) + .reduce((sum, it) => sum + it); + const sumCreatedNodes = savedData.data + .map((it) => it.pluginsByName) + .filter((it) => !!it[pluginName]) + .map((it) => it[pluginName].createdNodes) + .reduce((sum, it) => sum + it); + const sumVisitedNodes = savedData.data + .map((it) => it.pluginsByName) + .filter((it) => !!it[pluginName]) + .map((it) => it[pluginName].visitedNodes) + .reduce((sum, it) => sum + it); + + summary.pluginsByName[pluginName] = { + transformTime: sumTransformTime, + transformTimeDeps: sumTransformTimeDeps, + createdNodes: sumCreatedNodes, + visitedNodes: sumVisitedNodes, + }; + } + + savedData.summary = summary; + } + + fs.writeFileSync(outFilePath, JSON.stringify(savedData)); + } + } +} diff --git a/ets1.2/libarkts/src/arkts-api/utilities/extensions.ts b/ets1.2/libarkts/src/arkts-api/utilities/extensions.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5d688ab04b80be4f91af151dc87fecc455a241e --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/utilities/extensions.ts @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { KNativePointer, KUInt } from '@koalaui/interop'; +import type { + ClassDefinition, + ETSFunctionType, + ETSModule, + ETSParameterExpression, + Expression, + MethodDefinition, + NumberLiteral, + Program, + ScriptFunction, + SourcePosition, +} from '../../../generated'; +import { ExternalSource } from '../peers/ExternalSource'; +import { Es2pandaAstNodeType, Es2pandaModuleFlag } from '../../../generated/Es2pandaEnums'; +import { global } from '../static/global'; +import { acceptNativeObjectArrayResult, passNodeArray, unpackNodeArray, unpackNonNullableNode } from './private'; +import type { AstNode } from '../peers/AstNode'; + +export function extension_ETSModuleGetNamespaceFlag(this: ETSModule): Es2pandaModuleFlag { + return ( + (this.isETSScript ? Es2pandaModuleFlag.MODULE_FLAG_ETSSCRIPT : 0) + + (this.isNamespace ? Es2pandaModuleFlag.MODULE_FLAG_NAMESPACE : 0) + + (this.isNamespaceChainLastNode ? Es2pandaModuleFlag.MODULE_FLAG_NAMESPACE_CHAIN_LAST_NODE : 0) + ); +} + +// this is a workaround for overloads not included in children list +export function extension_MethodDefinitionSetChildrenParentPtr(this: MethodDefinition) { + global.es2panda._AstNodeSetChildrenParentPtr(global.context, this.peer); + const overloads = this.overloads; + for (const overload of overloads) { + overload.setBaseOverloadMethod(this); + overload.parent = this; // overloads are not listed as children in native + } +} + +export function extension_MethodDefinitionOnUpdate(this: MethodDefinition, original: MethodDefinition): void { + this.setChildrenParentPtr(); + global.es2panda._AstNodeOnUpdate(global.context, this.peer, original.peer); + const originalBase = original.baseOverloadMethod; + if (originalBase) { + this.setBaseOverloadMethod(originalBase); + } +} + +// Improve: generate checker related stuff +export function extension_ScriptFunctionGetSignaturePointer(this: ScriptFunction): KNativePointer { + return global.es2panda._Checker_ScriptFunctionSignature(global.context, this.peer); +} + +export function extension_ScriptFunctionSetSignaturePointer( + this: ScriptFunction, + signaturePointer: KNativePointer +): void { + global.es2panda._Checker_ScriptFunctionSetSignature(global.context, this.peer, signaturePointer); +} + +// Improve: weird API +export function extension_ScriptFunctionGetParamsCasted(this: ScriptFunction): readonly ETSParameterExpression[] { + return unpackNodeArray( + global.generatedEs2panda._ScriptFunctionParams(global.context, this.peer), + Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PARAMETER_EXPRESSION + ); +} + +// Improve: perhaps "preferredReturnType" stuff can be removed later if "signature" is always enough +export function extension_ScriptFunctionGetPreferredReturnTypePointer(this: ScriptFunction): KNativePointer { + return global.es2panda._Checker_ScriptFunctionGetPreferredReturnType(global.context, this.peer); +} + +export function extension_ScriptFunctionSetPreferredReturnTypePointer( + this: ScriptFunction, + typePointer: KNativePointer +): void { + global.es2panda._Checker_ScriptFunctionSetPreferredReturnType(global.context, this.peer, typePointer); +} + +// Improve: generate checker related stuff +export function extension_ExpressionGetPreferredTypePointer(this: Expression): KNativePointer { + return global.es2panda._Checker_ExpressionGetPreferredType(global.context, this.peer); +} + +export function extension_ExpressionSetPreferredTypePointer(this: Expression, typePointer: KNativePointer): void { + global.es2panda._Checker_ExpressionSetPreferredType(global.context, this.peer, typePointer); +} + +// Improve: weird API +export function extension_ProgramGetAstCasted(this: Program): ETSModule { + return unpackNonNullableNode( + global.generatedEs2panda._ProgramAst(global.context, this.peer), + Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE + ); +} + +// Improve: generate methods with string[] args or return type +export function extension_ProgramGetExternalSources(this: Program): ExternalSource[] { + return acceptNativeObjectArrayResult( + global.es2panda._ProgramExternalSources(global.context, this.peer), + ExternalSource.instantiate + ); +} + +// Improve: SourcePositionLine is global in idl +export function extension_SourcePositionGetLine(this: SourcePosition): KUInt { + return global.generatedEs2panda._SourcePositionLine(global.context, this.peer); +} + +// Improve: SourcePositionCol is not described in idl +export function extension_SourcePositionGetCol(this: SourcePosition): KUInt { + return global.es2panda._SourcePositionCol(global.context, this.peer); +} + +// Improve: SourcePositionIndex is global in idl +export function extension_SourcePositionGetIndex(this: SourcePosition): KUInt { + return global.generatedEs2panda._SourcePositionIndex(global.context, this.peer); +} + +export function extension_SourcePositionToString(this: SourcePosition): string { + return `:${this.getLine() + 1}:${this.getCol()}`; +} + +// Improve: weird API +export function extension_NumberLiteralValue(this: NumberLiteral): number { + return +this.dumpSrc(); +} + +// Improve: weird API +export function extension_ClassDefinitionSetBody(this: ClassDefinition, body: readonly AstNode[]): void { + global.es2panda._ClassDefinitionSetBody(global.context, this.peer, passNodeArray(body), body.length); +} + +// Improve: weird API +export function extension_ETSFunctionTypeGetParamsCasted(this: ETSFunctionType): readonly ETSParameterExpression[] { + return unpackNodeArray( + global.generatedEs2panda._ETSFunctionTypeParamsConst(global.context, this.peer), + Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PARAMETER_EXPRESSION + ); +} diff --git a/ets1.2/libarkts/src/arkts-api/utilities/nativePtrDecoder.ts b/ets1.2/libarkts/src/arkts-api/utilities/nativePtrDecoder.ts new file mode 100644 index 0000000000000000000000000000000000000000..bec618505320708ead43d9732de06d63a19a697a --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/utilities/nativePtrDecoder.ts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { int32 } from '@koalaui/common'; +import { + Access, + ArrayDecoder, + CallbackRegistry, + NativeStringBase, + nullptr, + pointer, + providePlatformDefinedData, + withByteArray, +} from '@koalaui/interop'; +import { global } from '../static/global'; + +class NativeString extends NativeStringBase { + constructor(ptr: pointer) { + super(ptr); + } + protected bytesLength(): int32 { + return global.interop._StringLength(this.ptr); + } + protected getData(data: Uint8Array): void { + withByteArray(data, Access.WRITE, (dataPtr: pointer) => { + global.interop._StringData(this.ptr, dataPtr, data.length); + }); + } + close(): void { + global.interop._InvokeFinalizer(this.ptr, global.interop._GetStringFinalizer()); + this.ptr = nullptr; + } +} + +providePlatformDefinedData({ + nativeString(ptr: pointer): NativeStringBase { + return new NativeString(ptr); + }, + nativeStringArrayDecoder(): ArrayDecoder { + throw new Error('Not yet implemented'); + }, + callbackRegistry(): CallbackRegistry | undefined { + return undefined; + }, +}); + +export class NativePtrDecoder extends ArrayDecoder { + getArraySize(blob: pointer) { + return global.interop._GetPtrVectorSize(blob); + } + disposeArray(blob: pointer): void { + // Improve: + } + getArrayElement(blob: pointer, index: int32): pointer { + return global.interop._GetPtrVectorElement(blob, index); + } +} + +// This decoder uses a napi's external buffer and +// it is not efficient for small arraya(guessing, less than 10) +export class OptimizedNativePtrDecoder { + disposeArray(blob: pointer): void { + // Improve: + } + decode(blob: pointer): BigUint64Array { + return global.interop._GetPtrVector(blob); + } + decodeAndCopy(blob: pointer): Array { + const data = global.interop._GetPtrVector(blob); + const result = Array.from(data); + this.disposeArray(blob); + return result; + } +} diff --git a/ets1.2/libarkts/src/arkts-api/utilities/performance.ts b/ets1.2/libarkts/src/arkts-api/utilities/performance.ts new file mode 100644 index 0000000000000000000000000000000000000000..24069abf98f77dd0956dc907645406aff5aa82bf --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/utilities/performance.ts @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import * as process from 'process'; +import { global as localGlobal } from '../static/global'; + +const BYTES_PER_KIBIBYTE = 1024; + +interface MemoryContext { + startTime: number; + startMemory: { + rss: number; + heapTotal: number; + heapUsed: number; + external: number; + arrayBuffers: number; + }; +} + +interface Event { + name: string; + startTime: number; + endTime?: number; + parentEvent?: string; + duration?: number; +} + +function formatTime(ms: number): string { + const milliseconds = Math.floor(ms % 1000); + const seconds = Math.floor((ms / 1000) % 60); + const minutes = Math.floor((ms / (1000 * 60)) % 60); + const hours = Math.floor(ms / (1000 * 60 * 60)); + + return `${pad(hours, 2)}:${pad(minutes, 2)}:${pad(seconds, 2)}:${pad(milliseconds, 3)}`; +} + +function pad(value: number, length: number): string { + return value.toString().padStart(length, '0'); +} + +function round(value: number, index: number = 2): number { + const factor = Math.pow(10, index); + return Math.round(value * factor) / factor; +} + +export class Performance { + private static instance: Performance; + private events: Map; + private historyEvents = new Map(); + private scopes: string[]; + private shouldSkip: boolean; + private totalDuration: number; + private memoryContexts = new Map(); + private memoryTrackerEnable: boolean; + private constructor() { + this.events = new Map(); + this.historyEvents = new Map(); + this.scopes = []; + this.shouldSkip = true; + this.memoryTrackerEnable = false; + this.totalDuration = 0; + } + + public static getInstance(): Performance { + if (!this.instance) { + this.instance = new Performance(); + } + return this.instance; + } + + skip(shouldSkip: boolean = true): void { + this.shouldSkip = shouldSkip; + } + + enableMemoryTracker(enableMemoryTracker: boolean = false): void { + this.memoryTrackerEnable = enableMemoryTracker; + } + + createEvent(name: string): Event { + if (this.shouldSkip) { + return { name: '', startTime: 0 }; + } + const startTime: number = performance.now(); + const newEvent: Event = { name, startTime }; + this.events.set(name, newEvent); + this.scopes.push(name); + return newEvent; + } + + stopEvent(name: string, shouldLog: boolean = false): Event { + if (this.shouldSkip) { + return { name: '', startTime: 0 }; + } + if (!this.events.has(name) || this.scopes.length === 0) { + throw new Error(`Event ${name} is not created.`); + } + if (this.scopes[this.scopes.length - 1] !== name) { + console.warn(`[PERFORMANCE WARNING] Event ${name} early exit.`); + } + this.scopes.pop(); + + const event: Event = this.events.get(name)!; + const endTime: number = performance.now(); + const parentEvent: string = this.scopes[this.scopes.length - 1]; + const duration: number = endTime - event.startTime; + if (!parentEvent) { + this.totalDuration += duration; + } + + if (shouldLog) { + console.log( + `[PERFORMANCE] name: ${event.name}, parent: ${parentEvent}, duration: ${formatTime(duration)}(${round(duration)}), total: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})` + ); + } + + const newEvent = { ...event, endTime, parentEvent, duration }; + const history = this.historyEvents.get(parentEvent ?? null) || []; + this.historyEvents.set(parentEvent ?? null, [...history, newEvent]); + return newEvent; + } + + stopLastEvent(shouldLog: boolean = false): Event { + if (this.shouldSkip) { + return { name: '', startTime: 0 }; + } + if (this.scopes.length === 0) { + throw new Error('No last event'); + } + const name: string = this.scopes.pop()!; + if (!this.events.has(name)) { + throw new Error(`Event ${name} is not created.`); + } + + const event: Event = this.events.get(name)!; + const endTime: number = performance.now(); + const parentEvent: string = this.scopes[this.scopes.length - 1]; + const duration: number = endTime - event.startTime; + if (!parentEvent) { + this.totalDuration += duration; + } + + if (shouldLog) { + console.log( + `[PERFORMANCE] name: ${event.name}, parent: ${parentEvent}, duration: ${formatTime(duration)}(${round(duration)}), total: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})` + ); + } + + const newEvent = { ...event, endTime, parentEvent, duration }; + const history = this.historyEvents.get(parentEvent ?? null) || []; + this.historyEvents.set(parentEvent ?? null, [...history, newEvent]); + return newEvent; + } + + clearAllEvents(shouldLog: boolean = false): void { + if (this.shouldSkip) { + return; + } + for (let i = 0; i < this.scopes.length; i++) { + this.stopLastEvent(shouldLog); + } + this.events = new Map(); + } + + clearTotalDuration(): void { + this.totalDuration = 0; + } + + clearHistory(): void { + this.historyEvents = new Map(); + } + + visualizeEvents(shouldLog: boolean = false): void { + if (this.shouldSkip) { + return; + } + const that = this; + function buildVisualization(parentKey: string | null, indentLevel: number): [string, number] { + const children = that.historyEvents.get(parentKey) || []; + let result = ''; + + children.forEach((child) => { + const indent = ' '.repeat(indentLevel); + const duration = child.duration ?? 0; + const [_result, count] = buildVisualization(child.name, indentLevel + 1); + result += `${indent}- ${child.name}: ${formatTime(duration)}(${round(duration)}), ${count}\n`; + result += _result; + }); + + return [result, children.length]; + } + + const [finalResult, _] = buildVisualization(null, 0); + if (shouldLog) { + console.log(`[PERFORMANCE] ===== FINAL RESULT ====`); + console.log(`TOTAL: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})`); + console.log(finalResult.trimEnd()); + console.log(`[PERFORMANCE] ===== FINAL RESULT ====`); + } + } + + startMemRecord(label: string = `measurement-${Date.now()}`): void { + // 强制进行垃圾回收(需要 Node.js 启动时添加 --expose-gc 参数) + if (!this.memoryTrackerEnable) { + return; + } + if (global.gc) { + (global as any).gc(); + } + const startMemory = process.memoryUsage(); + this.memoryContexts.set(label, { + startTime: Date.now(), + startMemory: { + rss: startMemory.rss / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE), + heapTotal: startMemory.heapTotal / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE), + heapUsed: startMemory.heapUsed / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE), + external: startMemory.external / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE), + arrayBuffers: (startMemory.arrayBuffers || 0) / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE), + }, + }); + + return; + } + + stopMemRecord(label: string = `measurement-${Date.now()}`, runGc: boolean = false): void { + if (!this.memoryTrackerEnable) { + return; + } + const context = this.memoryContexts.get(label); + + if (!context) { + console.error(`未找到标签为 "${label}" 的内存测量上下文`); + return; + } + + // 可选:在测量结束前执行垃圾回收 + if (runGc && global.gc) { + (global as any).gc(); + } + + // 记录结束时的内存使用情况 + const endTime = Date.now(); + const endMemory = process.memoryUsage(); + + // 计算内存使用增量 + const memoryDiff = { + rss: endMemory.rss / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE) - context.startMemory.rss, + heapTotal: endMemory.heapTotal / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE) - context.startMemory.heapTotal, + heapUsed: endMemory.heapUsed / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE) - context.startMemory.heapUsed, + external: endMemory.external / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE) - context.startMemory.external, + arrayBuffers: + (endMemory.arrayBuffers || 0) / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE) - + context.startMemory.arrayBuffers, + }; + const duration = endTime - context.startTime; + + console.log('[PERFORMANCE]', `内存测量结果 [标签: ${label}]`); + console.log('[PERFORMANCE]', `执行时间: ${duration}ms`); + console.log('---------------------------------------------------------------'); + console.log('[PERFORMANCE]', `内存类型 | 开始值(MB) | 结束值(MB) | 增量(MB)`); + console.log('---------------------------------------------------------------'); + console.log( + '[PERFORMANCE]', + `RSS | ${context.startMemory.rss.toFixed(2)} | ${(endMemory.rss / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE)).toFixed(2)} | ${memoryDiff.rss.toFixed(2)}` + ); + console.log( + '[PERFORMANCE]', + `Heap Total | ${context.startMemory.heapTotal.toFixed(2)} | ${(endMemory.heapTotal / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE)).toFixed(2)} | ${memoryDiff.heapTotal.toFixed(2)}` + ); + console.log( + '[PERFORMANCE]', + `Heap Used | ${context.startMemory.heapUsed.toFixed(2)} | ${(endMemory.heapUsed / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE)).toFixed(2)} | ${memoryDiff.heapUsed.toFixed(2)}` + ); + console.log( + '[PERFORMANCE]', + `External | ${context.startMemory.external.toFixed(2)} | ${(endMemory.external / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE)).toFixed(2)} | ${memoryDiff.external.toFixed(2)}` + ); + if (endMemory.arrayBuffers !== undefined) { + console.log( + `Array Buffers | ${context.startMemory.arrayBuffers.toFixed(2)} | ${((endMemory.arrayBuffers || 0) / (BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE)).toFixed(2)} | ${memoryDiff.arrayBuffers.toFixed(2)}` + ); + } + console.log('---------------------------------------------------------------'); + this.memoryContexts.delete(label); + return; + } + + memoryTrackerReset(): void { + if (!this.memoryTrackerEnable) { + return; + } + localGlobal.es2panda._MemoryTrackerReset(localGlobal.context); + } + + memoryTrackerGetDelta(tag: string): void { + if (!this.memoryTrackerEnable) { + return; + } + console.log('---------------------------------------------------------------'); + console.log('[PERFORMANCE] Increamental memory:', tag); + localGlobal.es2panda._MemoryTrackerGetDelta(localGlobal.context); + console.log('---------------------------------------------------------------'); + } + + memoryTrackerPrintCurrent(tag: string): void { + if (!this.memoryTrackerEnable) { + return; + } + console.log('---------------------------------------------------------------'); + console.log('[PERFORMANCE] Current total memory:', tag); + localGlobal.es2panda._MemoryTrackerPrintCurrent(localGlobal.context); + console.log('---------------------------------------------------------------'); + } +} diff --git a/ets1.2/libarkts/src/arkts-api/utilities/private.ts b/ets1.2/libarkts/src/arkts-api/utilities/private.ts new file mode 100644 index 0000000000000000000000000000000000000000..95fe0ce9e783415a149de4dc1684f24d0ccbf612 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/utilities/private.ts @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { global } from '../static/global'; +import { isNumber, throwError } from '../../utils'; +import { KInt, KNativePointer as KPtr, KNativePointer, nullptr, withString, withStringArray } from '@koalaui/interop'; +import { NativePtrDecoder } from './nativePtrDecoder'; +//import { OptimizedNativePtrDecoder as NativePtrDecoder } from "./nativePtrDecoder" +import { + Es2pandaAstNodeType, + Es2pandaModifierFlags, + Es2pandaScriptFunctionFlags, +} from '../../../generated/Es2pandaEnums'; +import { nodeFrom } from '../class-by-peer'; +import { AstNode } from '../peers/AstNode'; +import { ArktsObject } from '../peers/ArktsObject'; + +export const arrayOfNullptr = new BigUint64Array([nullptr]); + +export const allFlags = Object.values(Es2pandaModifierFlags) + .filter(isNumber) + .reduce((prev, next) => prev | next, 0); + +export function assertValidPeer(peer: KPtr, expectedKind: Es2pandaAstNodeType): void { + if (peer === nullptr) { + throwError(`invalid peer`); + } + + if (global.validatePeerTypes) { + const peerType = global.generatedEs2panda._AstNodeTypeConst(global.context, peer); + if ( + peerType === Es2pandaAstNodeType.AST_NODE_TYPE_STRUCT_DECLARATION && + expectedKind === Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION + ) { + // Improve: Struct is a child class of Class + return; + } + if ( + peerType === Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION && + expectedKind === Es2pandaAstNodeType.AST_NODE_TYPE_IMPORT_DECLARATION + ) { + // Improve: ETSImportDeclaration is a child of a ImportDeclaration + return; + } + if ( + peerType === Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE && + expectedKind === Es2pandaAstNodeType.AST_NODE_TYPE_BLOCK_STATEMENT + ) { + // Improve: ETSModule is a child of a BlockStatement + return; + } + if (peerType !== expectedKind) { + throwError(`expected: ${Es2pandaAstNodeType[expectedKind]}, got: ${Es2pandaAstNodeType[peerType]}`); + } + } +} + +export function acceptNativeObjectArrayResult( + arrayObject: KNativePointer, + factory: (instance: KNativePointer) => T +): T[] { + // For OptimizedNativePtrDecoder + //const decoded = new NativePtrDecoder().decode(arrayObject) + //return decoded.reduce((prev, curr) => { + // prev.push(factory(curr)) + // return prev + //}, [] as T[]) + return new NativePtrDecoder().decode(arrayObject).map(factory); +} + +export function unpackNonNullableNode(peer: KNativePointer, typeHint?: Es2pandaAstNodeType): T { + if (peer === nullptr) { + throwError('peer is NULLPTR (maybe you should use unpackNode)'); + } + return nodeFrom(peer, typeHint); +} + +export function unpackNode(peer: KNativePointer, typeHint?: Es2pandaAstNodeType): T | undefined { + if (peer === nullptr) { + return undefined; + } + return nodeFrom(peer, typeHint); +} + +export function passNode(node: ArktsObject | undefined): KNativePointer { + return node?.peer ?? nullptr; +} + +export function unpackNodeArray(nodesPtr: KNativePointer, typeHint?: Es2pandaAstNodeType): T[] { + if (nodesPtr === nullptr) { + return []; + } + // For OptimizedNativePtrDecoder + //const decoded = new NativePtrDecoder().decode(nodesPtr) + //return decoded.reduce((prev, curr) => { + // prev.push(unpackNonNullableNode(curr, typeHint)) + // return prev + //}, [] as T[]) + return new NativePtrDecoder().decode(nodesPtr).map((peer: KNativePointer) => unpackNonNullableNode(peer, typeHint)); +} + +export function passNodeArray(nodes: readonly ArktsObject[] | undefined): BigUint64Array { + return new BigUint64Array(nodes?.filter((it) => it.peer != undefined)?.map((node) => BigInt(node.peer)) ?? []); +} + +export function unpackString(peer: KNativePointer): string { + return global.interop._RawUtf8ToString(peer); +} + +// Improve: use direct string arguments instead. +export function passString(str: string | undefined): string { + return str ?? ''; +} + +// Improve: use direct string arguments instead. +export function passStringArray(strings: readonly string[]): string[] { + return withStringArray(strings, (it: string[]) => it); +} + +export function passNodeWithNewModifiers(node: T, modifiers: KInt): T { + return unpackNonNullableNode(node.peer).updateModifiers(modifiers); +} + +export function scriptFunctionHasBody(peer: KNativePointer): boolean { + const flags = global.generatedEs2panda._ScriptFunctionFlagsConst(global.context, peer); + return ( + (flags & Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_EXTERNAL) === 0 && + (flags & Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_EXTERNAL_OVERLOAD) === 0 + ); +} + +export function updateNodeByNode(node: T, original: T): T { + if (original.peer === nullptr) { + throwError('update called on NULLPTR'); + } + node.onUpdate(original); + return node; +} + +export function nodeType(node: AstNode): Es2pandaAstNodeType { + return global.generatedEs2panda._AstNodeTypeConst(global.context, passNode(node)); +} diff --git a/ets1.2/libarkts/src/arkts-api/utilities/public.ts b/ets1.2/libarkts/src/arkts-api/utilities/public.ts new file mode 100644 index 0000000000000000000000000000000000000000..1858116577e8132b7ca74efc73d3aa1db2df3327 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/utilities/public.ts @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { global } from '../static/global'; +import { isNumber, throwError, withWarning } from '../../utils'; +import { KNativePointer, nullptr, KInt, KUInt } from '@koalaui/interop'; +import { + passNode, + unpackNodeArray, + unpackNonNullableNode, + passString, + unpackString, + passStringArray, + unpackNode, +} from './private'; +import { + Es2pandaContextState, + Es2pandaModifierFlags, + Es2pandaMethodDefinitionKind, + Es2pandaAstNodeType, + Es2pandaPluginDiagnosticType, +} from '../../../generated/Es2pandaEnums'; +import type { AstNode } from '../peers/AstNode'; +import { + DiagnosticInfo, + Identifier, + isConditionalExpression, + SourcePosition, + SourceRange, + SuggestionInfo, + VariableDeclarator, +} from '../../../generated'; +import { + type AnnotationUsage, + ClassDefinition, + ClassProperty, + ETSModule, + isClassDefinition, + isFunctionDeclaration, + isMemberExpression, + isScriptFunction, + isIdentifier, + isETSModule, + Program, + isObjectExpression, + ETSImportDeclaration, + isProperty, + isTSInterfaceDeclaration, + isNumberLiteral, + Property, + MemberExpression, + isMethodDefinition, + TypeNode, +} from '../../../generated'; +import { Config } from '../peers/Config'; +import { Context } from '../peers/Context'; +import { NodeCache } from '../node-cache'; +import { factory } from '../factory/nodeFactory'; +import { traceGlobal } from '../../tracer'; +import { DiagnosticKind } from '../peers/DiagnosticKind'; + +/** + * Improve: Replace or remove with better naming + * + * @deprecated + */ +export function createETSModuleFromContext(): ETSModule { + let program = global.generatedEs2panda._ContextProgram(global.context); + if (program == nullptr) { + throw new Error(`Program is null for context ${global.context.toString(16)}`); + } + const ast = global.generatedEs2panda._ProgramAst(global.context, program); + if (ast == nullptr) { + throw new Error(`AST is null for program ${program.toString(16)}`); + } + return new ETSModule(ast, Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE); +} + +/** + * Now used only in tests + * Improve: Remove or replace with better method + * + * @deprecated + */ +export function createETSModuleFromSource( + source: string, + state: Es2pandaContextState = Es2pandaContextState.ES2PANDA_STATE_PARSED +): ETSModule { + if (!global.configIsInitialized()) { + global.config = Config.createDefault().peer; + } + global.compilerContext = Context.createFromString(source); + proceedToState(state); + let program = global.generatedEs2panda._ContextProgram(global.compilerContext.peer); + if (program === nullptr) + throw new Error(`Program is null for ${source} 0x${global.compilerContext.peer.toString(16)}`); + return new ETSModule( + global.generatedEs2panda._ProgramAst(global.context, program), + Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE + ); +} + +export function metaDatabase(fileName: string): string { + if (fileName.endsWith('.meta.json')) throw new Error(`Must pass source, not database: ${fileName}`); + return `${fileName}.meta.json`; +} + +export function checkErrors() { + if (global.es2panda._ContextState(global.context) === Es2pandaContextState.ES2PANDA_STATE_ERROR) { + traceGlobal(() => `Terminated due to compilation errors occured`); + console.log(unpackString(global.generatedEs2panda._GetAllErrorMessages(global.context))); + // global.es2panda._DestroyConfig(global.config) + process.exit(1); + } +} + +export function proceedToState(state: Es2pandaContextState): void { + if (state <= global.es2panda._ContextState(global.context)) { + return; + } + NodeCache.clear(); + const before = Date.now(); + traceGlobal(() => `Proceeding to state ${Es2pandaContextState[state]}: start`); + global.es2panda._ProceedToState(global.context, state); + traceGlobal(() => `Proceeding to state ${Es2pandaContextState[state]}: done`); + const after = Date.now(); + global.profiler.proceededToState(after - before); + checkErrors(); +} + +/** @deprecated Use {@link rebindContext} instead */ +export function rebindSubtree(node: AstNode): void { + NodeCache.clear(); + traceGlobal(() => `Rebind: start`); + global.es2panda._AstNodeRebind(global.context, node.peer); + traceGlobal(() => `Rebind: done`); + checkErrors(); +} + +/** @deprecated Use {@link recheckSubtree} instead */ +export function recheckSubtree(node: AstNode): void { + NodeCache.clear(); + traceGlobal(() => `Recheck: start`); + global.generatedEs2panda._AstNodeRecheck(global.context, node.peer); + traceGlobal(() => `Recheck: done`); + checkErrors(); +} + +export function rebindContext(context: KNativePointer = global.context): void { + NodeCache.clear(); + traceGlobal(() => `Rebind: start`); + global.es2panda._AstNodeRebind( + context, + global.generatedEs2panda._ProgramAst(context, global.generatedEs2panda._ContextProgram(context)) + ); + traceGlobal(() => `Rebind: done`); + checkErrors(); +} + +export function recheckContext(context: KNativePointer = global.context): void { + NodeCache.clear(); + traceGlobal(() => `Recheck: start`); + global.generatedEs2panda._AstNodeRecheck( + context, + global.generatedEs2panda._ProgramAst(context, global.generatedEs2panda._ContextProgram(context)) + ); + traceGlobal(() => `Recheck: done`); + checkErrors(); +} + +export function getDecl(node: AstNode): AstNode | undefined { + if (isMemberExpression(node)) { + return getDeclFromArrayOrObjectMember(node); + } + if (isObjectExpression(node)) { + return getPeerObjectDecl(passNode(node)); + } + const decl = getPeerDecl(passNode(node)); + if (!!decl) { + return decl; + } + if (!!node.parent && isProperty(node.parent)) { + return getDeclFromProperty(node.parent); + } + return undefined; +} + +function getDeclFromProperty(node: Property): AstNode | undefined { + if (!node.key) { + return undefined; + } + if (!!node.parent && !isObjectExpression(node.parent)) { + return getPeerDecl(passNode(node.key)); + } + return getDeclFromObjectExpressionProperty(node); +} + +function getDeclFromObjectExpressionProperty(node: Property): AstNode | undefined { + const declNode = getPeerObjectDecl(passNode(node.parent)); + if (!declNode || !node.key || !isIdentifier(node.key)) { + return undefined; + } + let body: readonly AstNode[] = []; + if (isClassDefinition(declNode)) { + body = declNode.body; + } else if (isTSInterfaceDeclaration(declNode)) { + body = declNode.body?.body ?? []; + } + return body.find( + (statement) => + isMethodDefinition(statement) && + statement.kind === Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET && + !!statement.id && + !!node.key && + isIdentifier(node.key) && + statement.id.name === node.key.name + ); +} + +function getDeclFromArrayOrObjectMember(node: MemberExpression): AstNode | undefined { + if (isNumberLiteral(node.property)) { + return node.object ? getDecl(node.object) : undefined; + } + return node.property ? getDecl(node.property) : undefined; +} + +export function getPeerDecl(peer: KNativePointer): AstNode | undefined { + const decl = global.generatedEs2panda._DeclarationFromIdentifier(global.context, peer); + if (decl === nullptr) { + return undefined; + } + return unpackNonNullableNode(decl); +} + +export function declarationFromIdentifier(node: Identifier): AstNode | undefined { + return unpackNode(global.generatedEs2panda._DeclarationFromIdentifier(global.context, node.peer)); +} + +export function resolveGensymVariableDeclaratorForDefaultParam(node: VariableDeclarator): Identifier | undefined { + const init = node.init; + if ( + isConditionalExpression(init) && + isIdentifier(init.consequent) && + init.consequent.name.startsWith('gensym%%_') + ) { + return init.consequent; + } + return undefined; +} + +export function resolveGensymVariableDeclaratorForOptionalCall(node: VariableDeclarator): Identifier | undefined { + const init = node.init; + if (isIdentifier(node.id) && node.id.name.startsWith('gensym%%_') && isIdentifier(init)) { + return init; + } + return undefined; +} + +export function getPeerObjectDecl(peer: KNativePointer): AstNode | undefined { + const decl = global.es2panda._ClassVariableDeclaration(global.context, peer); + if (decl === nullptr) { + return undefined; + } + return unpackNonNullableNode(decl); +} + +export function getAnnotations(node: AstNode): readonly AnnotationUsage[] { + if (!isFunctionDeclaration(node) && !isScriptFunction(node) && !isClassDefinition(node)) { + throwError('for now annotations allowed only for: functionDeclaration, scriptFunction, classDefinition'); + } + return unpackNodeArray(global.es2panda._AnnotationAllowedAnnotations(global.context, node.peer, nullptr)); +} + +export function getOriginalNode(node: AstNode): AstNode { + if (node === undefined) { + // Improve: fix this + throwError('there is no arkts pair of ts node (unable to getOriginalNode)'); + } + if (node.originalPeer === nullptr) { + return node; + } + return unpackNonNullableNode(node.originalPeer); +} + +export function getFileName(): string { + return global.filePath; +} + +export function getJsDoc(node: AstNode): string | undefined { + const result = unpackString(global.generatedEs2panda._JsdocStringFromDeclaration(global.context, node.peer)); + return result === 'Empty Jsdoc' ? undefined : result; +} + +// Improve: It seems like Definition overrides AstNode modifiers +// with it's own modifiers which is completely unrelated set of flags. +// Use this function if you need +// the language level modifiers: public, declare, export, etc. +export function classDefinitionFlags(node: ClassDefinition): Es2pandaModifierFlags { + return global.generatedEs2panda._AstNodeModifiers(global.context, node.peer); +} + +// Improve: ClassProperty's optional flag is set by AstNode's modifiers flags. +export function classPropertySetOptional(node: ClassProperty, value: boolean): ClassProperty { + if (value) { + node.modifierFlags |= Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL; + } else { + node.modifierFlags &= Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL; + } + return node; +} + +export function hasModifierFlag(node: AstNode, flag: Es2pandaModifierFlags): boolean { + if (!node) return false; + + let modifiers; + if (isClassDefinition(node)) { + modifiers = classDefinitionFlags(node); + } else { + modifiers = node.modifierFlags; + } + return (modifiers & flag) === flag; +} + +export function modifiersToString(modifiers: Es2pandaModifierFlags): string { + return Object.values(Es2pandaModifierFlags) + .filter(isNumber) + .map((it) => { + console.log(it.valueOf(), Es2pandaModifierFlags[it], modifiers.valueOf() & it); + return (modifiers.valueOf() & it) === it ? Es2pandaModifierFlags[it] : ''; + }) + .join(' '); +} + +export function nameIfIdentifier(node: AstNode): string { + return isIdentifier(node) ? `'${node.name}'` : ''; +} + +export function nameIfETSModule(node: AstNode): string { + return isETSModule(node) ? `'${node.ident?.name}'` : ''; +} + +export function asString(node: AstNode | undefined): string { + return `${node?.constructor.name} ${node ? nameIfIdentifier(node) : undefined}`; +} + +const defaultPandaSdk = '../../../incremental/tools/panda/node_modules/@panda/sdk'; + +export function findStdlib(): string { + const sdk = + process.env.PANDA_SDK_PATH ?? + withWarning(defaultPandaSdk, `PANDA_SDK_PATH not set, assuming ${defaultPandaSdk}`); + return `${sdk}/ets/stdlib`; +} + +export function generateTsDeclarationsFromContext( + outputDeclEts: string, + outputEts: string, + exportAll: boolean, + isolated: boolean, + recordFile: string, + genAnnotations: boolean +): KInt { + return global.es2panda._GenerateTsDeclarationsFromContext( + global.context, + passString(outputDeclEts), + passString(outputEts), + exportAll, + isolated, + recordFile, + genAnnotations + ); +} + +export function setAllParents(ast: AstNode): void { + global.es2panda._AstNodeUpdateAll(global.context, ast.peer); +} + +export function getProgramFromAstNode(node: AstNode): Program { + return new Program(global.es2panda._AstNodeProgram(global.context, node.peer)); +} + +export function importDeclarationInsert(node: ETSImportDeclaration, program: Program): void { + global.generatedEs2panda._InsertETSImportDeclarationAndParse(global.context, program.peer, node.peer); +} + +export function signatureReturnType(signature: KNativePointer): KNativePointer { + if (!signature) { + return nullptr; + } + return global.es2panda._Checker_SignatureReturnType(global.context, signature); +} + +export function convertCheckerTypeToTypeNode(typePeer: KNativePointer | undefined): TypeNode | undefined { + if (!typePeer) { + return undefined; + } + return factory.createOpaqueTypeNode(global.es2panda._Checker_TypeClone(global.context, typePeer)); +} + +export function originalSourcePositionString(node: AstNode | undefined) { + if (!node) { + return `[undefined]`; + } + const originalPeer = node.originalPeer; + const sourcePosition = new SourcePosition( + global.generatedEs2panda._AstNodeStartConst(global.context, originalPeer) + ); + const program = new Program(global.es2panda._AstNodeProgram(global.context, originalPeer)); + if (!program.peer) { + // This can happen if we are calling this method on node that is in update now and parent chain does not lead to program + return `[${global.filePath}${sourcePosition.toString()}]`; + } + return `[${program.absoluteName}${sourcePosition.toString()}]`; +} + +export function generateStaticDeclarationsFromContext(outputPath: string): KInt { + return global.generatedEs2panda._GenerateStaticDeclarationsFromContext(global.context, passString(outputPath)); +} + +export function createTypeNodeFromTsType(node: AstNode): AstNode | undefined { + const typeAnnotation = global.es2panda._CreateTypeNodeFromTsType(global.context, node.peer); + if (typeAnnotation === nullptr) { + return undefined; + } + return unpackNonNullableNode(typeAnnotation); +} + +export function createSourcePosition(index: KUInt, line: KUInt): SourcePosition { + return new SourcePosition(global.generatedEs2panda._CreateSourcePosition(global.context, index, line)); +} + +export function createSourceRange(start: SourcePosition, end: SourcePosition): SourceRange { + return new SourceRange(global.generatedEs2panda._CreateSourceRange(global.context, start.peer, end.peer)); +} + +export function createDiagnosticInfo( + kind: DiagnosticKind, + position: SourcePosition, + ...args: string[] +): DiagnosticInfo { + return new DiagnosticInfo( + global.es2panda._CreateDiagnosticInfo( + global.context, + kind.peer, + passStringArray(args), + args.length, + position.peer + ) + ); +} + +export function createSuggestionInfo( + kind: DiagnosticKind, + substitutionCode: string, + title: string, + range: SourceRange, + ...args: string[] +): SuggestionInfo { + return new SuggestionInfo( + global.es2panda._CreateSuggestionInfo( + global.context, + kind.peer, + passStringArray(args), + args.length, + substitutionCode, + title, + range.peer + ) + ); +} + +export function createDiagnosticKind(message: string, type: Es2pandaPluginDiagnosticType): DiagnosticKind { + return new DiagnosticKind(global.es2panda._CreateDiagnosticKind(global.context, message, type)); +} + +export function logDiagnostic(kind: DiagnosticKind, pos: SourcePosition, ...args: string[]): void { + global.es2panda._LogDiagnostic(global.context, kind.peer, passStringArray(args), args.length, pos.peer); +} + +export function logDiagnosticWithSuggestion(diagnosticInfo: DiagnosticInfo, suggestionInfo: SuggestionInfo): void { + global.generatedEs2panda._LogDiagnosticWithSuggestion(global.context, diagnosticInfo.peer, suggestionInfo.peer); +} + +export function filterNodes(node: AstNode, filter: string): AstNode[] { + return unpackNodeArray(global.es2panda._FilterNodes(global.context, passNode(node), filter)); +} diff --git a/ets1.2/libarkts/src/arkts-api/visitor.ts b/ets1.2/libarkts/src/arkts-api/visitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..a31a4af59cdf2e93da42994b4bc044719b596050 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/visitor.ts @@ -0,0 +1,1052 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { isSameNativeObject } from '../arkts-api/peers/ArktsObject'; +import { + AnnotationUsage, + ArrayExpression, + ArrowFunctionExpression, + AssignmentExpression, + BinaryExpression, + BlockExpression, + BlockStatement, + CallExpression, + CatchClause, + ChainExpression, + ClassDeclaration, + ClassDefinition, + ClassProperty, + ClassStaticBlock, + ConditionalExpression, + DoWhileStatement, + ETSFunctionType, + ETSImportDeclaration, + ETSModule, + ETSNewClassInstanceExpression, + ETSParameterExpression, + ETSStructDeclaration, + ETSTuple, + ETSTypeReference, + ETSTypeReferencePart, + ETSUnionType, + Expression, + ExpressionStatement, + ForInStatement, + ForOfStatement, + ForUpdateStatement, + FunctionDeclaration, + FunctionExpression, + Identifier, + IfStatement, + MemberExpression, + MethodDefinition, + ObjectExpression, + Property, + ReturnStatement, + ScriptFunction, + Statement, + SwitchCaseStatement, + SwitchStatement, + TemplateElement, + TemplateLiteral, + TryStatement, + TSAsExpression, + TSClassImplements, + TSInterfaceBody, + TSInterfaceDeclaration, + TSInterfaceHeritage, + TSNonNullExpression, + TSTypeAliasDeclaration, + TSTypeParameter, + TSTypeParameterDeclaration, + TSTypeParameterInstantiation, + TypeNode, + UpdateExpression, + VariableDeclaration, + VariableDeclarator, + WhileStatement, +} from '../../generated'; +import { Es2pandaAstNodeType, Es2pandaImportKinds, Es2pandaLanguage } from '../../generated/Es2pandaEnums'; +import { factory } from './factory/nodeFactory'; +import { AstNode } from './peers/AstNode'; +import { global } from './static/global'; + +type Visitor = (node: AstNode, options?: object) => AstNode; + +export interface DoubleNode { + originNode: AstNode; + translatedNode: AstNode; +} + +export class StructInfo { + stateVariables: Set = new Set(); + initializeBody: AstNode[] = []; + updateBody: AstNode[] = []; +} + +export class GlobalInfo { + private _structCollection: Set; + private static instance: GlobalInfo; + private _structMap: Map; + + private constructor() { + this._structCollection = new Set(); + this._structMap = new Map(); + } + + public static getInfoInstance(): GlobalInfo { + if (!this.instance) { + this.instance = new GlobalInfo(); + } + return this.instance; + } + + public add(str: string): void { + this._structCollection.add(str); + } + + public getStructCollection(): Set { + return this._structCollection; + } + + public getStructInfo(structName: string): StructInfo { + const structInfo = this._structMap.get(structName); + if (!structInfo) { + return new StructInfo(); + } + return structInfo; + } + + public setStructInfo(structName: string, info: StructInfo): void { + this._structMap.set(structName, info); + } +} + +// Improve: rethink (remove as) +function nodeVisitor(node: T, visitor: Visitor): T { + if (node === undefined) { + return node; + } + const result = visitor(node) as T; + if (node !== result) { + global.updateTracker.update(); + } + return result; +} + +// Improve: rethink (remove as) +function nodesVisitor( + nodes: TIn, + visitor: Visitor +): T[] | TIn { + if (nodes === undefined) { + return nodes; + } + return nodes.map((node): T => { + const result = visitor(node) as T; + if (node != result) { + global.updateTracker.update(); + } + return result; + }); +} + +function visitBlockStatement(node: BlockStatement, visitor: Visitor): BlockStatement { + global.updateTracker.push(); + const newStatements: readonly Statement[] = nodesVisitor(node.statements, visitor); + if (global.updateTracker.check()) { + node.setStatements(newStatements); + } + return node; +} + +function visitETSModule(node: ETSModule, visitor: Visitor): ETSModule { + global.updateTracker.push(); + const newStatements: readonly Statement[] = nodesVisitor(node.statements, visitor); + const oldIdent = node.ident; + const newIdent = nodeVisitor(oldIdent, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newIdent, oldIdent)) { + const result = factory.createETSModule( + newStatements, + newIdent, + node.getNamespaceFlag(), + Es2pandaLanguage.LANGUAGE_ETS, + node.program + ); + result.onUpdate(node); + return result; + } + node.setStatements(newStatements); + } + return node; +} + +function visitCallExpression(node: CallExpression, visitor: Visitor): CallExpression { + global.updateTracker.push(); + const newCallee = nodeVisitor(node.callee, visitor); + const newArguments: readonly Expression[] = nodesVisitor(node.arguments, visitor); + const newTypeParams = nodeVisitor(node.typeParams, visitor); + const newTrailingBlock = nodeVisitor(node.trailingBlock, visitor); + if (global.updateTracker.check()) { + node.setCallee(newCallee); + node.setArguments(newArguments); + node.setTypeParams(newTypeParams); + node.setTrailingBlock(newTrailingBlock); + } + return node; +} + +function visitIdentifier(node: Identifier, visitor: Visitor): Identifier { + global.updateTracker.push(); + const newTypeAnnotation = nodeVisitor(node.typeAnnotation, visitor); + if (global.updateTracker.check()) { + const result = factory.createIdentifier(node.name, newTypeAnnotation); + result.onUpdate(node); + return result; + } + return node; +} + +function visitMemberExpression(node: MemberExpression, visitor: Visitor): MemberExpression { + global.updateTracker.push(); + const newObject = nodeVisitor(node.object, visitor); + const newProperty = nodeVisitor(node.property, visitor); + if (global.updateTracker.check()) { + node.setObject(newObject); + node.setProperty(newProperty); + } + return node; +} + +function visitETSTypeReference(node: ETSTypeReference, visitor: Visitor): ETSTypeReference { + global.updateTracker.push(); + const newPart = nodeVisitor(node.part, visitor); + if (global.updateTracker.check()) { + const result = factory.createETSTypeReference(newPart); + result.onUpdate(node); + return result; + } + return node; +} + +function visitETSTypeReferencePart(node: ETSTypeReferencePart, visitor: Visitor): ETSTypeReferencePart { + global.updateTracker.push(); + const newName = nodeVisitor(node.name, visitor); + const newTypeParams = nodeVisitor(node.typeParams, visitor); + const newPrev = nodeVisitor(node.previous, visitor); + if (global.updateTracker.check()) { + const result = factory.createETSTypeReferencePart(newName, newTypeParams, newPrev); + result.onUpdate(node); + return result; + } + return node; +} + +function visitScriptFunction(node: ScriptFunction, visitor: Visitor): ScriptFunction { + global.updateTracker.push(); + const newBody = nodeVisitor(node.body, visitor); + const oldTypeParams = node.typeParams; + const newTypeParams = nodeVisitor(oldTypeParams, visitor); + const newParams: readonly Expression[] = nodesVisitor(node.params, visitor); + const newReturnTypeAnnotation = nodeVisitor(node.returnTypeAnnotation, visitor); + const newId = nodeVisitor(node.id, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newTypeParams, oldTypeParams)) { + const result = factory.createScriptFunction( + newBody, + newTypeParams, + newParams, + newReturnTypeAnnotation, + node.hasReceiver, + node.flags, + node.modifierFlags, + newId, + newAnnotations, + node.getSignaturePointer(), + node.getPreferredReturnTypePointer() + ); + result.onUpdate(node); + return result; + } + node.setBody(newBody); + node.setParams(newParams); + node.setReturnTypeAnnotation(newReturnTypeAnnotation); + if (newId) node.setIdent(newId); + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitMethodDefinition(node: MethodDefinition, visitor: Visitor): MethodDefinition { + global.updateTracker.push(); + const oldId = node.id; + const newId = nodeVisitor(oldId, visitor); + const oldValue = node.value; + const newValue = nodeVisitor(oldValue, visitor); + const newOverloads: readonly MethodDefinition[] = nodesVisitor(node.overloads, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newValue, node.value) || !isSameNativeObject(newId, oldId)) { + const result = factory.createMethodDefinition( + node.kind, + newId, + newValue, + node.modifierFlags, + node.isComputed, + newOverloads + ); + result.onUpdate(node); + return result; + } + node.setOverloads(newOverloads); + newOverloads.forEach((it): void => { + it.setBaseOverloadMethod(node); + it.parent = node; + }); + } + return node; +} + +function visitArrowFunctionExpression(node: ArrowFunctionExpression, visitor: Visitor): ArrowFunctionExpression { + global.updateTracker.push(); + const oldFunction = node.function; + const newFunction = nodeVisitor(oldFunction, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newFunction, oldFunction)) { + const result = factory.createArrowFunctionExpression(newFunction, newAnnotations); + result.onUpdate(node); + return result; + } + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitFunctionDeclaration(node: FunctionDeclaration, visitor: Visitor): FunctionDeclaration { + global.updateTracker.push(); + const oldFunction = node.function; + const newFunction = nodeVisitor(oldFunction, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newFunction, oldFunction)) { + const result = factory.createFunctionDeclaration(newFunction, newAnnotations, node.isAnonymous); + result.onUpdate(node); + return result; + } + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitBlockExpression(node: BlockExpression, visitor: Visitor): BlockExpression { + global.updateTracker.push(); + const newStatements: readonly Statement[] = nodesVisitor(node.statements, visitor); + if (global.updateTracker.check()) { + const result = factory.createBlockExpression(newStatements); + result.onUpdate(node); + return result; + } + return node; +} + +function visitChainExpression(node: ChainExpression, visitor: Visitor): ChainExpression { + global.updateTracker.push(); + const newExpression = nodeVisitor(node.expression, visitor); + if (global.updateTracker.check()) { + const result = factory.createChainExpression(newExpression); + result.onUpdate(node); + return result; + } + return node; +} + +function visitExpressionStatement(node: ExpressionStatement, visitor: Visitor): ExpressionStatement { + global.updateTracker.push(); + const newExpression = nodeVisitor(node.expression, visitor); + if (global.updateTracker.check()) { + node.setExpression(newExpression); + } + return node; +} + +function visitETSStructDeclaration(node: ETSStructDeclaration, visitor: Visitor): ETSStructDeclaration { + global.updateTracker.push(); + const newDefinition = nodeVisitor(node.definition, visitor); + if (global.updateTracker.check()) { + node.setDefinition(newDefinition); + } + return node; +} + +function visitClassDeclaration(node: ClassDeclaration, visitor: Visitor): ClassDeclaration { + global.updateTracker.push(); + const newDefinition = nodeVisitor(node.definition, visitor); + if (global.updateTracker.check()) { + node.setDefinition(newDefinition); + } + return node; +} + +function visitTSInterfaceBody(node: TSInterfaceBody, visitor: Visitor): TSInterfaceBody { + global.updateTracker.push(); + const newBody = nodesVisitor(node.body, visitor); + if (global.updateTracker.check()) { + const result = factory.createTSInterfaceBody(newBody); + result.onUpdate(node); + return result; + } + return node; +} + +function visitClassDefinition(node: ClassDefinition, visitor: Visitor): ClassDefinition { + global.updateTracker.push(); + const newIdent = nodeVisitor(node.ident, visitor); + const newTypeParams = nodeVisitor(node.typeParams, visitor); + const oldSuperTypeParams = node.superTypeParams; + const newSuperTypeParams = nodeVisitor(oldSuperTypeParams, visitor); + const oldImplements = node.implements; + const newImplements: readonly TSClassImplements[] = nodesVisitor(oldImplements, visitor); + const newSuper = nodeVisitor(node.super, visitor); + const newBody = nodesVisitor(node.body, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if ( + !isSameNativeObject(oldSuperTypeParams, newSuperTypeParams) || + !isSameNativeObject(newImplements, oldImplements) + ) { + const result = factory.createClassDefinition( + newIdent, + newTypeParams, + newSuperTypeParams, + newImplements, + undefined /* can not pass node.ctor here because of mismatching types */, + newSuper, + newBody, + node.modifiers, + node.modifierFlags, + newAnnotations + ); + result.onUpdate(node); + return result; + } + node.setIdent(newIdent); + node.setTypeParams(newTypeParams); + node.setSuper(newSuper); + node.setBody(newBody); + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitETSParameterExpression(node: ETSParameterExpression, visitor: Visitor): ETSParameterExpression { + if (node.isRestParameter) { + /** there is no RestParameter node at .idl */ + return node; + } + global.updateTracker.push(); + const newIdent = nodeVisitor(node.ident, visitor); + const newInit = nodeVisitor(node.initializer, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + node.setIdent(newIdent); + node.setInitializer(newInit); + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitSwitchStatement(node: SwitchStatement, visitor: Visitor): SwitchStatement { + global.updateTracker.push(); + const newDiscriminant = nodeVisitor(node.discriminant, visitor); + const oldCases = node.cases; + const newCases: readonly SwitchCaseStatement[] = nodesVisitor(oldCases, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newCases, oldCases)) { + const result = factory.createSwitchStatement(newDiscriminant, newCases); + result.onUpdate(node); + return result; + } + node.setDiscriminant(newDiscriminant); + } + return node; +} + +function visitSwitchCaseStatement(node: SwitchCaseStatement, visitor: Visitor): SwitchCaseStatement { + global.updateTracker.push(); + const newTest = nodeVisitor(node.test, visitor); + const oldConsequent = node.consequent; + const newConsequent: readonly Statement[] = nodesVisitor(oldConsequent, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newConsequent, oldConsequent)) { + const result = factory.createSwitchCaseStatement(newTest, newConsequent); + result.onUpdate(node); + return result; + } + node.setTest(newTest); + } + return node; +} + +function visitTSInterfaceDeclaration(node: TSInterfaceDeclaration, visitor: Visitor): TSInterfaceDeclaration { + global.updateTracker.push(); + const newExtends: readonly TSInterfaceHeritage[] = nodesVisitor(node.extends, visitor); + const newIdent = nodeVisitor(node.id, visitor); + const newTypeParams = nodeVisitor(node.typeParams, visitor); + const newBody = nodeVisitor(node.body, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + const result = factory.createInterfaceDeclaration( + newExtends, + newIdent, + newTypeParams, + newBody, + node.isStatic, + node.isFromExternal, + node.modifierFlags + ); + result.onUpdate(node); + result.setAnnotations(newAnnotations); + return result; + } + return node; +} + +function visitIfStatement(node: IfStatement, visitor: Visitor): IfStatement { + global.updateTracker.push(); + const newTest = nodeVisitor(node.test, visitor); + const oldConsequent = node.consequent; + const newConsequent = nodeVisitor(oldConsequent, visitor); + const newAlternate = nodeVisitor(node.alternate, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newConsequent, oldConsequent)) { + const result = factory.createIfStatement(newTest, newConsequent, newAlternate); + result.onUpdate(node); + return result; + } + node.setTest(newTest); + if (newTest) newTest.parent = node; + node.setAlternate(newAlternate); + } + return node; +} + +function visitConditionalExpression(node: ConditionalExpression, visitor: Visitor): ConditionalExpression { + global.updateTracker.push(); + const newTest = nodeVisitor(node.test, visitor); + const newConsequent = nodeVisitor(node.consequent, visitor); + const newAlternate = nodeVisitor(node.alternate, visitor); + if (global.updateTracker.check()) { + node.setTest(newTest); + node.setConsequent(newConsequent); + node.setAlternate(newAlternate); + } + return node; +} + +function visitVariableDeclararion(node: VariableDeclaration, visitor: Visitor): VariableDeclaration { + global.updateTracker.push(); + const oldDeclarators = node.declarators; + const newDeclarators: readonly VariableDeclarator[] = nodesVisitor(oldDeclarators, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newDeclarators, oldDeclarators)) { + const result = factory.createVariableDeclaration(node.kind, newDeclarators, newAnnotations); + result.onUpdate(node); + return result; + } + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitVariableDeclarator(node: VariableDeclarator, visitor: Visitor): VariableDeclarator { + global.updateTracker.push(); + const oldId = node.id; + const newId = nodeVisitor(oldId, visitor); + const newInit = nodeVisitor(node.init, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newId, oldId)) { + const result = factory.createVariableDeclarator(node.flag, newId, newInit); + result.onUpdate(node); + return result; + } + node.setInit(newInit); + } + return node; +} + +function visitReturnStatement(node: ReturnStatement, visitor: Visitor): ReturnStatement { + global.updateTracker.push(); + const newArgument = nodeVisitor(node.argument, visitor); + if (global.updateTracker.check()) { + node.setArgument(newArgument); + } + return node; +} + +function visitTSAsExpression(node: TSAsExpression, visitor: Visitor): TSAsExpression { + global.updateTracker.push(); + const newExpr = nodeVisitor(node.expr, visitor); + const oldTypeAnnotation = node.typeAnnotation; + const newTypeAnnotation = nodeVisitor(oldTypeAnnotation, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newTypeAnnotation, oldTypeAnnotation)) { + const result = factory.createTSAsExpression(newExpr, newTypeAnnotation, node.isConst); + result.onUpdate(node); + return result; + } + node.setExpr(newExpr); + } + return node; +} + +function visitTemplateLiteral(node: TemplateLiteral, visitor: Visitor): TemplateLiteral { + global.updateTracker.push(); + const newQuasis: readonly TemplateElement[] = nodesVisitor(node.quasis, visitor); + const newExpression: readonly Expression[] = nodesVisitor(node.expressions, visitor); + if (global.updateTracker.check()) { + const result = factory.createTemplateLiteral(newQuasis, newExpression, node.multilineString); + result.onUpdate(node); + return result; + } + return node; +} + +function visitTSTypeAliasDeclaration(node: TSTypeAliasDeclaration, visitor: Visitor): TSTypeAliasDeclaration { + global.updateTracker.push(); + const oldId = node.id; + const newId = nodeVisitor(oldId, visitor); + const newTypeParams = nodeVisitor(node.typeParams, visitor); + const oldTypeAnnotation = node.typeAnnotation; + const newTypeAnnotation = nodeVisitor(oldTypeAnnotation, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newId, oldId) || !isSameNativeObject(newTypeAnnotation, oldTypeAnnotation)) { + const result = factory.createTSTypeAliasDeclaration( + newId, + newTypeParams, + newTypeAnnotation, + newAnnotations + ); + result.onUpdate(node); + return result; + } + node.setAnnotations(newAnnotations); + node.setTypeParameters(newTypeParams); + } + return node; +} + +function visitTryStatement(node: TryStatement, visitor: Visitor): TryStatement { + global.updateTracker.push(); + const newBlock = nodeVisitor(node.block, visitor); + const newCatchClauses: readonly CatchClause[] = nodesVisitor(node.catchClauses, visitor); + const newFinallyBlock = nodeVisitor(node.finallyBlock, visitor); + if (global.updateTracker.check()) { + const result = factory.createTryStatement(newBlock, newCatchClauses, newFinallyBlock, [], []); + result.onUpdate(node); + return result; + } + return node; +} + +function visitObjectExpression(node: ObjectExpression, visitor: Visitor): ObjectExpression { + global.updateTracker.push(); + const newProperties: readonly Expression[] = nodesVisitor(node.properties, visitor); + if (global.updateTracker.check()) { + const result = factory.createObjectExpression(newProperties, node.getPreferredTypePointer()); + result.onUpdate(node); + return result; + } + return node; +} + +function visitFunctionExpression(node: FunctionExpression, visitor: Visitor): FunctionExpression { + global.updateTracker.push(); + const newId = nodeVisitor(node.id, visitor); + const newFunction = nodeVisitor(node.function, visitor); + if (global.updateTracker.check()) { + const result = factory.createFunctionExpression(newId, newFunction); + result.onUpdate(node); + return result; + } + return node; +} + +function visitArrayExpression(node: ArrayExpression, visitor: Visitor): ArrayExpression { + global.updateTracker.push(); + const newElements: readonly Expression[] = nodesVisitor(node.elements, visitor); + if (global.updateTracker.check()) { + node.setElements(newElements); + } + return node; +} + +function visitAssignmentExpression(node: AssignmentExpression, visitor: Visitor): AssignmentExpression { + global.updateTracker.push(); + const newLeft = nodeVisitor(node.left, visitor); + const newRight = nodeVisitor(node.right, visitor); + if (global.updateTracker.check()) { + node.setLeft(newLeft); + node.setRight(newRight); + } + return node; +} + +function visitETSTyple(node: ETSTuple, visitor: Visitor): ETSTuple { + global.updateTracker.push(); + const newTypeAnnotationList: readonly TypeNode[] = nodesVisitor(node.tupleTypeAnnotationsList, visitor); + if (global.updateTracker.check()) { + node.setTypeAnnotationsList(newTypeAnnotationList); + } + return node; +} + +function visitETSUnionType(node: ETSUnionType, visitor: Visitor): ETSUnionType { + global.updateTracker.push(); + const oldTypes = node.types; + const newTypes: readonly TypeNode[] = nodesVisitor(oldTypes, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newTypes, oldTypes)) { + const result = factory.createETSUnionType(newTypes, newAnnotations); + result.onUpdate(node); + return result; + } + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitETSFunctionType(node: ETSFunctionType, visitor: Visitor): ETSFunctionType { + global.updateTracker.push(); + const oldTypeParams = node.typeParams; + const newTypeParams = nodeVisitor(oldTypeParams, visitor); + const oldParams = node.params; + const newParams: readonly Expression[] = nodesVisitor(oldParams, visitor); + const oldReturnTypeAnnotation = node.returnType; + const newReturnTypeAnnotation = nodeVisitor(oldReturnTypeAnnotation, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if ( + !isSameNativeObject(newTypeParams, oldTypeParams) || + !isSameNativeObject(newParams, oldParams) || + !isSameNativeObject(newReturnTypeAnnotation, oldReturnTypeAnnotation) + ) { + const result = factory.createETSFunctionType( + newTypeParams, + newParams, + newReturnTypeAnnotation, + node.isExtensionFunction, + node.flags, + newAnnotations + ); + result.onUpdate(node); + return result; + } + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitClassProperty(node: ClassProperty, visitor: Visitor): ClassProperty { + global.updateTracker.push(); + const oldKey = node.key; + const newKey = nodeVisitor(oldKey, visitor); + const newValue = nodeVisitor(node.value, visitor); + const newTypeAnnotation = nodeVisitor(node.typeAnnotation, visitor); + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newKey, oldKey)) { + const result = factory.createClassProperty( + newKey, + newValue, + newTypeAnnotation, + node.modifierFlags, + node.isComputed, + newAnnotations + ); + result.onUpdate(node); + return result; + } + node.setValue(newValue); + node.setTypeAnnotation(newTypeAnnotation); + node.setAnnotations(newAnnotations); + } + return node; +} + +function visitProperty(node: Property, visitor: Visitor): Property { + global.updateTracker.push(); + const newKey = nodeVisitor(node.key, visitor); + const newValue = nodeVisitor(node.value, visitor); + if (global.updateTracker.check()) { + const result = factory.createProperty(node.kind, newKey, newValue, node.isMethod, node.isComputed); + result.onUpdate(node); + return result; + } + return node; +} + +function visitBinaryExpression(node: BinaryExpression, visitor: Visitor): BinaryExpression { + global.updateTracker.push(); + const newLeft = nodeVisitor(node.left, visitor); + const newRight = nodeVisitor(node.right, visitor); + if (global.updateTracker.check()) { + node.setLeft(newLeft); + node.setRight(newRight); + } + return node; +} + +function visitETSNewClassInstanceExpression( + node: ETSNewClassInstanceExpression, + visitor: Visitor +): ETSNewClassInstanceExpression { + global.updateTracker.push(); + const oldTypeRef = node.typeRef; + const newTypeRef = nodeVisitor(oldTypeRef, visitor); + const newArguments: readonly Expression[] = nodesVisitor(node.arguments, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newTypeRef, oldTypeRef)) { + const result = factory.createETSNewClassInstanceExpression(newTypeRef, newArguments); + result.onUpdate(node); + return result; + } + node.setArguments(newArguments); + newArguments.forEach((it) => (it.parent = node)); + } + return node; +} + +function visitWhileStatement(node: WhileStatement, visitor: Visitor): WhileStatement { + global.updateTracker.push(); + const newTest = nodeVisitor(node.test, visitor); + const oldBody = node.body; + const newBody = nodeVisitor(node.body, visitor); + if (global.updateTracker.check()) { + if (!isSameNativeObject(newBody, oldBody)) { + const result = factory.createWhileStatement(newTest, newBody); + result.onUpdate(node); + return result; + } + node.setTest(newTest); + } + return node; +} + +function visitDoWhileStatement(node: DoWhileStatement, visitor: Visitor): DoWhileStatement { + global.updateTracker.push(); + const newBody = nodeVisitor(node.body, visitor); + const newTest = nodeVisitor(node.test, visitor); + if (global.updateTracker.check()) { + const result = factory.createDoWhileStatement(newBody, newTest); + result.onUpdate(node); + return result; + } + return node; +} + +function visitForUpdateStatement(node: ForUpdateStatement, visitor: Visitor): ForUpdateStatement { + global.updateTracker.push(); + const newInit = nodeVisitor(node.init, visitor); + const newTest = nodeVisitor(node.test, visitor); + const newUpdate = nodeVisitor(node.update, visitor); + const newBody = nodeVisitor(node.body, visitor); + if (global.updateTracker.check()) { + const result = factory.createForUpdateStatement(newInit, newTest, newUpdate, newBody); + result.onUpdate(node); + return result; + } + return node; +} + +function visitForInStatement(node: ForInStatement, visitor: Visitor): ForInStatement { + global.updateTracker.push(); + const newLeft = nodeVisitor(node.left, visitor); + const newRight = nodeVisitor(node.right, visitor); + const newBody = nodeVisitor(node.body, visitor); + if (global.updateTracker.check()) { + const result = factory.createForInStatement(newLeft, newRight, newBody); + result.onUpdate(node); + return result; + } + return node; +} + +function visitForOfStatement(node: ForOfStatement, visitor: Visitor): ForOfStatement { + global.updateTracker.push(); + const newLeft = nodeVisitor(node.left, visitor); + const newRight = nodeVisitor(node.right, visitor); + const newBody = nodeVisitor(node.body, visitor); + if (global.updateTracker.check()) { + const result = factory.createForOfStatement(newLeft, newRight, newBody, node.isAwait); + result.onUpdate(node); + return result; + } + return node; +} + +function visitETSImportDeclaration(node: ETSImportDeclaration, visitor: Visitor): ETSImportDeclaration { + global.updateTracker.push(); + const newSource = nodeVisitor(node.source, visitor); + const newSpecifiers = nodesVisitor(node.specifiers, visitor); + if (global.updateTracker.check()) { + const result = factory.createETSImportDeclaration( + newSource, + newSpecifiers, + Es2pandaImportKinds.IMPORT_KINDS_ALL + ); + result.onUpdate(node); + return result; + } + return node; +} + +function visitTSNonNullExpression(node: TSNonNullExpression, visitor: Visitor): TSNonNullExpression { + global.updateTracker.push(); + const newExpr = nodeVisitor(node.expr, visitor); + if (global.updateTracker.check()) { + node.setExpr(newExpr); + if (newExpr) newExpr.parent = node; + } + return node; +} + +function visitUpdateExpression(node: UpdateExpression, visitor: Visitor): UpdateExpression { + global.updateTracker.push(); + const newArgument = nodeVisitor(node.argument, visitor); + if (global.updateTracker.check()) { + const result = factory.createUpdateExpression(newArgument, node.operatorType, node.isPrefix); + result.onUpdate(node); + return result; + } + return node; +} + +function visitTSTypeParameterInstantiation( + node: TSTypeParameterInstantiation, + visitor: Visitor +): TSTypeParameterInstantiation { + global.updateTracker.push(); + const newParams: readonly TypeNode[] = nodesVisitor(node.params, visitor); + if (global.updateTracker.check()) { + const result = factory.createTSTypeParameterInstantiation(newParams); + result.onUpdate(node); + return result; + } + return node; +} + +function visitTSTypeParameterDeclaration( + node: TSTypeParameterDeclaration, + visitor: Visitor +): TSTypeParameterDeclaration { + global.updateTracker.push(); + const newParams: readonly TSTypeParameter[] = nodesVisitor(node.params, visitor); + if (global.updateTracker.check()) { + const result = factory.createTSTypeParameterDeclaration(newParams, node.requiredParams); + result.onUpdate(node); + return result; + } + return node; +} + +function visitClassStaticBlock(node: ClassStaticBlock, visitor: Visitor): ClassStaticBlock { + global.updateTracker.push(); + const newId = nodeVisitor(node.id, visitor); + const newFunction = nodeVisitor(node.function, visitor); + if (global.updateTracker.check()) { + const result = ClassStaticBlock.createClassStaticBlock(factory.createFunctionExpression(newId, newFunction)); + result.onUpdate(node); + return result; + } + return node; +} + +const visitsTable: (((node: any, visitor: Visitor) => any) | undefined)[] = []; + +export function initVisitsTable(): void { + const length = Object.values(Es2pandaAstNodeType).length / 2; + visitsTable.push(...new Array(length)); + + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_IDENTIFIER] = visitIdentifier; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_MEMBER_EXPRESSION] = visitMemberExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_TYPE_REFERENCE] = visitETSTypeReference; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_TYPE_REFERENCE_PART] = visitETSTypeReferencePart; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE] = visitETSModule; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION] = visitCallExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_FUNCTION_DECLARATION] = visitFunctionDeclaration; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_BLOCK_STATEMENT] = visitBlockStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_BLOCK_EXPRESSION] = visitBlockExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_CHAIN_EXPRESSION] = visitChainExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_EXPRESSION_STATEMENT] = visitExpressionStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_STRUCT_DECLARATION] = visitETSStructDeclaration; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION] = visitClassDeclaration; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DEFINITION] = visitClassDefinition; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION] = visitMethodDefinition; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_SCRIPT_FUNCTION] = visitScriptFunction; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PARAMETER_EXPRESSION] = visitETSParameterExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_SWITCH_STATEMENT] = visitSwitchStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_SWITCH_CASE_STATEMENT] = visitSwitchCaseStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TS_INTERFACE_DECLARATION] = visitTSInterfaceDeclaration; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TS_INTERFACE_BODY] = visitTSInterfaceBody; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_IF_STATEMENT] = visitIfStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_CONDITIONAL_EXPRESSION] = visitConditionalExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_VARIABLE_DECLARATION] = visitVariableDeclararion; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_VARIABLE_DECLARATOR] = visitVariableDeclarator; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION] = visitArrowFunctionExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_RETURN_STATEMENT] = visitReturnStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TS_AS_EXPRESSION] = visitTSAsExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TEMPLATE_LITERAL] = visitTemplateLiteral; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TS_TYPE_ALIAS_DECLARATION] = visitTSTypeAliasDeclaration; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TRY_STATEMENT] = visitTryStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION] = visitObjectExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_FUNCTION_EXPRESSION] = visitFunctionExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ARRAY_EXPRESSION] = visitArrayExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ASSIGNMENT_EXPRESSION] = visitAssignmentExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_TUPLE] = visitETSTyple; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_UNION_TYPE] = visitETSUnionType; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_FUNCTION_TYPE] = visitETSFunctionType; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY] = visitClassProperty; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_PROPERTY] = visitProperty; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_BINARY_EXPRESSION] = visitBinaryExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_NEW_CLASS_INSTANCE_EXPRESSION] = + visitETSNewClassInstanceExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_WHILE_STATEMENT] = visitWhileStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_DO_WHILE_STATEMENT] = visitDoWhileStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_FOR_UPDATE_STATEMENT] = visitForUpdateStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_FOR_IN_STATEMENT] = visitForInStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_FOR_OF_STATEMENT] = visitForOfStatement; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION] = visitETSImportDeclaration; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TS_NON_NULL_EXPRESSION] = visitTSNonNullExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_UPDATE_EXPRESSION] = visitUpdateExpression; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TS_TYPE_PARAMETER_DECLARATION] = visitTSTypeParameterDeclaration; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_TS_TYPE_PARAMETER_INSTANTIATION] = visitTSTypeParameterInstantiation; + visitsTable[Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_STATIC_BLOCK] = visitClassStaticBlock; +} + +initVisitsTable(); + +export function visitEachChild(node: AstNode, visitor: Visitor): AstNode { + global.profiler.nodeVisited(); + const visit = visitsTable[node.astNodeType]; + if (visit) { + return visit(node, visitor); + } + return node; +} diff --git a/ets1.2/libarkts/src/arkts-api/wrapper-compat.ts b/ets1.2/libarkts/src/arkts-api/wrapper-compat.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd07ba3ff1881959ccc50a972d6abe38fded0cc8 --- /dev/null +++ b/ets1.2/libarkts/src/arkts-api/wrapper-compat.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +// koala-wrapper compatibility helpers + +import { KNativePointer } from '@koalaui/interop'; +import { ETSModule } from '../../generated'; +import { createETSModuleFromContext } from './utilities/public'; +import { global } from './static/global'; + +export class EtsScript { + public static fromContext(): ETSModule { + return createETSModuleFromContext(); + } +} + +export function destroyConfig(config: KNativePointer): void { + global.es2panda._DestroyConfig(config); + global.resetConfig(); +} diff --git a/ets1.2/libarkts/src/checkSdk.ts b/ets1.2/libarkts/src/checkSdk.ts new file mode 100644 index 0000000000000000000000000000000000000000..add13308cacee875d4dd19d9ea0dc3d3af2b2567 --- /dev/null +++ b/ets1.2/libarkts/src/checkSdk.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import * as fs from 'fs'; +import * as path from 'path'; + +function reportErrorAndExit(message: string): never { + console.error(message); + process.exit(1); +} + +export function checkSDK() { + const panda = process.env.PANDA_SDK_PATH; + if (!panda) reportErrorAndExit(`Variable PANDA_SDK_PATH is not set, please fix`); + if (!fs.existsSync(path.join(panda, 'package.json'))) + reportErrorAndExit(`Variable PANDA_SDK_PATH not points to SDK`); + const packageJson = JSON.parse(fs.readFileSync(path.join(panda, 'package.json')).toString()); + const version = packageJson.version as string; + if (!version) reportErrorAndExit(`version is unknown`); + const packageJsonOur = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json')).toString()); + const expectedVersion = packageJsonOur.config.panda_sdk_version; + if (expectedVersion && expectedVersion != 'next' && version != expectedVersion) + console.log(`WARNING: Panda SDK version "${version}" doesn't match expected "${expectedVersion}"`); + else console.log(`Using Panda ${version}`); +} diff --git a/ets1.2/libarkts/src/index.ts b/ets1.2/libarkts/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9605890a76f36faf95721239a21ab31e28761ee --- /dev/null +++ b/ets1.2/libarkts/src/index.ts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +export * from './checkSdk'; +export * from './utils'; +export * from './reexport-for-generated'; +export * from '../generated/Es2pandaEnums'; +export * from '../generated'; + +export * from './arkts-api/utilities/performance'; +export * from './arkts-api/utilities/private'; +export * from './arkts-api/utilities/public'; +export * from './arkts-api/factory/nodeFactory'; +export * from './arkts-api/visitor'; +export * from './arkts-api/AbstractVisitor'; +export * from './arkts-api/plugins'; +export * from './arkts-api/ImportStorage'; +export * from './arkts-api/ProgramProvider'; +export * from './arkts-api/node-utilities/Program'; +export * from './arkts-api/node-utilities/ArkTsConfig'; + +export * from './arkts-api/peers/AstNode'; +export * from './arkts-api/peers/Config'; +export * from './arkts-api/peers/Context'; +export { GlobalContext } from './arkts-api/peers/Context'; +export * from './arkts-api/peers/ExternalSource'; +export * from './arkts-api/peers/ImportPathManager'; +export * from './arkts-api/peers/Options'; +export * from './arkts-api/peers/DiagnosticKind'; +export { global as arktsGlobal } from './arkts-api/static/global'; +export * from './arkts-api/static/globalUtils'; +export * as arkts from './arkts-api'; + +export * from './plugin-utils'; +export * from './tracer'; diff --git a/ets1.2/libarkts/src/plugin-utils.ts b/ets1.2/libarkts/src/plugin-utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..b731f02dc3c2dfbd59a752b2b0bc6dafb895af73 --- /dev/null +++ b/ets1.2/libarkts/src/plugin-utils.ts @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2025 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. + */ + +import { + Es2pandaContextState, + PluginContext, + ImportStorage, + arktsGlobal, + ProgramTransformer, + Program, + ProgramProvider, + CompilationOptions, + dumpProgramSrcFormatted, +} from './arkts-api'; +import { Tracer } from './tracer'; + +export interface RunTransformerHooks { + onProgramTransformStart?(options: CompilationOptions, program: Program): void; + onProgramTransformEnd?(options: CompilationOptions, program: Program): void; +} + +class ASTCache { + processedPrograms = new Set(); + constructor() {} + find(program: Program): boolean { + return this.processedPrograms.has(program.absoluteName); + } + update(program: Program) { + this.processedPrograms.add(program.absoluteName); + } +} + +export class DumpingHooks implements RunTransformerHooks { + constructor( + private state: Es2pandaContextState, + private pluginName: string, + private dumpAst: boolean = false + ) { + if (process.env.KOALA_DUMP_PLUGIN_AST) { + this.dumpAst = true; + } + } + onProgramTransformStart(options: CompilationOptions, program: Program) { + if (this.dumpAst) { + console.log(`BEFORE ${this.pluginName}:`); + dumpProgramSrcFormatted(program, true); + } + if (!options.isProgramForCodegeneration) arktsGlobal.profiler.transformDepStarted(); + } + onProgramTransformEnd(options: CompilationOptions, program: Program) { + if (!options.isProgramForCodegeneration) arktsGlobal.profiler.transformDepEnded(this.state, this.pluginName); + if (this.dumpAst) { + console.log(`AFTER ${this.pluginName}:`); + dumpProgramSrcFormatted(program, true); + } + } +} + +export function runTransformerOnProgram( + program: Program, + options: CompilationOptions, + transform: ProgramTransformer | undefined, + pluginContext: PluginContext, + hooks: RunTransformerHooks = {} +) { + arktsGlobal.filePath = program.absoluteName; + + Tracer.startProgramTracing(program); + + // Perform some additional actions before the transformation start + hooks.onProgramTransformStart?.(options, program); + + // Save currently existing imports in the program + const importStorage = new ImportStorage(program, options.state == Es2pandaContextState.ES2PANDA_STATE_PARSED); + + // Run the plugin itself + transform?.(program, options, pluginContext); + + // Update internal import information based on import modification by plugin + importStorage.update(); + + // Perform some additional actions after the transformation end + hooks.onProgramTransformEnd?.(options, program); + + Tracer.stopProgramTracing(); +} + +export function runTransformer( + prog: Program, + state: Es2pandaContextState, + transform: ProgramTransformer | undefined, + pluginContext: PluginContext, + hooks: RunTransformerHooks = {} +) { + // Program provider used to provide programs to transformer dynamically relative to inserted imports + const provider = new ProgramProvider(prog); + + // The first program provided by program provider is the main program + let currentProgram = provider.next(); + let isMainProgram = true; + + while (currentProgram) { + // Options passed to plugin and hooks + const options: CompilationOptions = { + isProgramForCodegeneration: isProgramForCodegeneration(currentProgram, isMainProgram), + state, + }; + + runTransformerOnProgram(currentProgram, options, transform, pluginContext, hooks); + + // The first program is always the main program + isMainProgram = false; + + // Proceed to the next program + currentProgram = provider.next(); + } +} + +function isProgramForCodegeneration(program: Program, isMainProgram: boolean): boolean { + if (!arktsGlobal.isContextGenerateAbcForExternalSourceFiles) { + return isMainProgram; + } + return program.isGenAbcForExternal; +} diff --git a/ets1.2/libarkts/src/reexport-for-generated.ts b/ets1.2/libarkts/src/reexport-for-generated.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d253cb508649d39cf70c879567be2494a16b69d --- /dev/null +++ b/ets1.2/libarkts/src/reexport-for-generated.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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. + */ +export { KNativePointer } from '@koalaui/interop'; +export { AstNode } from './arkts-api/peers/AstNode'; +export { ArktsObject, isSameNativeObject } from './arkts-api/peers/ArktsObject'; +export { NodeCache } from './arkts-api/node-cache'; +export { + passNode, + unpackNonNullableNode, + unpackNodeArray, + passNodeArray, + unpackNode, + unpackString, + assertValidPeer, + updateNodeByNode, +} from './arkts-api/utilities/private'; +export { nodeByType } from './arkts-api/class-by-peer'; +export { global } from './arkts-api/static/global'; +export { Es2pandaMemberExpressionKind } from '../generated/Es2pandaEnums'; +export * from './arkts-api/utilities/extensions'; diff --git a/ets1.2/libarkts/src/tracer.ts b/ets1.2/libarkts/src/tracer.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a1d56ece5022e1cdad22c7657ec0563bb30e308 --- /dev/null +++ b/ets1.2/libarkts/src/tracer.ts @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { Program } from '../generated'; +import { global } from './arkts-api/static/global'; + +export class Tracer { + static traceDir: string; + static GlobalTracer: Tracer; + static Tracers: Map; + static LRUTracer: Tracer | undefined; + + static startGlobalTracing(outDir: string) { + Tracer.traceDir = path.join(outDir, 'trace'); + fs.rmSync(Tracer.traceDir, { force: true, recursive: true }); + const globalTraceFile = path.join(Tracer.traceDir, '.global.txt'); + + Tracer.GlobalTracer = new Tracer(globalTraceFile); + Tracer.pushContext('tracer'); + traceGlobal(() => `Trace file created at ${globalTraceFile}`, true); + + Tracer.Tracers = new Map(); + } + + static startProgramTracing(program: Program) { + if (!Tracer.GlobalTracer) { + return; + } + const programPath = program.absoluteName; + if (programPath == '') { + return; + } + const suggestedTracer = Tracer.Tracers.get(programPath); + if (suggestedTracer) { + Tracer.LRUTracer = suggestedTracer; + return; + } + if (!global.arktsconfig) { + throw new Error('global.arktsconfig should be set for tracer usage'); + } + const relative = path.relative(global.arktsconfig?.baseUrl, programPath); + const traceFileSuggestedPath = relative.startsWith('..') + ? path.join(this.traceDir, 'external', program.absoluteName.slice(1)) + : path.join(this.traceDir, relative); + Tracer.LRUTracer = new Tracer( + path.join( + path.dirname(traceFileSuggestedPath), + path.basename(traceFileSuggestedPath, path.extname(traceFileSuggestedPath)) + '.txt' + ), + programPath + ); + } + + static stopProgramTracing() { + Tracer.LRUTracer = undefined; + } + + static stopGlobalTracing() { + Tracer.GlobalTracer.traceEventsStats(); + } + + private constructor( + private traceFilePath: string, + inputFilePath?: string + ) { + if (!fs.existsSync(path.dirname(traceFilePath))) { + fs.mkdirSync(path.dirname(traceFilePath), { recursive: true }); + } + if (inputFilePath) { + Tracer.Tracers.set(inputFilePath, this); + } + } + + trace(traceLog: string | undefined | void) { + if (!traceLog) { + return; + } + const lastContext = Tracer.lastContext(); + fs.appendFileSync(this.traceFilePath, `[${lastContext.padStart(12)}] ${traceLog}\n`, 'utf-8'); + } + + events: Map | undefined; + eventsPerContext: Map> | undefined; + + recordEvent(event: string) { + if (!this.events) { + this.events = new Map(); + } + this.events.set(event, (this.events.get(event) ?? 0) + 1); + + if (!this.eventsPerContext) { + this.eventsPerContext = new Map>(); + } + if (!this.eventsPerContext.has(Tracer.lastContext())) { + this.eventsPerContext.set(Tracer.lastContext(), new Map()); + } + const eventsPerContext = this.eventsPerContext.get(Tracer.lastContext()); + eventsPerContext?.set(event, (eventsPerContext.get(event) ?? 0) + 1); + } + + traceEventsStats() { + if (this.events && this.eventsPerContext) { + const maxLength = Math.max( + ...[...this.events.keys()].map((it) => `Event "${it}"`.length), + ...[...this.eventsPerContext?.keys()].map((it) => ` in context [${it}]`.length) + ); + this.trace(`Events stats:`); + this.events.forEach((eventCnt: number, event: string) => { + this.trace(`${`Event "${event}"`.padEnd(maxLength)}: ${eventCnt}`); + this.eventsPerContext?.forEach((localizedEventsMap: Map, context: string) => { + localizedEventsMap.forEach((localizedEventCnt: number, localizedEvent: string) => { + if (localizedEvent == event) { + this.trace(`${` in context [${context}]`.padEnd(maxLength)}: ${localizedEventCnt}`); + } + }); + }); + }); + } else { + this.trace('No events recorded'); + } + Tracer.popContext(); + } + + private static contexts: string[] = []; + + static lastContext() { + return Tracer.contexts[Tracer.contexts.length - 1]; + } + + static pushContext(newContext: string) { + Tracer.contexts.push(newContext); + } + + static popContext() { + Tracer.contexts.pop(); + } +} + +export function traceGlobal(traceLog: () => string | undefined | void, forceLogToConsole: boolean = false) { + if (forceLogToConsole) { + const result = traceLog(); + if (result) { + console.log(`[${Tracer.lastContext()}] ${result}`); + } + } + if (!Tracer.GlobalTracer) { + return; + } + Tracer.GlobalTracer.trace(traceLog()); +} + +export function trace(event: string, traceLog: () => string | undefined | void, forceLogToConsole: boolean = false) { + if (forceLogToConsole) { + const result = traceLog(); + if (result) { + console.log(`[${Tracer.lastContext()}] ${result}`); + } + } + if (!Tracer.GlobalTracer) { + return; + } + Tracer.LRUTracer?.trace(traceLog()); + Tracer.GlobalTracer.recordEvent(event); +} diff --git a/ets1.2/libarkts/src/ts-api/factory/nodeFactory.ts b/ets1.2/libarkts/src/ts-api/factory/nodeFactory.ts new file mode 100644 index 0000000000000000000000000000000000000000..be52bd987d4db245432bd72516fb0126fc894db8 --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/factory/nodeFactory.ts @@ -0,0 +1,1250 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { throwError } from '../../utils'; +import * as ts from '@koalaui/ets-tsc'; +import * as arkts from '../../arkts-api'; + +import { + passNode, + passNodeArray, + passToken, + passModifiersToScriptFunction, + passModifiers, + passIdentifier, + passTypeParams, + passVariableDeclarationKind, +} from '../utilities/private'; +import { SyntaxKind, NodeFlags } from '../static/enums'; +import { + Es2pandaContextState, + Es2pandaPrimitiveType, + Es2pandaMethodDefinitionKind, + Es2pandaModifierFlags, + Es2pandaScriptFunctionFlags, + Es2pandaMemberExpressionKind, + Es2pandaClassDefinitionModifiers, + Es2pandaVariableDeclarationKind, + Es2pandaVariableDeclaratorFlag, +} from '../../arkts-api'; +import { + // ts types: + Modifier, + BinaryOperatorToken, + Node, + Token, + Identifier, + StringLiteral, + FunctionDeclaration, + Block, + KeywordTypeNode, + PropertyAccessExpression, + ParameterDeclaration, + ReturnStatement, + IfStatement, + ExpressionStatement, + CallExpression, + ArrowFunction, + TypeReferenceNode, + BinaryExpression, + FunctionTypeNode, + TypeNode, + Expression, + Statement, + SourceFile, + ClassElement, + MethodDeclaration, + ConstructorDeclaration, + TypeParameterDeclaration, + NumericLiteral, + ClassDeclaration, + VariableDeclaration, + VariableDeclarationList, + VariableStatement, + UnionTypeNode, + SuperExpression, + ParenthesizedExpression, + ImportDeclaration, + ImportClause, + ImportSpecifier, +} from '../types'; + +// Improve: add flags and base +export function createNodeFactory() { + return { + createSourceFile, + updateSourceFile, + createIdentifier, + createStringLiteral, + createNumericLiteral, + createFunctionDeclaration, + updateFunctionDeclaration, + createParameterDeclaration, + updateParameterDeclaration, + createETSTypeReferenceNode, + updateTypeReferenceNode, + createKeywordTypeNode, + createBlock, + updateBlock, + createExpressionStatement, + updateExpressionStatement, + createReturnStatement, + updateReturnStatement, + createPropertyAccessExpression, + updatePropertyAccessExpression, + createCallExpression, + updateCallExpression, + createIfStatement, + updateIfStatement, + createToken, + createBinaryExpression, + updateBinaryExpression, + createArrowFunction, + updateArrowFunction, + createFunctionTypeNode, + updateFunctionTypeNode, + createMethodDeclaration, + updateMethodDeclaration, + createConstructorDeclaration, + updateConstructorDeclaration, + createTypeParameterDeclaration, + updateTypeParameterDeclaration, + createClassDeclaration, + updateClassDeclaration, + createVariableDeclarationList, + updateVariableDeclarationList, + createVariableStatement, + updateVariableStatement, + createVariableDeclaration, + updateVariableDeclaration, + createETSUnionTypeNode, + updateETSUnionTypeNode, + createSuper, + updateSuper, + createParenthesizedExpression, + updateParenthesizedExpression, + // createImportDeclaration, + createImportSpecifier, + }; + + // @api + // function createSourceFile( + // statements: readonly Statement[], + // endOfFileToken: EndOfFileToken, + // flags: NodeFlags, + // ): SourceFile; + function createSourceFile( + source: string, + state: Es2pandaContextState = Es2pandaContextState.ES2PANDA_STATE_PARSED + ): SourceFile { + const node = arkts.EtsScript.createFromSource(source, state); + return new SourceFile(node); + } + + // Improve: fix (now doesn't create a new node) + // @api + // updateSourceFile( + // node: SourceFile, + // statements: readonly Statement[], + // isDeclarationFile?: boolean, + // referencedFiles?: readonly FileReference[], + // typeReferences?: readonly FileReference[], + // hasNoDefaultLib?: boolean, + // libReferences?: readonly FileReference[] + // ): SourceFile; + function updateSourceFile(node: SourceFile, statements: readonly Statement[]): SourceFile { + return new SourceFile(arkts.EtsScript.updateByStatements(node.node, passNodeArray(statements))); + } + + // @api + // createIdentifier( + // text: string + // ): Identifier; + function createIdentifier(text: string, typeAnnotation?: TypeNode | undefined): Identifier { + return new Identifier(arkts.factory.createIdentifier(text, passNode(typeAnnotation))); + } + + // @api + // createStringLiteral( + // text: string, + // isSingleQuote?: boolean + // ): StringLiteral; + function createStringLiteral(str: string): StringLiteral { + return new StringLiteral(arkts.factory.createStringLiteral(str)); + } + + // @api + // createNumericLiteral( + // value: string | number, + // numericLiteralFlags: TokenFlags = TokenFlags.None + // ): NumericLiteral { + function createNumericLiteral(value: number): NumericLiteral { + return new NumericLiteral(arkts.factory.createNumberLiteral(value)); + } + + // @api + // createVariableDeclarationList( + // declarations: readonly VariableDeclaration[], + // flags = NodeFlags.None + // ): VariableDeclarationList + function createVariableDeclarationList( + declarations: readonly VariableDeclaration[], + flags: NodeFlags = NodeFlags.None + ): VariableDeclarationList { + return new VariableDeclarationList( + arkts.factory.createVariableDeclaration( + passModifiers([]), + passVariableDeclarationKind(flags), + passNodeArray(declarations) + ) + ); + } + + // @api + // updateVariableDeclarationList( + // node: VariableDeclarationList, + // declarations: readonly VariableDeclaration[] + // ): VariableDeclarationList + function updateVariableDeclarationList( + node: VariableDeclarationList, + declarations: readonly VariableDeclaration[] + ): VariableDeclarationList { + return new VariableDeclarationList( + arkts.factory.updateVariableDeclaration( + node.node, + passModifiers([]), + passVariableDeclarationKind(node.flags), + passNodeArray(declarations) + ) + ); + } + + // @api + // createVariableStatement( + // modifiers: readonly ModifierLike[] | undefined, + // declarationList: VariableDeclarationList | readonly VariableDeclaration[] + // ): VariableStatement + function createVariableStatement( + modifiers: readonly Modifier[] | undefined, + declarationList: VariableDeclarationList | readonly VariableDeclaration[] + ): VariableStatement { + const node: arkts.VariableDeclaration = + declarationList instanceof VariableDeclarationList + ? declarationList.node + : createVariableDeclarationList(declarationList, undefined).node; + return new VariableStatement( + arkts.factory.createVariableDeclaration(passModifiers(modifiers), node.declarationKind, node.declarators) + ); + } + + // @api + // updateVariableStatement( + // node: VariableStatement, + // modifiers: readonly ModifierLike[] | undefined, + // declarationList: VariableDeclarationList + // ): VariableStatement + function updateVariableStatement( + node: VariableStatement, + modifiers: readonly Modifier[] | undefined, + declarationList: VariableDeclarationList + ): VariableStatement { + return new VariableStatement( + arkts.factory.updateVariableDeclaration( + node.node, + passModifiers(modifiers), + declarationList.node.declarationKind, + declarationList.node.declarators + ) + ); + } + + // @api + // createVariableDeclaration( + // name: string | BindingName, + // exclamationToken: ExclamationToken | undefined, + // type: TypeNode | undefined, + // initializer: Expression | undefined + // ): VariableDeclaration + function createVariableDeclaration( + name: string | Identifier, + exclamationToken: undefined, + type: TypeNode | undefined, + initializer: Expression | undefined + ): VariableDeclaration { + return new VariableDeclaration( + arkts.factory.createVariableDeclarator( + // Improve: maybe incorrect + Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_UNKNOWN, + passIdentifier(name, type), + passNode(initializer) + ) + ); + } + + // @api + // function updateVariableDeclaration( + // node: VariableDeclaration, + // name: BindingName, + // exclamationToken: ExclamationToken | undefined, + // type: TypeNode | undefined, + // initializer: Expression | undefined + // ): VariableDeclaration + function updateVariableDeclaration( + node: VariableDeclaration, + name: Identifier, + exclamationToken: undefined, + type: TypeNode | undefined, + initializer: Expression | undefined + ): VariableDeclaration { + return new VariableDeclaration( + arkts.factory.updateVariableDeclarator( + node.node, + // Improve: maybe incorrect + Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_UNKNOWN, + passIdentifier(name, type), + passNode(initializer) + ) + ); + } + + // @api + // createFunctionDeclaration( + // modifiers: readonly ModifierLike[] | undefined, + // asteriskToken: AsteriskToken | undefined, + // name: string | Identifier | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // parameters: readonly ParameterDeclaration[], + // type: TypeNode | undefined, + // body: Block | undefined + // ): FunctionDeclaration; + function createFunctionDeclaration( + modifiers: readonly Modifier[] | undefined, + asteriskToken: undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined + ): FunctionDeclaration { + return new FunctionDeclaration( + arkts.factory.createFunctionDeclaration( + arkts.factory.createScriptFunction( + body?.node, + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + type?.node + ), + 0, + passModifiers(modifiers) | + Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | + Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + body === undefined, + passIdentifier(name) + ), + false + ) + ); + } + + // @api + // updateFunctionDeclaration( + // node: FunctionDeclaration, + // modifiers: readonly ModifierLike[] | undefined, + // asteriskToken: AsteriskToken | undefined, + // name: Identifier | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // parameters: readonly ParameterDeclaration[], + // type: TypeNode | undefined, + // body: Block | undefined + // ): FunctionDeclaration; + function updateFunctionDeclaration( + node: FunctionDeclaration, + modifiers: readonly Modifier[] | undefined, + asteriskToken: undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined + ): FunctionDeclaration { + return new FunctionDeclaration( + arkts.factory.updateFunctionDeclaration( + node.node, + arkts.factory.updateScriptFunction( + node.node.scriptFunction, + body?.node, + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + type?.node + ), + 0, + passModifiers(modifiers) | + Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | + Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + body === undefined, + passIdentifier(name) + ), + false + ) + ); + } + + // @api + // createParameterDeclaration( + // modifiers: readonly ModifierLike[] | undefined, + // dotDotDotToken: DotDotDotToken | undefined, + // name: string | BindingName, + // questionToken?: QuestionToken, + // type?: TypeNode, + // initializer?: Expression + // ): ParameterDeclaration; + function createParameterDeclaration( + modifiers: readonly Modifier[] | undefined, + dotDotDotToken: undefined, + name: string | Identifier, + questionToken?: undefined, + type?: TypeNode, + initializer?: Expression + ): ParameterDeclaration { + return new ParameterDeclaration( + arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier(name instanceof Identifier ? name.node.name : name, type?.node), + initializer?.node + ) + ); + } + + // @api + // function updateParameterDeclaration( + // node: ParameterDeclaration, + // modifiers: readonly ModifierLike[] | undefined, + // dotDotDotToken: DotDotDotToken | undefined, + // name: string | BindingName, + // questionToken: QuestionToken | undefined, + // type: TypeNode | undefined, + // initializer: Expression | undefined, + // ): ParameterDeclaration + function updateParameterDeclaration( + node: ParameterDeclaration, + modifiers: readonly Modifier[] | undefined, + dotDotDotToken: undefined, + name: string | Identifier, + questionToken?: undefined, + type?: TypeNode, + initializer?: Expression + ): ParameterDeclaration { + return new ParameterDeclaration( + arkts.factory.updateParameterDeclaration( + node.node, + arkts.factory.createIdentifier(name instanceof Identifier ? name.node.name : name, type?.node), + initializer?.node + ) + ); + } + + // @api + // createTypeParameterDeclaration( + // modifiers: readonly Modifier[] | undefined, + // name: string | Identifier, + // constraint?: TypeNode, + // defaultType?: TypeNode + // ): TypeParameterDeclaration; + function createTypeParameterDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode + ): TypeParameterDeclaration { + return new TypeParameterDeclaration( + arkts.factory.createTypeParameter( + passIdentifier(name), + constraint?.node, + defaultType?.node, + passModifiers(modifiers) + ) + ); + } + + // @api + // function updateTypeParameterDeclaration( + // node: TypeParameterDeclaration, + // modifiers: readonly Modifier[] | undefined, + // name: Identifier, + // constraint: TypeNode | undefined, + // defaultType: TypeNode | undefined + // ): TypeParameterDeclaration + function updateTypeParameterDeclaration( + node: TypeParameterDeclaration, + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode + ): TypeParameterDeclaration { + return new TypeParameterDeclaration( + arkts.factory.updateTypeParameter( + node.node, + passIdentifier(name), + constraint?.node, + defaultType?.node, + passModifiers(modifiers) + ) + ); + } + + // @api + // createETSUnionTypeNode( + // types: readonly TypeNode[] + // ): UnionTypeNode + function createETSUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode { + return new UnionTypeNode(arkts.factory.createETSUnionType(passNodeArray(types))); + } + + // @api + // function updateETSUnionTypeNode( + // node: UnionTypeNode, + // types: NodeArray + // ): UnionTypeNode + function updateETSUnionTypeNode(node: UnionTypeNode, types: readonly TypeNode[]): UnionTypeNode { + return new UnionTypeNode(arkts.factory.updateETSUnionType(node.node, passNodeArray(types))); + } + + // @api + // createETSTypeReferenceNode( + // typeName: string | EntityName, + // typeArguments?: readonly TypeNode[] + // ): TypeReferenceNode; + function createETSTypeReferenceNode(typeName: Identifier, typeArguments?: undefined): TypeReferenceNode { + return new TypeReferenceNode(arkts.factory.createETSTypeReferenceFromId(typeName.node)); + } + + // @api + // function updateTypeReferenceNode( + // node: TypeReferenceNode, + // typeName: EntityName, + // typeArguments: NodeArray | undefined + // ): TypeReferenceNode + function updateTypeReferenceNode( + node: TypeReferenceNode, + typeName: Identifier, + typeArguments?: undefined + ): TypeReferenceNode { + return new TypeReferenceNode(arkts.factory.updateTypeReferenceFromId(node.node, typeName.node)); + } + + // @api + // createKeywordTypeNode( + // kind: TKind + // ): KeywordTypeNode; + function createKeywordTypeNode(TKind: ts.KeywordTypeSyntaxKind): KeywordTypeNode { + function createKeywordTypeNodeFromString(keyword: string): KeywordTypeNode { + return new KeywordTypeNode( + arkts.factory.createETSTypeReferenceFromId(arkts.factory.createIdentifier(keyword)) + ); + } + + function createKeywordTypeNodeFromKind(kind: number): KeywordTypeNode { + return new KeywordTypeNode(arkts.factory.createPrimitiveType(kind)); + } + + const keywords = new Map([ + [ts.SyntaxKind.NumberKeyword, createKeywordTypeNodeFromString('number')], + [ts.SyntaxKind.StringKeyword, createKeywordTypeNodeFromString('string')], + [ts.SyntaxKind.AnyKeyword, createKeywordTypeNodeFromString('any')], + [ts.SyntaxKind.VoidKeyword, createKeywordTypeNodeFromKind(8)], + ]); + return keywords.get(TKind) ?? throwError('unsupported keyword'); + } + + // @api + // createBlock( + // statements: readonly Statement[], + // multiLine?: boolean + // ): Block; + function createBlock(statements: readonly Statement[], multiline?: boolean): Block { + return new Block(arkts.factory.createBlock(passNodeArray(statements))); + } + + // @api + // updateBlock( + // node: Block, + // statements: readonly Statement[] + // ): Block; + function updateBlock(node: Block, statements: readonly Statement[]): Block { + return new Block(arkts.factory.updateBlock(node.node, passNodeArray(statements))); + } + + // @api + // createExpressionStatement( + // expression: Expression + // ): ExpressionStatement; + function createExpressionStatement(expression: Expression): ExpressionStatement { + return new ExpressionStatement(arkts.factory.createExpressionStatement(expression.node)); + } + + // @api + // updateExpressionStatement( + // node: ExpressionStatement, + // expression: Expression + // ): ExpressionStatement; + function updateExpressionStatement(node: ExpressionStatement, expression: Expression): ExpressionStatement { + return new ExpressionStatement(arkts.factory.updateExpressionStatement(node.node, expression.node)); + } + + // @api + // createReturnStatement( + // expression?: Expression + // ): ReturnStatement; + function createReturnStatement(expression: Expression): ReturnStatement { + return new ReturnStatement(arkts.factory.createReturnStatement(expression.node)); + } + + // @api + // function updateReturnStatement( + // node: ReturnStatement, + // expression: Expression | undefined + // ): ReturnStatement + function updateReturnStatement(node: ReturnStatement, expression: Expression): ReturnStatement { + return new ReturnStatement(arkts.factory.updateReturnStatement(node.node, expression.node)); + } + + // @api + // createPropertyAccessExpression( + // expression: Expression, + // name: string | MemberName + // ): PropertyAccessExpression; + function createPropertyAccessExpression( + expression: Expression, + name: string | Identifier + ): PropertyAccessExpression { + return new PropertyAccessExpression( + arkts.factory.createMemberExpression( + expression.node, + passIdentifier(name), + Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ) + ); + } + + // @api + // updatePropertyAccessExpression( + // node: PropertyAccessExpression, + // expression: Expression, + // name: MemberName + // ): PropertyAccessExpression; + function updatePropertyAccessExpression( + node: PropertyAccessExpression, + expression: Expression, + name: Identifier + ): PropertyAccessExpression { + return new PropertyAccessExpression( + arkts.factory.updateMemberExpression( + node.node, + expression.node, + passIdentifier(name), + Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ) + ); + } + + // @api + // createCallExpression( + // expression: Expression, + // typeArguments: readonly TypeNode[] | undefined, + // argumentsArray: readonly Expression[] | undefined + // ): CallExpression; + function createCallExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined + ): CallExpression { + return new CallExpression( + arkts.factory.createCallExpression( + expression.node, + typeArguments !== undefined + ? arkts.factory.createTypeParameterDeclaration(passNodeArray(typeArguments)) + : undefined, + passNodeArray(argumentsArray) + ) + ); + } + + // @api + // updateCallExpression( + // node: CallExpression, + // expression: Expression, + // typeArguments: readonly TypeNode[] | undefined, + // argumentsArray: readonly Expression[] + // ): CallExpression; + function updateCallExpression( + node: CallExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined + ): CallExpression { + return new CallExpression( + arkts.factory.updateCallExpression( + node.node, + expression.node, + typeArguments !== undefined + ? arkts.factory.createTypeParameterDeclaration(passNodeArray(typeArguments)) + : undefined, + passNodeArray(argumentsArray) + ) + ); + } + + // @api + // createIfStatement( + // expression: Expression, + // thenStatement: Statement, + // elseStatement?: Statement + // ): IfStatement; + function createIfStatement( + expression: Expression, + thenStatement: Statement, + elseStatement?: undefined + ): IfStatement { + return new IfStatement( + arkts.factory.createIfStatement(passNode(expression), passNode(thenStatement), passNode(elseStatement)) + ); + } + + // @api + // updateIfStatement( + // expression: Expression, + // thenStatement: Statement, + // elseStatement: Statement | undefined + // ): IfStatement; + function updateIfStatement( + node: IfStatement, + expression: Expression, + thenStatement: Statement, + elseStatement?: undefined + ): IfStatement { + return new IfStatement( + arkts.factory.updateIfStatement( + node.node, + passNode(expression), + passNode(thenStatement), + passNode(elseStatement) + ) + ); + } + + // Improve: rewrite maybe + // @api + // createToken( + // token: SyntaxKind._ + // ): _; + function createToken(token: TKind) { + return new Token(token); + } + + // @api + // createBinaryExpression( + // left: Expression, + // operator: BinaryOperator | BinaryOperatorToken, + // right: Expression + // ): BinaryExpression; + function createBinaryExpression( + left: Expression, + operator: BinaryOperatorToken, + right: Expression + ): BinaryExpression { + return new BinaryExpression( + arkts.factory.createBinaryExpression(passNode(left), passToken(operator), passNode(right)) + ); + } + + // @api + // function updateBinaryExpression( + // node: BinaryExpression, + // left: Expression, + // operator: BinaryOperatorToken, + // right: Expression + // ): BinaryExpression + function updateBinaryExpression( + node: BinaryExpression, + left: Expression, + operator: BinaryOperatorToken, + right: Expression + ): BinaryExpression { + return new BinaryExpression( + arkts.factory.updateBinaryExpression(node.node, passNode(left), passToken(operator), passNode(right)) + ); + } + + // @api + // createArrowFunction( + // modifiers: readonly Modifier[] | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // parameters: readonly ParameterDeclaration[], + // type: TypeNode | undefined, + // equalsGreaterThanToken: EqualsGreaterThanToken | undefined, + // body: ConciseBody + // ): ArrowFunction; + function createArrowFunction( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanToken: Token | undefined, + body: Block + ) { + return new ArrowFunction( + arkts.factory.createArrowFunction( + arkts.factory.createScriptFunction( + passNode(body), + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + passNode(type) + ), + passModifiersToScriptFunction(modifiers) | Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + passModifiers(modifiers) | Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + undefined + ) + ) + ); + } + + // @api + // function updateArrowFunction( + // node: ArrowFunction, + // modifiers: readonly Modifier[] | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // parameters: readonly ParameterDeclaration[], + // type: TypeNode | undefined, + // equalsGreaterThanToken: EqualsGreaterThanToken, + // body: ConciseBody, + // ): ArrowFunction + function updateArrowFunction( + node: ArrowFunction, + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: undefined, + equalsGreaterThanToken: Token | undefined, + body: Block + ): ArrowFunction { + return new ArrowFunction( + arkts.factory.updateArrowFunction( + node.node, + arkts.factory.updateScriptFunction( + node.node.scriptFunction, + passNode(body), + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + passNode(type) + ), + passModifiersToScriptFunction(modifiers) | Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + passModifiers(modifiers) | Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + undefined + ) + ) + ); + } + + // @api + // function createClassDeclaration( + // modifiers: readonly ModifierLike[] | undefined, + // name: string | Identifier | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // heritageClauses: readonly HeritageClause[] | undefined, + // members: readonly ClassElement[], + // ): ClassDeclaration + function createClassDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly TypeParameterDeclaration[] | undefined, + members: readonly ClassElement[] + ): ClassDeclaration { + return new ClassDeclaration( + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + passIdentifier(name), + passNodeArray(members), + // passModifiers(modifiers) | es2panda_ModifierFlags.MODIFIER_FLAGS_PUBLIC | es2panda_ModifierFlags.MODIFIER_FLAGS_STATIC, + Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + // Improve: pass through modifiers + Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_NONE, + passTypeParams(typeParameters), + undefined + ) + ) + ); + } + + // @api + // updateClassDeclaration( + // node: ClassDeclaration, + // modifiers: readonly ModifierLike[] | undefined, + // name: Identifier | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // heritageClauses: readonly HeritageClause[] | undefined, + // members: readonly ClassElement[] + // ): ClassDeclaration; + function updateClassDeclaration( + node: ClassDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: undefined, + members: readonly ClassElement[] + ): ClassDeclaration { + return new ClassDeclaration( + arkts.factory.updateClassDeclaration( + node.node, + arkts.factory.updateClassDefinition( + node.node.definition, + passIdentifier(name), + passNodeArray(members), + // passModifiers(modifiers) | es2panda_ModifierFlags.MODIFIER_FLAGS_PUBLIC | es2panda_ModifierFlags.MODIFIER_FLAGS_STATIC, + Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + // Improve: pass through modifiers + Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_NONE, + passTypeParams(typeParameters) + ) + ) + ); + } + + // @api + // tsc: createFunctionTypeNode( + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // parameters: readonly ParameterDeclaration[], + // type: TypeNode + // ): FunctionTypeNode; + function createFunctionTypeNode( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode + ): FunctionTypeNode { + return new FunctionTypeNode( + arkts.factory.createFunctionType( + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + passNode(type) + ), + Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE + ) + ); + } + + // @api + // function updateFunctionTypeNode( + // node: FunctionTypeNode, + // typeParameters: NodeArray | undefined, + // parameters: NodeArray, + // type: TypeNode, + // ): FunctionTypeNode + function updateFunctionTypeNode( + node: FunctionTypeNode, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode + ): FunctionTypeNode { + return new FunctionTypeNode( + arkts.factory.updateFunctionType( + node.node, + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + passNode(type) + ), + Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE + ) + ); + } + + // Improve: fix modifiers + // @api + // createMethodDeclaration( + // modifiers: readonly ModifierLike[] | undefined, + // asteriskToken: AsteriskToken | undefined, + // name: string | PropertyName, + // questionToken: QuestionToken | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // parameters: readonly ParameterDeclaration[], + // type: TypeNode | undefined, + // body: Block | undefined + // ): MethodDeclaration; + function createMethodDeclaration( + modifiers: readonly Modifier[] | undefined, + asteriskToken: undefined, + name: string | Identifier, + questionToken: undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined + ): MethodDeclaration { + const _name = passIdentifier(name); + return new MethodDeclaration( + arkts.factory.createMethodDefinition( + Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + _name, + arkts.factory.createFunctionExpression( + arkts.factory.createScriptFunction( + passNode(body), + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + passNode(type) + ), + 0, + passModifiers(modifiers) | Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC || + Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + false, + _name + ) + ), + passModifiers(modifiers), + false + ) + ); + } + + // @api + // tsc: updateMethodDeclaration( + // node: MethodDeclaration, + // modifiers: readonly ModifierLike[] | undefined, + // asteriskToken: AsteriskToken | undefined, + // name: PropertyName, + // questionToken: QuestionToken | undefined, + // typeParameters: readonly TypeParameterDeclaration[] | undefined, + // parameters: readonly ParameterDeclaration[], + // type: TypeNode | undefined, + // body: Block | undefined + // ): MethodDeclaration; + function updateMethodDeclaration( + node: MethodDeclaration, + modifiers: readonly Modifier[] | undefined, + asteriskToken: undefined, + name: Identifier, + questionToken: undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: undefined, + body: Block | undefined + ): MethodDeclaration { + const _name = passIdentifier(name); + return new MethodDeclaration( + arkts.factory.updateMethodDefinition( + node.node, + Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + _name, + arkts.factory.createFunctionExpression( + // Improve: maybe fix + arkts.factory.updateScriptFunction( + node.node.scriptFunction, + passNode(body), + arkts.FunctionSignature.create( + passTypeParams(typeParameters), + passNodeArray(parameters), + passNode(type) + ), + 0, + passModifiers(modifiers) | Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC || + Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + false, + _name + ) + ), + passModifiers(modifiers), + false + ) + ); + } + + // @api + // createConstructorDeclaration( + // modifiers: readonly ModifierLike[] | undefined, + // parameters: readonly ParameterDeclaration[], + // body: Block | undefined + // ): ConstructorDeclaration; + function createConstructorDeclaration( + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined + ): ConstructorDeclaration { + const _name = arkts.factory.createIdentifier('constructor'); + return new ConstructorDeclaration( + arkts.factory.createMethodDefinition( + Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, + _name, + arkts.factory.createFunctionExpression( + arkts.factory.createScriptFunction( + passNode(body), + arkts.FunctionSignature.create( + undefined, + passNodeArray(parameters), + // Improve: change to void maybe + undefined + ), + passModifiersToScriptFunction(modifiers) | + Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_CONSTRUCTOR, + passModifiers(modifiers) | + Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | + Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + false, + _name + ) + ), + passModifiers(modifiers) | Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + false + ) + ); + } + + // @api + // function updateConstructorDeclaration( + // node: ConstructorDeclaration, + // modifiers: readonly ModifierLike[] | undefined, + // parameters: readonly ParameterDeclaration[], + // body: Block | undefined, + // ): ConstructorDeclaration + function updateConstructorDeclaration( + node: ConstructorDeclaration, + modifiers: readonly Modifier[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined + ): ConstructorDeclaration { + const _name = arkts.factory.updateIdentifier(node.node.name, 'constructor'); + return new ConstructorDeclaration( + arkts.factory.updateMethodDefinition( + node.node, + Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, + _name, + arkts.factory.createFunctionExpression( + // Improve: maybe fix + arkts.factory.updateScriptFunction( + node.node.scriptFunction, + passNode(body), + arkts.FunctionSignature.create( + undefined, + passNodeArray(parameters), + // Improve: change to void maybe + undefined + ), + passModifiersToScriptFunction(modifiers) | + Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_CONSTRUCTOR, + passModifiers(modifiers) | + Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | + Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + false, + _name + ) + ), + passModifiers(modifiers) | Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + false + ) + ); + } + + // @api + // tsc: createSuper( + // ): SuperExpression; + function createSuper(): SuperExpression { + return new SuperExpression(arkts.factory.createSuperExpression()); + } + + // @api + // tsc: updateSuper( + // node: SuperExpression + // ): SuperExpression; + function updateSuper(node: SuperExpression): SuperExpression { + return new SuperExpression(arkts.factory.updateSuperExpression(node.node)); + } + + // @api + // tsc: createParenthesizedExpression( + // expression: Expression + // ): ParenthesizedExpression; + function createParenthesizedExpression(expression: Expression): ParenthesizedExpression { + return expression; + // Improve: + // return new ParenthesizedExpression( + // expression + // ) + } + + // @api + // tsc: updateParenthesizedExpression( + // node: ParenthesizedExpression, + // expression: Expression + // ): ParenthesizedExpression; + function updateParenthesizedExpression( + node: ParenthesizedExpression, + expression: Expression + ): ParenthesizedExpression { + return expression; + // Improve: + // return new ParenthesizedExpression( + // expression + // ) + } + + // // @api + // // createImportDeclaration( + // // decorators: readonly Decorator[] | undefined, + // // modifiers: readonly Modifier[] | undefined, + // // importClause: ImportClause | undefined, + // // moduleSpecifier: Expression, + // // assertClause?: AssertClause + // // ): ImportDeclaration; + // function createImportDeclaration( + // decorators: undefined, + // modifiers: readonly Modifier[] | undefined, + // importClause: ImportClause | undefined, + // moduleSpecifier: StringLiteral, + // assertClause?: undefined + // ): ImportDeclaration { + // return new ImportDeclaration( + // arkts.EtsImportDeclaration.create( + // undefined, + // arkts.ImportSource.create(moduleSpecifier.node), + + // ) + // ) + // } + + // @api + // createImportSpecifier( + // isTypeOnly: boolean, + // propertyName: Identifier | undefined, + // name: Identifier + // ): ImportSpecifier; + function createImportSpecifier( + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier + ): ImportSpecifier { + return new ImportSpecifier(name.node); + } +} + +export const factory = createNodeFactory(); diff --git a/ets1.2/libarkts/src/ts-api/factory/nodeTests.ts b/ets1.2/libarkts/src/ts-api/factory/nodeTests.ts new file mode 100644 index 0000000000000000000000000000000000000000..d646a08ef2c4b0896a324be0a58d7a7399c7b255 --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/factory/nodeTests.ts @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { SyntaxKind } from '@koalaui/ets-tsc'; + +import { + ArrowFunction, + Block, + CallExpression, + ClassDeclaration, + ExpressionStatement, + FunctionDeclaration, + FunctionExpression, + FunctionTypeNode, + GetAccessorDeclaration, + Identifier, + MethodDeclaration, + MethodSignature, + Node, + ParameterDeclaration, + PropertyAccessExpression, + PropertyDeclaration, + PropertySignature, + SetAccessorDeclaration, + SourceFile, + VariableDeclaration, + VariableDeclarationList, + VariableStatement, +} from '../types'; + +export function isIdentifier(node: Node): node is Identifier { + return node.kind === SyntaxKind.Identifier; +} + +export function isCallExpression(node: Node): node is CallExpression { + return node.kind === SyntaxKind.CallExpression; +} + +export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression { + return node.kind === SyntaxKind.PropertyAccessExpression; +} + +export function isFunctionDeclaration(node: Node): node is FunctionDeclaration { + return node.kind === SyntaxKind.FunctionDeclaration; +} + +export function isMethodDeclaration(node: Node): node is MethodDeclaration { + return node.kind === SyntaxKind.MethodDeclaration; +} + +export function isSourceFile(node: Node): node is SourceFile { + return node.kind === SyntaxKind.SourceFile; +} + +export function isExpressionStatement(node: Node): node is ExpressionStatement { + return node.kind === SyntaxKind.ExpressionStatement; +} + +export function isArrowFunction(node: Node): node is ArrowFunction { + return node.kind === SyntaxKind.ArrowFunction; +} + +export function isClassDeclaration(node: Node): node is ClassDeclaration { + return node.kind === SyntaxKind.ClassDeclaration; +} + +export function isBlock(node: Node): node is Block { + return node.kind === SyntaxKind.Block; +} + +export function isFunctionExpression(node: Node): node is FunctionExpression { + return node.kind === SyntaxKind.FunctionExpression; +} + +export function isParameter(node: Node): node is ParameterDeclaration { + return node.kind === SyntaxKind.Parameter; +} + +export function isVariableDeclaration(node: Node): node is VariableDeclaration { + return node.kind === SyntaxKind.VariableDeclaration; +} + +export function isVariableDeclarationList(node: Node): node is VariableDeclarationList { + return node.kind === SyntaxKind.VariableDeclarationList; +} + +export function isPropertyDeclaration(node: Node): node is PropertyDeclaration { + return node.kind === SyntaxKind.PropertyDeclaration; +} + +export function isPropertySignature(node: Node): node is PropertySignature { + return node.kind === SyntaxKind.PropertySignature; +} + +export function isFunctionTypeNode(node: Node): node is FunctionTypeNode { + return node.kind === SyntaxKind.FunctionType; +} + +export function isMethodSignature(node: Node): node is MethodSignature { + return node.kind === SyntaxKind.MethodSignature; +} + +export function isGetAccessorDeclaration(node: Node): node is GetAccessorDeclaration { + return node.kind === SyntaxKind.GetAccessor; +} + +export function isSetAccessorDeclaration(node: Node): node is SetAccessorDeclaration { + return node.kind === SyntaxKind.SetAccessor; +} + +export function isVariableStatement(node: Node): node is VariableStatement { + return node.kind === SyntaxKind.VariableStatement; +} diff --git a/ets1.2/libarkts/src/ts-api/index.ts b/ets1.2/libarkts/src/ts-api/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..731ef384fc474f57ea1b68c2002953bfb52b00ad --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +// Improve: remove private export +export * from './utilities/private'; +export * from './utilities/public'; +export * from './types'; +export * from './factory/nodeFactory'; +export * from './factory/nodeTests'; +export { visitEachChild } from './visitor/visitor'; +export { SyntaxKind, NodeFlags } from './static/enums'; + +// from ArkTS api +export * from '../arkts-api/static/global'; +export { Es2pandaContextState as ContextState, Es2pandaPrimitiveType as Es2pandaPrimitiveType } from '../arkts-api'; diff --git a/ets1.2/libarkts/src/ts-api/static/enums.ts b/ets1.2/libarkts/src/ts-api/static/enums.ts new file mode 100644 index 0000000000000000000000000000000000000000..bbc2b2798032d2e8b974ff55eaff5c4862b2e318 --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/static/enums.ts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +export { SyntaxKind } from '@koalaui/ets-tsc'; +export { TokenSyntaxKind } from '@koalaui/ets-tsc'; +export { NodeFlags } from '@koalaui/ets-tsc'; diff --git a/ets1.2/libarkts/src/ts-api/types.ts b/ets1.2/libarkts/src/ts-api/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8d50bffe09e1d63b443321f87fb2f63dec13796 --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/types.ts @@ -0,0 +1,1075 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as ts from '@koalaui/ets-tsc'; +import * as arkts from '../arkts-api'; + +import { throwError } from '../utils'; +import { + passModifiers, + emptyImplementation, + unpackModifiers, + unpackNode, + unpackNodeArray, + unpackVariableDeclarationKind, +} from './utilities/private'; +import { SyntaxKind } from './static/enums'; + +// Improve: write implementation +export interface TransformationContext {} + +// Improve: write implementation +export interface Program {} + +// Improve: remove U type param +export type NodeArray< + T extends Node, + U extends arkts.AstNode | undefined = arkts.AstNode | undefined, +> = ts.NodeArray; + +export abstract class Node implements ts.Node { + constructor(node: T) { + this.node = node; + } + + readonly node: T; + + // Improve: remove any + get parent(): any { + if (this.node === undefined) { + throwError('trying to get parent of undefined _node'); + } + return unpackNode(this.node.parent); + } + + set parent(node: Node) { + if (this.node === undefined) { + throwError('trying to set parent of undefined'); + } + if (node.node === undefined) { + throwError('trying to set parent to undefined'); + } + this.node.parent = node.node; + } + + set modifiers(flags: readonly Modifier[] | undefined) { + if (this.node === undefined) { + throwError('trying to set modifiers of undefined'); + } + this.node.modifiers = passModifiers(flags); + } + + get modifiers(): NodeArray { + return unpackModifiers(this.node?.modifiers); + } + + abstract kind: SyntaxKind; + + // Improve: + forEachChild( + cbNode: (node: ts.Node) => T | undefined, + cbNodeArray?: ((nodes: ts.NodeArray) => T | undefined) | undefined + ): T | undefined { + throw new Error('Method not implemented.'); + } + getSourceFile(): ts.SourceFile { + throw new Error('Method not implemented.'); + } + getChildCount(sourceFile?: ts.SourceFile | undefined): number { + throw new Error('Method not implemented.'); + } + getChildAt(index: number, sourceFile?: ts.SourceFile | undefined): ts.Node { + throw new Error('Method not implemented.'); + } + getChildren(sourceFile?: ts.SourceFile | undefined): ts.Node[] { + throw new Error('Method not implemented.'); + } + + getStart(sourceFile?: ts.SourceFile | undefined, includeJsDocComment?: boolean | undefined): number { + throw new Error('Method not implemented.'); + } + getFullStart(): number { + throw new Error('Method not implemented.'); + } + getEnd(): number { + throw new Error('Method not implemented.'); + } + getWidth(sourceFile?: ts.SourceFileLike | undefined): number { + throw new Error('Method not implemented.'); + } + getFullWidth(): number { + throw new Error('Method not implemented.'); + } + getLeadingTriviaWidth(sourceFile?: ts.SourceFile | undefined): number { + throw new Error('Method not implemented.'); + } + getFullText(sourceFile?: ts.SourceFile | undefined): string { + throw new Error('Method not implemented.'); + } + getText(sourceFile?: ts.SourceFile | undefined): string { + throw new Error('Method not implemented.'); + } + getFirstToken(sourceFile?: ts.SourceFile | undefined): ts.Node | undefined { + throw new Error('Method not implemented.'); + } + getLastToken(sourceFile?: ts.SourceFile | undefined): ts.Node | undefined { + throw new Error('Method not implemented.'); + } + + get symbol(): ts.Symbol { + return emptyImplementation(); + } + get flags(): ts.NodeFlags { + return emptyImplementation(); + } + get pos(): number { + return emptyImplementation(); + } + get end(): number { + return emptyImplementation(); + } +} + +// Improve: add all tokens +export type BinaryOperator = ts.SyntaxKind.PlusToken | ts.SyntaxKind.MinusToken | ts.SyntaxKind.AsteriskToken; + +export type BinaryOperatorToken = Token; + +// Improve: rethink maybe (temporary solution) +export class Token extends Node { + constructor(kind: TKind) { + super(undefined); + this.kind = kind; + } + + readonly kind: TKind; +} + +export type ModifierSyntaxKind = + // | SyntaxKind.ConstructorKeyword + | SyntaxKind.AbstractKeyword + | SyntaxKind.AccessorKeyword + | SyntaxKind.AsyncKeyword + | SyntaxKind.ConstKeyword + | SyntaxKind.DeclareKeyword + | SyntaxKind.DefaultKeyword + | SyntaxKind.ExportKeyword + | SyntaxKind.InKeyword + | SyntaxKind.PrivateKeyword + | SyntaxKind.ProtectedKeyword + | SyntaxKind.PublicKeyword + | SyntaxKind.ReadonlyKeyword + | SyntaxKind.OutKeyword + | SyntaxKind.OverrideKeyword + | SyntaxKind.StaticKeyword; + +export class Modifier extends Node { + constructor(kind: ModifierSyntaxKind) { + super(undefined); + this.kind = kind; + } + + public toString(): string { + return `${this.kind}`; + } + + kind: ModifierSyntaxKind; +} + +export abstract class Expression extends Node implements ts.Expression { + // Improve: support minimal interface + _expressionBrand: any; +} + +export class FunctionDeclaration + extends Node + implements ts.FunctionDeclaration, FunctionLikeDeclarationBase +{ + constructor(node: arkts.FunctionDeclaration) { + super(node); + this.name = unpackNode(node.name); + this.body = unpackNode(node.body); + this.typeParameters = unpackNodeArray(node.typeParamsDecl?.parameters); + this.type = unpackNode(node.returnType); + this.parameters = unpackNodeArray(node.parameters); + } + + readonly name?: Identifier | undefined; + readonly body?: Block | undefined; + readonly typeParameters?: NodeArray | undefined; + readonly type?: TypeNode | undefined; + readonly parameters: NodeArray; + readonly kind: ts.SyntaxKind.FunctionDeclaration = ts.SyntaxKind.FunctionDeclaration; + + // brands + _functionLikeDeclarationBrand: any; + _declarationBrand: any; + _statementBrand: any; +} + +export class FunctionExpression + extends Node + implements ts.FunctionExpression, FunctionLikeDeclarationBase +{ + constructor(node: arkts.FunctionExpression) { + super(node); + this.name = unpackNode(node.scriptFunction.ident); + if (node.scriptFunction.body === undefined) { + throwError('body expected to be not undefined'); + } + this.body = unpackNode(node.scriptFunction.body); + this.parameters = unpackNodeArray(node.scriptFunction.parameters); + } + + readonly name?: Identifier; + readonly body: Block; + readonly parameters: NodeArray; + readonly kind: ts.SyntaxKind.FunctionExpression = ts.SyntaxKind.FunctionExpression; + + // brands + _primaryExpressionBrand: any; + _memberExpressionBrand: any; + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; + _functionLikeDeclarationBrand: any; + _declarationBrand: any; +} + +export class Identifier extends Node implements ts.Identifier, Expression { + constructor(node: arkts.Identifier) { + super(node); + this.text = node.name; + } + + readonly text: string; + readonly kind: ts.SyntaxKind.Identifier = ts.SyntaxKind.Identifier; + + // Improve: + get escapedText(): ts.__String { + return emptyImplementation(); + } + + // brands + _primaryExpressionBrand: any; + _memberExpressionBrand: any; + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; + _declarationBrand: any; +} + +export class PrivateIdentifier extends Node implements ts.PrivateIdentifier, Expression { + constructor(node: arkts.Identifier) { + super(node); + this.text = node.name; + if (!node.isPrivate) { + throwError('identifier expected to be private'); + } + } + + readonly text: string; + readonly kind: ts.SyntaxKind.PrivateIdentifier = ts.SyntaxKind.PrivateIdentifier; + + // Improve: + get escapedText(): ts.__String { + return emptyImplementation(); + } + + // brands + _primaryExpressionBrand: any; + _memberExpressionBrand: any; + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; + _declarationBrand: any; +} + +export abstract class Statement extends Node implements ts.Statement { + // brands + _statementBrand: any; +} + +export class Block extends Node implements ts.Block { + constructor(node: arkts.BlockStatement) { + super(node); + this.statements = unpackNodeArray(node.statements); + } + + readonly statements: NodeArray; + readonly kind: ts.SyntaxKind.Block = ts.SyntaxKind.Block; + + // brands + _statementBrand: any; +} + +export class SourceFile extends Node implements ts.SourceFile { + constructor(node: arkts.EtsScript) { + super(node); + + this.statements = unpackNodeArray(this.node.statements); + } + + readonly statements: NodeArray; + readonly kind: ts.SyntaxKind.SourceFile = ts.SyntaxKind.SourceFile; + + // Improve: + getLineAndCharacterOfPosition(pos: number): ts.LineAndCharacter { + throw new Error('Method not implemented.'); + } + getLineEndOfPosition(pos: number): number { + throw new Error('Method not implemented.'); + } + getLineStarts(): readonly number[] { + throw new Error('Method not implemented.'); + } + getPositionOfLineAndCharacter(line: number, character: number): number { + throw new Error('Method not implemented.'); + } + update(newText: string, textChangeRange: ts.TextChangeRange): ts.SourceFile { + throw new Error('Method not implemented.'); + } + get endOfFileToken(): ts.Token { + return emptyImplementation(); + } + get fileName(): string { + return emptyImplementation(); + } + get text() { + return emptyImplementation(); + } + get amdDependencies(): readonly ts.AmdDependency[] { + return emptyImplementation(); + } + get referencedFiles(): readonly ts.FileReference[] { + return emptyImplementation(); + } + get typeReferenceDirectives(): readonly ts.FileReference[] { + return emptyImplementation(); + } + get libReferenceDirectives(): readonly ts.FileReference[] { + return emptyImplementation(); + } + get languageVariant(): ts.LanguageVariant { + return emptyImplementation(); + } + get isDeclarationFile(): boolean { + return emptyImplementation(); + } + get hasNoDefaultLib(): boolean { + return emptyImplementation(); + } + get languageVersion(): ts.ScriptTarget { + return emptyImplementation(); + } + + // brands + _declarationBrand: any; +} + +export abstract class LeftHandSideExpression + extends Node + implements ts.LeftHandSideExpression, Expression +{ + // brands + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; +} + +export class ExpressionStatement extends Node implements ts.ExpressionStatement, Statement { + constructor(node: arkts.ExpressionStatement) { + super(node); + this.expression = unpackNode(this.node.expression); + } + + readonly expression: Expression; + readonly kind: ts.SyntaxKind.ExpressionStatement = ts.SyntaxKind.ExpressionStatement; + + // brands + _statementBrand: any; +} + +export class CallExpression extends Node implements ts.CallExpression, LeftHandSideExpression { + constructor(node: arkts.CallExpression) { + super(node); + this.expression = unpackNode(node.expression); + this.arguments = unpackNodeArray(node.arguments); + } + + readonly expression: LeftHandSideExpression; + readonly arguments: NodeArray; + readonly kind: ts.SyntaxKind.CallExpression = ts.SyntaxKind.CallExpression; + + // brands + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; + _declarationBrand: any; +} + +export class PropertyAccessExpression + extends Node + implements ts.PropertyAccessExpression, Expression +{ + constructor(node: arkts.MemberExpression) { + super(node); + this.expression = unpackNode(node.object); + this.name = unpackNode(node.property); + } + + readonly expression: LeftHandSideExpression; + readonly name: Identifier; + readonly kind: ts.SyntaxKind.PropertyAccessExpression = ts.SyntaxKind.PropertyAccessExpression; + + // brands + _memberExpressionBrand: any; + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; + _declarationBrand: any; +} + +export class StringLiteral extends Node implements ts.StringLiteral { + constructor(node: arkts.StringLiteral) { + super(node); + + this.text = node.str; + } + + readonly text: string; + readonly kind: ts.SyntaxKind.StringLiteral = ts.SyntaxKind.StringLiteral; + + // brands + _literalExpressionBrand: any; + _primaryExpressionBrand: any; + _memberExpressionBrand: any; + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; + _declarationBrand: any; +} + +export class ClassDeclaration extends Node implements ts.ClassDeclaration { + constructor(node: arkts.ClassDeclaration) { + super(node); + this.name = unpackNode(node.definition.name); + this.members = unpackNodeArray(node.definition.members); + this.typeParameters = unpackNodeArray(node.definition.typeParamsDecl?.parameters); + } + + readonly name: Identifier; + readonly members: NodeArray; + readonly typeParameters?: NodeArray; + readonly kind: ts.SyntaxKind.ClassDeclaration = ts.SyntaxKind.ClassDeclaration; + + // brands + _declarationBrand: any; + _statementBrand: any; +} + +export abstract class ClassElement extends Node implements ts.ClassElement { + // brands + _declarationBrand: any; + _classElementBrand: any; +} + +export type MemberName = Identifier | PrivateIdentifier; + +// Improve: support +// export type PropertyName = Identifier | StringLiteral | NumericLiteral | ts.ComputedPropertyName | PrivateIdentifier; +export type PropertyName = Identifier | StringLiteral | NumericLiteral | PrivateIdentifier; + +// Improve: support +export type DeclarationName = PropertyName; +// | JsxAttributeName +// | StringLiteralLike +// | ElementAccessExpression +// | BindingPattern +// | EntityNameExpression; + +export interface Declaration extends Node {} + +export abstract class NamedDeclaration extends Node implements ts.NamedDeclaration, Declaration { + readonly name?: DeclarationName; + + // brands + _declarationBrand: any; +} + +export type SignatureDeclaration = + | ts.CallSignatureDeclaration + | ts.ConstructSignatureDeclaration + | MethodSignature + | ts.IndexSignatureDeclaration + | FunctionTypeNode + | ts.ConstructorTypeNode + | ts.JSDocFunctionType + | FunctionDeclaration + | MethodDeclaration + | ConstructorDeclaration + | ts.AccessorDeclaration + | FunctionExpression + | ArrowFunction; + +export interface SignatureDeclarationBase extends NamedDeclaration {} + +export type VariableLikeDeclaration = + | ts.VariableDeclaration + | ParameterDeclaration + | ts.BindingElement + | PropertyDeclaration + | ts.PropertyAssignment + | PropertySignature + | ts.JsxAttribute + | ts.ShorthandPropertyAssignment + | ts.EnumMember + | ts.JSDocPropertyTag + | ts.JSDocParameterTag; + +export interface FunctionLikeDeclarationBase extends SignatureDeclarationBase { + // brands + _functionLikeDeclarationBrand: any; +} + +// Improve: support +// export type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction; +export type FunctionLikeDeclaration = + | FunctionDeclaration + | MethodDeclaration + | ConstructorDeclaration + | FunctionExpression + | ArrowFunction; + +export class MethodSignature extends Node implements ts.MethodSignature, SignatureDeclarationBase { + constructor(node: arkts.AstNode) { + super(node); + } + + // readonly name: PropertyName + // readonly parameters: NodeArray + readonly kind: ts.SyntaxKind.MethodSignature = ts.SyntaxKind.MethodSignature; + + // Improve: + name: any; + parameters: any; + + // brands + _declarationBrand: any; + _typeElementBrand: any; +} + +// export class MethodDeclaration extends Node implements ts.MethodDeclaration, FunctionLikeDeclarationBase, ClassElement { +export class MethodDeclaration extends Node implements ts.MethodDeclaration, ClassElement { + constructor(node: arkts.MethodDefinition) { + super(node); + this.name = unpackNode(node.name); + this.parameters = unpackNodeArray(node.scriptFunction.parameters); + this.body = unpackNode(node.scriptFunction.body); + } + + // tsc: readonly name?: PropertyName + readonly name: Identifier; + readonly parameters: NodeArray; + // tsc: readonly body?: FunctionBody | undefined + readonly body?: Block | undefined; + readonly kind: ts.SyntaxKind.MethodDeclaration = ts.SyntaxKind.MethodDeclaration; + + // brands + _functionLikeDeclarationBrand: any; + _classElementBrand: any; + _objectLiteralBrand: any; + _declarationBrand: any; +} + +// export class ConstructorDeclaration extends Node implements ts.ConstructorDeclaration, FunctionLikeDeclarationBase, ClassElement { +export class ConstructorDeclaration + extends Node + implements ts.ConstructorDeclaration, ClassElement +{ + constructor(node: arkts.MethodDefinition) { + super(node); + this.name = unpackNode(node.name); + this.parameters = unpackNodeArray(node.scriptFunction.parameters); + this.body = unpackNode(node.scriptFunction.body); + } + + // ts: readonly name?: PropertyName + readonly name: Identifier; + readonly parameters: NodeArray; + // ts: readonly body?: FunctionBody | undefined + readonly body?: Block; + readonly kind: ts.SyntaxKind.Constructor = ts.SyntaxKind.Constructor; + + // brands + _functionLikeDeclarationBrand: any; + _classElementBrand: any; + _objectLiteralBrand: any; + _declarationBrand: any; +} + +// Improve: specify arkts.AstNode type +export class PropertySignature extends Node implements ts.TypeElement { + constructor(node: arkts.AstNode) { + super(node); + } + + readonly name?: PropertyName; + readonly kind: ts.SyntaxKind.PropertySignature = ts.SyntaxKind.PropertySignature; + + // brands + _typeElementBrand: any; + _declarationBrand: any; +} + +// Improve: specify arkts.AstNode type +export class PropertyDeclaration extends Node implements ts.PropertyDeclaration, ClassElement { + constructor(node: arkts.AstNode) { + super(node); + } + + readonly kind: ts.SyntaxKind.PropertyDeclaration = ts.SyntaxKind.PropertyDeclaration; + + // Improve: + name: any; + + // brands + _classElementBrand: any; + _declarationBrand: any; +} + +// Improve: specify arkts.AstNode type +export class GetAccessorDeclaration + extends Node + implements ts.GetAccessorDeclaration, FunctionLikeDeclarationBase, ClassElement +{ + constructor(node: arkts.AstNode) { + super(node); + } + + // readonly name: PropertyName + // readonly parameters: NodeArray + readonly kind: ts.SyntaxKind.GetAccessor = ts.SyntaxKind.GetAccessor; + + // Improve: + name: any; + parameters: any; + + // brands + _functionLikeDeclarationBrand: any; + _declarationBrand: any; + _classElementBrand: any; + _typeElementBrand: any; + _objectLiteralBrand: any; +} + +// Improve: specify arkts.AstNode type +export class SetAccessorDeclaration + extends Node + implements ts.SetAccessorDeclaration, FunctionLikeDeclarationBase, ClassElement +{ + constructor(node: arkts.AstNode) { + super(node); + } + + // readonly name: PropertyName + // readonly parameters: NodeArray + readonly kind: ts.SyntaxKind.SetAccessor = ts.SyntaxKind.SetAccessor; + + // Improve: + name: any; + parameters: any; + + // brands + _functionLikeDeclarationBrand: any; + _declarationBrand: any; + _classElementBrand: any; + _typeElementBrand: any; + _objectLiteralBrand: any; +} + +export class ParameterDeclaration + extends Node + implements ts.ParameterDeclaration, NamedDeclaration +{ + constructor(node: arkts.ETSParameterExpression) { + super(node); + } + + readonly kind: ts.SyntaxKind.Parameter = ts.SyntaxKind.Parameter; + + // Improve: + name: any; + + // brands + _declarationBrand: any; +} + +export type BindingName = Identifier | ts.BindingPattern; + +export class VariableStatement extends Node implements ts.VariableStatement { + constructor(node: arkts.VariableDeclaration) { + super(node); + this.declarationList = new VariableDeclarationList(node); + } + + readonly declarationList: VariableDeclarationList; + readonly kind: ts.SyntaxKind.VariableStatement = ts.SyntaxKind.VariableStatement; + + // brands + _statementBrand: any; +} + +export class VariableDeclarationList extends Node implements ts.VariableDeclarationList { + constructor(node: arkts.VariableDeclaration) { + super(node); + this.declarations = unpackNodeArray(node.declarators); + } + + readonly declarations: NodeArray; + get flags(): ts.NodeFlags { + return unpackVariableDeclarationKind(this.node.declarationKind); + } + readonly kind: ts.SyntaxKind.VariableDeclarationList = ts.SyntaxKind.VariableDeclarationList; +} + +export class VariableDeclaration + extends Node + implements ts.VariableDeclaration, NamedDeclaration +{ + constructor(node: arkts.VariableDeclarator) { + super(node); + this.name = unpackNode(node.name); + } + + readonly name: Identifier; + readonly kind: ts.SyntaxKind.VariableDeclaration = ts.SyntaxKind.VariableDeclaration; + + // brands + _declarationBrand: any; +} + +export class TypeParameterDeclaration extends Node implements ts.TypeParameterDeclaration { + constructor(node: arkts.TSTypeParameter) { + super(node); + this.name = unpackNode(node.name); + } + + readonly name: Identifier; + readonly kind: ts.SyntaxKind.TypeParameter = ts.SyntaxKind.TypeParameter; + + // brands + _declarationBrand: any; +} + +export abstract class TypeNode extends Node implements ts.TypeNode { + // brands + _typeNodeBrand: any; +} + +export class KeywordTypeNode + extends Node + implements ts.KeywordTypeNode, TypeNode +{ + constructor(node: arkts.ETSPrimitiveType | arkts.ETSTypeReference) { + super(node); + } + + readonly kind: ts.KeywordTypeSyntaxKind = ts.SyntaxKind.UnknownKeyword; + + // brands + _typeNodeBrand: any; +} + +export class TypeReferenceNode extends Node implements ts.TypeReferenceNode, TypeNode { + constructor(node: arkts.AstNode) { + super(node); + } + + readonly kind: ts.SyntaxKind.TypeReference = ts.SyntaxKind.TypeReference; + + // Improve: + typeName: any; + + // brands + _typeNodeBrand: any; +} + +export class FunctionTypeNode + extends Node + implements ts.FunctionTypeNode, TypeNode, SignatureDeclarationBase +{ + constructor(node: arkts.AstNode) { + super(node); + } + + readonly name?: DeclarationName; + readonly kind: ts.SyntaxKind.FunctionType = ts.SyntaxKind.FunctionType; + + // Improve: support minimal interface + parameters: any; + type: any; + + // brands + _typeNodeBrand: any; + _declarationBrand: any; +} + +export class UnionTypeNode extends Node implements ts.UnionTypeNode, TypeNode { + constructor(node: arkts.ETSUnionType) { + super(node); + this.types = unpackNodeArray(node.types); + } + + readonly types: NodeArray; + readonly kind: ts.SyntaxKind.UnionType = ts.SyntaxKind.UnionType; + + // brands + _typeNodeBrand: any; +} + +export class ReturnStatement extends Node implements ts.ReturnStatement, Statement { + constructor(node: arkts.ReturnStatement) { + super(node); + this.expression = unpackNode(node.argument); + } + + readonly expression: Expression | undefined; + readonly kind: ts.SyntaxKind.ReturnStatement = ts.SyntaxKind.ReturnStatement; + + // brands + _statementBrand: any; +} + +export class IfStatement extends Node implements ts.IfStatement { + constructor(node: arkts.IfStatement) { + super(node); + } + + readonly kind: ts.SyntaxKind.IfStatement = ts.SyntaxKind.IfStatement; + + // Improve: + thenStatement: any; + expression: any; + + // brands + _statementBrand: any; +} + +export class BinaryExpression extends Node implements ts.BinaryExpression { + constructor(node: arkts.BinaryExpression) { + super(node); + } + + readonly kind: ts.SyntaxKind.BinaryExpression = ts.SyntaxKind.BinaryExpression; + + // Improve: + left: any; + right: any; + operatorToken: any; + + // brands + _expressionBrand: any; + _declarationBrand: any; +} + +export class AssignmentExpression extends Node implements ts.AssignmentExpression { + constructor(node: arkts.AssignmentExpression) { + super(node); + } + + readonly kind: ts.SyntaxKind.BinaryExpression = ts.SyntaxKind.BinaryExpression; + + // Improve: + right: any; + left: any; + operatorToken: any; + + // brands + _expressionBrand: any; + _declarationBrand: any; +} + +export class ArrowFunction extends Node implements ts.ArrowFunction { + constructor(node: arkts.ArrowFunctionExpression) { + super(node); + if (node.scriptFunction.body === undefined) { + throwError('node.scriptFunction.body not expected to be undefined'); + } + this.body = unpackNode(node.scriptFunction.body); + this.parameters = unpackNodeArray(node.scriptFunction.parameters); + } + + get name(): never { + return throwError(`name doesn't exist for ArrowFunction`); + } + readonly body: Block; + readonly parameters: NodeArray; + readonly kind: ts.SyntaxKind.ArrowFunction = ts.SyntaxKind.ArrowFunction; + + // Improve: + equalsGreaterThanToken: any; + + // brands + _expressionBrand: any; + _functionLikeDeclarationBrand: any; + _declarationBrand: any; +} + +export class NumericLiteral extends Node implements ts.NumericLiteral, Declaration { + constructor(node: arkts.NumberLiteral) { + super(node); + + this.text = `${node.value}`; + } + + readonly text: string; + readonly kind: ts.SyntaxKind.NumericLiteral = ts.SyntaxKind.NumericLiteral; + + // brands + _literalExpressionBrand: any; + _declarationBrand: any; + _primaryExpressionBrand: any; + _memberExpressionBrand: any; + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; +} + +export class SuperExpression extends Node implements ts.SuperExpression { + constructor(node: arkts.SuperExpression) { + super(node); + } + + readonly kind: ts.SyntaxKind.SuperKeyword = ts.SyntaxKind.SuperKeyword; + + // brands + _primaryExpressionBrand: any; + _memberExpressionBrand: any; + _leftHandSideExpressionBrand: any; + _updateExpressionBrand: any; + _unaryExpressionBrand: any; + _expressionBrand: any; +} + +export class HeritageClause extends Node implements ts.HeritageClause { + constructor(node: arkts.SuperExpression) { + super(node); + } + + readonly kind: ts.SyntaxKind.HeritageClause = ts.SyntaxKind.HeritageClause; + // token: ts.SyntaxKind.ExtendsKeyword | ts.SyntaxKind.ImplementsKeyword + // types: ts.NodeArray + + // Improve: + token: any; + types: any; +} + +// Improve: there is no ParenthesizedExpression in ArkTS, +// so for temporary solution we're just gonna ignore this type of nodes +// and replace it with Expression underneath +export type ParenthesizedExpression = Expression; +// export class ParenthesizedExpression extends Node implements ts.ParenthesizedExpression { +// constructor(expression: Expression) { +// super(undefined) +// this.expression = expression +// } + +// readonly expression: Expression +// readonly kind: ts.SyntaxKind.ParenthesizedExpression = ts.SyntaxKind.ParenthesizedExpression + +// // brands +// _primaryExpressionBrand: any +// _memberExpressionBrand: any +// _leftHandSideExpressionBrand: any +// _updateExpressionBrand: any +// _unaryExpressionBrand: any +// _expressionBrand: any +// } + +// Improve: +export class ImportDeclaration extends Node implements ts.ImportDeclaration { + constructor(node: arkts.UnsupportedNode) { + super(node); + } + + readonly kind: ts.SyntaxKind.ImportDeclaration = ts.SyntaxKind.ImportDeclaration; + + // Improve: + moduleSpecifier: any; + + // brands + _statementBrand: any; +} + +// Improve: +export class ImportClause extends Node implements ts.ImportClause { + constructor(node: arkts.UnsupportedNode) { + super(node); + } + + readonly kind: ts.SyntaxKind.ImportClause = ts.SyntaxKind.ImportClause; + + // Improve: + isTypeOnly: any; + + // brands + _declarationBrand: any; +} + +// Improve: +export class NamedImports extends Node implements ts.NamedImports { + constructor(node: arkts.UnsupportedNode) { + super(node); + } + + readonly kind: ts.SyntaxKind.NamedImports = ts.SyntaxKind.NamedImports; + + // Improve: + elements: any; +} + +export class ImportSpecifier extends Node implements ts.ImportSpecifier { + constructor(node: arkts.Identifier) { + super(node); + this.name = unpackNode(this.node); + } + + readonly name: Identifier; + readonly kind: ts.SyntaxKind.ImportSpecifier = ts.SyntaxKind.ImportSpecifier; + + // Improve: + isTypeOnly: any; + + // brands + _declarationBrand: any; +} + +export class UnsupportedNode extends Node implements ts.Node { + constructor(node: arkts.AstNode) { + super(node); + } + + readonly kind: ts.SyntaxKind = SyntaxKind.Unknown; +} diff --git a/ets1.2/libarkts/src/ts-api/utilities/private.ts b/ets1.2/libarkts/src/ts-api/utilities/private.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9334fbe90b0b7c9d2f8789f14b6bed831827156 --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/utilities/private.ts @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { throwError } from '../../utils'; + +import * as ts from '../'; +import * as arkts from '../../arkts-api'; + +import { KInt } from '@koalaui/interop'; +import { SyntaxKind, TokenSyntaxKind, NodeFlags } from '../static/enums'; +import { + Es2pandaAstNodeType, + Es2pandaModifierFlags, + Es2pandaScriptFunctionFlags, + Es2pandaTokenType, + Es2pandaVariableDeclarationKind, +} from '../../arkts-api'; + +export function emptyImplementation(): any { + throwError('Not yet implemented'); +} + +type kindTypes = + | { new (node: arkts.AstNode): ts.Node } + | { new (node: arkts.Identifier): ts.Identifier } + | { new (node: arkts.EtsScript): ts.SourceFile } + | { new (node: arkts.StringLiteral): ts.StringLiteral } + | { new (node: arkts.NumberLiteral): ts.NumericLiteral } + | { new (node: arkts.ExpressionStatement): ts.ExpressionStatement } + | { new (node: arkts.FunctionDeclaration): ts.FunctionDeclaration } + | { new (node: arkts.ReturnStatement): ts.ReturnStatement } + | { new (node: arkts.ETSParameterExpression): ts.ParameterDeclaration } + | { new (node: arkts.CallExpression): ts.CallExpression } + | { new (node: arkts.BlockStatement): ts.Block } + | { new (node: arkts.TSTypeParameter): ts.TypeParameterDeclaration } + | { new (node: arkts.MemberExpression): ts.PropertyAccessExpression } + | { new (node: arkts.IfStatement): ts.IfStatement } + | { new (node: arkts.ETSTypeReference): ts.TypeReferenceNode } + | { new (node: arkts.ETSPrimitiveType | arkts.ETSTypeReference): ts.KeywordTypeNode } + | { new (node: arkts.BinaryExpression): ts.BinaryExpression } + | { new (node: arkts.ETSUnionType): ts.UnionTypeNode } + | { new (node: arkts.ArrowFunctionExpression): ts.ArrowFunction } + | { new (node: arkts.ClassDeclaration): ts.ClassDeclaration } + | { new (node: arkts.MethodDefinition): ts.MethodDeclaration } + | { new (node: arkts.VariableDeclarator): ts.VariableDeclaration } + | { new (node: arkts.VariableDeclaration): ts.VariableStatement }; + +export function classByEtsNode(node: arkts.AstNode) { + const types = new Map([ + [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE, ts.SourceFile], + [Es2pandaAstNodeType.AST_NODE_TYPE_IDENTIFIER, ts.Identifier], + [Es2pandaAstNodeType.AST_NODE_TYPE_STRING_LITERAL, ts.StringLiteral], + [Es2pandaAstNodeType.AST_NODE_TYPE_NUMBER_LITERAL, ts.NumericLiteral], + [Es2pandaAstNodeType.AST_NODE_TYPE_EXPRESSION_STATEMENT, ts.ExpressionStatement], + [Es2pandaAstNodeType.AST_NODE_TYPE_FUNCTION_DECLARATION, ts.FunctionDeclaration], + [Es2pandaAstNodeType.AST_NODE_TYPE_RETURN_STATEMENT, ts.ReturnStatement], + [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PARAMETER_EXPRESSION, ts.ParameterDeclaration], + [Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, ts.CallExpression], + [Es2pandaAstNodeType.AST_NODE_TYPE_BLOCK_STATEMENT, ts.Block], + [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_TYPE_REFERENCE, ts.TypeReferenceNode], + [Es2pandaAstNodeType.AST_NODE_TYPE_TS_TYPE_PARAMETER, ts.TypeParameterDeclaration], + [Es2pandaAstNodeType.AST_NODE_TYPE_MEMBER_EXPRESSION, ts.PropertyAccessExpression], + [Es2pandaAstNodeType.AST_NODE_TYPE_IF_STATEMENT, ts.IfStatement], + [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PRIMITIVE_TYPE, ts.KeywordTypeNode], + [Es2pandaAstNodeType.AST_NODE_TYPE_BINARY_EXPRESSION, ts.BinaryExpression], + [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_UNION_TYPE, ts.UnionTypeNode], + [Es2pandaAstNodeType.AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION, ts.ArrowFunction], + [Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, ts.ClassDeclaration], + [Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, ts.MethodDeclaration], + [Es2pandaAstNodeType.AST_NODE_TYPE_VARIABLE_DECLARATION, ts.VariableStatement], + [Es2pandaAstNodeType.AST_NODE_TYPE_VARIABLE_DECLARATOR, ts.VariableDeclaration], + [Es2pandaAstNodeType.AST_NODE_TYPE_SUPER_EXPRESSION, ts.SuperExpression], + + [Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_STATIC_BLOCK, ts.UnsupportedNode], + [Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, ts.UnsupportedNode], + [Es2pandaAstNodeType.AST_NODE_TYPE_ETS_IMPORT_DECLARATION, ts.UnsupportedNode], + ]); + + return types.get(node.type) ?? throwError(`UNSUPPORTED NODE (ts): ${Es2pandaAstNodeType[node.type]}`); +} + +// Improve: add checks for casts in functions below + +export function unpackNode>(node: U): T; +export function unpackNode>(node: U): T | undefined; +export function unpackNode>(node: U): T | undefined { + if (node === undefined) { + return undefined; + } + return new (classByEtsNode(node))(node as any) as T; +} + +export function passNode(node: ts.Node): T; +export function passNode(node: ts.Node | undefined): T | undefined; +export function passNode(node: ts.Node | undefined): T | undefined { + if (node === undefined) { + return undefined; + } + return (node.node as T) ?? throwError('trying to pass non-compatible node'); +} + +export function unpackNodeArray>( + nodes: readonly U[] +): ts.NodeArray; +export function unpackNodeArray>( + nodes: readonly U[] | undefined +): ts.NodeArray | undefined; +export function unpackNodeArray>( + nodes: readonly U[] | undefined +): ts.NodeArray | undefined { + return nodes?.map((node: U) => unpackNode(node)) as ReadonlyArray> as ts.NodeArray; +} + +export function passNodeArray(nodes: readonly ts.Node[]): T[]; +export function passNodeArray(nodes: readonly ts.Node[] | undefined): T[] | undefined; +export function passNodeArray(nodes: readonly ts.Node[] | undefined): T[] | undefined { + return nodes?.map((node: ts.Node) => passNode(node)); +} + +export function passIdentifier(node: ts.Identifier | string, typeAnnotation?: ts.TypeNode): arkts.Identifier; +export function passIdentifier( + node: ts.Identifier | string | undefined, + typeAnnotation?: ts.TypeNode +): arkts.Identifier | undefined; +export function passIdentifier( + node: ts.Identifier | string | undefined, + typeAnnotation?: ts.TypeNode +): arkts.Identifier | undefined { + if (node === undefined) { + return undefined; + } + if (node instanceof ts.Identifier) { + if (typeAnnotation === undefined) { + return node.node; + } + return arkts.Identifier.create(node.node.name, passNode(typeAnnotation)); + } + return arkts.Identifier.create(node, passNode(typeAnnotation)); +} + +// Improve: support optional params +export function passTypeParams( + params: readonly ts.TypeParameterDeclaration[] | undefined +): arkts.TSTypeParameterDeclaration | undefined { + if (params === undefined) { + return undefined; + } + return arkts.factory.createTypeParameterDeclaration(passNodeArray(params)); +} + +export function unpackModifiers(modifiers: KInt | undefined): ts.NodeArray { + const translation = new Map([ + // [Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, SyntaxKind.UnknownKeyword], + // [Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, SyntaxKind.ConstructorKeyword], + + [Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT, SyntaxKind.AbstractKeyword], + // Improve: unsupported + // [Es2pandaModifierFlags. , SyntaxKind.AccessorKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_ASYNC, SyntaxKind.AsyncKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_CONST, SyntaxKind.ConstKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE, SyntaxKind.DeclareKeyword], + // Improve: choose one + // [Es2pandaModifierFlags.MODIFIER_FLAGS_DEFAULT_EXPORT, SyntaxKind.DefaultClause], + // [Es2pandaModifierFlags.MODIFIER_FLAGS_DEFAULT_EXPORT, SyntaxKind.DefaultKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT, SyntaxKind.ExportKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_IN, SyntaxKind.InKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, SyntaxKind.PrivateKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_PROTECTED, SyntaxKind.ProtectedKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, SyntaxKind.PublicKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_OUT, SyntaxKind.OutKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_OVERRIDE, SyntaxKind.OverrideKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_READONLY, SyntaxKind.ReadonlyKeyword], + [Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, SyntaxKind.StaticKeyword], + ]); + + const bits = function* (flags: KInt) { + let bit: KInt = 1; + while (flags >= bit) { + if ((flags & bit) > 0) { + yield bit; + } + bit <<= 1; + } + }; + if (modifiers === undefined) { + return [] as ReadonlyArray as ts.NodeArray; + } + let mods: ts.Modifier[] = []; + for (const bit of bits(modifiers)) { + mods.push(new ts.Modifier(translation.get(bit) ?? throwError(`Unsupported modifier: ${bit}`))); + } + return mods as ReadonlyArray as ts.NodeArray; +} + +export function passModifiers( + modifiers: ReadonlyArray | undefined +): KInt { + const translation = new Map([ + // [SyntaxKind.UnknownKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_NONE], + // [SyntaxKind.ConstructorKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR], + + [SyntaxKind.AbstractKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT], + // Improve: unsupported + // [SyntaxKind.AccessorKeyword, Es2pandaModifierFlags.], + [SyntaxKind.AsyncKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_ASYNC], + [SyntaxKind.ConstKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_CONST], + [SyntaxKind.DeclareKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE], + [SyntaxKind.DefaultKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_DEFAULT_EXPORT], + [SyntaxKind.ExportKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT], + [SyntaxKind.InKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_IN], + [SyntaxKind.PrivateKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE], + [SyntaxKind.ProtectedKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_PROTECTED], + [SyntaxKind.PublicKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC], + [SyntaxKind.OutKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_OUT], + [SyntaxKind.OverrideKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_OVERRIDE], + [SyntaxKind.ReadonlyKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_READONLY], + [SyntaxKind.StaticKeyword, Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC], + ]); + + if (modifiers === undefined) { + return Es2pandaModifierFlags.MODIFIER_FLAGS_NONE; + } + return modifiers + .map((mod: ts.Modifier | undefined | Es2pandaModifierFlags) => { + if (mod === undefined) { + return Es2pandaModifierFlags.MODIFIER_FLAGS_NONE; + } + if (typeof mod === 'object') { + return translation.get(mod.kind) ?? throwError(`Unsupported modifier: ${mod.kind}`); + } + return mod; + }) + .reduce((prev, curr) => prev | curr, Es2pandaModifierFlags.MODIFIER_FLAGS_NONE); +} + +export function passToken(token: ts.Token): KInt { + const translation = new Map([ + [SyntaxKind.PlusToken, Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_PLUS], + [SyntaxKind.MinusToken, Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_MINUS], + [SyntaxKind.AsteriskToken, Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_MULTIPLY], + ]); + + return translation.get(token.kind) ?? throwError('unsupported token'); +} + +export function passModifiersToScriptFunction(modifiers: readonly ts.Modifier[] | undefined): KInt { + const translation = new Map([ + [SyntaxKind.StaticKeyword, Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_STATIC_BLOCK], + [SyntaxKind.AsyncKeyword, Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ASYNC], + [SyntaxKind.PublicKeyword, Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE], + ]); + + return ( + modifiers?.reduce( + (prev, curr) => + prev | (translation.get(curr.kind) ?? throwError(`Unsupported ScriptFunction flag: ${curr.kind}`)), + Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE + ) ?? Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE + ); +} + +export function passVariableDeclarationKind(flags: NodeFlags): Es2pandaVariableDeclarationKind { + const translation = new Map([ + [NodeFlags.Const, Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_CONST], + [NodeFlags.Let, Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET], + [NodeFlags.None, Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_VAR], + ]); + + return translation.get(flags) ?? throwError('unsupported VariableDeclarationKind'); +} + +export function unpackVariableDeclarationKind(kind: Es2pandaVariableDeclarationKind): NodeFlags { + const translation = new Map([ + [Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_CONST, NodeFlags.Const], + [Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, NodeFlags.Let], + [Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_VAR, NodeFlags.None], + ]); + + return translation.get(kind) ?? throwError('unsupported VariableDeclarationKind'); +} diff --git a/ets1.2/libarkts/src/ts-api/utilities/public.ts b/ets1.2/libarkts/src/ts-api/utilities/public.ts new file mode 100644 index 0000000000000000000000000000000000000000..d28b050d02dd354613c321a0e91a674dd1630b83 --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/utilities/public.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { global } from '../../arkts-api/static/global'; +import { throwError } from '../../utils'; +import * as ts from '../.'; +import { KNativePointer, nullptr } from '@koalaui/interop'; +import { unpackNonNullableNode } from '../../arkts-api'; + +export { proceedToState, startChecker } from '../../arkts-api'; + +// Improve: like in arkts utils +export function getDecl(node: ts.Node): ts.Node | undefined { + if (node.node === undefined) { + throwError('there is no arkts pair of ts node (unable to getDecl)'); + } + let decl: KNativePointer = node.node.peer; + decl = global.es2panda._AstNodeVariableConst(global.context, decl); + if (decl === nullptr) { + return undefined; + } + decl = global.es2panda._VariableDeclaration(global.context, decl); + if (decl === nullptr) { + return undefined; + } + decl = global.es2panda._DeclNode(global.context, decl); + if (decl === nullptr) { + return undefined; + } + return ts.unpackNode(unpackNonNullableNode(decl)); +} + +// Improve: like in arkts utils +export function getOriginalNode(node: ts.Node): ts.Node { + if (node.node === undefined) { + // Improve: fix this + throwError('there is no arkts pair of ts node (unable to getOriginalNode)'); + } + if (node.node.originalPeer === nullptr) { + return node; + } + return ts.unpackNode(unpackNonNullableNode(node.node.originalPeer)); +} diff --git a/ets1.2/libarkts/src/ts-api/visitor/visitor.ts b/ets1.2/libarkts/src/ts-api/visitor/visitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d38bb32d39f976fcffef6a2a93cbfe30a204f34 --- /dev/null +++ b/ets1.2/libarkts/src/ts-api/visitor/visitor.ts @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { throwError } from '../../utils'; + +import * as ts from '../.'; +import { factory } from '../factory/nodeFactory'; +import { SyntaxKind } from '../static/enums'; + +type Visitor = (node: ts.Node) => ts.Node; + +// Improve: rethink (remove as) +function nodeVisitor(node: T, visitor: Visitor): T { + if (node === undefined) { + return node; + } + return visitor(node) as T; +} + +// Improve: rethink (remove as) +function nodesVisitor | undefined>( + nodes: TIn, + visitor: Visitor +): T[] | TIn { + if (nodes === undefined) { + return nodes; + } + return nodes.map((node) => visitor(node) as T); +} + +type VisitEachChildFunction = (node: T, visitor: Visitor) => T; + +// Improve: add more nodes +type HasChildren = + | ts.SourceFile + | ts.FunctionDeclaration + | ts.ExpressionStatement + | ts.CallExpression + | ts.PropertyAccessExpression + | ts.ClassDeclaration + | ts.MethodDeclaration + | ts.Block + | ts.VariableStatement + | ts.VariableDeclarationList; + +type VisitEachChildTable = { [TNode in HasChildren as TNode['kind']]: VisitEachChildFunction }; + +// Improve: add more nodes +const visitEachChildTable: VisitEachChildTable = { + [SyntaxKind.SourceFile]: function (node: ts.SourceFile, visitor: Visitor) { + return factory.updateSourceFile(node, nodesVisitor(node.statements, visitor)); + }, + [SyntaxKind.FunctionDeclaration]: function (node: ts.FunctionDeclaration, visitor: Visitor) { + return factory.updateFunctionDeclaration( + node, + node.modifiers, + undefined, + nodeVisitor(node.name, visitor), + nodesVisitor(node.typeParameters, visitor), + nodesVisitor(node.parameters, visitor), + nodeVisitor(node.type, visitor), + nodeVisitor(node.body, visitor) + ); + }, + [SyntaxKind.ExpressionStatement]: function (node: ts.ExpressionStatement, visitor: Visitor) { + return factory.updateExpressionStatement(node, nodeVisitor(node.expression, visitor)); + }, + [SyntaxKind.CallExpression]: function (node: ts.CallExpression, visitor: Visitor) { + return factory.updateCallExpression( + node, + nodeVisitor(node.expression, visitor), + undefined, + nodesVisitor(node.arguments, visitor) + ); + }, + [SyntaxKind.PropertyAccessExpression]: function (node: ts.PropertyAccessExpression, visitor: Visitor) { + return factory.updatePropertyAccessExpression( + node, + nodeVisitor(node.expression, visitor), + nodeVisitor(node.name, visitor) + ); + }, + [SyntaxKind.ClassDeclaration]: function (node: ts.ClassDeclaration, visitor: Visitor) { + return factory.updateClassDeclaration( + node, + undefined, + nodeVisitor(node.name, visitor), + undefined, + undefined, + nodesVisitor(node.members, visitor) + ); + }, + [SyntaxKind.MethodDeclaration]: function (node: ts.MethodDeclaration, visitor: Visitor) { + return factory.updateMethodDeclaration( + node, + undefined, + undefined, + nodeVisitor(node.name, visitor), + undefined, + undefined, + nodesVisitor(node.parameters, visitor), + undefined, + nodeVisitor(node.body, visitor) + ); + }, + [SyntaxKind.Block]: function (node: ts.Block, visitor: Visitor) { + return factory.updateBlock(node, nodesVisitor(node.statements, visitor)); + }, + [SyntaxKind.VariableStatement]: function (node: ts.VariableStatement, visitor: Visitor) { + return factory.updateVariableStatement(node, undefined, nodeVisitor(node.declarationList, visitor)); + }, + [SyntaxKind.VariableDeclarationList]: function (node: ts.VariableDeclarationList, visitor: Visitor) { + return factory.updateVariableDeclarationList(node, nodesVisitor(node.declarations, visitor)); + }, +}; + +function nodeHasChildren(node: ts.Node): node is HasChildren { + return node.kind in visitEachChildTable; +} + +export function visitEachChild(node: T, visitor: Visitor): T { + const visitFunc = (visitEachChildTable as Record | undefined>)[node.kind]; + if (nodeHasChildren(node) && visitFunc === undefined) { + throwError('Unsupported node kind: ' + node.kind); + } + return visitFunc === undefined ? node : visitFunc(node, visitor); +} diff --git a/ets1.2/libarkts/src/utils.ts b/ets1.2/libarkts/src/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..e229ffc507331f367e8f4cceb1fd3990a0932ac8 --- /dev/null +++ b/ets1.2/libarkts/src/utils.ts @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +export function throwError(error: string): never { + throw new Error(error); +} + +export function withWarning(value: T, message: string): T { + // console.warn(message) + return value; +} + +export function isNumber(value: any): value is number { + return typeof value === `number`; +} + +function replacePercentOutsideStrings(code: string): string { + const stringPattern = /("[^"]*"|'[^']*'|`[^`]*`)/g; + const percentPattern = /(?(); + strings.forEach((string) => { + const placeholder = `__STRING_PLACEHOLDER_${placeholderCounter++}__`; + placeholderMap.set(placeholder, string); + code = code.replace(string, placeholder); + }); + + code = code.replace(percentPattern, '_'); + + placeholderMap.forEach((originalString, placeholder) => { + code = code.replace(new RegExp(placeholder, 'g'), originalString); + }); + + return code; +} + +function replaceIllegalHashes(code: string): string { + const stringPattern = /("[^"]*"|'[^']*'|`[^`]*`)/g; + const strings = code.match(stringPattern) || []; + + let placeholderCounter = 0; + const placeholderMap = new Map(); + strings.forEach((string) => { + const placeholder = `__STRING_PLACEHOLDER_${placeholderCounter++}__`; + placeholderMap.set(placeholder, string); + code = code.replace(string, placeholder); + }); + + code = code.replace(/#/g, '_'); + + placeholderMap.forEach((originalString, placeholder) => { + code = code.replace(new RegExp(placeholder, 'g'), originalString); + }); + + return code; +} + +function replaceGensymWrappers(code: string): string { + const indices = [...code.matchAll(/\({let/g)].map((it) => it.index); + const replacements: string[][] = []; + for (var i of indices) { + if (!i) { + continue; + } + var j = i + 1, + depth = 1; + while (j < code.length) { + if (code[j] == '(') { + depth++; + } + if (code[j] == ')') { + depth--; + } + if (depth == 0) { + break; + } + j++; + } + + if (j == code.length) { + continue; + } + + const base = code.substring(i, j + 1); + if (base.match(/\({let/)?.length! > 1) { + // don't touch if contains nested constructions + continue; + } + const fixed = base.replaceAll( + /^\({let ([_%a-zA-Z0-9]+?) = (?!\({let)([\s\S]*?);\n([\s\S]*?)}\)$/g, + (match, name: string, val: string, expr: string) => { + let rightExpr = expr.slice(expr.lastIndexOf(name) + name.length, -1); + if (rightExpr[0] != '.') { + rightExpr = `.${rightExpr}`; + } + return `(${val}?${rightExpr})`; + } + ); + replacements.push([base, fixed]); + } + for (var [b, f] of replacements) { + code = code.replace(b, f); + } + return code; +} + +function addExports(code: string): string { + const exportAstNodes = [ + ' enum', + 'let', + 'const', + 'class', + 'abstract class', + '@Entry() @Component() final class', + '@Component() final class', + 'interface', + '@interface', + 'type', + 'enum', + 'final class', + 'function', + 'declare interface', + '@memo_stable() declare interface', + '@memo_stable() interface', + '@Retention({policy:"SOURCE"}) @interface', + '@memo() function', + '@memo_entry() function', + '@memo_intrinsic() function', + ]; + exportAstNodes.forEach((astNodeText) => { + code = code.replaceAll(`\n${astNodeText}`, `\nexport ${astNodeText}`); + }); + // Improve: this is a temporary workaround and should be replaced with a proper import/export handling in future + code = code.replaceAll(/\n(@memo\(\) @BuilderLambda\(\{value:"\w+"\}\)) function/g, '\n$1 export function'); + const fix = [ + ['export @memo() function', '@memo() export function'], + ['export @memo_entry() function', '@memo_entry() export function'], + ['export @memo_intrinsic() function', '@memo_intrinsic() export function'], + ['export @memo_stable()', '@memo_stable() export'], + ['export class OhosRouter', 'export default class OhosRouter'], + ]; + for (var [f, t] of fix) { + code = code.replaceAll(f, t); + } + return code.replaceAll('\nexport function main()', '\nfunction main()'); +} + +function excludePartialInterfaces(code: string): string { + return code + .replaceAll(/export interface (.*)\$partial<>([\s\S]*?)}/g, '') + .replaceAll(/interface (.*)\$partial<>([\s\S]*?)}/g, ''); +} + +function fixEnums(code: string) { + const lines = code.split('\n'); + const enums = []; + for (let i = 0; i + 1 < lines.length; i++) { + if ( + lines[i].trimStart().startsWith(`export final class`) && + lines[i + 1].trimStart().startsWith(`private readonly _ordinal`) + ) { + const name = lines[i].split(' ')[3]; + enums.push(name); + } + } + enums.forEach((name) => { + const regexp = new RegExp(`${name}\\.(\\w+)(.)`, `g`); + code = code.replaceAll(regexp, (match, p1, p2) => { + if (!p1.startsWith('_') && p2 == ':') { + // this colon is for switch case, not for type + return `${name}.${p1}.valueOf()${p2}`; + } + return match; + }); + const idents = [...code.matchAll(new RegExp(`(\\w+?)([\\W])(\\w+?): ${name}`, `g`))] + .filter((it) => it[1] != 'readonly' && it[1] != '_get') + .map((it) => it[3]); + // work manually with a couple of cases not to write one more bracket parser + if (code.includes(`const eventKind = (deserializer.readInt32() as CallbackEventKind);`)) { + // this is for file arkui/src/generated/peers/CallbacksChecker.ts + idents.push(`eventKind`); + code = code.replace( + `const eventKind = (deserializer.readInt32() as CallbackEventKind);`, + `const eventKind = CallbackEventKind.fromValue(deserializer.readInt32());` + ); + } + if (code.includes(`switch ((type as EventType))`)) { + // this is for file arkui/src/Application.ts + code = code.replace(`switch ((type as EventType))`, `switch (type)`); + } + idents.forEach((id) => { + code = code.replaceAll(`${id} as int32`, `${id}.valueOf()`); + code = code.replaceAll(`switch (${id})`, `switch (${id}.valueOf())`); + }); + }); + return code; +} + +function fixEmptyDeclareNamespace(code: string): string { + const lines = code.split('\n'); + for (let i = 0; i < lines.length; i++) { + if (lines[i].startsWith('export declare namespace') && !lines[i].endsWith('{')) { + lines[i] += ' {}'; + } + } + return lines.join('\n'); +} + +/* + Improve: + 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 { + //console.error("====") + // console.error(text.split('\n').map((it, index) => `${`${index + 1}`.padStart(4)} |${it}`).join('\n')) + const dumperUnwrappers = [ + addExports, + fixEmptyDeclareNamespace, + fixEnums, + replaceGensymWrappers, // nested + replaceGensymWrappers, // nested + replaceGensymWrappers, + replaceIllegalHashes, + replacePercentOutsideStrings, + excludePartialInterfaces, + (code: string) => code.replaceAll('', '_cctor_'), + (code: string) => code.replaceAll('public constructor() {}', ''), + ]; + // console.error("====") + // console.error(dumperUnwrappers.reduceRight((code, f) => f(code), text).split('\n').map((it, index) => `${`${index + 1}`.padStart(4)} |${it}`).join('\n')) + return dumperUnwrappers.reduceRight((code, f) => f(code), text); +} + +export function getEnumName(enumType: any, value: number): string | undefined { + return enumType[value]; +} diff --git a/ets1.2/libarkts/test/arkts-api/expressions/call-expression.test.ts b/ets1.2/libarkts/test/arkts-api/expressions/call-expression.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3132fc8dee3e6c019dfb718b87a078fb4c850ead --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/expressions/call-expression.test.ts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as arkts from "../../../src/arkts-api" + +suite(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + function _() {}; + ` + + const sample_out = + ` + function _() {}; + console.log('out') + ` + + let script = arkts.createETSModuleFromSource(sample_in) + + script = arkts.factory.updateETSModule( + script, + [ + script.statements[0], + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createIdentifier( + 'console' + ), + arkts.Identifier.create2Identifier( + 'log' + ), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [ + arkts.factory.createStringLiteral( + 'out' + ) + ], + undefined, + false, + false, + undefined, + ) + ) + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + sample_out + ) + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/functions/create.test.ts b/ets1.2/libarkts/test/arkts-api/functions/create.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d222e07f1c73862420e76c235fecf1fe12f58649 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/functions/create.test.ts @@ -0,0 +1,262 @@ +/* + * Copyright (c) 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. + */ + +import * as util from "../../test-util" +import * as arkts from "../../../src/arkts-api" + +suite(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + function _() {}; + ` + + const sample_out = + ` + function _() {}; + function foo() { + console.log("AAA") + } + foo() + ` + + let script = arkts.createETSModuleFromSource(sample_in) + + const scriptFunc = + arkts.factory.createScriptFunction( + arkts.factory.createBlockStatement( + [ + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createIdentifier( + 'console' + ), + arkts.factory.createIdentifier( + 'log' + ), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [ + arkts.factory.createStringLiteral( + 'AAA' + ) + ], + undefined, + false, + false, + undefined, + ) + ) + ] + ), + undefined, + [], + undefined, + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + arkts.factory.createIdentifier("foo"), + undefined, + ) + + const funcDecl = + arkts.factory.createFunctionDeclaration( + scriptFunc, + [], + false + ) + funcDecl.updateModifiers(scriptFunc.modifierFlags) + + script = arkts.factory.updateETSModule( + script, + [ + script.statements[0], + funcDecl, + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createIdentifier( + 'foo' + ), + [], + undefined, + false, + false, + undefined, + ) + ) + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + sample_out + ) + }) + + test("sample-2", function() { + const sample_in = + ` + function _() {}; + ` + + const sample_out = + ` + function _() {}; + function foo(x: int, y: string = "bbb") { + console.log(x) + console.log(y) + } + foo(0) + ` + + let script = arkts.createETSModuleFromSource(sample_in) + + const scriptFunc = + arkts.factory.createScriptFunction( + arkts.factory.createBlockStatement( + [ + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createIdentifier( + 'console' + ), + arkts.factory.createIdentifier( + 'log' + ), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [ + arkts.factory.createIdentifier( + 'x' + ) + ], + undefined, + false, + false, + undefined, + ) + ), + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createIdentifier( + 'console' + ), + arkts.factory.createIdentifier( + 'log' + ), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [ + arkts.factory.createIdentifier( + 'y' + ) + ], + undefined, + false, + false, + undefined, + ) + ) + ] + ), + undefined, + [ + arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier( + 'x', + arkts.factory.createETSPrimitiveType( + arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_INT + ) + ), + false + ), + arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier( + 'y', + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier( + 'string' + ) + ) + ) + ), + false, + arkts.factory.createStringLiteral( + 'bbb' + ) + ) + ], + undefined, + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + arkts.factory.createIdentifier("foo"), + undefined, + ) + + const funcDecl = + arkts.factory.createFunctionDeclaration( + scriptFunc, + [], + false + ) + funcDecl.updateModifiers(scriptFunc.modifierFlags) + + script = arkts.factory.updateETSModule( + script, + [ + script.statements[0], + funcDecl, + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createIdentifier( + 'foo' + ), + [ + arkts.factory.createNumberLiteral( + 0 + ) + ], + undefined, + false, + false, + undefined, + ) + ) + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + sample_out + ) + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/general/annotations.test.ts b/ets1.2/libarkts/test/arkts-api/general/annotations.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f6564beff7b60458e139afb6c6a39391ca1f11bf --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/general/annotations.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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. + */ + +import * as util from "../../test-util" +import * as arkts from "../../../src/arkts-api" +import { assert } from "@koalaui/harness" + +suite(util.basename(__filename), () => { + test("annotated-function-1", function() { + const sample_in = + ` + @annotation1 + @annotation2 + function foo() {} + ` + + let script = arkts.createETSModuleFromSource( + sample_in, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + ) + + const annotations = arkts.getAnnotations(script.statements[0]) + + const names = annotations.map((annot) => { + if (annot.expr === undefined) { + throw new Error('annotation expression is undefined') + } + if (!arkts.isIdentifier(annot.expr)) { + throw new Error('annotation expected to be Identifier') + } + return annot.expr.name + }) + + assert.equal(names.join(', '), 'annotation1, annotation2') + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/general/basic.test.ts b/ets1.2/libarkts/test/arkts-api/general/basic.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e76d7c4bbc45371129b970f9aaa36ea341b59ec8 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/general/basic.test.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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. + */ + +import * as util from "../../test-util" +import * as arkts from "../../../src/arkts-api" + +suite(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + ` + + let script = arkts.createETSModuleFromSource(sample_in) + + script = arkts.factory.updateETSModule( + script, + [ + arkts.factory.createExpressionStatement( + arkts.factory.createIdentifier( + 'abc' + ) + ) + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + ` + abc + `, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + ) + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/general/jsdoc.test.ts b/ets1.2/libarkts/test/arkts-api/general/jsdoc.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee4890ba3bf217899a3d0114f8887c72330969f3 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/general/jsdoc.test.ts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as util from "../../test-util" +import * as arkts from "../../../src/arkts-api" +import { assert } from "@koalaui/harness" +import { + isMethodDefinition, + isBlockStatement, + isClassDeclaration, + isFunctionDeclaration, + isStatement, + isTSTypeAliasDeclaration, + isClassProperty, + getJsDoc, + isIdentifier +} from "../../../src/arkts-api" + +suite(util.basename(__filename), () => { + const comments: string[] = [ + '/** Regular function */' , + '/** Type T */', + '/** Class A */', + '/** Method */', + '/** Return type */', + '/** Property */', + ] + + test("jsdoc", function() { + const sample_in = ` + ${comments[0]} + export function foo(); + ${comments[1]} + type T = int; + ${comments[2]} + export class A { + ${comments[3]} + a_foo(): // colon here + ${comments[4]} + void {} + ${comments[5]} + private a_prop: number = 1 + }` + + let script = arkts.createETSModuleFromSource( + sample_in, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + ) + + const jsdocs: (string | undefined)[] = [] + for (const stmt of script.statements) { + jsdocs.push(getJsDoc(stmt)) + if (isClassDeclaration(stmt)) { + const body = stmt.definition?.body ?? [] + for (const node of body) { + jsdocs.push(getJsDoc(node)) + + if (isMethodDefinition(node) && isIdentifier(node.key) && + node.key.name === 'a_foo' && node.function?.returnTypeAnnotation) { + jsdocs.push(getJsDoc(node.function?.returnTypeAnnotation)) + } + } + } + } + + assert.equal( + comments + .concat('') // implicit ctor returns undefined + .join(','), + jsdocs + .join(',') + ) + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/general/recheck.test.ts b/ets1.2/libarkts/test/arkts-api/general/recheck.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f233a7084fd59dbe6aa05268fcc978623844499a --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/general/recheck.test.ts @@ -0,0 +1,189 @@ +/* + * Copyright (c) 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. + */ + +import * as util from "../../test-util" +import * as arkts from "../../../src/arkts-api" + +const PANDA_SDK_PATH = process.env.PANDA_SDK_PATH ?? '../../incremental/tools/panda/node_modules/@panda/sdk' + +function createConfig() { + arkts.arktsGlobal.config = arkts.Config.create([ + '_', + '--arktsconfig', + 'arktsconfig.json', + './plugins/input/main.ets', + '--extension', + 'ets', + '--stdlib', + `${PANDA_SDK_PATH}/ets/stdlib`, + '--output', + './build/main.abc' + ]).peer +} + +class RenameTestFunction extends arkts.AbstractVisitor { + visitor(node: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + // Don't change name at checked state, add another import + if (arkts.isImportDeclaration(node)) return node + if (arkts.isIdentifier(node) && node.name == "testFunction") { + return arkts.factory.createIdentifier("testFunctionChanged") + } + return node + } +} + + +suite(util.basename(__filename), () => { + + + test("add import at parsed state and proceed to checked", function() { + createConfig() + arkts.initVisitsTable() + + const code = + ` + console.log("test") + ` + + arkts.arktsGlobal.filePath = "./plugins/input/main.ets" + arkts.arktsGlobal.compilerContext = arkts.Context.createFromString(code) + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED) + + const program = arkts.arktsGlobal.compilerContext!.program + const importStorage = new arkts.ImportStorage(program, true) + const module = program.ast as arkts.ETSModule + + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, + ), + ...module.statements, + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + importStorage.update() + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) + + arkts.recheckContext() + + util.assert.equal( + program.ast.dumpSrc(), ` +import { testFunction as testFunction } from "./library"; + +function main() {} + +console.log("test"); +`, + `invalid result: ${program.ast.dumpSrc()}`) + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) + }) + + test("change function name in main program and in dependency", function() { + createConfig() + arkts.initVisitsTable() + + const code = + ` + import { testFunction } from "./library" + testFunction() + ` + + arkts.arktsGlobal.filePath = "./plugins/input/main.ets" + arkts.arktsGlobal.compilerContext = arkts.Context.createFromString(code) + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) + + const program = arkts.arktsGlobal.compilerContext!.program + const importStorage = new arkts.ImportStorage(program, true) + const module = program.ast as arkts.ETSModule + + arkts.arktsGlobal.compilerContext!.program.getExternalSources().forEach(it => { + if (!it.getName().includes("library")) return + it.programs.forEach(program => { + program.setAst(new RenameTestFunction().visitor(program.ast)) + }) + }) + + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.updateETSImportDeclaration( + module.statements[0] as arkts.ETSImportDeclaration, + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunctionChanged' + ), + arkts.factory.createIdentifier( + 'testFunctionChanged' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, + ), + ...module.statements.slice(1), + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + + program.setAst(new RenameTestFunction().visitor(program.ast)) + + importStorage.update() + arkts.recheckContext() + + util.assert.equal( + program.ast.dumpSrc(), ` +import { testFunctionChanged as testFunctionChanged } from "./library"; + +function main() {} + +testFunctionChanged(); +`, + `invalid result: ${program.ast.dumpSrc()}`) + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/import-export/import.test.ts b/ets1.2/libarkts/test/arkts-api/import-export/import.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4727774f54da7c2007c05245cd332913f2fe1ea --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/import-export/import.test.ts @@ -0,0 +1,242 @@ +/* + * Copyright (c) 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. + */ + +import * as util from "../../test-util" +import * as arkts from "../../../src/arkts-api" +import { global } from "../../../src/arkts-api/static/global" + + +suite(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + ` + + let script = arkts.createETSModuleFromSource(sample_in) + + script = arkts.factory.updateETSModule( + script, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './variable' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'X' + ), + arkts.factory.createIdentifier( + 'X' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, + ) + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + ` + import { X } from "./variable" + `, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + ) + }) + + test("sample-2-rewrite", function() { + const sample_in = + ` + import { Y } from "./variable" + ` + + let script = arkts.createETSModuleFromSource(sample_in) + const importDeclaration = script.statements[0] as arkts.ETSImportDeclaration + + script = arkts.factory.updateETSModule( + script, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './variable' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'X' + ), + arkts.factory.createIdentifier( + 'X' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, + ), + ...script.statements, + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + ` + import { X } from "./variable" + import { Y } from "./variable" + `, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + ) + }) + + test("rewrite-imported-variable", function() { + const sample_in = + ` + import { Y } from "./variable" + + function main() { + console.log(X) + } + ` + + let script = arkts.createETSModuleFromSource(sample_in) + const importDeclaration = script.statements[0] as arkts.ETSImportDeclaration + + script = arkts.factory.updateETSModule( + script, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './variable' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'X' + ), + arkts.factory.createIdentifier( + 'X' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, + ), + ...script.statements, + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + ` + import { X } from "./variable" + import { Y } from "./variable" + + function main() { + console.log(X) + } + `, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + ) + + // util.cleanGenerated() + // util.fileToAbc(`./input/variable.sts`, true) + // util.contextToAbc() + // util.runAbc(`./generated/main.abc`, ['./generated/variable.abc']) + }) + + test("rewrite-imported-function", function() { + const sample_in = + ` + import { f } from "./f" + function main() {} + ` + + let script = arkts.createETSModuleFromSource(sample_in) + const functionDeclaration: arkts.FunctionDeclaration = script.statements[1] as arkts.FunctionDeclaration + const scriptFunction: arkts.ScriptFunction = functionDeclaration.function! + + const newScriptFunc = + arkts.factory.updateScriptFunction( + scriptFunction, + arkts.factory.createBlockStatement( + [ + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createIdentifier( + 'f' + ), + [], + undefined, + false, + false, + undefined, + ) + ) + ] + ), + undefined, + [], + undefined, + false, + scriptFunction.flags, + scriptFunction.modifierFlags, + scriptFunction.id!, + undefined, + ) + + const newFuncDecl = + arkts.factory.updateFunctionDeclaration( + functionDeclaration, + newScriptFunc, + [], + false + ) + newFuncDecl.updateModifiers(newScriptFunc.modifierFlags) + + script = arkts.factory.updateETSModule( + script, + [ + script.statements[0], + newFuncDecl + ], + script.ident, + script.getNamespaceFlag(), + script.program, + ) + + util.ARKTS_TEST_ASSERTION( + script, + ` + import { f } from "./f" + function main() { + f() + } + `, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + ) + + // util.cleanGenerated() + // util.fileToAbc(`./input/f.sts`, true) + // util.contextToAbc() + // util.runAbc(`./generated/main.abc`, ['./generated/f.abc']) + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/recheck/arktsconfig.json b/ets1.2/libarkts/test/arkts-api/recheck/arktsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..a0a1a87886101252b596d34ce445bf2d2e8f63ca --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/arktsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "outDir": "./build/abc", + "baseUrl": "." + }, + "include": ["./**/*.ts"] +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/constructor/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/constructor/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..52b9b2e2e6c8825934e12877936cd3e5f1a3644f --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/constructor/index.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../src/arkts-api" + +class ConstructorWithOverload extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + if (arkts.isScriptFunction(node) && node.id?.name == "constructor") { + return arkts.factory.updateScriptFunction( + node, + arkts.factory.createBlockStatement( + [ + + arkts.factory.createIfStatement( + arkts.factory.createBooleanLiteral(true), + arkts.factory.createReturnStatement(), + undefined + ), + ...(arkts.isBlockStatement(node.body) ? node.body.statements : []), + ] + ), + node.typeParams, + node.params, + node.returnTypeAnnotation, + node.hasReceiver, + node.flags, + node.modifierFlags, + node.id, + node.annotations + ) + } + return node + } +} + +export function constructorWithOverload(program: arkts.Program) { + program.setAst(new ConstructorWithOverload().visitor(program.ast)) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/constructor/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/constructor/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..77d192544a663c738c67499d9f27c4c843da3fae --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/constructor/main.ets @@ -0,0 +1,5 @@ + +class XXX { + constructor(x: ()=>void, y?: ()=>void) { + } +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..a668a5a62f9306ef69c29a89197fe3f4037a5de1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/dump-src/main.ets @@ -0,0 +1,12 @@ + +import { C as C } from "./library"; + +import { f as f } from "./library"; + +function main() {} + +f(); +class D { + public c = new C(); +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d131f3cd2b7e0c17b1ec32b04b131eb728aea640 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/index.ts @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +class ExportClass extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + if (arkts.isClassDeclaration(node) && node.definition?.ident?.name == "C") { + node.modifierFlags |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT + } + return node + } +} + +export function addUseImportClassSameFileAndExportClass(program: arkts.Program, options: arkts.CompilationOptions) { + if (options.isProgramForCodegeneration) { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' + ), + arkts.factory.createIdentifier( + 'C' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) + ) + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } else { + program.setAst(new ExportClass().visitor(program.ast)) + } + return program +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/library.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/library.ets new file mode 100644 index 0000000000000000000000000000000000000000..17667d2341a877d57ac6ff421ca1386ba4bebf22 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/library.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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. + */ + +export declare function f(): void + +class C { + +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..0d31540d6ff2d83b82b231e29cd1d5fab27c2fb3 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/add-export/main.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 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. + */ + +import { f } from "./library" + +f() diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..a668a5a62f9306ef69c29a89197fe3f4037a5de1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/dump-src/main.ets @@ -0,0 +1,12 @@ + +import { C as C } from "./library"; + +import { f as f } from "./library"; + +function main() {} + +f(); +class D { + public c = new C(); +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d0f11addf0773a775a92f1a4e80a150b67ac3f7 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/index.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function addUseImportClassSameFile(program: arkts.Program, options: arkts.CompilationOptions) { + if (options.isProgramForCodegeneration) { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' + ), + arkts.factory.createIdentifier( + 'C' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) + ) + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } + return program +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/library.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/library.ets new file mode 100644 index 0000000000000000000000000000000000000000..7e717b8cc8fe9f36fc58fc44a7b7c450a9278568 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/library.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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. + */ + +export declare function f(): void + +export class C { + +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..0d31540d6ff2d83b82b231e29cd1d5fab27c2fb3 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/basic/main.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 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. + */ + +import { f } from "./library" + +f() diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..a668a5a62f9306ef69c29a89197fe3f4037a5de1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/dump-src/main.ets @@ -0,0 +1,12 @@ + +import { C as C } from "./library"; + +import { f as f } from "./library"; + +function main() {} + +f(); +class D { + public c = new C(); +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..15d194c3b1834f66a82861277d040caa89c33aa6 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/index.ts @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function addUseImportClassSameFileAndCreateClass(program: arkts.Program, options: arkts.CompilationOptions) { + if (options.isProgramForCodegeneration) { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' + ), + arkts.factory.createIdentifier( + 'C' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) + ) + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } else { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + ...module.statements, + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier( + "C" + ), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, + arkts.factory.createIdentifier("constructor"), + arkts.factory.createFunctionExpression( + arkts.factory.createIdentifier("constructor"), + arkts.factory.createScriptFunction( + arkts.factory.createBlockStatement( + [], + ), + undefined, + [], + undefined, + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_CONSTRUCTOR, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.factory.createIdentifier("constructor"), + [], + ) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + false, + [], + ), + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT, + ) + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } + return program +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/library.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/library.ets new file mode 100644 index 0000000000000000000000000000000000000000..e97afd392c7f7a88b99ca7f3112d4b7c93111e28 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/library.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + +export declare function f(): void diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..0d31540d6ff2d83b82b231e29cd1d5fab27c2fb3 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/create-class/main.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 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. + */ + +import { f } from "./library" + +f() diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..a668a5a62f9306ef69c29a89197fe3f4037a5de1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/dump-src/main.ets @@ -0,0 +1,12 @@ + +import { C as C } from "./library"; + +import { f as f } from "./library"; + +function main() {} + +f(); +class D { + public c = new C(); +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..959a6d6459fd1e75b3fd15f4a6ee2bcbe095e66a --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +class StructToClass extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + if (arkts.isETSStructDeclaration(node)) { + return arkts.factory.createClassDeclaration( + node.definition, + ) + } + return node + } +} + +export function rewriteStructToClass(program: arkts.Program, options: arkts.CompilationOptions) { + if (!options.isProgramForCodegeneration) { + program.setAst(new StructToClass().visitor(program.ast)) + } + return program +} + +class ExportClass extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + if (arkts.isClassDeclaration(node) && node.definition?.ident?.name == "C") { + node.modifierFlags |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT + } + return node + } +} + +export function addUseImportClassSameFileAfterRewritingStructToClass(program: arkts.Program, options: arkts.CompilationOptions) { + if (options.isProgramForCodegeneration) { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' + ), + arkts.factory.createIdentifier( + 'C' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) + ) + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } else { + program.setAst(new ExportClass().visitor(program.ast as arkts.ETSModule)) + } + return program +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/library.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/library.ets new file mode 100644 index 0000000000000000000000000000000000000000..a84fea72c678bb42746294822a766a583a988bfb --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/library.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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. + */ + +export declare function f(): void + +struct C { + +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..0d31540d6ff2d83b82b231e29cd1d5fab27c2fb3 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/exports/struct-to-class/main.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 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. + */ + +import { f } from "./library" + +f() diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..39557636fc77d7c24784db40b2ea95259dcd66d2 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function addImportNewFile(program: arkts.Program, options: arkts.CompilationOptions) { + if (options.isProgramForCodegeneration) { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } + return program +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/library.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/library.ts new file mode 100644 index 0000000000000000000000000000000000000000..a38c17c74a063eff1f70187e96138f96995ea380 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/library.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 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. + */ + +export function testFunction(): string { + return "yes" +} +export function anotherFunction(): string { + return "no" +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..0310cbba14b1342ebfa00b5e78ee9f4ef3ff4251 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-new-file/main.ets @@ -0,0 +1,2 @@ + +console.log("test") diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..5a1437a8f147e90ef6cfe8df62b88fda05efdba1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/dump-src/main.ets @@ -0,0 +1,8 @@ + +import { testFunction as testFunction } from "./library"; + +import { anotherFunction as anotherFunction } from "./library"; + +function main() {} + +console.log("test"); diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd6e17d76ab0bb803766d600f67ef462de29f5e8 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function addImportSameFile(program: arkts.Program, options: arkts.CompilationOptions) { + if (options.isProgramForCodegeneration) { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } + return program +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/library.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/library.ts new file mode 100644 index 0000000000000000000000000000000000000000..a38c17c74a063eff1f70187e96138f96995ea380 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/library.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 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. + */ + +export function testFunction(): string { + return "yes" +} +export function anotherFunction(): string { + return "no" +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..e5adb0b5d7e06cd2b8854e19cf1654f6998c4f3b --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-same-file/main.ets @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 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. + */ + +import { anotherFunction } from "./library" +console.log("test") diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..6d464e2dc0523ab6bad59963c51dac89d5490952 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/dump-src/main.ets @@ -0,0 +1,9 @@ + +import { testFunction as testFunction } from "./library"; + +import { anotherFunction as anotherFunction } from "./library"; + +function main() {} + +console.log("test"); +testFunction() diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e21a8ab7b1bb3839c51144b3fb2958a47f63b34 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function addUseImportSameFile(program: arkts.Program, options: arkts.CompilationOptions) { + if (options.isProgramForCodegeneration) { + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createIdentifier("testFunction"), + [], + undefined, + false, + false, + undefined + ) + ) + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) + ) + } + return program +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/library.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/library.ts new file mode 100644 index 0000000000000000000000000000000000000000..a38c17c74a063eff1f70187e96138f96995ea380 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/library.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 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. + */ + +export function testFunction(): string { + return "yes" +} +export function anotherFunction(): string { + return "no" +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..e5adb0b5d7e06cd2b8854e19cf1654f6998c4f3b --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/add-use-same-file/main.ets @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 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. + */ + +import { anotherFunction } from "./library" +console.log("test") diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..951b36b32a961171c56b877adc32650dc850e4c1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/dump-src/main.ets @@ -0,0 +1,8 @@ + +import { One as One } from "./one_recursive"; + +import { Two as Two } from "./two_recursive"; + +function main() {} + + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..43a9433ed75236cfbdcd96732626e88b0debf71f --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/index.ts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +class InsertParameter extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + if (arkts.isScriptFunction(node) && + (node.id?.name == "one" || node.id?.name == "two") ) { + + return arkts.factory.updateScriptFunction( + node, + node.body, + node.typeParams, + [ + arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier("createdParam", arkts.factory.createETSPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_BOOLEAN)), + false, + undefined, + undefined + ) + ], + node.returnTypeAnnotation, + node.hasReceiver, + node.flags, + node.modifierFlags, + node.id, + node.annotations + ) + } + return node + } +} + +export function insertParameter(program: arkts.Program) { + program.setAst(new InsertParameter().visitor(program.ast)) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..2e116ff7b2489399a52958a87ec48c2cd32e8f00 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/main.ets @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 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. + */ + +import { One } from "./one_recursive" +import { Two } from "./two_recursive" diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/one_recursive.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/one_recursive.ts new file mode 100644 index 0000000000000000000000000000000000000000..bbc749b12407dc1c9f4cc453571e6f6798a6ab74 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/one_recursive.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import { Two } from "./two_recursive" + +export interface One { + two(): Two { + throw new Error("") + } +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/two_recursive.ts b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/two_recursive.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee28528bd7bc288ede551b0cf379c62cfa4d2443 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/imports/recursive/two_recursive.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import { One } from "./one_recursive" + +export interface Two { + one(): One { + throw new Error("") + } +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/lambda/unchanged/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/lambda/unchanged/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..39e8569f3c8720ab00ce3ad15739cebcdb9f7218 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/lambda/unchanged/dump-src/main.ets @@ -0,0 +1,29 @@ + +function main() {} + +function foo(): void { + HasInstantiate.$_instantiate((() => { + return new HasInstantiate(); + }), "foo"); +} + +function hasTrailing(first?: string, trailing?: (()=> void)): void { + ({let gensym%%_865 = trailing; + (((gensym%%_865) == (null)) ? undefined : gensym%%_865())}); +} + +function bar(zzz: string): void { + hasTrailing("xxx"); + hasTrailing("xxx", (() => { + const d = zzz; + })); +} + + +class HasInstantiate { + public static $_instantiate(factory: (()=> HasInstantiate), arg: string) {} + + public constructor() {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/lambda/unchanged/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/lambda/unchanged/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..354f2045d2f6220667a3bd4a009adb2ab91ef0f0 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/lambda/unchanged/main.ets @@ -0,0 +1,23 @@ + +class HasInstantiate { + static $_instantiate(factory: () => HasInstantiate, arg: string) { + } +} + +function foo(): void { + HasInstantiate("foo") +} + +function hasTrailing(first?: string, trailing?: () => void): void { + trailing?.() +} + +function bar(zzz: string): void { + + hasTrailing("xxx") + + hasTrailing("xxx") { + const d = zzz + } +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..7f71199d32709a92abd87e94387f2e7a08c5ccc0 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/dump-src/main.ets @@ -0,0 +1,10 @@ + +function main() {} + + +interface I { + set f(f: ((createdParam: boolean)=> void)) + get f(): ((createdParam: boolean)=> void) + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f305ebeda4518463e1b0e94ce3d8226ee502dfac --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/index.ts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +class InsertParameterToType extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + if (arkts.isETSFunctionType(node)) { + return arkts.factory.createETSFunctionType( + node.typeParams, + [ + arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier("createdParam", arkts.factory.createETSPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_BOOLEAN)), + false, + undefined, + undefined + ), + ...node.params + ], + node.returnType, + node.isExtensionFunction, + node.flags, + node.annotations, + ) + } + return node + } +} + +export function insertParameterToType(program: arkts.Program) { + program.setAst(new InsertParameterToType().visitor(program.ast)) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..d158146d3da863a3fb8feefc4390b28771ec0c5c --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/overloads/getter-setter/main.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 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. + */ + +interface I { + set f(f: () => void) + get f(): () => void +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/recheck.test.ts b/ets1.2/libarkts/test/arkts-api/recheck/recheck.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b32f9208e759d153d37519452b02ac48d1c9873 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/recheck.test.ts @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2024-2025 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. + */ + +import * as fs from "node:fs" +import * as util from "../../test-util" +import * as arkts from "../../../src" +import { constructorWithOverload } from "./constructor" +import { updateTopLevelClass } from "./simple" +import { renameClass } from "./simple/rename-class" +import { addClassMethod } from "./simple/add-class-method" +import { addVariableDeclaration } from "./simple/add-variable" +import { addThisReference } from "./this" +import { insertParameterToType } from "./overloads/getter-setter" +import { insertParameter } from "./imports/recursive" +import { addImportSameFile } from "./imports/add-same-file" +import { addUseImportSameFile } from "./imports/add-use-same-file" +import { addImportNewFile } from "./imports/add-new-file" +import { addUseImportClassSameFile } from "./exports/basic" +import { addUseImportClassSameFileAndExportClass } from "./exports/add-export" +import { addUseImportClassSameFileAndCreateClass } from "./exports/create-class" +import { addUseImportClassSameFileAfterRewritingStructToClass, rewriteStructToClass } from "./exports/struct-to-class" + +const DIR = './test/arkts-api/recheck' +const PANDA_SDK_PATH = process.env.PANDA_SDK_PATH ?? '../../incremental/tools/panda/node_modules/@panda/sdk' + +function createConfig(file: string) { + fs.mkdirSync(`${DIR}/build/abc/${file}`, { recursive: true }) + arkts.arktsGlobal.filePath = `${DIR}/${file}/main.ets` + arkts.arktsGlobal.config = arkts.Config.create([ + '_', + '--arktsconfig', + `${DIR}/arktsconfig.json`, + `${DIR}/${file}/main.ets`, + '--extension', + 'ets', + '--stdlib', + `${PANDA_SDK_PATH}/ets/stdlib`, + '--output', + `${DIR}/build/abc/${file}/main.abc` + ]).peer + + arkts.initVisitsTable() +} + +function createContext(file: string) { + const code = fs.readFileSync(`${DIR}/${file}/main.ets`, 'utf-8') + arkts.arktsGlobal.filePath = `${DIR}/${file}/main.ets` + arkts.arktsGlobal.compilerContext = arkts.Context.createFromString(code) +} + +function proceedToParsed() { + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED) +} + +function proceedToChecked() { + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) +} + +function applyTransformOnState(transform?: arkts.ProgramTransformer, state: arkts.Es2pandaContextState = arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) { + arkts.runTransformer(arkts.arktsGlobal.compilerContext!.program, state, transform, new arkts.PluginContextImpl(), {}) +} + +function recheck() { + arkts.recheckSubtree(arkts.createETSModuleFromContext()) +} + +function dumpSrc(file: string) { + const src = arkts.createETSModuleFromContext().dumpSrc() + fs.mkdirSync(`${DIR}/${file}/dump-src`, { recursive: true }) + fs.writeFileSync(`${DIR}/${file}/dump-src/main.ets`, src) +} + +function dumpJson(file: string) { + const json = arkts.createETSModuleFromContext().dumpJson() + fs.mkdirSync(`${DIR}/${file}/dump-json`, { recursive: true }) + fs.writeFileSync(`${DIR}/${file}/dump-json/main.json`, json) +} + +function assertSrc(file: string) { + const src = arkts.createETSModuleFromContext().dumpSrc() + const expected = fs.readFileSync(`${DIR}/${file}/dump-src/main.ets`, 'utf-8') + util.assert.equal(filterGensym(src), filterGensym(expected)) +} + +function assertJson(file: string) { + const json = arkts.createETSModuleFromContext().dumpJson() + const expected = fs.readFileSync(`${DIR}/${file}/dump-json/main.json`, 'utf-8') + util.assert.equal(json, expected) +} + +function filterGensym(value: string): string { + return value.replaceAll(/gensym%%_[0-9]*/g, "gensym_XXX") +} + +function proceedToBin() { + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) +} + +interface TestOptions { + skipSrc?: boolean, + skipJson?: boolean, +} + +const defaultTestOptions: TestOptions = { + skipSrc: false, + skipJson: true, +} + +function runTest( + file: string, + transform?: arkts.ProgramTransformer, + userOptions: TestOptions = defaultTestOptions +) { + const options = { + skipSrc: userOptions.skipSrc ?? defaultTestOptions.skipSrc, + skipJson: userOptions.skipJson ?? defaultTestOptions.skipJson, + } + createConfig(file) + createContext(file) + proceedToChecked() + applyTransformOnState(transform) + recheck() + if (process.env.TEST_GOLDEN == "1") { + if (!options.skipSrc) dumpSrc(file) + if (!options.skipJson) dumpJson(file) + } else { + if (!options.skipSrc) assertSrc(file) + if (!options.skipJson) assertJson(file) + } + proceedToBin() +} + +function runTestWithParsedTransform( + file: string, + parsedTransform?: arkts.ProgramTransformer, + transform?: arkts.ProgramTransformer, + userOptions: TestOptions = defaultTestOptions +) { + const options = { + skipSrc: userOptions.skipSrc ?? defaultTestOptions.skipSrc, + skipJson: userOptions.skipJson ?? defaultTestOptions.skipJson, + } + createConfig(file) + createContext(file) + proceedToParsed() + applyTransformOnState(parsedTransform, arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED) + proceedToChecked() + applyTransformOnState(transform) + recheck() + if (process.env.TEST_GOLDEN == "1") { + if (!options.skipSrc) dumpSrc(file) + if (!options.skipJson) dumpJson(file) + } else { + if (!options.skipSrc) assertSrc(file) + if (!options.skipJson) assertJson(file) + } + proceedToBin() +} + +suite(util.basename(__filename), () => { + suite('static', () => { + test("function", () => { + runTest('static/function', undefined) + }) + + test.skip("public setter", () => { + runTest('static/public-setter', undefined) + }) + + test.skip("constructor with overload", () => { + runTest('static/constructor', undefined) + }) + + // es2panda issue 24821 + test.skip("property", () => { + runTest('static/property', undefined) + }) + + test("typed property", () => { + runTest('static/typed-property', undefined) + }) + + test("trailing block", () => { + runTest('static/trailing-block', undefined) + }) + + test("import type", () => { + runTest('static/import-type', undefined) + }) + + test("import all", () => { + runTest('static/import-all', undefined) + }) + }) + + suite('simple', () => { + test('rename class', () => { + runTest('simple/rename-class', (program: arkts.Program) => { + program.setAst(updateTopLevelClass(program.ast as arkts.ETSModule, renameClass)) + }) + }) + + test('add class method', () => { + runTest('simple/add-class-method', (program: arkts.Program) => { + program.setAst(updateTopLevelClass(program.ast as arkts.ETSModule, addClassMethod)) + }) + }) + + test('add variable declaration', () => { + runTest('simple/add-variable', (program: arkts.Program) => { + program.setAst(updateTopLevelClass(program.ast as arkts.ETSModule, addVariableDeclaration)) + }) + }) + }) + + test.skip('constructor', () => { + runTest('constructor', constructorWithOverload) + }) + + test('add this reference', () => { + runTest('this', addThisReference) + }) + + suite('lambda', () => { + test('compiler produced lambdas unchanged', () => { + runTest('lambda/unchanged', undefined) + }) + }) + + suite('imports', () => { + test('add another import from the same file with dedicated API', () => { + runTest('imports/add-same-file', addImportSameFile) + }) + + test('add another import from the same file with dedicated API and use it', () => { + runTest('imports/add-use-same-file', addUseImportSameFile) + }) + + test.skip('add import from the new file with dedicated API', () => { + runTest('imports/add-new-file', addImportNewFile) + }) + + test('recursive', () => { + runTest('imports/recursive', insertParameter) + }) + }) + + suite('overloads', () => { + test('getter and setter both modified simultaneously', () => { + runTest('overloads/getter-setter', insertParameterToType) + }) + }) + + suite('exports', () => { + test('import existing exported class', () => { + runTest('exports/basic', addUseImportClassSameFile) + }) + + test('import existing not exported class', () => { + runTest('exports/add-export', addUseImportClassSameFileAndExportClass) + }) + + test('import created class', () => { + runTest('exports/create-class', addUseImportClassSameFileAndCreateClass) + }) + + test('export struct as class', () => { + runTestWithParsedTransform('exports/struct-to-class', rewriteStructToClass, addUseImportClassSameFileAfterRewritingStructToClass) + }) + }) +}) diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..aeb6e10b7585d74241c6c72e8833eb7f75cd286d --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/dump-src/main.ets @@ -0,0 +1,13 @@ + +function main() {} + + +class C { + public g(): double { + return 5; + } + + public constructor() {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..38d3ebcdc721a3fae4da12417286efb8e754d5af --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/index.ts @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function addClassMethod(node: arkts.ClassDefinition) { + return arkts.factory.updateClassDefinition( + node, + node.ident, + node.typeParams, + node.superTypeParams, + node.implements, + undefined, + node.super, + [ + arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + arkts.factory.createIdentifier("g"), + arkts.factory.createFunctionExpression( + arkts.factory.createIdentifier("g"), + arkts.factory.createScriptFunction( + arkts.factory.createBlockStatement([ + arkts.factory.createReturnStatement( + arkts.factory.createNumberLiteral(5) + ) + ]), + undefined, + [], + arkts.factory.createETSPrimitiveType( + arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_DOUBLE, + ), + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + arkts.factory.createIdentifier("g"), + undefined, + ) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false, + ), + ...node.body, + ], + node.modifiers, + node.modifierFlags + ) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..96041f4f2bd132009d7c06ce704d10ef206d9d2e --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-class-method/main.ets @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 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. + */ + +class C { +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..534b4a38d65bdaafd82b2f68e4a7ea83cc620f1e --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/dump-src/main.ets @@ -0,0 +1,13 @@ + +function main() {} + + +class C { + public f(): void { + const x = ((1) + (4)); + } + + public constructor() {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd15fbbd215fa8164344c27a7b8e55dee2c6e648 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/index.ts @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function addVariableDeclaration(node: arkts.ClassDefinition) { + return arkts.factory.updateClassDefinition( + node, + node.ident, + node.typeParams, + node.superTypeParams, + node.implements, + undefined, + node.super, + [ + ...node.body.map((node: arkts.AstNode) => { + if (!arkts.isMethodDefinition(node)) { + return node + } + if (node.id?.name != "f") { + return node + } + if (!arkts.isFunctionExpression(node.value)) { + return node + } + const func = node.value.function + if (!func || !arkts.isBlockStatement(func.body)) { + return node + } + return arkts.factory.updateMethodDefinition( + node, + node.kind, + node.key, + arkts.factory.updateFunctionExpression( + node.value, + node.id, + arkts.factory.updateScriptFunction( + func, + arkts.factory.updateBlockStatement( + func.body, + [ + arkts.factory.createVariableDeclaration( + arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_CONST, + [ + arkts.factory.createVariableDeclarator( + arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_CONST, + arkts.factory.createIdentifier("x"), + arkts.factory.createBinaryExpression( + arkts.factory.createNumberLiteral(1), + arkts.factory.createNumberLiteral(4), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_PLUS, + ), + ), + ], + ), + ...func.body.statements, + ], + ), + func.typeParams, + func.params, + func.returnTypeAnnotation, + func.hasReceiver, + func.flags, + func.modifierFlags, + func.id, + func.annotations, + ), + ), + node.modifierFlags, + node.isComputed, + node.overloads, + ) + }) + ], + node.modifiers, + node.modifierFlags + ) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..408125c2b4b2a22a708ba13ff54bae651b3285ab --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/add-variable/main.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +class C { + f(): void { + } +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/simple/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..1966eff8eadb63a6eed9a979938dcdcccf9a9b77 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/index.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../src/arkts-api" + +export function updateTopLevelClass( + module: arkts.ETSModule, + update: (node: arkts.ClassDefinition) => arkts.ClassDefinition +) { + return arkts.factory.updateETSModule( + module, + [ + ...module.statements.map((node) => { + if (!arkts.isClassDeclaration(node)) { + return node + } + if (!arkts.isClassDefinition(node.definition)) { + return node + } + if (node.definition.ident?.name == "C") { + return arkts.factory.updateClassDeclaration( + node, + update(node.definition) + ) + } + return node + }) + ], + module.ident, + module.getNamespaceFlag(), + module.program, + ) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..b91d6ad10f82db415ab0d794ff579a81e70b4eaf --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/dump-src/main.ets @@ -0,0 +1,11 @@ + +function main() {} + + +class D { + public f(): void {} + + public constructor() {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c930e924aaef3abee06b1b8546217c8432a6302e --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../../src/arkts-api" + +export function renameClass(node: arkts.ClassDefinition) { + return arkts.factory.updateClassDefinition( + node, + node.ident ? arkts.factory.updateIdentifier( + node.ident, + "D" + ) : undefined, + node.typeParams, + node.superTypeParams, + node.implements, + undefined, + node.super, + node.body, + node.modifiers, + node.modifierFlags + ) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..64541ccc260c088a2955cf31b3c121a797d76cc5 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/simple/rename-class/main.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 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. + */ + +class C { + f(): void { + } +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/constructor/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/constructor/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..2339dcfc717a53690eeaa38d4b19582c77009c97 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/constructor/dump-src/main.ets @@ -0,0 +1,14 @@ + +function main(): void {} + + + +class XXX { + constructor(x: (()=> void)) { + this(x, undefined); + } + + public constructor(x: (()=> void), y: (()=> void) | undefined) {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/constructor/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/constructor/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..5916c50417c70fbdc10c4def077c165df6dfd3b1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/constructor/main.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 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. + */ + +class XXX { + constructor(x: ()=>void, y?: ()=>void) { + } +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/function/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/function/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..2d4ba9e9542eef9fd8300f31f22fa900e9e907f1 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/function/dump-src/main.ets @@ -0,0 +1,6 @@ + +function main() {} + +function foo(): void {} + + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/function/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/function/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..2c0360369803ad3484835777dd439988186dd684 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/function/main.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + +function foo(): void {} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..ee631c93e23b358831ded14d64532f1d8ab85af0 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/dump-src/main.ets @@ -0,0 +1,6 @@ + +import * as library from "./library"; + +function main() {} + + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/library.ts b/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/library.ts new file mode 100644 index 0000000000000000000000000000000000000000..e76c034cae87408f2f5f2d2fd654168933a11512 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/library.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +export class Scope { + static scope(): Scope { + throw new Error("") + } + cached(): T { + throw new Error("") + } +} + +export interface ExportedType { + scope( value: () => V ) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..802b16326bf22b7a1bb6cc7f7a2b78ef75d113b2 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/import-all/main.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as library from "./library" diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..93843db2f86c0880c4140912875b10383a2ac10d --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/dump-src/main.ets @@ -0,0 +1,6 @@ + +import { ExportedType as ExportedType } from "./library"; + +function main() {} + + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/library.ts b/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/library.ts new file mode 100644 index 0000000000000000000000000000000000000000..e76c034cae87408f2f5f2d2fd654168933a11512 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/library.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +export class Scope { + static scope(): Scope { + throw new Error("") + } + cached(): T { + throw new Error("") + } +} + +export interface ExportedType { + scope( value: () => V ) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..8bef6f3001b4084331c94ce3d2e6d5a1a081b042 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/import-type/main.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 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. + */ + +import { ExportedType } from "./library" diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/property/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/property/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..0cdc54eb9ec5b3611e1d7dbf889b35e5a28ebad7 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/property/main.ets @@ -0,0 +1,8 @@ + +interface I { + prop: boolean +} + +class C implements I { + prop = true +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..49c59c1b4c0232bd99f2233abbaa0683bc149290 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/dump-src/main.ets @@ -0,0 +1,24 @@ + +import { AnimatedState as AnimatedState, one as one } from "./library"; + +let x: (AnimatedState | undefined); + +function main(): void {} + +if (x) { + x!.paused = true +} + +class AnimatedStateImpl implements AnimatedState { + set paused(paused: boolean) { + throw new Error(""); + } + + public get paused(): boolean { + throw new Error(""); + } + + public constructor() {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/library.ts b/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/library.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f38c5ffaf4ab7b9ef62e4f354b41e36e4d74ffe --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/library.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 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. + */ + +export interface AnimatedState { + paused: boolean +} + +class AnimatedStateImpl implements AnimatedState { + get paused(): boolean { + throw new Error("") + } + set paused(paused: boolean) { + throw new Error("") + } +} + +export function one() { + +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..f9676161864d3b65e9526fe9880d95e2ecc00560 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/public-setter/main.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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. + */ + +import { AnimatedState, one } from "./library" + +let x: AnimatedState|undefined +if (x) x!.paused = true +class AnimatedStateImpl implements AnimatedState { + get paused(): boolean { + throw new Error("") + } + set paused(paused: boolean) { + throw new Error("") + } +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/trailing-block/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/trailing-block/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..b8097f64c43fb3fc4f2ceda9cd56bafefa384fcc --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/trailing-block/dump-src/main.ets @@ -0,0 +1,17 @@ + +function main() {} + + +class C { + public f(arg: (()=> void)): void {} + + public g(): void { + this.f((() => { + const x = 11; + })); + } + + public constructor() {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/trailing-block/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/trailing-block/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..826ec914b9842dead5985b3faeda05d8dca60c01 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/trailing-block/main.ets @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 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. + */ + +class C { + f(arg: () => void): void { } + + g(): void { + this.f() { + const x = 6 + 5 + } + } +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/typed-property/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/typed-property/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..d48f5918c712d3fb6b32d0107dee051cb40f1ddb --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/typed-property/dump-src/main.ets @@ -0,0 +1,24 @@ + +function main() {} + + +interface I { + get prop(): boolean + set prop(prop: boolean) + +} + +class C implements I { + public constructor() {} + + private _$property$_prop: boolean = true; + public get prop(): boolean { + return this._$property$_prop; + } + set prop(_$property$_prop: boolean) { + this._$property$_prop = _$property$_prop; + return; + } + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/static/typed-property/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/static/typed-property/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..6cddab31224d58a02616fa2f571345d2600dee4d --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/static/typed-property/main.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +interface I { + prop: boolean +} + +class C implements I { + prop: boolean = true +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/this/dump-src/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/this/dump-src/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..814a569298a5c056e8dcbdc3855ab35db73a0679 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/this/dump-src/main.ets @@ -0,0 +1,14 @@ + +function main() {} + + +class A { + public no_this(): void { + this; + console.log("test"); + } + + public constructor() {} + +} + diff --git a/ets1.2/libarkts/test/arkts-api/recheck/this/index.ts b/ets1.2/libarkts/test/arkts-api/recheck/this/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..65a35d8756ced9c843e5f6ae3a5472ec5c08eeb2 --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/this/index.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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. + */ + +import * as arkts from "../../../../src/arkts-api" + +class AddThisReference extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + const node = this.visitEachChild(beforeChildren) + if (arkts.isScriptFunction(node) && node.id?.name == "no_this") { + return arkts.factory.updateScriptFunction( + node, + arkts.factory.createBlockStatement( + [ + + arkts.factory.createExpressionStatement( + arkts.factory.createThisExpression() + ), + ...(arkts.isBlockStatement(node.body) ? node.body.statements : []), + ] + ), + node.typeParams, + node.params, + node.returnTypeAnnotation, + node.hasReceiver, + node.flags, + node.modifierFlags, + node.id, + node.annotations + ) + } + return node + } +} + +export function addThisReference(program: arkts.Program) { + program.setAst(new AddThisReference().visitor(program.ast)) +} diff --git a/ets1.2/libarkts/test/arkts-api/recheck/this/main.ets b/ets1.2/libarkts/test/arkts-api/recheck/this/main.ets new file mode 100644 index 0000000000000000000000000000000000000000..c3dc450b6b52592337bedf34a59673ca6ac9129a --- /dev/null +++ b/ets1.2/libarkts/test/arkts-api/recheck/this/main.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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. + */ + +class A { + no_this(): void { + console.log("test") + } +} diff --git a/ets1.2/libarkts/test/test-util.ts b/ets1.2/libarkts/test/test-util.ts new file mode 100644 index 0000000000000000000000000000000000000000..73b4e6e80f2dbc1d2af6d546edf964abd549d6e9 --- /dev/null +++ b/ets1.2/libarkts/test/test-util.ts @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import { global } from "../src/arkts-api/static/global" +import * as arkts from "../src/arkts-api" + +import * as pth from "path" +import { assert } from "@koalaui/harness" +import { exec, execSync } from "child_process" + +export { Es2pandaNativeModule } from "../src/Es2pandaNativeModule" +export { assert } from "@koalaui/harness" + +export function alignText(text: string): string { + const lines = text.replace(/\t/gy, ' ').split('\n') + + const shift = + lines + .map((str: string) => str.search(/\S/)) + .reduce( + (prev: number, curr: number) => { + if (prev === -1) { + return curr + } + if (curr === -1) { + return prev + } + return Math.min(prev, curr) + } + ) + return lines.map(str => str.slice((shift === -1) ? 0 : shift)).join('\n').trim() +} + +export function basename(fileName: string) { + return pth.basename(fileName).split('.')[0] +} + +export function assertEqualsSource(sourceResult: string, sourceExpect: string, message?: string) { + assert.equal( + sourceResult.trim().split('\n').map((line: string) => line.trim()).join('\n'), + sourceExpect.trim().split('\n').map((line: string) => line.trim()).join('\n'), + message + ) +} + +export function ARKTS_TEST_ASSERTION(node: arkts.ETSModule, source: string, state?: arkts.Es2pandaContextState) { + const finalState: arkts.Es2pandaContextState = (() => { + if (state !== undefined) { + return state + } + if (process.env.STATE_CHECKED !== undefined) { + return arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED + } + return arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED + })() + arkts.proceedToState(finalState) + + const ast = node.dumpJson() + const src = node.dumpSrc() + const dump = node.dump() + + try { + const script = arkts.createETSModuleFromSource(source, finalState) + assertEqualsSource(src, script.dumpSrc(), 'Error on SOURCE comparison') + assert.equal(ast, script.dumpJson(), 'Error on JSON comparison') + assert.equal(dump, script.dump(), 'Error on DUMP comparison') + } finally { + global.es2panda._DestroyContext(global.context) + } +} + + + +export function cleanGenerated(): void { + exec('npm run clean:generated') +} + +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('mkdir -p ./generated') + execSync(`mv ./${file}.abc ./generated/${file}.abc`) +} + +export function contextToAbc(): void { + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) + // Improve: get name of file + execSync('mkdir -p ./generated') + execSync('mv ./main.abc ./generated/main.abc') +} + +export function runAbc(path: string = './generated/main.abc', modules?: readonly string[]): void { + const modulesStr: string = (modules === undefined) ? '' : (':' + modules.join(':')) + + exec(`../../incremental/tools/panda/node_modules/@panda/sdk/linux_host_tools/bin/ark --load-runtimes=ets --boot-panda-files=../../incremental/tools/panda/node_modules/@panda/sdk/ets/etsstdlib.abc${modulesStr} ${path} ETSGLOBAL::main`, + (error: any, stdout: string, stderr: string) => { + if (error !== null) { + assert(false, `failed to run abc: ${error}`) + } + console.log(`stdout: ${stdout}`); + console.log(`stderr: ${stderr}`); + } + ) +} + +export function assertEqualsBinaryOutput(output: string, ctx: Mocha.Context): void { + if (process.env.TEST_BIN === undefined) { + ctx.skip() + } + try { + contextToAbc() + exec( + 'npm run run:abc', + (error: any, stdout: string, stderr: string) => { + if (error !== null) { + assert(false, `failed to run abc: ${error}`) + } + const lines = stdout.trim().split('\n') + assert(lines.length >= 2) + assert.equal(lines[0], '> run:abc') + assert.equal(stderr, '') + if (lines.length === 2) { + assert.equal('', output.trim()) + } else { + assert.equal(lines.splice(2).join('\n').trim(), output.trim()) + } + } + ) + } finally { + global.es2panda._DestroyContext(global.context) + } +} + +export function trimLines(value: string): string { + return value.split('\n').map(it => it.trim()).join('\n') +} + +export function equalTrimming(value1: string, value2: string, message: string) { + return assert.equal( + trimLines(value1), + trimLines(value2), + message + ) +} diff --git a/ets1.2/libarkts/test/ts-api/classes/heritage/extends.test.ts b/ets1.2/libarkts/test/ts-api/classes/heritage/extends.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a57a64cb8571fcb6f097cc3a6840e540ac44f43 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/classes/heritage/extends.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../../test-util" +import * as ts from "../../../../src/ts-api" +import { factory } from "../../../../src/ts-api" + +// Improve: +suite.skip(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + abstract class A {}; + abstract class C {}; + interface D {}; + class B extends A implements C, D {}; + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + // sourceFile = factory.updateSourceFile( + // sourceFile, + // [ + // factory.createClassDeclaration( + // [ + // factory.createToken(ts.SyntaxKind.AbstractKeyword) + // ], + // factory.createIdentifier("A"), + // undefined, + // undefined, + // [] + // ), + // factory.createClassDeclaration( + // undefined, + // factory.createIdentifier("B"), + // undefined, + // [ + // factory.createHeritageClause( + // ts.SyntaxKind.ExtendsKeyword, + // [ + // factory.createExpressionWithTypeArguments( + // factory.createIdentifier("A"), + // undefined + // ) + // ] + // ) + // ], + // [] + // ) + // ] + // ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + abstract class A {}; + class B extends A {}; + ` + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/cross/cross.test.ts b/ets1.2/libarkts/test/ts-api/cross/cross.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..de273c4aa9f445211ab1277e1431dce527eee9f6 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/cross/cross.test.ts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + test("imported-function-call", function() { + const sample_in = + ` + import { X } from "./variable" + + export function main() { + console.log(X) + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + util.cleanGenerated() + util.fileToAbc(`./input/variable.sts`, true) + util.contextToAbc() + util.runAbc(`./generated/main.abc`, ['./generated/variable.abc']) + }) + + test("rewrite-imported-function-call", function() { + const sample_in = + ` + import { X } from "./variable" + + export function main() { + console.log(Y) + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + util.cleanGenerated() + util.fileToAbc(`./input/variable.sts`, true) + util.contextToAbc() + util.runAbc(`./generated/main.abc`, ['./generated/variable.abc']) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/functions/function-declaration/create-function-declaration.test.ts b/ets1.2/libarkts/test/ts-api/functions/function-declaration/create-function-declaration.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd329a7337bee2010ad65c242a9d01debc4fea2e --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/functions/function-declaration/create-function-declaration.test.ts @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../../test-util" +import * as ts from "../../../../src/ts-api" +import { factory } from "../../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + test("empty-function", function() { + // function test_func() { + // // empty + // } + + const sample_in = `` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcDecl = ts.factory.createFunctionDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("test_func"), + undefined, + [], + undefined, + ts.factory.createBlock( + [], + true + ) + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + funcDecl + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function test_func() {} + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + test("empty-function-with-param", function() { + const sample_in = `` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcParams = [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("x"), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + undefined + ) + ] + const funcDecl = ts.factory.createFunctionDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("test_func"), + undefined, + funcParams, + undefined, + ts.factory.createBlock( + [], + true + ) + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + funcDecl + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function test_func(x: number) {} + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + test("empty-function-with-string-param", function() { + // function test_func(x: string) { + // // empty + // } + + const sample_in = `` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcParams = [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("x"), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined + ) + ] + const funcDecl = ts.factory.createFunctionDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("test_func"), + undefined, + funcParams, + undefined, + ts.factory.createBlock( + [], + true + ) + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + funcDecl + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function test_func(x: string) {} + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + test("async-empty-function", function() { + // async function test_func() {} + + const sample_in = `` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcDecl = ts.factory.createFunctionDeclaration( + [ + ts.factory.createToken(ts.SyntaxKind.AsyncKeyword) + ], + undefined, + ts.factory.createIdentifier("test_func"), + undefined, + [], + undefined, + ts.factory.createBlock( + [], + true + ) + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + funcDecl + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + async function test_func() {} + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + test.skip("empty-method-with-public-static-modifiers", function() { + const sample_in = + ` + class A { + } + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let classDecl = sourceFile.statements[0] + util.assert(ts.isClassDeclaration(classDecl)) + + classDecl = factory.updateClassDeclaration( + classDecl, + undefined, + factory.createIdentifier("A"), + undefined, + undefined, + [ + factory.createMethodDeclaration( + [ + factory.createToken(ts.SyntaxKind.PublicKeyword), + factory.createToken(ts.SyntaxKind.StaticKeyword) + ], + undefined, + factory.createIdentifier("test_func"), + undefined, + undefined, + [], + undefined, + factory.createBlock( + [], + false + ) + ), + factory.createConstructorDeclaration( + [ + factory.createToken(ts.SyntaxKind.PublicKeyword) + ], + [], + factory.createBlock( + [], + false + ) + ) + ] + ) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + classDecl + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + class A { + public static test_func() {} + + public constructor() {} + + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + test("function-with-type-parameters", function() { + // function test_func(): void {} + + const sample_in = + ` + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcDecl = ts.factory.createFunctionDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("test_func"), + [ + ts.factory.createTSTypeParameterDeclaration( + undefined, + ts.factory.createIdentifier("T"), + undefined, + undefined + ), + ts.factory.createTSTypeParameterDeclaration( + undefined, + ts.factory.createIdentifier("K"), + undefined, + undefined + ) + ], + [], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + ts.factory.createBlock( + [], + true + ) + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + funcDecl + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function test_func(): void {} + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + // Improve: change 0 -> 777 (waiting fix) + test("sample-1", function() { + const sample_in = + ` + console.log("OK") + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcDecl = factory.createFunctionDeclaration( + undefined, + undefined, + factory.createIdentifier("foo"), + undefined, + [ + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("x"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + factory.createNumericLiteral(0) + ), + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("y"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + factory.createStringLiteral("abc") + ) + ], + factory.createETSUnionTypeNode([ + factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword) + ]), + factory.createBlock( + [factory.createReturnStatement(factory.createBinaryExpression( + factory.createIdentifier("x"), + factory.createToken(ts.SyntaxKind.PlusToken), + factory.createIdentifier("y") + ))], + true + ) + ) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + funcDecl, + sourceFile.statements[0] + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(x: number = 0, y: string = "abc"): number | string { + return x + y + } + console.log("OK") + ` + ) + }) + + // Improve: change 0 -> 777 (waiting fix) + test("sample-2", function() { + const sample_in = + ` + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcDecl = ts.factory.createFunctionDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("foo"), + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("x"), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + ts.factory.createNumericLiteral(0) + ), + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("y"), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + ts.factory.createStringLiteral("abc") + ) + ], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + ts.factory.createBlock( + [ + ts.factory.createReturnStatement( + ts.factory.createIdentifier("x") + ) + ], + true + ) + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + funcDecl, + // sourceFile.statements[0] + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(x: number = 0, y: string = "abc"): number { + return x + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/functions/function-declaration/update-function-declaration.test.ts b/ets1.2/libarkts/test/ts-api/functions/function-declaration/update-function-declaration.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed3b74fe70182bc40478dc2bd9a5308c63621911 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/functions/function-declaration/update-function-declaration.test.ts @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../../test-util" +import * as ts from "../../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + // adding y: string to signature + test("update-name-and-add-param-to-function", function() { + // function new_test_func(x: number, y: string) { + // // empty + // } + + const sample_in = + ` + function test_func(x: number) { + // empty + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + + const newParam = ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("y"), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined + ) + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + ts.factory.createIdentifier("new_test_func"), + undefined, + [ + ...testFunc.parameters, + newParam + ], + undefined, + testFunc.body + ) + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function new_test_func(x: number, y: string) {} + ` + ) + }) + + // adding memo params to signature + test("add-params-to-memo-function", function() { + // function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number) { + // // empty + // } + + const sample_in = + ` + function foo(x: number) { + // empty + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + + testFunc = util.addMemoParamsToFunctionDeclaration(testFunc) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number) {} + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + // adding identifier x + test("add-identifier-to-function-body", function() { + // function foo() { + // x + // } + + const sample_in = + ` + function foo(x: string) { + // empty + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + util.assert(testFunc.body !== undefined) + + let body_statements = [ + ...testFunc.body.statements, + ts.factory.createExpressionStatement(ts.factory.createIdentifier("x")) + ] + + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + testFunc.name, + undefined, + testFunc.parameters, + undefined, + ts.factory.updateBlock( + testFunc.body, + body_statements + ) + ) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(x: string) { + x + } + ` + ) + }) + + // adding __memo_scope.recache + test("add-property-access-expression-to-function-body", function() { + // function foo() { + // __memo_scope.recache + // } + + const sample_in = + ` + function foo() { + // empty + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + util.assert(testFunc.body !== undefined) + + let body_statements = [ + ...testFunc.body.statements, + ts.factory.createExpressionStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("recache") + ) + ) + ] + + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + testFunc.name, + undefined, + testFunc.parameters, + undefined, + ts.factory.updateBlock( + testFunc.body, + body_statements + ) + ) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo() { + __memo_scope.recache; + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + // body memo rewrite (adding return statement) + test("add-return-statement-to-function-body", function() { + // function foo() { + // return __memo_scope.recache() + // } + + const sample_in = + ` + function foo() { + // empty + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + util.assert(testFunc.body !== undefined) + + let body_statements = [ + ...testFunc.body.statements, + ts.factory.createReturnStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("recache") + ), + undefined, + undefined + ) + ) + ] + + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + testFunc.name, + undefined, + testFunc.parameters, + undefined, + ts.factory.updateBlock( + testFunc.body, + body_statements + ) + ) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo() { + return __memo_scope.recache(); + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + // body memo rewrite (adding if statement) + test("add-if-statement-to-function-body", function() { + // function foo() { + // if (__memo_scope.unchanged) + // return __memo_scope.cached + // } + + const sample_in = + ` + function foo() { + // empty + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + util.assert(testFunc.body !== undefined) + + let body_statements = [ + ts.factory.createIfStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("unchanged") + ), + ts.factory.createBlock([ + ts.factory.createReturnStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("cached") + ) + ) + ]), + undefined + ), + ...testFunc.body.statements + ] + + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + testFunc.name, + undefined, + testFunc.parameters, + undefined, + ts.factory.updateBlock( + testFunc.body, + body_statements + ) + ) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo() { + if (__memo_scope.unchanged) { + return __memo_scope.cached; + } + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + // body memo rewrite + test("function-declaration-memo-rewrite", function() { + // function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + // if (__memo_scope.unchanged) + // return __memo_scope.cached + // content(__memo_context, __memo_id + "key_id_main.ts") + // return __memo_scope.recache() + // } + + const sample_in = + ` + function foo() { + // empty + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + util.assert(testFunc.body !== undefined) + + let body_statements = [ + ts.factory.createIfStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("unchanged") + ), + ts.factory.createBlock([ + ts.factory.createReturnStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("cached") + ) + ) + ]), + undefined + ), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createIdentifier("content"), + undefined, + [ + ts.factory.createIdentifier("__memo_context"), + ts.factory.createBinaryExpression( + ts.factory.createIdentifier("__memo_id"), + ts.factory.createToken(ts.SyntaxKind.PlusToken), + ts.factory.createStringLiteral("key_id_main.ts") + ) + ] + )), + ts.factory.createReturnStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("recache") + ), + undefined, + undefined + ) + ), + ...testFunc.body.statements + ] + + testFunc = util.addMemoParamsToFunctionDeclaration(testFunc) + util.assert(ts.isFunctionDeclaration(testFunc)) + util.assert(testFunc.body !== undefined) + + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + testFunc.name, + undefined, + testFunc.parameters, + undefined, + ts.factory.updateBlock( + testFunc.body, + body_statements + ) + ) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + if (__memo_scope.unchanged) { + return __memo_scope.cached; + } + content(__memo_context, ((__memo_id) + ("key_id_main.ts"))); + return __memo_scope.recache(); + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + test("return-lambda", function() { + const sample_in = + ` + function foo() {} + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + ts.factory.createIdentifier("foo"), + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("x"), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined + ) + ], + undefined, + ts.factory.createBlock( + [ + ts.factory.createReturnStatement( + ts.factory.createCallExpression( + ts.factory.createParenthesizedExpression( + ts.factory.createArrowFunction( + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("val"), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + ts.factory.createIdentifier("x") + ) + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock( + [ + ts.factory.createExpressionStatement( + ts.factory.createIdentifier("val") + ) + ], + false + ) + ) + ), + undefined, + [] + ) + ) + ], + true + ) + ) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(x: string) { + return ((val: string = x) => { val })() + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/functions/lambda-function/builder-lambda.test.ts b/ets1.2/libarkts/test/ts-api/functions/lambda-function/builder-lambda.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8fd8ffb5f9c7115c533a0fdc4473102f58fa97a3 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/functions/lambda-function/builder-lambda.test.ts @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../../test-util" +import * as ts from "../../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + test("adding-lambda-param-to-signature", function() { + // _Foo((instance: string) => { + // // empty + // }, "label"); + + const sample_in = + ` + Foo("label") + + function Foo(text: string): void { + console.log(text) + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const newName = "_Foo" + const paramName = "instance" + + const firstStatement = sourceFile.statements[0] + util.assert(ts.isExpressionStatement(firstStatement)) + const node = firstStatement.expression + util.assert(ts.isCallExpression(node)) + + const instanceLambdaBody = ts.factory.createBlock([]) + const lambdaParams = [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier(paramName), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined + ) + ] + + const lambda = ts.factory.createArrowFunction( + undefined, + undefined, + lambdaParams, + undefined, + undefined, + instanceLambdaBody + ) + + const result = ts.factory.updateCallExpression( + node, + ts.factory.createIdentifier(newName), + undefined, + [ + lambda, + ...node.arguments + ] + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + ts.factory.createExpressionStatement(result) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + _Foo(((instance: string) => {}), "label") + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) + + test("adding-body-to-lambda-param", function() { + // _Foo((instance: string) => { + // instance.bar().qux(); + // }, "label1", "label2"); + + const sample_in = + ` + Foo(instance.bar().qux(), "label1", "label2") + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const newName = "_Foo" + const paramName = "instance" + + const firstStatement = sourceFile.statements[0] + util.assert(ts.isExpressionStatement(firstStatement)) + + const node = firstStatement.expression + util.assert(ts.isCallExpression(node)) + + const instanceLambdaBody = ts.factory.createBlock([ + ts.factory.createExpressionStatement( + node.arguments[0] + ) + ]) + const lambdaParams = [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier(paramName), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined + ) + ] + + const lambda = ts.factory.createArrowFunction( + undefined, + undefined, + lambdaParams, + undefined, + undefined, + instanceLambdaBody + ) + + const result = ts.factory.updateCallExpression( + node, + ts.factory.createIdentifier(newName), + undefined, + [ + lambda, + ...node.arguments.slice(1) + ] + ) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + ts.factory.createExpressionStatement(result) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + _Foo(((instance: string) => { + instance.bar().qux(); + }), "label1", "label2") + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/functions/lambda-function/lambda-param-memoization.test.ts b/ets1.2/libarkts/test/ts-api/functions/lambda-function/lambda-param-memoization.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2982ad6eaa21113e6345af17cd86d0977e908e49 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/functions/lambda-function/lambda-param-memoization.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../../test-util" +import * as ts from "../../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + // full memo rewrite + test("memo-function-with-lambda-memo-param", function() { + // function foo( + // __memo_context: __memo_context_type, + // __memo_id: __memo_id_type, + // content: (__memo_context: __memo_context_type, __memo_id: __memo_id_type) => void + // ) { + // if (__memo_scope.unchanged) + // return __memo_scope.cached + // content(__memo_context, __memo_id + "key_id_main.ts") + // return __memo_scope.recache() + // } + + const sample_in = + ` + function foo( + content: () => void + ) { + content() + } + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + let testFunc = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(testFunc)) + + let body_statements = [ + ts.factory.createIfStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("unchanged") + ), + ts.factory.createBlock([ + ts.factory.createReturnStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("cached") + ) + ) + ]), + undefined + ), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createIdentifier("content"), + undefined, + [ + ts.factory.createIdentifier("__memo_context"), + ts.factory.createBinaryExpression( + ts.factory.createIdentifier("__memo_id"), + ts.factory.createToken(ts.SyntaxKind.PlusToken), + ts.factory.createStringLiteral("key_id_main.ts") + ) + ] + )), + ts.factory.createReturnStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier("__memo_scope"), + ts.factory.createIdentifier("recache") + ), + undefined, + undefined + ) + ) + ] + + testFunc = util.addMemoParamsToFunctionDeclaration(testFunc) + util.assert(ts.isFunctionDeclaration(testFunc)) + util.assert(testFunc.body !== undefined) + + const newLambdaParams = [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("__memo_context"), + undefined, + ts.factory.createETSTypeReferenceNode( + ts.factory.createIdentifier("__memo_context_type"), + undefined + ) + ), + ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("__memo_id"), + undefined, + ts.factory.createETSTypeReferenceNode( + ts.factory.createIdentifier("__memo_id_type"), + undefined + ), + ) + ] + + const newLambdaParam = ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("content"), + undefined, + ts.factory.createFunctionTypeNode( + undefined, + newLambdaParams, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword) + ), + undefined + ) + + testFunc = ts.factory.updateFunctionDeclaration( + testFunc, + undefined, + undefined, + testFunc.name, + undefined, + [ + testFunc.parameters[0], + testFunc.parameters[1], + newLambdaParam + ], + undefined, + ts.factory.updateBlock( + testFunc.body, + body_statements + ) + ) + util.assert(ts.isFunctionDeclaration(testFunc)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + testFunc + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, content: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { + if (__memo_scope.unchanged) { + return __memo_scope.cached; + } + content(__memo_context, ((__memo_id) + ("key_id_main.ts"))); + return __memo_scope.recache(); + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED, + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/general/abc-gen.test.ts b/ets1.2/libarkts/test/ts-api/general/abc-gen.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0a8411de1c3e965ef51d80ddcfc59605c7635b4c --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/general/abc-gen.test.ts @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" + +// tests for abc generation (now failing on CI) +suite.skip(util.basename(__filename), () => { + test("updating-expression-statement", function() { + const sample_in = + ` + function foo(lambda: (instance: string) => string): void { + console.log(lambda("ABC")) + } + + foo((instance: string) => { return instance }) + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const expressionStatement = sourceFile.statements[1] + util.assert(ts.isExpressionStatement(expressionStatement)) + + const newStatements = [ + sourceFile.statements[0], + ts.factory.updateExpressionStatement( + expressionStatement, + expressionStatement.expression + ) + ] + + ts.factory.updateSourceFile(sourceFile, newStatements) + + util.assertEqualsBinaryOutput('ABC', this) + }) + + test("updating-function-declaration", function() { + const sample_in = + ` + function foo(): void { + console.log("A") + return + } + + foo() + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const funcDecl = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(funcDecl)) + + const newStatements = [ + ts.factory.updateFunctionDeclaration( + funcDecl, + undefined, + undefined, + funcDecl.name, + undefined, + funcDecl.parameters, + undefined, + funcDecl.body, + ), + sourceFile.statements[1], + ] + + ts.factory.updateSourceFile(sourceFile, newStatements) + + util.assertEqualsBinaryOutput('A', this) + }) + + test("updating-lambda-call", function() { + const sample_in = + ` + function foo(builder: () => void) {} + foo(() => {}) + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + const exprStatement = sourceFile.statements[1] + util.assert(ts.isExpressionStatement(exprStatement)) + const callExpr = exprStatement.expression + util.assert(ts.isCallExpression(callExpr)) + + util.assert(ts.isArrowFunction(callExpr.arguments[0])) + const lambdaArg = + ts.factory.createArrowFunction( + undefined, + undefined, + [], + undefined, + undefined, + callExpr.arguments[0].body + ) + + util.assert(ts.isIdentifier(callExpr.expression)) + const newStatements = [ + sourceFile.statements[0], + ts.factory.updateExpressionStatement( + exprStatement, + ts.factory.updateCallExpression( + callExpr, + ts.factory.createIdentifier('foo'), + undefined, + [ + lambdaArg, + ] + ) + ) + ] + ts.factory.updateSourceFile(sourceFile, newStatements) + + util.assertEqualsBinaryOutput('', this) + }) + + test("changing-variable-annotation", function() { + const sample_in = + ` + class A {} + + let x: AB + + console.log("ok") + ` + + let sourceFile = ts.factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const varDecl = sourceFile.statements[1] + util.assert(ts.isVariableStatement(varDecl)) + + const declList = varDecl.declarationList + util.assert(ts.isVariableDeclarationList(declList)) + + const x = declList.declarations[0] + util.assert(ts.isVariableDeclaration(x)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + sourceFile.statements[0], + ts.factory.updateVariableStatement( + varDecl, + undefined, + // declList + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration( + ts.factory.createIdentifier("x"), + undefined, + ts.factory.createETSTypeReferenceNode( + ts.factory.createIdentifier("A") + ), + undefined + )], + undefined + ) + ), + sourceFile.statements[2] + ] + ) + + util.assertEqualsBinaryOutput('ok', this) + }) + + test.skip("function-expression", function() { + const sample_in = + ` + const foo = function() { console.log("abc"); }; + foo(); + ` + + ts.factory.createSourceFile(sample_in) + util.assertEqualsBinaryOutput('abc', this) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/general/basic.test.ts b/ets1.2/libarkts/test/ts-api/general/basic.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f5a1a236a6ac581d1846d10fb330a240dec3523 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/general/basic.test.ts @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" +import { factory } from "../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + factory.createExpressionStatement( + factory.createIdentifier("abc") + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + abc + `, + ts.ContextState.ES2PANDA_STATE_PARSED + ) + }) + + test("sample-2", function() { + const sample_in = + ` + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + factory.createFunctionDeclaration( + undefined, + undefined, + factory.createIdentifier("test"), + undefined, + [], + undefined, + factory.createBlock( + [], + true + ) + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function test() {} + `, + ts.ContextState.ES2PANDA_STATE_PARSED + ) + }) + + test("sample-3", function() { + const sample_in = + ` + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + factory.createFunctionDeclaration( + undefined, + undefined, + factory.createIdentifier("test"), + undefined, + [ + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("x"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined + ) + ], + factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + factory.createBlock( + [ + factory.createReturnStatement( + factory.createNumericLiteral(0) + ) + ], + true + ) + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function test(x: string): number { + return 0; + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED + ) + }) + + test("sample-4", function() { + const sample_in = + ` + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + factory.createFunctionDeclaration( + undefined, + undefined, + factory.createIdentifier("test"), + [ + factory.createTSTypeParameterDeclaration( + undefined, + factory.createIdentifier("T"), + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined + ) + ], + [ + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("x"), + undefined, + factory.createETSTypeReferenceNode( + factory.createIdentifier("T"), + undefined + ), + undefined + ) + ], + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + factory.createBlock( + [ + factory.createReturnStatement( + factory.createStringLiteral("aaa") + ) + ], + true + ) + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function test(x: T): string { + return "aaa" + } + `, + ts.ContextState.ES2PANDA_STATE_PARSED + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/general/import.test.ts b/ets1.2/libarkts/test/ts-api/general/import.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f649094a1aa83dc9f4d14a26a8b66b984e9ce68 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/general/import.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + // Improve: doesn't running now, but compiles (config gets only one file) + test("sample-1", function() { + const sample_in = + ` + import { TEST } from "./export" + console.log(TEST) + ` + + // util.getDefaultSetup(sample_in) + + // util.generateBinAndRun() + }) + + test("sample-2", function() { + const sample_in = + ` + import { power as F } from "std/math" + console.log(F(2, 10)) + ` + + // util.getDefaultSetup(sample_in) + + // arkts.proceedToState(arkts.ContextState.ES2PANDA_STATE_CHECKED) + + // const classDecl = arkts.nodeByPeer(util.getStatement(1)) + // util.assert(arkts.isClassDeclaration(classDecl)) + + // const method = classDecl.members[1] + // util.assert(arkts.isMethodDeclaration(method)) + + // const body = method.body! + // util.assert(arkts.isBlock(body)) + + // const exprStatement = body.statements[0] + // util.assert(arkts.isExpressionStatement(exprStatement)) + + // const callExpr = exprStatement.expression + // util.assert(arkts.isCallExpression(callExpr)) + + // const F = callExpr.arguments[0] + // util.assert(arkts.isCallExpression(F)) + + // const ident = F.expression + // util.assert(arkts.isIdentifier(ident)) + + // console.log(arkts.dumpJsonNode(ident)) + + // const decl = arkts.getDecl(ident) + // if (decl !== undefined) { + // console.log(arkts.dumpJsonNode(decl)) + // } else { + // console.log(decl) + // } + + // util.generateBinAndRun() + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/import-export/import.test.ts b/ets1.2/libarkts/test/ts-api/import-export/import.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..66c2928a22acbc045c59ad72df28aa3787591c5b --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/import-export/import.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" +import { factory } from "../../../src/ts-api" + +// Improve: +suite.skip(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + import { X } from "./variable" + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + // sourceFile = factory.updateSourceFile( + // sourceFile, + // [ + // factory.createImportDeclaration( + // undefined, + // factory.createImportClause( + // false, + // undefined, + // factory.createNamedImports( + // [ + // factory.createImportSpecifier( + // false, + // undefined, + // factory.createIdentifier("X") + // ) + // ] + // ) + // ), + // factory.createStringLiteral("./variable"), + // undefined + // ) + // ] + // ) + + // util.assertEqualsAfter( + // sourceFile, + // ` + // import { X } from "./variable" + // `, + // ts.ContextState.ES2PANDA_STATE_PARSED + // ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/keyword-super/in-constructor.test.ts b/ets1.2/libarkts/test/ts-api/keyword-super/in-constructor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c51ab999aca8459253ab482f2bbbe0e7e2c16489 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/keyword-super/in-constructor.test.ts @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" +import { factory } from "../../../src/ts-api" + +// Improve: +suite.skip(util.basename(__filename), () => { + test("sample-1", function() { + const sample_in = + ` + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + // sourceFile = factory.updateSourceFile( + // sourceFile, + // [ + // factory.createClassDeclaration( + // [factory.createToken(ts.SyntaxKind.AbstractKeyword)], + // factory.createIdentifier("A"), + // undefined, + // undefined, + // [factory.createConstructorDeclaration( + // undefined, + // [factory.createParameterDeclaration( + // undefined, + // undefined, + // factory.createIdentifier("x"), + // undefined, + // factory.createETSTypeReferenceNode( + // factory.createIdentifier("int"), + // undefined + // ), + // undefined + // )], + // factory.createBlock( + // [], + // false + // ) + // )] + // ), + // factory.createClassDeclaration( + // undefined, + // factory.createIdentifier("B"), + // undefined, + // [factory.createHeritageClause( + // ts.SyntaxKind.ExtendsKeyword, + // [factory.createExpressionWithTypeArguments( + // factory.createIdentifier("A"), + // undefined + // )] + // )], + // [factory.createConstructorDeclaration( + // undefined, + // [factory.createParameterDeclaration( + // undefined, + // undefined, + // factory.createIdentifier("x"), + // undefined, + // factory.createETSTypeReferenceNode( + // factory.createIdentifier("int"), + // undefined + // ), + // undefined + // )], + // factory.createBlock( + // [factory.createExpressionStatement(factory.createCallExpression( + // factory.createSuper(), + // undefined, + // [factory.createIdentifier("x")] + // ))], + // true + // ) + // )] + // ) + // ] + // ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + abstract class A { + constructor(x: int) {} + }; + + class B extends A { + constructor(x: int) { + super(x) + } + } + ` + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/variables/create-variable.test.ts b/ets1.2/libarkts/test/ts-api/variables/create-variable.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..18fa959be431b68ca87325e2ae7002a6fcadbe72 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/variables/create-variable.test.ts @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" +import { factory } from "../../../src/ts-api" + +suite.skip(util.basename(__filename), () => { + test("const-number", function() { + const sample_in = + ` + function f() {} + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const varDecl = factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("x"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + factory.createNumericLiteral(0) + ) + ], + ts.NodeFlags.Const + ) + ) + + const f = sourceFile.statements[0] + util.assert(ts.isFunctionDeclaration(f)) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + factory.updateFunctionDeclaration( + f, + f.modifiers, + undefined, + f.name, + f.typeParameters, + f.parameters, + f.type, + factory.createBlock([ + varDecl + ]) + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function f() { + const x: number = 0 + } + ` + ) + }) + + test("declaration-list", function() { + // const x: number = 0, y: string = "a", z = 0 + + const sample_in = `const x = 1` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const varStatement = sourceFile.statements[0] + util.assert(ts.isVariableStatement(varStatement)) + + sourceFile = ts.factory.updateSourceFile( + sourceFile, + [ + factory.updateVariableStatement( + varStatement, + [ + // Improve: not ok maybe (problem with ModifierFlags) + factory.createToken(ts.SyntaxKind.PublicKeyword), + factory.createToken(ts.SyntaxKind.StaticKeyword), + factory.createToken(ts.SyntaxKind.ConstKeyword), + ], + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("x"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + factory.createNumericLiteral(0) + ), + factory.createVariableDeclaration( + factory.createIdentifier("y"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + factory.createStringLiteral("a") + ), + factory.createVariableDeclaration( + factory.createIdentifier("z"), + undefined, + undefined, + factory.createNumericLiteral(0) + ) + ], + ts.NodeFlags.Const + ) + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + const x: number = 0, y: string = "a", z = 0 + ` + ) + }) + + test.skip("let-vars", function() { + const sample_in = + ` + const x = 0 + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + const varStatement = sourceFile.statements[0] + util.assert(ts.isVariableStatement(varStatement)) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + factory.updateVariableStatement( + varStatement, + [ + // Improve: not ok maybe (problem with ModifierFlags) + factory.createToken(ts.SyntaxKind.PublicKeyword), + factory.createToken(ts.SyntaxKind.StaticKeyword), + ], + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("x"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + factory.createNumericLiteral(0) + ), + factory.createVariableDeclaration( + factory.createIdentifier("y"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + factory.createStringLiteral("a") + ), + factory.createVariableDeclaration( + factory.createIdentifier("z"), + undefined, + undefined, + factory.createNumericLiteral(0) + ) + ], + ts.NodeFlags.Let + ) + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + let x: number = 0, y: string = "a", z = 0 + ` + ) + }) + + test("parenthesized-expression", function() { + const sample_in = + ` + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + sourceFile = factory.updateSourceFile( + sourceFile, + [ + factory.createVariableStatement( + [ + // Improve: not ok maybe (problem with ModifierFlags) + factory.createToken(ts.SyntaxKind.PublicKeyword), + factory.createToken(ts.SyntaxKind.StaticKeyword), + factory.createToken(ts.SyntaxKind.ConstKeyword), + ], + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("x"), + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + factory.createBinaryExpression( + factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createNumericLiteral(0), + factory.createToken(ts.SyntaxKind.PlusToken), + factory.createNumericLiteral(0) + ) + ), + factory.createToken(ts.SyntaxKind.AsteriskToken), + factory.createNumericLiteral(0) + ) + ) + ], + ts.NodeFlags.Const + ) + ) + ] + ) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + const x: number = (0 + 0) * 0 + ` + ) + }) + + test.skip("question-mark", function() { + const sample_in = + ` + function foo(x?: number | undefined) { + console.log(x); + } + foo() + ` + + let sourceFile = factory.createSourceFile(sample_in) + util.assert(ts.isSourceFile(sourceFile)) + + util.TS_TEST_ASSERTION( + sourceFile, + ` + function foo(x?: number | undefined) { + console.log(x); + } + foo() + `, + ts.ContextState.ES2PANDA_STATE_PARSED + ) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/visitors-and-transformers/analysis-visitor.test.ts b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/analysis-visitor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..357d2204347ddb88855aa555e0007fe4927384cc --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/analysis-visitor.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +// import * as util from "../../test-util" +// import * as ts from "../../../src/ts-api" +// import { AnalysisVisitor } from "../../../plugins/src/analysis-visitor" +// import { Tracer } from "../../../plugins/src/util" +// import { Rewrite } from "../../../plugins/src/transformation-context" +// +// suite(util.getSuiteTitle(__filename), () => { +// test("sample-1", function() { +// const sample_in = +// ` +// const _memo_x: string = "A" +// +// function _memo_foo() {} +// +// _memo_foo() +// ` +// +// let sourceFile = ts.factory.createSourceFile(sample_in) +// util.assert(ts.isSourceFile(sourceFile)) +// +// // ts.proceedToState(ts.ContextState.ES2PANDA_STATE_CHECKED) +// +// const options = {} +// +// const tracer = new Tracer(options) +// const rewrite = new Rewrite(sourceFile, options) +// +// const result = new AnalysisVisitor(tracer, rewrite).visitor(sourceFile) +// util.assert(ts.isSourceFile(result)) +// +// util.assert(rewrite.functionTable.size === 1) +// util.assert(rewrite.callTable.size === 1) +// util.assert(rewrite.variableTable.size === 1) +// }) +// }) diff --git a/ets1.2/libarkts/test/ts-api/visitors-and-transformers/builder-lambda-rewrite.test.ts b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/builder-lambda-rewrite.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..45c1407fb1516d38c04f2159a28f09c7fe7f5b45 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/builder-lambda-rewrite.test.ts @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +// import * as util from "../../test-util" +// import * as ts from "../../../src/ts-api" +// import { factory } from "../../../src/ts-api" +// import { BuilderLambdaTransformer } from "../../../plugins/src/builder-lambda-transformer" +// +// suite.skip(util.getSuiteTitle(__filename), () => { +// test("builder-lambda-transformer-sample-1", function() { +// // foo((instance: string) => { +// // return instance; +// // }, "label"); +// +// const sample_in = +// ` +// _BuilderLambdaCall_foo("label") +// ` +// +// let sourceFile = factory.createSourceFile(sample_in) +// util.assert(ts.isSourceFile(sourceFile)) +// +// const builderLambdaTransformer = new BuilderLambdaTransformer() +// +// const result = builderLambdaTransformer.visitor(sourceFile) +// util.assert(ts.isSourceFile(result)) +// +// util.TS_TEST_ASSERTION( +// result, +// ` +// foo(((instance: string) => { +// return instance; +// }), "label") +// `, +// ts.ContextState.ES2PANDA_STATE_PARSED, +// ) +// }) +// +// test("builder-lambda-transformer-sample-2", function() { +// // foo((instance: string) => { +// // return instance.bar().qux(); +// // }, "label1", "label2"); +// +// const sample_in = +// ` +// _BuilderLambdaCall_foo("label1", "label2").bar().qux() +// ` +// +// let sourceFile = factory.createSourceFile(sample_in) +// util.assert(ts.isSourceFile(sourceFile)) +// +// const builderLambdaTransformer = new BuilderLambdaTransformer() +// +// const result = builderLambdaTransformer.visitor(sourceFile) +// util.assert(ts.isSourceFile(result)) +// +// util.TS_TEST_ASSERTION( +// result, +// ` +// foo(((instance: string) => { +// return instance.bar().qux(); +// }), "label1", "label2") +// `, +// ts.ContextState.ES2PANDA_STATE_PARSED, +// ) +// }) +// +// // Improve: update nodes properly (now failing to generate bin) +// test("builder-lambda-transformer-sample-3", function() { +// // function Foo(builder: (instance: string) => string, arg1: string): void { +// // console.log(arg1 + builder("ABC")) +// // } +// // Foo((instance: string) => { +// // return instance.charAt(1) +// // }, "> second_char_of_ABC: ") +// +// const sample_in = +// ` +// function Foo(builder: (instance: string) => string, arg1: string): void { +// console.log(arg1 + builder("ABC")) +// } +// +// _BuilderLambdaCall_Foo("> second_char_of_ABC: ").charAt(1) +// ` +// +// let sourceFile = factory.createSourceFile(sample_in) +// util.assert(ts.isSourceFile(sourceFile)) +// +// const builderLambdaTransformer = new BuilderLambdaTransformer() +// +// const result = builderLambdaTransformer.visitor(sourceFile) +// util.assert(ts.isSourceFile(result)) +// +// util.TS_TEST_ASSERTION( +// result, +// ` +// function Foo(builder: ((instance: string)=> string), arg1: string): void { +// console.log(((arg1) + (builder("ABC")))); +// } +// +// Foo(((instance: string) => { +// return instance.charAt(1); +// }), "> second_char_of_ABC: ") +// `, +// ts.ContextState.ES2PANDA_STATE_PARSED, +// ) +// }) +// }) diff --git a/ets1.2/libarkts/test/ts-api/visitors-and-transformers/function-rewrite.test.ts b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/function-rewrite.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..acd40a0249789f7ed6eca281739326f802637c94 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/function-rewrite.test.ts @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +// import * as util from "../../test-util" +// import * as ts from "../../../src/ts-api" +// import global from "src/arkts-api/static/global" +// import { FunctionTransformer } from "../../../plugins/src/function-transformer" +// import { PrintVisitor } from "../../../plugins/src/print-visitor" +// +// suite.skip(util.getSuiteTitle(__filename), () => { +// test("function-transformer-sample-1", function() { +// const sample_in = +// ` +// const x: string = "A" +// +// function _REWRITE_foo() { +// console.log("FUNC CALLED: " + x) +// } +// +// _REWRITE_foo() +// ` +// +// const sourceFile = ts.factory.createSourceFile(sample_in, ts.ContextState.ES2PANDA_STATE_CHECKED) +// util.assert(ts.isSourceFile(sourceFile)) +// +// // util.nativeModule._VarBinderSetContext(global.context) +// // util.nativeModule._VarBinderSetProgram(global.context) +// // util.nativeModule._VarBinderSetGenStdLib(global.context, false) +// // util.nativeModule._VarBinderInitTopScope(global.context) +// // util.nativeModule._VarBinderIdentifierAnalysis(global.context) +// +// const result = (new FunctionTransformer()).visitor(sourceFile) +// util.assert(ts.isSourceFile(result)) +// +// util.TS_TEST_ASSERTION( +// sourceFile, +// ` +// const x: string = "A" +// +// function foo(x: string) { +// console.log("FUNC CALLED: " + x) +// } +// +// foo("SAMPLE") +// `, +// ts.ContextState.ES2PANDA_STATE_CHECKED, +// ) +// +// // Improve: +// util.nativeModule._VarBinderInitTopScope(global.context) +// util.nativeModule._VarBinderIdentifierAnalysis(global.context) +// ts.proceedToState(ts.ContextState.ES2PANDA_STATE_BIN_GENERATED) +// }) +// }) diff --git a/ets1.2/libarkts/test/ts-api/visitors-and-transformers/memo-rewrite.test.ts b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/memo-rewrite.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2aa9d54d53f53f74a95b73e8b93e854371e7a217 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/memo-rewrite.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as util from "../../test-util" +import * as ts from "../../../src/ts-api" +import { MemoTransformer } from "../../../plugins/src/memo-transformer" + +suite.skip(util.basename(__filename), () => { + test("memo-transformer-sample-1", function() { + const sample_in = + ` + function _MEMO_foo() { + console.log("MEMO FUNC CALLED!") + } + + _MEMO_foo() + ` + + // util.getDefaultSetup(sample_in) + + // arkts.proceedToState(arkts.ContextState.ES2PANDA_STATE_CHECKED) + + // const sourceFile = arkts.makeView(util.AstProvider.provideAst()) + + // const memoTransformer = new MemoTransformer() + // const transformed = memoTransformer.visitor(sourceFile) + + // console.log(arkts.dumpSrcNode(sourceFile)) + }) +}) diff --git a/ets1.2/libarkts/test/ts-api/visitors-and-transformers/print-visitor.test.ts b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/print-visitor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..736a67e53db03887c81855e15bea58c92bd16f96 --- /dev/null +++ b/ets1.2/libarkts/test/ts-api/visitors-and-transformers/print-visitor.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +// import * as ts from "../../../src/ts-api" +// import * as util from "../../test-util" +// import { PrintVisitor } from "../../../plugins/src/print-visitor" +// +// suite.skip(util.getSuiteTitle(__filename), () => { +// test("sample-1", function() { +// const source = +// ` +// class Base { +// public a: int = 1; +// public method() { +// this.a = 2; +// } +// } +// class Derived extends Base {} +// function foo() { +// } +// function goo() { +// } +// function main(): void { +// let derived: Base = new Derived(); +// derived.method(); +// } +// ` +// const expected = +// ` +// SourceFile (mods: []) +// ClassDeclaration (mods: [1,4]) +// Identifier (mods: []) +// PropertyDeclaration (mods: [4]) +// MethodDeclaration (mods: [4]) +// Identifier (mods: []) +// Block (mods: []) +// ExpressionStatement (mods: []) +// AssignmentExpression (mods: []) +// MethodDeclaration (mods: []) +// Identifier (mods: []) +// Block (mods: []) +// ClassDeclaration (mods: [1,4]) +// Identifier (mods: []) +// MethodDeclaration (mods: []) +// Identifier (mods: []) +// Block (mods: []) +// FunctionDeclaration (mods: [1,4]) +// Identifier (mods: []) +// Block (mods: []) +// FunctionDeclaration (mods: [1,4]) +// Identifier (mods: []) +// Block (mods: []) +// FunctionDeclaration (mods: [1,4]) +// Identifier (mods: []) +// ETSPrimitiveType (mods: []) +// Block (mods: []) +// VariableStatement (mods: []) +// VariableDeclarationList (mods: []) +// VariableDeclaration (mods: []) +// ExpressionStatement (mods: []) +// CallExpression (mods: []) +// PropertyAccessExpression (mods: []) +// Identifier (mods: []) +// Identifier (mods: []) +// ` +// let sourceFile = ts.factory.createSourceFile(source) +// const output = (new PrintVisitor()).astToString(sourceFile) +// +// util.assert.equal(util.alignText(output), util.alignText(expected)) +// }) +// }) diff --git a/ets1.2/libarkts/test/tsconfig.json b/ets1.2/libarkts/test/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..b66a126a9af084f18e03fae9afd97279dcdb50cc --- /dev/null +++ b/ets1.2/libarkts/test/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "@koalaui/build-common/tsconfig.json", + "compilerOptions": { + "rootDir": "../", + "baseUrl": "../", + "outDir": "build/test", + "module": "CommonJS" + }, + "include": [ + "../src/**/*.ts", + "../test/**/*.ts", + "../examples/**/*.ts" + ], + "exclude": [ + "./ts-api/**/*" + ] +} diff --git a/ets1.2/libarkts/tools/issue_gen.mjs b/ets1.2/libarkts/tools/issue_gen.mjs new file mode 100644 index 0000000000000000000000000000000000000000..f6e1bae225e72caa1425b042a35ae91328099180 --- /dev/null +++ b/ets1.2/libarkts/tools/issue_gen.mjs @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2023 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. + */ + +import * as fs from 'fs' +import * as path from 'path' + +process.chdir(path.resolve('./')) + +const issue_src = fs.readFileSync('../playground/src/playground.cc', { encoding: 'utf8', flag: 'r' }) + +const component_src = +` +### Component + +Plugin API + +` + +const revision_src = +` +### Revision + +"@panda/sdk": "1.5.0-dev.9184" + +` + +const reproduction_src = +` +### Reproduction + +\`\`\` +${issue_src} +\`\`\` + +` + +// Improve: +const log = `` + +const log_src = +` +### Log + +\`\`\` +${log} +\`\`\` +` + +console.log( + component_src + + revision_src + + reproduction_src + + log_src +) diff --git a/ets1.2/libarkts/tsconfig.host.json b/ets1.2/libarkts/tsconfig.host.json new file mode 100644 index 0000000000000000000000000000000000000000..73e04374e272aef15efa9265a13b154c18adbeca --- /dev/null +++ b/ets1.2/libarkts/tsconfig.host.json @@ -0,0 +1,12 @@ +{ + "extends": "@koalaui/build-common/tsconfig.json", + "compilerOptions": { + "outDir": "build", + "baseUrl": ".", + "rootDir": "./src-host", + "module": "esnext" + }, + "include": [ + "./src-host/**/*.ts" + ] +} diff --git a/ets1.2/libarkts/tsconfig.json b/ets1.2/libarkts/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..d3785c1ff7ccf64c635740e93891bff80c525f91 --- /dev/null +++ b/ets1.2/libarkts/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "@koalaui/build-common/tsconfig.json", + "compilerOptions": { + "outDir": "build", + "baseUrl": ".", + "rootDir": ".", + "module": "esnext", + "tsBuildInfoFile": "./build/tsconfig.tsbuildinfo" + }, + "include": [ + "./src/**/*.ts", + "./generated/**/*.ts" + ], + "exclude": [ + "./src/ts-api/**/*.ts" + ] +} diff --git a/ets1.2/libarkts/tsconfig.plugin.json b/ets1.2/libarkts/tsconfig.plugin.json new file mode 100644 index 0000000000000000000000000000000000000000..b984e32b04420e5823c5b0ce024c019aefedcb8d --- /dev/null +++ b/ets1.2/libarkts/tsconfig.plugin.json @@ -0,0 +1,12 @@ +{ + "extends": "@koalaui/build-common/tsconfig.json", + "compilerOptions": { + "outDir": "build/plugins", + "baseUrl": ".", + "rootDir": "./plugins", + "module": "esnext" + }, + "include": [ + "./plugins/src/**/*.ts" + ] +} diff --git a/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.cc b/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.cc index 0a26aa8d920df4db5ecabed9306d5159fd870d59..81e851fb1845aa4bbcde1e799727474053e9bfe6 100644 --- a/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.cc +++ b/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.cc @@ -1,14 +1,14 @@ -/* - * Copyright (c) 2022-2025 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. - */ \ No newline at end of file +/* + * Copyright (c) 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. + */ diff --git a/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.h b/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.h index 7295002dd8b09db1f130158bb2b5b95c23dbb0f8..511a2e24de25dc5b14ba67881ef06976dcbfa54b 100644 --- a/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.h +++ b/koala-wrapper/koalaui/interop/src/cpp/cangjie/convertors-cj.h @@ -18,18 +18,18 @@ #include #include -#include #include +#include -#include "koala-types.h" #include "interop-logging.h" +#include "koala-types.h" #define KOALA_INTEROP_EXPORT extern "C" -#define MAKE_CJ_EXPORT(name, type, flag) \ - __attribute__((constructor)) \ - static void __init_ets_##name() { \ - CJExports::getInstance()->addImpl("_"#name, type, reinterpret_cast(Ark_##name), flag); \ +#define MAKE_CJ_EXPORT(name, type, flag) \ + __attribute__((constructor)) static void __init_ets_##name() \ + { \ + CJExports::getInstance()->addImpl("_" #name, type, reinterpret_cast(Ark_##name), flag); \ } class CJExports { @@ -39,7 +39,8 @@ public: static CJExports* getInstance(); void addImpl(const char* name, const char* type, void* impl); - const std::vector>& getImpls() { + const std::vector>& getImpls() + { return implementations; } }; @@ -47,27 +48,37 @@ public: template struct InteropTypeConverter { using InteropType = T; - static inline T convertFrom(InteropType value) { return value; } - static inline InteropType convertTo(T value) { return value; } + static inline T convertFrom(InteropType value) + { + return value; + } + static inline InteropType convertTo(T value) + { + return value; + } }; -template -inline T getArgument(typename InteropTypeConverter::InteropType arg) { +template +inline T getArgument(typename InteropTypeConverter::InteropType arg) +{ return InteropTypeConverter::convertFrom(arg); } -template -inline typename InteropTypeConverter::InteropType makeResult(T value) { +template +inline typename InteropTypeConverter::InteropType makeResult(T value) +{ return InteropTypeConverter::convertTo(value); } template<> struct InteropTypeConverter { using InteropType = KDouble; - static inline KInteropNumber convertFrom(InteropType value) { + static inline KInteropNumber convertFrom(InteropType value) + { return KInteropNumber::fromDouble(value); } - static inline InteropType convertTo(KInteropNumber value) { + static inline InteropType convertTo(KInteropNumber value) + { return value.asDouble(); } }; @@ -75,804 +86,752 @@ struct InteropTypeConverter { template<> struct InteropTypeConverter { using InteropType = char*; - static KStringPtr convertFrom(InteropType value) { + static KStringPtr convertFrom(InteropType value) + { return KStringPtr(value); } - static InteropType convertTo(const KStringPtr& value) { + static InteropType convertTo(const KStringPtr& value) + { return value.data(); } }; // TODO: Rewrite all others to typed convertors. -#define KOALA_INTEROP_0(name, Ret) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name() { \ - KOALA_MAYBE_LOG(name) \ - return makeResult(impl_##name()); \ -} +#define KOALA_INTEROP_0(name, Ret) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name() \ + { \ + KOALA_MAYBE_LOG(name) \ + return makeResult(impl_##name()); \ + } // MAKE_CJ_EXPORT(name, #Ret, 0) -#define KOALA_INTEROP_1(name, Ret, P0) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - return makeResult(impl_##name(p0)); \ -} +#define KOALA_INTEROP_1(name, Ret, P0) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + return makeResult(impl_##name(p0)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0, 0) -#define KOALA_INTEROP_2(name, Ret, P0, P1) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - return makeResult(impl_##name(p0, p1)); \ -} +#define KOALA_INTEROP_2(name, Ret, P0, P1) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + return makeResult(impl_##name(p0, p1)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1, 0) -#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - return makeResult(impl_##name(p0, p1, p2)); \ -} +#define KOALA_INTEROP_3(name, Ret, P0, P1, P2) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + return makeResult(impl_##name(p0, p1, p2)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2, 0) -#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - return makeResult(impl_##name(p0, p1, p2, p3)); \ -} +#define KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + return makeResult(impl_##name(p0, p1, p2, p3)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3, 0) -#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4)); \ -} +#define KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4, 0) -#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5)); \ -} +#define KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5, 0) -#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ -} +#define KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6, 0) -#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6, \ - InteropTypeConverter::InteropType _p7 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ -} +#define KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7, 0) -#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6, \ - InteropTypeConverter::InteropType _p7, \ - InteropTypeConverter::InteropType _p8 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ -} +#define KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8, 0) -#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6, \ - InteropTypeConverter::InteropType _p7, \ - InteropTypeConverter::InteropType _p8, \ - InteropTypeConverter::InteropType _p9 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ -} +#define KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)); \ + } // MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9, 0) -#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6, \ - InteropTypeConverter::InteropType _p7, \ - InteropTypeConverter::InteropType _p8, \ - InteropTypeConverter::InteropType _p9, \ - InteropTypeConverter::InteropType _p10 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ -} -// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, 0) - -#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6, \ - InteropTypeConverter::InteropType _p7, \ - InteropTypeConverter::InteropType _p8, \ - InteropTypeConverter::InteropType _p9, \ - InteropTypeConverter::InteropType _p10, \ - InteropTypeConverter::InteropType _p11 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - P11 p11 = getArgument(_p11); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ -} -// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11, 0) - -#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6, \ - InteropTypeConverter::InteropType _p7, \ - InteropTypeConverter::InteropType _p8, \ - InteropTypeConverter::InteropType _p9, \ - InteropTypeConverter::InteropType _p10, \ - InteropTypeConverter::InteropType _p11, \ - InteropTypeConverter::InteropType _p12 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - P11 p11 = getArgument(_p11); \ - P12 p12 = getArgument(_p12); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ -} -// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12, 0) - -#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4, \ - InteropTypeConverter::InteropType _p5, \ - InteropTypeConverter::InteropType _p6, \ - InteropTypeConverter::InteropType _p7, \ - InteropTypeConverter::InteropType _p8, \ - InteropTypeConverter::InteropType _p9, \ - InteropTypeConverter::InteropType _p10, \ - InteropTypeConverter::InteropType _p11, \ - InteropTypeConverter::InteropType _p12, \ - InteropTypeConverter::InteropType _p13 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - P11 p11 = getArgument(_p11); \ - P12 p12 = getArgument(_p12); \ - P13 p13 = getArgument(_p13); \ - return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ -} -// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 "|" #P11 "|" #P12 "|" #P13, 0) - -#define KOALA_INTEROP_V0(name) \ -KOALA_INTEROP_EXPORT void name() { \ - KOALA_MAYBE_LOG(name) \ - impl_##name(); \ - return; \ -} - -#define KOALA_INTEROP_V1(name, P0) \ -KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - impl_##name(p0); \ - return; \ -} - -#define KOALA_INTEROP_V2(name, P0, P1) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - impl_##name(p0, p1); \ - return; \ -} - -#define KOALA_INTEROP_V3(name, P0, P1, P2) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - impl_##name(p0, p1, p2); \ - return; \ -} - -#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - impl_##name(p0, p1, p2, p3); \ - return; \ -} +#define KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); \ + } +// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10, +// 0) + +#define KOALA_INTEROP_12(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)); \ + } +// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 +// "|" #P11, 0) + +#define KOALA_INTEROP_13(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)); \ + } +// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 +// "|" #P11 "|" #P12, 0) + +#define KOALA_INTEROP_14(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4, \ + InteropTypeConverter::InteropType _p5, InteropTypeConverter::InteropType _p6, \ + InteropTypeConverter::InteropType _p7, InteropTypeConverter::InteropType _p8, \ + InteropTypeConverter::InteropType _p9, InteropTypeConverter::InteropType _p10, \ + InteropTypeConverter::InteropType _p11, InteropTypeConverter::InteropType _p12, \ + InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + P13 p13 = getArgument(_p13); \ + return makeResult(impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)); \ + } +// MAKE_CJ_EXPORT(name, #Ret "|" #P0 "|" #P1 "|" #P2 "|" #P3 "|" #P4 "|" #P5 "|" #P6 "|" #P7 "|" #P8 "|" #P9 "|" #P10 +// "|" #P11 "|" #P12 "|" #P13, 0) + +#define KOALA_INTEROP_V0(name) \ + KOALA_INTEROP_EXPORT void name() \ + { \ + KOALA_MAYBE_LOG(name) \ + impl_##name(); \ + return; \ + } -#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - impl_##name(p0, p1, p2, p3, p4); \ - return; \ -} +#define KOALA_INTEROP_V1(name, P0) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + impl_##name(p0); \ + return; \ + } -#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - impl_##name(p0, p1, p2, p3, p4, p5); \ - return; \ -} +#define KOALA_INTEROP_V2(name, P0, P1) \ + KOALA_INTEROP_EXPORT void name( \ + typename InteropTypeConverter::InteropType _p0, typename InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + impl_##name(p0, p1); \ + return; \ + } -#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6); \ - return; \ -} +#define KOALA_INTEROP_V3(name, P0, P1, P2) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + impl_##name(p0, p1, p2); \ + return; \ + } -#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6, \ - typename InteropTypeConverter::InteropType _p7 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ - return; \ -} +#define KOALA_INTEROP_V4(name, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + impl_##name(p0, p1, p2, p3); \ + return; \ + } -#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6, \ - typename InteropTypeConverter::InteropType _p7, \ - typename InteropTypeConverter::InteropType _p8 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ - return; \ -} +#define KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + impl_##name(p0, p1, p2, p3, p4); \ + return; \ + } -#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6, \ - typename InteropTypeConverter::InteropType _p7, \ - typename InteropTypeConverter::InteropType _p8, \ - typename InteropTypeConverter::InteropType _p9 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ - return; \ -} +#define KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + impl_##name(p0, p1, p2, p3, p4, p5); \ + return; \ + } -#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6, \ - typename InteropTypeConverter::InteropType _p7, \ - typename InteropTypeConverter::InteropType _p8, \ - typename InteropTypeConverter::InteropType _p9, \ - typename InteropTypeConverter::InteropType _p10 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ - return; \ -} +#define KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6); \ + return; \ + } -#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6, \ - typename InteropTypeConverter::InteropType _p7, \ - typename InteropTypeConverter::InteropType _p8, \ - typename InteropTypeConverter::InteropType _p9, \ - typename InteropTypeConverter::InteropType _p10, \ - typename InteropTypeConverter::InteropType _p11 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - P11 p11 = getArgument(_p11); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ - return; \ -} +#define KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7); \ + return; \ + } -#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6, \ - typename InteropTypeConverter::InteropType _p7, \ - typename InteropTypeConverter::InteropType _p8, \ - typename InteropTypeConverter::InteropType _p9, \ - typename InteropTypeConverter::InteropType _p10, \ - typename InteropTypeConverter::InteropType _p11, \ - typename InteropTypeConverter::InteropType _p12 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - P11 p11 = getArgument(_p11); \ - P12 p12 = getArgument(_p12); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ - return; \ -} +#define KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8); \ + return; \ + } -#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ -KOALA_INTEROP_EXPORT void name( \ - typename InteropTypeConverter::InteropType _p0, \ - typename InteropTypeConverter::InteropType _p1, \ - typename InteropTypeConverter::InteropType _p2, \ - typename InteropTypeConverter::InteropType _p3, \ - typename InteropTypeConverter::InteropType _p4, \ - typename InteropTypeConverter::InteropType _p5, \ - typename InteropTypeConverter::InteropType _p6, \ - typename InteropTypeConverter::InteropType _p7, \ - typename InteropTypeConverter::InteropType _p8, \ - typename InteropTypeConverter::InteropType _p9, \ - typename InteropTypeConverter::InteropType _p10, \ - typename InteropTypeConverter::InteropType _p11, \ - typename InteropTypeConverter::InteropType _p12, \ - typename InteropTypeConverter::InteropType _p13 \ -) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - P5 p5 = getArgument(_p5); \ - P6 p6 = getArgument(_p6); \ - P7 p7 = getArgument(_p7); \ - P8 p8 = getArgument(_p8); \ - P9 p9 = getArgument(_p9); \ - P10 p10 = getArgument(_p10); \ - P11 p11 = getArgument(_p11); \ - P12 p12 = getArgument(_p12); \ - P13 p13 = getArgument(_p13); \ - impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ - return; \ -} +#define KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); \ + return; \ + } -#define KOALA_INTEROP_CTX_0(name, Ret) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name() { \ - KOALA_MAYBE_LOG(name) \ - KVMContext ctx = (KVMContext)0; \ - return makeResult(impl_##name(ctx)); \ -} +#define KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + return; \ + } -#define KOALA_INTEROP_CTX_1(name, Ret, P0) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - KVMContext ctx = (KVMContext)0; \ - return makeResult(impl_##name(ctx, p0)); \ -} +#define KOALA_INTEROP_V12(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10, \ + typename InteropTypeConverter::InteropType _p11) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ + return; \ + } -#define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - KVMContext ctx = (KVMContext)0; \ - return makeResult(impl_##name(ctx, p0, p1)); \ -} +#define KOALA_INTEROP_V13(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10, \ + typename InteropTypeConverter::InteropType _p11, typename InteropTypeConverter::InteropType _p12) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + return; \ + } +#define KOALA_INTEROP_V14(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ + KOALA_INTEROP_EXPORT void name(typename InteropTypeConverter::InteropType _p0, \ + typename InteropTypeConverter::InteropType _p1, typename InteropTypeConverter::InteropType _p2, \ + typename InteropTypeConverter::InteropType _p3, typename InteropTypeConverter::InteropType _p4, \ + typename InteropTypeConverter::InteropType _p5, typename InteropTypeConverter::InteropType _p6, \ + typename InteropTypeConverter::InteropType _p7, typename InteropTypeConverter::InteropType _p8, \ + typename InteropTypeConverter::InteropType _p9, typename InteropTypeConverter::InteropType _p10, \ + typename InteropTypeConverter::InteropType _p11, typename InteropTypeConverter::InteropType _p12, \ + typename InteropTypeConverter::InteropType _p13) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + P5 p5 = getArgument(_p5); \ + P6 p6 = getArgument(_p6); \ + P7 p7 = getArgument(_p7); \ + P8 p8 = getArgument(_p8); \ + P9 p9 = getArgument(_p9); \ + P10 p10 = getArgument(_p10); \ + P11 p11 = getArgument(_p11); \ + P12 p12 = getArgument(_p12); \ + P13 p13 = getArgument(_p13); \ + impl_##name(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ + return; \ + } -#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - KVMContext ctx = (KVMContext)0; \ - return makeResult(impl_##name(ctx, p0, p1, p2)); \ -} +#define KOALA_INTEROP_CTX_0(name, Ret) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name() \ + { \ + KOALA_MAYBE_LOG(name) \ + KVMContext ctx = (KVMContext)0; \ + return makeResult(impl_##name(ctx)); \ + } -#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \ -KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ - InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - KVMContext ctx = (KVMContext)0; \ - return makeResult(impl_##name(ctx, p0, p1, p2, p3)); \ -} +#define KOALA_INTEROP_CTX_1(name, Ret, P0) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + KVMContext ctx = (KVMContext)0; \ + return makeResult(impl_##name(ctx, p0)); \ + } +#define KOALA_INTEROP_CTX_2(name, Ret, P0, P1) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name( \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + KVMContext ctx = (KVMContext)0; \ + return makeResult(impl_##name(ctx, p0, p1)); \ + } -#define KOALA_INTEROP_CALL_INT(venv, id, length, args) \ -{ \ - int32_t rv = 0; \ - return rv; \ -} -#define KOALA_INTEROP_CALL_VOID(venv, id, length, args) \ -{ \ -} +#define KOALA_INTEROP_CTX_3(name, Ret, P0, P1, P2) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + KVMContext ctx = (KVMContext)0; \ + return makeResult(impl_##name(ctx, p0, p1, p2)); \ + } +#define KOALA_INTEROP_CTX_4(name, Ret, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + KVMContext ctx = (KVMContext)0; \ + return makeResult(impl_##name(ctx, p0, p1, p2, p3)); \ + } -#define KOALA_INTEROP_CALL_VOID_INTS32(venv, id, argc, args) KOALA_INTEROP_CALL_VOID(venv, id, (argc) * sizeof(int32_t), args) -#define KOALA_INTEROP_CALL_INT_INTS32(venv, id, argc, args) KOALA_INTEROP_CALL_INT(venv, id, (argc) * sizeof(int32_t), args) +#define KOALA_INTEROP_CTX_5(name, Ret, P0, P1, P2, P3, P4) \ + KOALA_INTEROP_EXPORT InteropTypeConverter::InteropType name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + KVMContext ctx = (KVMContext)0; \ + return makeResult(impl_##name(ctx, p0, p1, p2, p3, p4)); \ + } +#define KOALA_INTEROP_CALL_INT(venv, id, length, args) \ + { \ + int32_t rv = 0; \ + return rv; \ + } +#define KOALA_INTEROP_CALL_VOID(venv, id, length, args) \ + {} + +#define KOALA_INTEROP_CALL_VOID_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_VOID(venv, id, (argc) * sizeof(int32_t), args) +#define KOALA_INTEROP_CALL_INT_INTS32(venv, id, argc, args) \ + KOALA_INTEROP_CALL_INT(venv, id, (argc) * sizeof(int32_t), args) + +#define KOALA_INTEROP_CTX_V1(name, P0) \ + KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + impl_##name(nullptr, p0); \ + } -#define KOALA_INTEROP_CTX_V1(name, P0) \ -KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0) {\ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - impl_##name(nullptr, p0); \ -} +#define KOALA_INTEROP_CTX_V2(name, P0, P1) \ + KOALA_INTEROP_EXPORT void name( \ + InteropTypeConverter::InteropType _p0, InteropTypeConverter::InteropType _p1) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + impl_##name(nullptr, p0, p1); \ + } -#define KOALA_INTEROP_CTX_V2(name, P0, P1) \ -KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - impl_##name(nullptr, p0, p1); \ -} +#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ + KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + impl_##name(nullptr, p0, p1, p2); \ + } -#define KOALA_INTEROP_CTX_V3(name, P0, P1, P2) \ -KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - impl_##name(nullptr, p0, p1, p2); \ -} +#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ + KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + impl_##name(nullptr, p0, p1, p2, p3); \ + } -#define KOALA_INTEROP_CTX_V4(name, P0, P1, P2, P3) \ -KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - impl_##name(nullptr, p0, p1, p2, p3); \ -} +#define KOALA_INTEROP_CTX_V5(name, P0, P1, P2, P3, P4) \ + KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ + InteropTypeConverter::InteropType _p1, InteropTypeConverter::InteropType _p2, \ + InteropTypeConverter::InteropType _p3, InteropTypeConverter::InteropType _p4) \ + { \ + KOALA_MAYBE_LOG(name) \ + P0 p0 = getArgument(_p0); \ + P1 p1 = getArgument(_p1); \ + P2 p2 = getArgument(_p2); \ + P3 p3 = getArgument(_p3); \ + P4 p4 = getArgument(_p4); \ + impl_##name(nullptr, p0, p1, p2, p3, p4); \ + } -#define KOALA_INTEROP_CTX_V5(name, P0, P1, P2, P3, P4) \ -KOALA_INTEROP_EXPORT void name(InteropTypeConverter::InteropType _p0, \ - InteropTypeConverter::InteropType _p1, \ - InteropTypeConverter::InteropType _p2, \ - InteropTypeConverter::InteropType _p3, \ - InteropTypeConverter::InteropType _p4) { \ - KOALA_MAYBE_LOG(name) \ - P0 p0 = getArgument(_p0); \ - P1 p1 = getArgument(_p1); \ - P2 p2 = getArgument(_p2); \ - P3 p3 = getArgument(_p3); \ - P4 p4 = getArgument(_p4); \ - impl_##name(nullptr, p0, p1, p2, p3, p4); \ -} +#define KOALA_INTEROP_DIRECT_0(name, Ret) KOALA_INTEROP_0(name, Ret) +#define KOALA_INTEROP_DIRECT_1(name, Ret, P0) KOALA_INTEROP_1(name, Ret, P0) +#define KOALA_INTEROP_DIRECT_2(name, Ret, P0, P1) KOALA_INTEROP_2(name, Ret, P0, P1) +#define KOALA_INTEROP_DIRECT_3(name, Ret, P0, P1, P2) KOALA_INTEROP_3(name, Ret, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_4(name, Ret, P0, P1, P2, P3) KOALA_INTEROP_4(name, Ret, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_5(name, Ret, P0, P1, P2, P3, P4) KOALA_INTEROP_5(name, Ret, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_6(name, Ret, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_6(name, Ret, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) \ + KOALA_INTEROP_7(name, Ret, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_8(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_9(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_10(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_11(name, Ret, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) +#define KOALA_INTEROP_DIRECT_V0(name) KOALA_INTEROP_V0(name) +#define KOALA_INTEROP_DIRECT_V1(name, P0) KOALA_INTEROP_V1(name, P0) +#define KOALA_INTEROP_DIRECT_V2(name, P0, P1) KOALA_INTEROP_V2(name, P0, P1) +#define KOALA_INTEROP_DIRECT_V3(name, P0, P1, P2) KOALA_INTEROP_V3(name, P0, P1, P2) +#define KOALA_INTEROP_DIRECT_V4(name, P0, P1, P2, P3) KOALA_INTEROP_V4(name, P0, P1, P2, P3) +#define KOALA_INTEROP_DIRECT_V5(name, P0, P1, P2, P3, P4) KOALA_INTEROP_V5(name, P0, P1, P2, P3, P4) +#define KOALA_INTEROP_DIRECT_V6(name, P0, P1, P2, P3, P4, P5) KOALA_INTEROP_V6(name, P0, P1, P2, P3, P4, P5) +#define KOALA_INTEROP_DIRECT_V7(name, P0, P1, P2, P3, P4, P5, P6) KOALA_INTEROP_V7(name, P0, P1, P2, P3, P4, P5, P6) +#define KOALA_INTEROP_DIRECT_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) \ + KOALA_INTEROP_V8(name, P0, P1, P2, P3, P4, P5, P6, P7) +#define KOALA_INTEROP_DIRECT_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) \ + KOALA_INTEROP_V9(name, P0, P1, P2, P3, P4, P5, P6, P7, P8) +#define KOALA_INTEROP_DIRECT_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + KOALA_INTEROP_V10(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9) +#define KOALA_INTEROP_DIRECT_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + KOALA_INTEROP_V11(name, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) #define KOALA_INTEROP_THROW(vmContext, object, ...) \ - do { \ - ASSERT(false); \ - return __VA_ARGS__; \ - } while (0) + do { \ + /* Improve: implement*/ ASSERT(false); \ + return __VA_ARGS__; \ + } while (0) #define KOALA_INTEROP_THROW_STRING(vmContext, message, ...) \ - do { \ - ASSERT(false); \ - return __VA_ARGS__; \ - } while (0) + do { \ + /* Improve: implement*/ ASSERT(false); \ + return __VA_ARGS__; \ + } while (0) -#endif // CONVERTORS_CJ_H \ No newline at end of file +#endif // CONVERTORS_CJ_H