idlize

Форк
0
/
ModifierPrinter.ts 
523 строки · 19.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 { IndentedPrinter } from "../../IndentedPrinter";
17
import { DeclarationTable, DeclarationTarget, FieldRecord, PrimitiveType } from "../DeclarationTable";
18
import { accessorStructList,
19
         cStyleCopyright,
20
         completeModifiersContent,
21
         appendModifiersCommonPrologue,
22
         appendViewModelBridge,
23
         makeFileNameFromClassName,
24
         modifierStructList,
25
         warning } from "../FileGenerators";
26
import { PeerClass } from "../PeerClass";
27
import { PeerLibrary } from "../PeerLibrary";
28
import { MethodSeparatorVisitor, PeerMethod } from "../PeerMethod";
29
import { DelegateSignatureBuilder } from "./DelegatePrinter";
30
import { PeerGeneratorConfig } from "../PeerGeneratorConfig";
31
import { MaterializedClass, MaterializedMethod } from "../Materialized";
32
import { Language, groupBy } from "../../util";
33
import { CppLanguageWriter, createLanguageWriter, LanguageWriter } from "../LanguageWriters";
34
import { LibaceInstall } from "../../Install";
35

36
class MethodSeparatorPrinter extends MethodSeparatorVisitor {
37
    public readonly printer = new IndentedPrinter()
38
    constructor(
39
        declarationTable: DeclarationTable,
40
        method: PeerMethod,
41
    ) {
42
        super(declarationTable, method)
43
        this.delegateSignatureBuilder = new DelegateSignatureBuilder(declarationTable, method)
44
        this.accessChain = method.argConvertors.map((convertor, index) => [{
45
            name: convertor.param,
46
            type: method.declarationTargets[index],
47
            isPointerType: convertor.isPointerType(),
48
        }])
49
    }
50

51
    private readonly delegateSignatureBuilder: DelegateSignatureBuilder
52
    private readonly accessChain: {name: string, type: DeclarationTarget, isPointerType: boolean}[][]
53
    private generateAccessTo(argIndex: number, fieldName?: string) {
54
        const argAccessChain = this.accessChain[argIndex]
55
        if (argAccessChain[argAccessChain.length - 1].type === PrimitiveType.Undefined) {
56
            return `{}`
57
        }
58
        let resultAccess = argAccessChain[0].name
59
        for (let i = 1; i < argAccessChain.length; i++) {
60
            const fieldAccess = argAccessChain[i-1].isPointerType ? '->' : '.'
61
            resultAccess += `${fieldAccess}${argAccessChain[i].name}`
62
        }
63

64
        if (fieldName) {
65
            const fieldAccess = argAccessChain[argAccessChain.length-1].isPointerType ? '->' : '.'
66
            resultAccess += `${fieldAccess}${fieldName}`
67
        }
68
        return resultAccess
69
    }
70

71
    protected override onPushUnionScope(argIndex: number, field: FieldRecord, selectorValue: number): void {
72
        super.onPushUnionScope(argIndex, field, selectorValue)
73
        this.printer.print(`if (${this.generateAccessTo(argIndex, 'selector')} == ${selectorValue}) {`)
74
        this.printer.pushIndent()
75
        this.accessChain[argIndex].push({
76
            name: field.name,
77
            type: field.declaration,
78
            isPointerType: false
79
        })
80
        this.delegateSignatureBuilder.pushUnionScope(argIndex, field)
81
    }
82

83
    protected override onPopUnionScope(argIndex: number): void {
84
        super.onPopUnionScope(argIndex)
85
        this.accessChain[argIndex].pop()
86
        this.printer.popIndent()
87
        this.printer.print('}')
88
        this.delegateSignatureBuilder.popScope(argIndex)
89
    }
90

91
    protected override onPushOptionScope(argIndex: number, target: DeclarationTarget, exists: boolean): void {
92
        super.onPushOptionScope(argIndex, target, exists)
93
        if (exists) {
94
            this.printer.print(`if (${this.generateAccessTo(argIndex, 'tag')} != ${PrimitiveType.UndefinedTag}) {`)
95
            this.accessChain[argIndex].push({
96
                name: "value",
97
                type: target,
98
                isPointerType: false,
99
            })
100
        } else {
101
            this.printer.print(`if (${this.generateAccessTo(argIndex, 'tag')} == ${PrimitiveType.UndefinedTag}) {`)
102
            this.accessChain[argIndex].push({
103
                name: "UNDEFINED",
104
                type: PrimitiveType.Undefined,
105
                isPointerType: false,
106
            })
107
        }
108
        this.printer.pushIndent()
109
        this.delegateSignatureBuilder.pushOptionScope(argIndex, target, exists)
110
    }
111

112
    protected override onPopOptionScope(argIndex: number): void {
113
        super.onPopUnionScope(argIndex)
114
        this.accessChain[argIndex].pop()
115
        this.printer.popIndent()
116
        this.printer.print('}')
117
        this.delegateSignatureBuilder.popScope(argIndex)
118
    }
119

120
    protected generateInseparableFieldName(argIndex: number) {
121
        return `arg${argIndex}_inseparable_value`
122
    }
123

124
    onVisitInseparableArg(argIndex: number): void {
125
        super.onVisitInseparableArg(argIndex)
126
        const argChain = this.accessChain[argIndex]
127
        const arg = argChain[argChain.length - 1]
128
        const type = this.declarationTable.computeTargetName(arg.type, false)
129
        const maybePointer = arg.isPointerType
130
            ? '*'
131
            : arg.type !== PrimitiveType.Undefined ? '&' : ''
132
        this.printer.print(`const ${type} ${maybePointer}${this.generateInseparableFieldName(argIndex)} = ${this.generateAccessTo(argIndex)};`)
133
    }
134

135
    onVisitInseparable(): void {
136
        super.onVisitInseparable()
137
        const delegateIdentifier = this.delegateSignatureBuilder.buildIdentifier()
138
        let delegateArgs = Array.from({length: this.method.argConvertors.length}, (_, argIndex) => {
139
            return this.generateInseparableFieldName(argIndex)
140
        })
141
        if (this.method.hasReceiver())
142
            delegateArgs = [this.method.generateReceiver()!.argName, ...delegateArgs]
143
        this.printer.print(`${delegateIdentifier}(${delegateArgs.join(', ')});`)
144
    }
145
}
146

