idlize

Форк
0
/
DelegatePrinter.ts 
344 строки · 11.5 Кб
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 * as path from "path";
17
import * as fs from "fs";
18
import { IndentedPrinter } from "../../IndentedPrinter";
19
import { DeclarationTable, DeclarationTarget, FieldRecord, PrimitiveType } from "../DeclarationTable";
20
import { cStyleCopyright, completeDelegatesImpl, makeFileNameFromClassName, makeIncludeGuardDefine, warning } from "../FileGenerators";
21
import { PeerLibrary } from "../PeerLibrary";
22
import { MethodSeparatorVisitor, PeerMethod } from "../PeerMethod";
23
import { PeerClass } from "../PeerClass";
24
import { MaterializedClass } from "../Materialized";
25
import { CppLanguageWriter, PrinterLike } from "../LanguageWriters";
26
import { LibaceInstall } from "../../Install";
27

28
export class DelegateSignatureBuilder {
29
    constructor(
30
        private readonly declarationTable: DeclarationTable,
31
        private readonly method: PeerMethod
32
    ) {
33
        this.args = method.argConvertors.map((convertor, index) => {
34
            return [{
35
                argName: convertor.param,
36
                argType: convertor.nativeType(false),
37
                isPointerType: convertor.isPointerType(),
38
            }]
39
        })
40
    }
41

42
    private readonly args: {
43
        argName: string,
44
        argType: string,
45
        isPointerType: boolean,
46
        exists?: boolean,
47
    }[][]
48

49
    pushUnionScope(argIndex: number, field: FieldRecord): void {
50
        this.args[argIndex].push({
51
            argName: field.name,
52
            argType: this.declarationTable.computeTargetName(field.declaration, false),
53
            isPointerType: false,
54
        })
55
    }
56

57
    pushOptionScope(argIndex: number, target: DeclarationTarget, exists: boolean): void {
58
        const arg = this.args[argIndex]
59
        arg.push({
60
            argName: arg[arg.length - 1].argName,
61
            argType: this.declarationTable.computeTargetName(exists ? target : PrimitiveType.Undefined, false),
62
            isPointerType: false,
63
            exists: exists,
64
        })
65
    }
66

67
    popScope(argIndex: number): void {
68
        this.args[argIndex].pop()
69
    }
70

71
    buildIdentifier(): string {
72
        const argsPostfix = this.args
73
            .map(argStack => argStack.map(argStackItem => {
74
                return argStackItem.exists !== undefined
75
                    ? (argStackItem.exists ? "Def" : "Undef")
76
                    : argStackItem.argType
77
            }))
78
            .map(argStack => argStack.join('_'))
79
            .join('__')
80
        return `${this.method.implName}__${argsPostfix}`
81
    }
82

83
    buildSignature(): string {
84
        let args = this.args
85
            .map(argStack => argStack[argStack.length - 1])
86
            .map((arg, index) => {
87
                return arg.isPointerType
88
                    ? `const ${arg.argType} *arg_${index}`
89
                    : `const ${arg.argType} &arg_${index}`
90
            })
91
        if (this.method.hasReceiver()) {
92
            const receiver = this.method.generateReceiver()!
93
            args = [`${receiver.argType} ${receiver.argName}`, ...args]
94
        }
95
        return `${this.method.retType} ${this.buildIdentifier()}(${args.join(', ')})`
96
    }
97
}
98

