idlize

Форк
0
/
BridgeCcPrinter.ts 
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

16
import { IndentedPrinter } from "../../IndentedPrinter";
17
import { Language, capitalize, dropSuffix, isDefined } from "../../util";
18
import { ArgConvertor, ArrayConvertor } from "../Convertors";
19
import { PrimitiveType } from "../DeclarationTable";
20
import { bridgeCcCustomDeclaration, bridgeCcGeneratedDeclaration } from "../FileGenerators";
21
import { createLanguageWriter, Method, NamedMethodSignature, Type } from "../LanguageWriters";
22
import { PeerLibrary } from "../PeerLibrary";
23
import { PeerMethod } from "../PeerMethod";
24
import { CUSTOM_API, CustomAPI } from "../CustomAPI"
25

26
//const VM_CONTEXT_TYPE = new Type(`${PeerGeneratorConfig.cppPrefix}Ark_VMContext`)
27

28
class BridgeCcVisitor {
29
    readonly generatedApi = createLanguageWriter(Language.CPP)
30
    readonly customApi = createLanguageWriter(Language.CPP)
31

32
    constructor(
33
        private readonly library: PeerLibrary,
34
        private readonly callLog: boolean,
35
    ) {}
36

37
    private generateApiCall(method: PeerMethod, modifierName?: string): string {
38
        // TODO: may be need some translation tables?
39
        let clazz = modifierName ?? dropSuffix(dropSuffix(dropSuffix(method.originalParentName, "Method"), "Attribute"), "Interface")
40
        return `get${capitalize(clazz)}${method.apiKind}()`
41
    }
42

43
    // TODO: may be this is another method of ArgConvertor?
44
    private generateApiArgument(argConvertor: ArgConvertor): string {
45
        const prefix = argConvertor.isPointerType() ? `(const ${argConvertor.nativeType(false)}*)&`: "    "
46
        if (argConvertor.useArray)
47
            return `${prefix}${argConvertor.param}_value`
48
        else
49
            return `${argConvertor.convertorArg(argConvertor.param, this.generatedApi)}`
50
    }
51

52
    private printAPICall(method: PeerMethod, modifierName?: string) {
53
        const hasReceiver = method.hasReceiver()
54
        const argConvertors = method.argConvertors
55
        const isVoid = method.retConvertor.isVoid
56
        const modifier = this.generateApiCall(method, modifierName)
57
        const peerMethod = method.peerMethodName
58
        const 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?
61
        const args = receiver.concat(argConvertors.map(it => this.generateApiArgument(it))).join(", ")
62
        const call = `${isVoid ? "" : "return "}${method.apiCall}->${modifier}->${peerMethod}(${args});`
63
        if (this.callLog) this.printCallLog(method, method.apiCall, modifier)
64
        this.generatedApi.print(call)
65
    }
66

67
    private printNativeBody(method: PeerMethod, modifierName?: string) {
68
        this.generatedApi.pushIndent()
69
        if (method.hasReceiver()) {
70
            this.generatedApi.print(`${method.receiverType} self = reinterpret_cast<${method.receiverType}>(thisPtr);`)
71
        }
72
        let deserializerCreated = false
73
        method.argConvertors.forEach(it => {
74
            if (it.useArray) {
75
                if (!deserializerCreated) {
76
                    this.generatedApi.print(`Deserializer thisDeserializer(thisArray, thisLength);`)
77
                    deserializerCreated = true
78
                }
79
                let result = `${it.param}_value`
80
                this.generatedApi.print(`${it.nativeType(false)} ${result};`)
81
                this.generatedApi.writeStatement(it.convertorDeserialize(`this`, result, this.generatedApi))
82
            }
83
        })
84
        this.printAPICall(method, modifierName)
85
        this.generatedApi.popIndent()
86
    }
87

88
    private static varCnt : number = 0;
89

90
    private printCallLog(method: PeerMethod, api: string, modifier: string) {
91
        this.generatedApi.print(`if (needGroupedLog(2)) {`)
92
        this.generatedApi.pushIndent()
93
        this.generatedApi.print('std::string _logData;')
94
        this.generatedApi.print('std::string _tmp;')
95
        this.generatedApi.print('static int _num = 0;')
96
        this.generatedApi.print(`static int _array_num = 0;`);
97
        let varNames : string[] = new Array<string>()
98
        for (let i = 0; i < method.argConvertors.length; ++i) {
99
            let it = method.argConvertors[i]
100
            let name = this.generateApiArgument(it) // it.param + '_value'
101
            if (it instanceof ArrayConvertor) {
102
                this.generatedApi.print(`_tmp = "", generateStdArrayDefinition(&_tmp, ${name});`);
103
                this.generatedApi.print(`_logData.append("  auto array" + std::to_string(_array_num) + " = " + _tmp + ";");`);
104
                this.generatedApi.print(`_logData.append("\\n");`);
105
                this.generatedApi.print(`_tmp = "", WriteToString(&_tmp, ${name}, "array" + std::to_string(_array_num));`)
106
                this.generatedApi.print("_array_num += 1;")
107
            } else {
108
                this.generatedApi.print(`_tmp = "", WriteToString(&_tmp, ${name});`)
109
            }
110
            varNames.push(`var${BridgeCcVisitor.varCnt}`)
111
            let ptrType = `const ${it.nativeType(false)}`
112
            this.generatedApi.print(`_logData.append("  ${ptrType} ${varNames[i]}_" + std::to_string(_num) + " = " + _tmp + ";\\n");`)
113
            BridgeCcVisitor.varCnt += 1
114
        }
115

116
        this.generatedApi.print(`_logData.append("  ${api}->${modifier}->${method.peerMethodName}(");`)
117
        if (method.hasReceiver()) {
118
            this.generatedApi.print(`_logData.append("(Ark_NativePointer)");`)
119
            this.generatedApi.print(`_logData.append("peer" + std::to_string((uintptr_t)thisPtr));`);
120
            if (method.argConvertors.length > 0)
121
                this.generatedApi.print(`_logData.append(", ");`)
122
        }
123
        method.argConvertors.forEach((it, index) => {
124
            if (it.nativeType(false) != "Ark_Number"
125
                && (it.tsTypeName == "number" || it.tsTypeName == "boolean")) {
126
                this.generatedApi.print(`_logData.append("${varNames[index]}_" + std::to_string(_num));`)
127
            } else {
128
                this.generatedApi.print(`_logData.append("&${varNames[index]}_" + std::to_string(_num));`)
129
            }
130
            if (index < method.argConvertors.length - 1)
131
                this.generatedApi.print(`_logData.append(", ");`)
132
        })
133
        this.generatedApi.print("_num += 1;")
134
        this.generatedApi.print(`_logData.append(");\\n");`)
135
        this.generatedApi.print(`appendGroupedLog(2, _logData);`)
136
        this.generatedApi.popIndent()
137
        this.generatedApi.print(`}`)
138
    }
139

140
    private generateCParameterTypes(argConvertors: ArgConvertor[], hasReceiver: boolean): string[] {
141
        const receiver = hasReceiver ? [PrimitiveType.NativePointer.getText()] : []
142
        let ptrCreated = false;
143
        for (let i = 0; i < argConvertors.length; ++i) {
144
            let it = argConvertors[i]
145
            if (it.useArray) {
146
                if (!ptrCreated) {
147
                    receiver.push(`uint8_t*, int32_t`)
148
                    ptrCreated = true
149
                }
150
            } else {
151
                receiver.push(it.interopType(this.generatedApi.language))
152
            }
153
        }
154
        return receiver
155
    }
156

157
    private generateCMacroSuffix(method: PeerMethod): string {
158
        let counter = method.hasReceiver() ? 1 : 0
159
        let arrayAdded = false
160
        method.argConvertors.forEach(it => {
161
            if (it.useArray) {
162
                if (!arrayAdded) {
163
                    counter += 2
164
                    arrayAdded = true
165
                }
166
            } else {
167
                counter += 1
168
            }
169
        })
170
        return `${method.retConvertor.macroSuffixPart()}${counter}`
171
    }
172

173
    private generateCParameters(method: PeerMethod, argConvertors: ArgConvertor[]): string[] {
174
        let maybeReceiver = method.hasReceiver() ? [`${PrimitiveType.NativePointer.getText()} thisPtr`] : []
175
        let ptrCreated = false;
176
        for (let i = 0; i < argConvertors.length; ++i) {
177
            let it = argConvertors[i]
178
            if (it.useArray) {
179
                if (!ptrCreated) {
180
                    maybeReceiver.push(`uint8_t* thisArray, int32_t thisLength`)
181
                    ptrCreated = true
182
                }
183
            } else {
184
                let type = it.interopType(this.generatedApi.language)
185
                switch (type) {
186
                    case "KStringPtr":
187
                        type = `const KStringPtr&`
188
                        break
189
                    case "KLength":
190
                        type = `const KLength&`
191
                        break
192
                }
193
                maybeReceiver.push(`${type} ${it.param}`)
194
            }
195
        }
196
        return maybeReceiver
197
    }
198

199
    private printMethod(method: PeerMethod, modifierName?: string) {
200
        const retConvertor = method.retConvertor
201
        const argConvertors = method.argConvertors
202

203
        let cName = `${method.originalParentName}_${method.overloadedName}`
204
        let rv = retConvertor.nativeType()
205
        this.generatedApi.print(`${retConvertor.nativeType()} impl_${cName}(${this.generateCParameters(method, argConvertors).join(", ")}) {`)
206
        this.generatedApi.pushIndent()
207
        this.printNativeBody(method, modifierName)
208
        this.generatedApi.popIndent()
209
        this.generatedApi.print(`}`)
210
        let macroArgs = [cName, method.maybeCRetType(retConvertor)].concat(this.generateCParameterTypes(argConvertors, method.hasReceiver()))
211
            .filter(isDefined)
212
            .join(", ")
213
        const suffix = this.generateCMacroSuffix(method)
214
        this.generatedApi.print(`KOALA_INTEROP_${suffix}(${macroArgs})`)
215
        this.generatedApi.print(` `)
216
    }
217

218
    printCustomApiMethod(c: CustomAPI, m: Method) {
219
        const sig = m.signature as NamedMethodSignature
220
        const capitalizedName = capitalize(m.name)
221
        const retType = c.getArgType(sig.returnType)
222
        const argsType =sig.args.map(it => c.getArgType(it))
223
        const method = new Method(`impl_${capitalizedName}`, new NamedMethodSignature(
224
            retType, argsType, sig.argsNames))
225

226
        this.customApi.writeMethodImplementation(method, writer => {
227
            let castNames: string[] = []
228
            sig.args.forEach((it, index) => {
229
                const type = c.getCastType(it)
230
                const name = sig.argsNames[index];
231
                let castName = name
232
                if (c.getArgType(it).name !== type.name) {
233
                    castName = `${name}Cast`
234
                    const cast = it.name.endsWith("Enum") ? `${type.name}(${name})` : `(${type.name}) ${name}`
235
                    this.customApi.print(`${type.name} ${castName} = ${cast};`)
236
                }
237
                castNames = castNames.concat(castName)
238
            })
239
            const ret = sig.returnType === Type.Void ? "" : "return "
240
            this.customApi.print(`${ret}GetArkUI${c.apiName}()->${m.name}(${castNames.join(", ")});`)
241
        })
242
        const v = sig.returnType === Type.Void ? "V" : "";
243
        let args = c.withContext ? argsType.slice(1) : argsType
244
        const size = args.length
245
        args = sig.returnType === Type.Void ? args : [retType, ...args]
246
        const comma = args.length > 0 ? ", " : ""
247
        const CTX = c.withContext ? "_CTX" : ""
248
        this.customApi.print(`KOALA_INTEROP${CTX}_${v}${size}(${capitalizedName}${comma}${args.map(it => it.name).join(", ")})\n`)
249
    }
250

251
    print(): void {
252
        for (const file of this.library.files) {
253
            for (const peer of file.peersToGenerate.values()) {
254
                for (const method of peer.methods) {
255
                    this.printMethod(method, peer.componentName)
256
                }
257
            }
258
        }
259

260
        this.generatedApi.print("\n// Accessors\n")
261
        for (const clazz of this.library.materializedClasses.values()) {
262
            for (const method of [clazz.ctor, clazz.finalizer].concat(clazz.methods)) {
263
                this.printMethod(method)
264
            }
265
        }
266

267
        this.customApi.print("\n// custom API methods\n")
268
        for(const customApi of CUSTOM_API) {
269
            for(const method of customApi.methods) {
270
                this.printCustomApiMethod(customApi, method)
271
            }
272
        }
273
    }
274
}
275

276
export function printBridgeCcGenerated(peerLibrary: PeerLibrary, callLog: boolean): string {
277
    const visitor = new BridgeCcVisitor(peerLibrary, callLog)
278
    visitor.print()
279
    return bridgeCcGeneratedDeclaration(visitor.generatedApi.getOutput())
280
}
281

282
export function printBridgeCcCustom(peerLibrary: PeerLibrary, callLog: boolean): string {
283
    const visitor = new BridgeCcVisitor(peerLibrary, callLog)
284
    visitor.print()
285
    return bridgeCcCustomDeclaration(visitor.customApi.getOutput())
286
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.