147
export class ModifierVisitor {
148
    dummy = createLanguageWriter(Language.CPP)
149
    real = createLanguageWriter(Language.CPP)
150
    modifiers = createLanguageWriter(Language.CPP)
151
    getterDeclarations = createLanguageWriter(Language.CPP)
152
    modifierList = createLanguageWriter(Language.CPP)
153

154
    constructor(
155
        protected library: PeerLibrary,
156
    ) { }
157

158
    printDummyImplFunctionBody(method: PeerMethod) {
159
        let _ = this.dummy
160
        _.writeStatement(
161
            _.makeCondition(
162
                _.makeString("!needGroupedLog(1)"),
163
                _.makeReturn(
164
                    method.retConvertor.isVoid ? undefined : _.makeString(method.dummyReturnValue ?? "0"))))
165
        _.print(`string out("${method.toStringName}(");`)
166
        method.argConvertors.forEach((argConvertor, index) => {
167
            if (index > 0) this.dummy.print(`out.append(", ");`)
168
            _.print(`WriteToString(&out, ${argConvertor.param});`)
169
        })
170
        _.print(`out.append(")");`)
171
        const retVal = method.dummyReturnValue
172
        if (retVal  !== undefined) {
173
            _.print(`out.append("[return ${retVal}]");`)
174
        }
175
        _.print(`appendGroupedLog(1, out);`)
176
        this.printReturnStatement(this.dummy, method, retVal)
177
    }
178

179
    printModifierImplFunctionBody(method: PeerMethod) {
180
        const visitor = new MethodSeparatorPrinter(
181
            this.library.declarationTable,
182
            method
183
        )
184
        visitor.visit()
185
        // This is the entry point to delegate print.
186
        // visitor.printer.getOutput().forEach(it => this.real.print(it))
187
        this.printReturnStatement(this.real, method)
188
    }
189

190
    private printReturnStatement(printer: LanguageWriter, method: PeerMethod, returnValue: string | undefined = undefined) {
191
        if (!method.retConvertor.isVoid) {
192
            printer.print(`return ${returnValue ?? "0"};`)
193
        }
194
    }
195

196
    printMethodProlog(printer: LanguageWriter, method: PeerMethod) {
197
        const apiParameters = method.generateAPIParameters().join(", ")
198
        const signature = `${method.retType} ${method.implName}(${apiParameters}) {`
199
        printer.print(signature)
200
        printer.pushIndent()
201
    }
202

203
    printMethodEpilog(printer: LanguageWriter) {
204
        printer.popIndent()
205
        printer.print(`}`)
206
    }
207

208
    printRealAndDummyModifier(method: PeerMethod) {
209
        this.printMethodProlog(this.dummy, method)
210
        this.printMethodProlog(this.real, method)
211
        this.printDummyImplFunctionBody(method)
212
        this.printModifierImplFunctionBody(method)
213
        this.printMethodEpilog(this.dummy)
214
        this.printMethodEpilog(this.real)
215

216
        this.modifiers.print(`${method.implNamespaceName}::${method.implName},`)
217
    }
218

219
    printClassProlog(clazz: PeerClass) {
220
        const component = clazz.componentName
221
        const modifierStructImpl = `ArkUI${component}ModifierImpl`
222

223
        this.modifiers.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${component}Modifier* Get${component}Modifier() {`)
224
        this.modifiers.pushIndent()
225
        this.modifiers.print(`static const ${PeerGeneratorConfig.cppPrefix}ArkUI${component}Modifier ${modifierStructImpl} {`)
226
        this.modifiers.pushIndent()
227

228
        this.modifierList.print(`Get${component}Modifier,`)
229
    }
230

231
    printClassEpilog(clazz: PeerClass) {
232
        const name = clazz.componentName
233
        const modifierStructImpl = `ArkUI${name}ModifierImpl`
234

235
        this.modifiers.popIndent()
236
        this.modifiers.print(`};`)
237
        this.modifiers.print(`return &${modifierStructImpl};`)
238
        this.modifiers.popIndent()
239
        this.modifiers.print(`}\n`)
240

241
        this.getterDeclarations.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${name}Modifier* Get${name}Modifier();`)
242
    }