99
class MethodDelegatePrinter extends MethodSeparatorVisitor {
100
    public readonly declPrinter = new IndentedPrinter()
101
    public readonly implPrinter = new IndentedPrinter()
102
    private delegateSignatureBuilder: DelegateSignatureBuilder
103
    private emittedSignatures = new Set();
104
    constructor(
105
        declarationTable: DeclarationTable,
106
        method: PeerMethod,
107
    ) {
108
        super(declarationTable, method)
109
        this.delegateSignatureBuilder = new DelegateSignatureBuilder(declarationTable, method)
110
    }
111

112
    protected override onPushUnionScope(argIndex: number, field: FieldRecord, selectorValue: number): void {
113
        super.onPushUnionScope(argIndex, field, selectorValue)
114
        this.delegateSignatureBuilder!.pushUnionScope(argIndex, field)
115
    }
116

117
    protected override onPopUnionScope(argIndex: number): void {
118
        super.onPopUnionScope(argIndex)
119
        this.delegateSignatureBuilder.popScope(argIndex)
120
    }
121

122
    protected override onPushOptionScope(argIndex: number, target: DeclarationTarget, exists: boolean): void {
123
        super.onPushOptionScope(argIndex, target, exists)
124
        this.delegateSignatureBuilder.pushOptionScope(argIndex, target, exists)
125
    }
126

127
    protected override onPopOptionScope(argIndex: number): void {
128
        this.delegateSignatureBuilder.popScope(argIndex)
129
    }
130

131
    onVisitInseparable(): void {
132
        const signature = this.delegateSignatureBuilder.buildSignature()
133
        if (!this.emittedSignatures.has(signature)) {
134
            this.declPrinter.print(`${signature};`)
135
            const retStatement = this.method.retConvertor.isVoid ? "" :`return 0;`
136
            this.implPrinter.print(`${signature} { ${retStatement} }`)
137
            this.emittedSignatures.add(signature)
138
        }
139
    }
140
}
141

142
class DelegateVisitor {
143
    readonly api: IndentedPrinter = new IndentedPrinter()
144
    readonly impl: IndentedPrinter = new IndentedPrinter()
145

146
    constructor(
147
        private readonly library: PeerLibrary,
148
    ) {}
149

150
    private printMethod(method: PeerMethod) {
151
        const visitor = new MethodDelegatePrinter(
152
            this.library.declarationTable,
153
            method,
154
        )
155
        visitor.visit()
156
        visitor.declPrinter.getOutput().forEach(it => this.api.print(it))
157
        visitor.implPrinter.getOutput().forEach(it => this.impl.print(it))
158
    }
159

160
    print(): void {
161
        for (const file of this.library.files) {
162
            for (const peer of file.peers.values()) {
163
                for (const method of peer.methods) {
164
                    this.printMethod(method)
165
                }
166
            }
167
        }
168
        for (const materialized of this.library.materializedClasses.values()) {
169
            this.printMethod(materialized.ctor)
170
            this.printMethod(materialized.finalizer)
171
            for (const method of materialized.methods) {
172
                this.printMethod(method)
173
            }
174
        }
175
    }
176
}
177

178
export function printDelegatesHeaders(library: PeerLibrary): string {
179
    const visitor = new DelegateVisitor(library)
180
    visitor.api.print(`#pragma once
181

182
#include "arkoala_api.h"
183
`)
184
    visitor.print()
185
    // TODO here can be conflicts between different union filds with same types
186
    const uniqueDeclarations = Array.from(new Set(visitor.api.getOutput()))
187
    return uniqueDeclarations.join('\n')
188
}
189

190
export function printDelegatesImplementation(library: PeerLibrary): string {
191
    const visitor = new DelegateVisitor(library)
192
    visitor.print()
193
    // TODO here can be conflicts between different union filds with same types
194
    const uniqueDeclarations = Array.from(new Set(visitor.impl.getOutput()))
195
    return completeDelegatesImpl(uniqueDeclarations.join('\n'))
196
}
197

198
export function printDelegatesAsMultipleFiles(library: PeerLibrary, libace: LibaceInstall, options: DelegateFileOptions = {}) {
199
    const visitor = new MultiFileDelegateVisitor(library)
200
    visitor.print()
201
    visitor.emitSync(libace, options)
202
}
203

204

205
interface MultiFileDelegatePrinters {
206
    api: IndentedPrinter
207
    impl: IndentedPrinter
208
}
209

