idlize
286 строк · 12.9 Кб
1/*
2* Copyright (c) 2024 Huawei Device Co., Ltd.
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16import { IndentedPrinter } from "../../IndentedPrinter";
17import { Language, capitalize, dropSuffix, isDefined } from "../../util";
18import { ArgConvertor, ArrayConvertor } from "../Convertors";
19import { PrimitiveType } from "../DeclarationTable";
20import { bridgeCcCustomDeclaration, bridgeCcGeneratedDeclaration } from "../FileGenerators";
21import { createLanguageWriter, Method, NamedMethodSignature, Type } from "../LanguageWriters";
22import { PeerLibrary } from "../PeerLibrary";
23import { PeerMethod } from "../PeerMethod";
24import { CUSTOM_API, CustomAPI } from "../CustomAPI"
25
26//const VM_CONTEXT_TYPE = new Type(`${PeerGeneratorConfig.cppPrefix}Ark_VMContext`)
27
28class BridgeCcVisitor {
29readonly generatedApi = createLanguageWriter(Language.CPP)
30readonly customApi = createLanguageWriter(Language.CPP)
31
32constructor(
33private readonly library: PeerLibrary,
34private readonly callLog: boolean,
35) {}
36
37private generateApiCall(method: PeerMethod, modifierName?: string): string {
38// TODO: may be need some translation tables?
39let clazz = modifierName ?? dropSuffix(dropSuffix(dropSuffix(method.originalParentName, "Method"), "Attribute"), "Interface")
40return `get${capitalize(clazz)}${method.apiKind}()`
41}
42
43// TODO: may be this is another method of ArgConvertor?
44private generateApiArgument(argConvertor: ArgConvertor): string {
45const prefix = argConvertor.isPointerType() ? `(const ${argConvertor.nativeType(false)}*)&`: " "
46if (argConvertor.useArray)
47return `${prefix}${argConvertor.param}_value`
48else
49return `${argConvertor.convertorArg(argConvertor.param, this.generatedApi)}`
50}
51
52private printAPICall(method: PeerMethod, modifierName?: string) {
53const hasReceiver = method.hasReceiver()
54const argConvertors = method.argConvertors
55const isVoid = method.retConvertor.isVoid
56const modifier = this.generateApiCall(method, modifierName)
57const peerMethod = method.peerMethodName
58const receiver = hasReceiver ? ['self'] : []
59// TODO: how do we know the real amount of arguments of the API functions?
60// Do they always match in TS and in C one to one?
61const args = receiver.concat(argConvertors.map(it => this.generateApiArgument(it))).join(", ")
62const call = `${isVoid ? "" : "return "}${method.apiCall}->${modifier}->${peerMethod}(${args});`
63if (this.callLog) this.printCallLog(method, method.apiCall, modifier)
64this.generatedApi.print(call)
65}
66
67private printNativeBody(method: PeerMethod, modifierName?: string) {
68this.generatedApi.pushIndent()
69if (method.hasReceiver()) {
70this.generatedApi.print(`${method.receiverType} self = reinterpret_cast<${method.receiverType}>(thisPtr);`)
71}
72let deserializerCreated = false
73method.argConvertors.forEach(it => {
74if (it.useArray) {
75if (!deserializerCreated) {
76this.generatedApi.print(`Deserializer thisDeserializer(thisArray, thisLength);`)
77deserializerCreated = true
78}
79let result = `${it.param}_value`
80this.generatedApi.print(`${it.nativeType(false)} ${result};`)
81this.generatedApi.writeStatement(it.convertorDeserialize(`this`, result, this.generatedApi))
82}
83})
84this.printAPICall(method, modifierName)
85this.generatedApi.popIndent()
86}
87
88private static varCnt : number = 0;
89
90private printCallLog(method: PeerMethod, api: string, modifier: string) {
91this.generatedApi.print(`if (needGroupedLog(2)) {`)
92this.generatedApi.pushIndent()
93this.generatedApi.print('std::string _logData;')
94this.generatedApi.print('std::string _tmp;')
95this.generatedApi.print('static int _num = 0;')
96this.generatedApi.print(`static int _array_num = 0;`);
97let varNames : string[] = new Array<string>()
98for (let i = 0; i < method.argConvertors.length; ++i) {
99let it = method.argConvertors[i]
100let name = this.generateApiArgument(it) // it.param + '_value'
101if (it instanceof ArrayConvertor) {
102this.generatedApi.print(`_tmp = "", generateStdArrayDefinition(&_tmp, ${name});`);
103this.generatedApi.print(`_logData.append(" auto array" + std::to_string(_array_num) + " = " + _tmp + ";");`);
104this.generatedApi.print(`_logData.append("\\n");`);
105this.generatedApi.print(`_tmp = "", WriteToString(&_tmp, ${name}, "array" + std::to_string(_array_num));`)
106this.generatedApi.print("_array_num += 1;")
107} else {
108this.generatedApi.print(`_tmp = "", WriteToString(&_tmp, ${name});`)
109}
110varNames.push(`var${BridgeCcVisitor.varCnt}`)
111let ptrType = `const ${it.nativeType(false)}`
112this.generatedApi.print(`_logData.append(" ${ptrType} ${varNames[i]}_" + std::to_string(_num) + " = " + _tmp + ";\\n");`)
113BridgeCcVisitor.varCnt += 1
114}
115
116this.generatedApi.print(`_logData.append(" ${api}->${modifier}->${method.peerMethodName}(");`)
117if (method.hasReceiver()) {
118this.generatedApi.print(`_logData.append("(Ark_NativePointer)");`)
119this.generatedApi.print(`_logData.append("peer" + std::to_string((uintptr_t)thisPtr));`);
120if (method.argConvertors.length > 0)
121this.generatedApi.print(`_logData.append(", ");`)
122}
123method.argConvertors.forEach((it, index) => {
124if (it.nativeType(false) != "Ark_Number"
125&& (it.tsTypeName == "number" || it.tsTypeName == "boolean")) {
126this.generatedApi.print(`_logData.append("${varNames[index]}_" + std::to_string(_num));`)
127} else {
128this.generatedApi.print(`_logData.append("&${varNames[index]}_" + std::to_string(_num));`)
129}
130if (index < method.argConvertors.length - 1)
131this.generatedApi.print(`_logData.append(", ");`)
132})
133this.generatedApi.print("_num += 1;")
134this.generatedApi.print(`_logData.append(");\\n");`)
135this.generatedApi.print(`appendGroupedLog(2, _logData);`)
136this.generatedApi.popIndent()
137this.generatedApi.print(`}`)
138}
139
140private generateCParameterTypes(argConvertors: ArgConvertor[], hasReceiver: boolean): string[] {
141const receiver = hasReceiver ? [PrimitiveType.NativePointer.getText()] : []
142let ptrCreated = false;
143for (let i = 0; i < argConvertors.length; ++i) {
144let it = argConvertors[i]
145if (it.useArray) {
146if (!ptrCreated) {
147receiver.push(`uint8_t*, int32_t`)
148ptrCreated = true
149}
150} else {
151receiver.push(it.interopType(this.generatedApi.language))
152}
153}
154return receiver
155}
156
157private generateCMacroSuffix(method: PeerMethod): string {
158let counter = method.hasReceiver() ? 1 : 0
159let arrayAdded = false
160method.argConvertors.forEach(it => {
161if (it.useArray) {
162if (!arrayAdded) {
163counter += 2
164arrayAdded = true
165}
166} else {
167counter += 1
168}
169})
170return `${method.retConvertor.macroSuffixPart()}${counter}`
171}
172
173private generateCParameters(method: PeerMethod, argConvertors: ArgConvertor[]): string[] {
174let maybeReceiver = method.hasReceiver() ? [`${PrimitiveType.NativePointer.getText()} thisPtr`] : []
175let ptrCreated = false;
176for (let i = 0; i < argConvertors.length; ++i) {
177let it = argConvertors[i]
178if (it.useArray) {
179if (!ptrCreated) {
180maybeReceiver.push(`uint8_t* thisArray, int32_t thisLength`)
181ptrCreated = true
182}
183} else {
184let type = it.interopType(this.generatedApi.language)
185switch (type) {
186case "KStringPtr":
187type = `const KStringPtr&`
188break
189case "KLength":
190type = `const KLength&`
191break
192}
193maybeReceiver.push(`${type} ${it.param}`)
194}
195}
196return maybeReceiver
197}
198
199private printMethod(method: PeerMethod, modifierName?: string) {
200const retConvertor = method.retConvertor
201const argConvertors = method.argConvertors
202
203let cName = `${method.originalParentName}_${method.overloadedName}`
204let rv = retConvertor.nativeType()
205this.generatedApi.print(`${retConvertor.nativeType()} impl_${cName}(${this.generateCParameters(method, argConvertors).join(", ")}) {`)
206this.generatedApi.pushIndent()
207this.printNativeBody(method, modifierName)
208this.generatedApi.popIndent()
209this.generatedApi.print(`}`)
210let macroArgs = [cName, method.maybeCRetType(retConvertor)].concat(this.generateCParameterTypes(argConvertors, method.hasReceiver()))
211.filter(isDefined)
212.join(", ")
213const suffix = this.generateCMacroSuffix(method)
214this.generatedApi.print(`KOALA_INTEROP_${suffix}(${macroArgs})`)
215this.generatedApi.print(` `)
216}
217
218printCustomApiMethod(c: CustomAPI, m: Method) {
219const sig = m.signature as NamedMethodSignature
220const capitalizedName = capitalize(m.name)
221const retType = c.getArgType(sig.returnType)
222const argsType =sig.args.map(it => c.getArgType(it))
223const method = new Method(`impl_${capitalizedName}`, new NamedMethodSignature(
224retType, argsType, sig.argsNames))
225
226this.customApi.writeMethodImplementation(method, writer => {
227let castNames: string[] = []
228sig.args.forEach((it, index) => {
229const type = c.getCastType(it)
230const name = sig.argsNames[index];
231let castName = name
232if (c.getArgType(it).name !== type.name) {
233castName = `${name}Cast`
234const cast = it.name.endsWith("Enum") ? `${type.name}(${name})` : `(${type.name}) ${name}`
235this.customApi.print(`${type.name} ${castName} = ${cast};`)
236}
237castNames = castNames.concat(castName)
238})
239const ret = sig.returnType === Type.Void ? "" : "return "
240this.customApi.print(`${ret}GetArkUI${c.apiName}()->${m.name}(${castNames.join(", ")});`)
241})
242const v = sig.returnType === Type.Void ? "V" : "";
243let args = c.withContext ? argsType.slice(1) : argsType
244const size = args.length
245args = sig.returnType === Type.Void ? args : [retType, ...args]
246const comma = args.length > 0 ? ", " : ""
247const CTX = c.withContext ? "_CTX" : ""
248this.customApi.print(`KOALA_INTEROP${CTX}_${v}${size}(${capitalizedName}${comma}${args.map(it => it.name).join(", ")})\n`)
249}
250
251print(): void {
252for (const file of this.library.files) {
253for (const peer of file.peersToGenerate.values()) {
254for (const method of peer.methods) {
255this.printMethod(method, peer.componentName)
256}
257}
258}
259
260this.generatedApi.print("\n// Accessors\n")
261for (const clazz of this.library.materializedClasses.values()) {
262for (const method of [clazz.ctor, clazz.finalizer].concat(clazz.methods)) {
263this.printMethod(method)
264}
265}
266
267this.customApi.print("\n// custom API methods\n")
268for(const customApi of CUSTOM_API) {
269for(const method of customApi.methods) {
270this.printCustomApiMethod(customApi, method)
271}
272}
273}
274}
275
276export function printBridgeCcGenerated(peerLibrary: PeerLibrary, callLog: boolean): string {
277const visitor = new BridgeCcVisitor(peerLibrary, callLog)
278visitor.print()
279return bridgeCcGeneratedDeclaration(visitor.generatedApi.getOutput())
280}
281
282export function printBridgeCcCustom(peerLibrary: PeerLibrary, callLog: boolean): string {
283const visitor = new BridgeCcVisitor(peerLibrary, callLog)
284visitor.print()
285return bridgeCcCustomDeclaration(visitor.customApi.getOutput())
286}