243

244
    pushNamespace(namespaceName: string) {
245
        this.real.print(`namespace ${namespaceName} {`)
246
        this.dummy.print(`namespace ${namespaceName} {`)
247
        this.real.pushIndent()
248
        this.dummy.pushIndent()
249
    }
250

251
    popNamespace(namespaceName: string) {
252
        this.real.popIndent()
253
        this.dummy.popIndent()
254
        this.real.print(`} // ${namespaceName}`)
255
        this.dummy.print(`} // ${namespaceName}`)
256
    }
257

258
    printPeerClassModifiers(clazz: PeerClass) {
259
        this.printClassProlog(clazz)
260
        // TODO: move to Object.groupBy when move to nodejs 21
261
        const namespaces: Map<string, PeerMethod[]> = groupBy(clazz.methods, it => it.implNamespaceName)
262
        Array.from(namespaces.keys()).forEach (namespaceName => {
263
            this.pushNamespace(namespaceName)
264
            namespaces.get(namespaceName)?.forEach(
265
                method => this.printRealAndDummyModifier(method)
266
            )
267
            this.popNamespace(namespaceName)
268
        })
269
        this.printClassEpilog(clazz)
270
    }
271

272
    // TODO: have a proper Peer module visitor
273
    printRealAndDummyModifiers() {
274
        this.library.files.forEach(file => {
275
            file.peers.forEach(clazz => this.printPeerClassModifiers(clazz))
276
        })
277
    }
278
}
279

280
class AccessorVisitor extends ModifierVisitor {
281
    accessors = createLanguageWriter(Language.CPP)
282
    accessorList = createLanguageWriter(Language.CPP)
283

284
    constructor(library: PeerLibrary) {
285
        super(library)
286
    }
287

288
    override printRealAndDummyModifiers() {
289
        super.printRealAndDummyModifiers()
290
        this.library.materializedClasses.forEach(c => this.printRealAndDummyAccessor(c))
291
    }
292

293
    printRealAndDummyAccessor(clazz: MaterializedClass) {
294
        this.printMaterializedClassProlog(clazz)
295
        // Materialized class methods share the same namespace
296
        // so take the first one.
297
        const namespaceName = clazz.methods[0].implNamespaceName
298
        this.pushNamespace(namespaceName);
299
        [clazz.ctor, clazz.finalizer].concat(clazz.methods).forEach(method => {
300
            this.printMaterializedMethod(this.dummy, method, m => this.printDummyImplFunctionBody(m))
301
            this.printMaterializedMethod(this.real, method, m => this.printModifierImplFunctionBody(m))
302
            this.accessors.print(`${method.implNamespaceName}::${method.implName},`)
303
        })
304
        this.popNamespace(namespaceName)
305
        this.printMaterializedClassEpilog(clazz)
306
    }
307

308
    printMaterializedClassProlog(clazz: MaterializedClass) {
309
        const accessor = `${clazz.className}Accessor`
310
        this.accessors.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${accessor}* Get${accessor}() {`)
311
        this.accessors.pushIndent()
312
        this.accessors.print(`static const ${PeerGeneratorConfig.cppPrefix}ArkUI${accessor} ${accessor}Impl {`)
313
        this.accessors.pushIndent()
314
        this.accessorList.print(`Get${accessor},`)
315
    }
316

317
    printMaterializedClassEpilog(clazz: MaterializedClass) {
318
        const accessor = `${clazz.className}Accessor`
319
        this.accessors.popIndent()
320
        this.accessors.print(`};`)
321
        this.accessors.print(`return &${accessor}Impl;`)
322
        this.accessors.popIndent()
323
        this.accessors.print(`}\n`)
324
        this.getterDeclarations.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${accessor}* Get${accessor}();`)
325
    }