210
class MultiFileDelegateVisitor {
211
    private readonly printers: Map<string, MultiFileDelegatePrinters> = new Map();
212
    private api?: IndentedPrinter
213
    private impl?: IndentedPrinter
214

215
    constructor(
216
        private readonly library: PeerLibrary,
217
    ) {}
218

219
    private printMethod(method: PeerMethod) {
220
        const visitor = new MethodDelegatePrinter(
221
            this.library.declarationTable,
222
            method,
223
        )
224
        visitor.visit()
225
        visitor.declPrinter.getOutput().forEach(it => this.api!.print(it))
226
        visitor.implPrinter.getOutput().forEach(it => this.impl!.print(it))
227
    }
228

229
    private onPeerStart(clazz: PeerClass) {
230
        let slug = makeFileNameFromClassName(clazz.componentName)
231
        this.pushPrinters(slug)
232
    }
233

234
    private onPeerEnd(_clazz: PeerClass) {
235
        this.api = this.impl = undefined
236
    }
237

238
    private onMaterializedClassStart(clazz: MaterializedClass) {
239
        let slug = makeFileNameFromClassName(clazz.className)
240
        this.pushPrinters(slug)
241
    }
242

243
    private onMaterializedClassEnd(_clazz: MaterializedClass) {
244
        this.api = this.impl = undefined
245
    }
246

247
    private pushPrinters(slug: string) {
248
        let printers = this.printers.get(slug)
249
        if (printers) {
250
            this.api = printers.api
251
            this.impl = printers.impl
252
            return
253
        }
254
        let api = this.api = new IndentedPrinter()
255
        let impl = this.impl = new IndentedPrinter()
256
        this.printers.set(slug, { api, impl })
257
    }
258

259
    print() {
260
        for (const file of this.library.files) {
261
            for (const peer of file.peers.values()) {
262
                this.onPeerStart(peer)
263
                for (const method of peer.methods) {
264
                    this.printMethod(method)
265
                }
266
                this.onPeerEnd(peer)
267
            }
268
        }
269
        for (const materialized of this.library.materializedClasses.values()) {
270
            this.onMaterializedClassStart(materialized)
271
            this.printMethod(materialized.ctor)
272
            this.printMethod(materialized.finalizer)
273
            for (const method of materialized.methods) {
274
                this.printMethod(method)
275
            }
276
            this.onMaterializedClassEnd(materialized)
277
        }
278
    }
279

280
    emitSync(libace: LibaceInstall, options: DelegateFileOptions): void {
281
        for (const [slug, { api, impl }] of this.printers) {
282
            printDelegateImplementation(libace.delegateCpp(slug), impl, options);
283
            printDelegateHeader(libace.delegateHeader(slug), api, options);
284
        }
285
    }
286
}
287

288
export interface DelegateFileOptions {
289
    namespace?: string
290
}
291

292
function printDelegateImplementation(filePath: string, source: PrinterLike, options: DelegateFileOptions) {
293
    const writer = new CppLanguageWriter(new IndentedPrinter())
294
    writer.writeLines(cStyleCopyright)
295
    writer.writeMultilineCommentBlock(warning)
296
    writer.print("")
297

298

299
    const headerName = path.basename(filePath, ".cpp") + ".h"
300
    writer.writeInclude(`../generated/interface/${headerName}`)
301
    writer.print("")
302

303
    if (options.namespace) {
304
        writer.pushNamespace(options.namespace)
305
    }
306

307
    writer.concat(source)
308

309
    if (options.namespace) {
310
        writer.popNamespace()
311
    }
312

313
    writer.print("")
314
    writer.printTo(filePath)
315
}
316

317

318
function printDelegateHeader(filePath: string, source: PrinterLike, options: DelegateFileOptions) {
319
    const writer = new CppLanguageWriter(new IndentedPrinter())
320
    writer.writeLines(cStyleCopyright)
321
    writer.writeMultilineCommentBlock(warning)
322
    writer.print("")
323

324
    const includeGuardDefine = makeIncludeGuardDefine(filePath)
325
    writer.print(`#ifndef ${includeGuardDefine}`)
326
    writer.print(`#define ${includeGuardDefine}`)
327
    writer.print("")
328

329
    writer.writeInclude("arkoala_api_generated.h")
330
    writer.print("")
331

332
    if (options.namespace) {
333
        writer.pushNamespace(options.namespace)
334
    }
335

336
    writer.concat(source)
337

338
    if (options.namespace) {
339
        writer.popNamespace()
340
    }
341
    writer.print(`\n#endif // ${includeGuardDefine}`)
342
    writer.print("")
343
    writer.printTo(filePath)
344
}
345

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

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

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

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