326

327
    printMaterializedMethod(printer: LanguageWriter, method: MaterializedMethod, printBody: (m: MaterializedMethod) => void) {
328
        this.printMethodProlog(printer, method)
329
        printBody(method)
330
        this.printMethodEpilog(printer)
331
    }
332
}
333

334
class MultiFileModifiersVisitorState {
335
    dummy = createLanguageWriter(Language.CPP)
336
    real = createLanguageWriter(Language.CPP)
337
    accessorList = createLanguageWriter(Language.CPP)
338
    accessors = createLanguageWriter(Language.CPP)
339
    modifierList = createLanguageWriter(Language.CPP)
340
    modifiers = createLanguageWriter(Language.CPP)
341
    getterDeclarations = createLanguageWriter(Language.CPP)
342
}
343

344
class MultiFileModifiersVisitor extends AccessorVisitor {
345
    private stateByFile = new Map<string, MultiFileModifiersVisitorState>()
346

347
    printPeerClassModifiers(clazz: PeerClass): void {
348
        this.onFileStart(clazz.componentName)
349
        super.printPeerClassModifiers(clazz)
350
        this.onFileEnd()
351
    }
352

353
    onFileStart(className: string) {
354
        const slug = makeFileNameFromClassName(className)
355
        let state = this.stateByFile.get(slug)
356
        if (!state) {
357
            state = new MultiFileModifiersVisitorState()
358
            this.stateByFile.set(slug, state)
359
        }
360
        this.dummy = state.dummy
361
        this.real = state.real
362
        this.accessors = state.accessors
363
        this.accessorList = state.accessorList
364
        this.modifiers = state.modifiers
365
        this.modifierList = state.modifierList
366
        this.getterDeclarations = state.getterDeclarations
367
    }
368

369
    onFileEnd() {
370
    }
371

372
    printRealAndDummyAccessor(clazz: MaterializedClass): void {
373
        this.onFileStart(clazz.className)
374
        super.printRealAndDummyAccessor(clazz)
375
        this.onFileEnd()
376
    }
377

378
    emitRealSync(libace: LibaceInstall, options: ModifierFileOptions): void {
379
        const modifierList = createLanguageWriter(Language.CPP)
380
        const accessorList = createLanguageWriter(Language.CPP)
381
        const getterDeclarations = createLanguageWriter(Language.CPP)
382

383
        for (const [slug, state] of this.stateByFile) {
384
            const filePath = libace.modifierCpp(slug)
385
            printModifiersImplFile(filePath, slug, state, options)
386
            modifierList.concat(state.modifierList)
387
            accessorList.concat(state.accessorList)
388
            getterDeclarations.concat(state.getterDeclarations)
389
        }
390

391
        const commonFilePath = libace.allModifiers
392
        const commonFileContent = getterDeclarations
393
            .concat(modifierStructList(modifierList))
394
            .concat(accessorStructList(accessorList))
395

396
        printModifiersCommonImplFile(commonFilePath, commonFileContent, options)
397
        printApiImplFile(libace.viewModelBridge, options)
398
    }
399
}
400

401
export function printRealAndDummyModifiers(peerLibrary: PeerLibrary): {dummy: LanguageWriter, real: LanguageWriter} {
402
    const visitor = new ModifierVisitor(peerLibrary)
403
    visitor.printRealAndDummyModifiers()
404
    const dummy =
405
        visitor.dummy.concat(visitor.modifiers).concat(modifierStructList(visitor.modifierList))
406
    const real =
407
        visitor.real.concat(visitor.modifiers).concat(modifierStructList(visitor.modifierList))
408
    return {dummy, real}
409
}
410

411
export function printRealAndDummyAccessors(peerLibrary: PeerLibrary): {dummy: LanguageWriter, real: LanguageWriter} {
412
    const visitor = new AccessorVisitor(peerLibrary)
413
    peerLibrary.materializedClasses.forEach(c => visitor.printRealAndDummyAccessor(c))
414

415
    const dummy =
416
        visitor.dummy.concat(visitor.accessors).concat(accessorStructList(visitor.accessorList))
417

418
    const real =
419
        visitor.real.concat(visitor.accessors).concat(accessorStructList(visitor.accessorList))
420
    return {dummy, real}
421
}
422

423
export interface Namespaces {
424
    generated: string,
425
    base: string
426
}
427

428
export interface ModifierFileOptions {
429
    basicVersion: number;
430
    fullVersion: number;
431
    extendedVersion: number;
432

433
    namespaces?: Namespaces
434
}
435

436
export function printRealModifiersAsMultipleFiles(library: PeerLibrary, libace: LibaceInstall, options: ModifierFileOptions) {
437
    const visitor = new MultiFileModifiersVisitor(library)
438
    visitor.printRealAndDummyModifiers()
439
    visitor.emitRealSync(libace, options)
440
}
441

442
function printModifiersImplFile(filePath: string, slug: string, state: MultiFileModifiersVisitorState, options: ModifierFileOptions) {
443
    const writer = new CppLanguageWriter(new IndentedPrinter())
444
    writer.writeLines(cStyleCopyright)
445

446
    writer.writeInclude(`arkoala_api_generated.h`)
447
    writer.print("")
448

449
    if (options.namespaces) {
450
        writer.pushNamespace(options.namespaces.generated)
451
    }
452

453
    writer.concat(state.real)
454
    writer.concat(state.modifiers)
455
    writer.concat(state.accessors)
456

457
    if (options.namespaces) {
458
        writer.popNamespace()
459
    }
460

461
    writer.print("")
462
    writer.printTo(filePath)
463
}
464

465
function printModifiersCommonImplFile(filePath: string, content: LanguageWriter, options: ModifierFileOptions) {
466
    const writer = new CppLanguageWriter(new IndentedPrinter())
467
    writer.writeLines(cStyleCopyright)
468
    writer.writeMultilineCommentBlock(warning)
469
    writer.print("")
470

471
    writer.writeInclude('arkoala-macros.h')
472
    writer.writeInclude('core/interfaces/arkoala/arkoala_api.h')
473
    writer.writeInclude('node_api.h')
474
    writer.print("")
475

476
    if (options.namespaces) {
477
        writer.pushNamespace(options.namespaces.base)
478
    }
479
    writer.concat(appendModifiersCommonPrologue())
480

481
    if (options.namespaces) {
482
        writer.popNamespace()
483
    }
484

485
    writer.print("")
486

487
    if (options.namespaces) {
488
        writer.pushNamespace(options.namespaces.generated)
489
    }
490

491
    writer.concat(completeModifiersContent(content, options.basicVersion, options.fullVersion, options.extendedVersion))
492

493
    if (options.namespaces) {
494
        writer.popNamespace()
495
    }
496

497
    writer.print("")
498
    writer.printTo(filePath)
499
}
500

501
function printApiImplFile(filePath: string, options: ModifierFileOptions) {
502
    const writer = new CppLanguageWriter(new IndentedPrinter())
503
    writer.writeLines(cStyleCopyright)
504
    writer.writeMultilineCommentBlock(warning)
505
    writer.print("")
506

507
    writer.writeInclude('core/interfaces/arkoala/arkoala_api.h')
508
    writer.writeInclude('arkoala_api_generated.h')
509
    writer.writeInclude('base/utils/utils.h')
510
    writer.writeInclude('core/pipeline/base/element_register.h')
511
    writer.print("")
512

513
    if (options.namespaces) {
514
        writer.pushNamespace(options.namespaces.base)
515
    }
516
    writer.concat(appendViewModelBridge())
517

518
    if (options.namespaces) {
519
        writer.popNamespace()
520
    }
521

522
    writer.printTo(filePath)
523
}
524

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

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

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

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