idlize
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
16import { IndentedPrinter } from "../../IndentedPrinter";
17import { DeclarationTable, DeclarationTarget, FieldRecord, PrimitiveType } from "../DeclarationTable";
18import { accessorStructList,
19cStyleCopyright,
20completeModifiersContent,
21appendModifiersCommonPrologue,
22appendViewModelBridge,
23makeFileNameFromClassName,
24modifierStructList,
25warning } from "../FileGenerators";
26import { PeerClass } from "../PeerClass";
27import { PeerLibrary } from "../PeerLibrary";
28import { MethodSeparatorVisitor, PeerMethod } from "../PeerMethod";
29import { DelegateSignatureBuilder } from "./DelegatePrinter";
30import { PeerGeneratorConfig } from "../PeerGeneratorConfig";
31import { MaterializedClass, MaterializedMethod } from "../Materialized";
32import { Language, groupBy } from "../../util";
33import { CppLanguageWriter, createLanguageWriter, LanguageWriter } from "../LanguageWriters";
34import { LibaceInstall } from "../../Install";
35
36class MethodSeparatorPrinter extends MethodSeparatorVisitor {
37public readonly printer = new IndentedPrinter()
38constructor(
39declarationTable: DeclarationTable,
40method: PeerMethod,
41) {
42super(declarationTable, method)
43this.delegateSignatureBuilder = new DelegateSignatureBuilder(declarationTable, method)
44this.accessChain = method.argConvertors.map((convertor, index) => [{
45name: convertor.param,
46type: method.declarationTargets[index],
47isPointerType: convertor.isPointerType(),
48}])
49}
50
51private readonly delegateSignatureBuilder: DelegateSignatureBuilder
52private readonly accessChain: {name: string, type: DeclarationTarget, isPointerType: boolean}[][]
53private generateAccessTo(argIndex: number, fieldName?: string) {
54const argAccessChain = this.accessChain[argIndex]
55if (argAccessChain[argAccessChain.length - 1].type === PrimitiveType.Undefined) {
56return `{}`
57}
58let resultAccess = argAccessChain[0].name
59for (let i = 1; i < argAccessChain.length; i++) {
60const fieldAccess = argAccessChain[i-1].isPointerType ? '->' : '.'
61resultAccess += `${fieldAccess}${argAccessChain[i].name}`
62}
63
64if (fieldName) {
65const fieldAccess = argAccessChain[argAccessChain.length-1].isPointerType ? '->' : '.'
66resultAccess += `${fieldAccess}${fieldName}`
67}
68return resultAccess
69}
70
71protected override onPushUnionScope(argIndex: number, field: FieldRecord, selectorValue: number): void {
72super.onPushUnionScope(argIndex, field, selectorValue)
73this.printer.print(`if (${this.generateAccessTo(argIndex, 'selector')} == ${selectorValue}) {`)
74this.printer.pushIndent()
75this.accessChain[argIndex].push({
76name: field.name,
77type: field.declaration,
78isPointerType: false
79})
80this.delegateSignatureBuilder.pushUnionScope(argIndex, field)
81}
82
83protected override onPopUnionScope(argIndex: number): void {
84super.onPopUnionScope(argIndex)
85this.accessChain[argIndex].pop()
86this.printer.popIndent()
87this.printer.print('}')
88this.delegateSignatureBuilder.popScope(argIndex)
89}
90
91protected override onPushOptionScope(argIndex: number, target: DeclarationTarget, exists: boolean): void {
92super.onPushOptionScope(argIndex, target, exists)
93if (exists) {
94this.printer.print(`if (${this.generateAccessTo(argIndex, 'tag')} != ${PrimitiveType.UndefinedTag}) {`)
95this.accessChain[argIndex].push({
96name: "value",
97type: target,
98isPointerType: false,
99})
100} else {
101this.printer.print(`if (${this.generateAccessTo(argIndex, 'tag')} == ${PrimitiveType.UndefinedTag}) {`)
102this.accessChain[argIndex].push({
103name: "UNDEFINED",
104type: PrimitiveType.Undefined,
105isPointerType: false,
106})
107}
108this.printer.pushIndent()
109this.delegateSignatureBuilder.pushOptionScope(argIndex, target, exists)
110}
111
112protected override onPopOptionScope(argIndex: number): void {
113super.onPopUnionScope(argIndex)
114this.accessChain[argIndex].pop()
115this.printer.popIndent()
116this.printer.print('}')
117this.delegateSignatureBuilder.popScope(argIndex)
118}
119
120protected generateInseparableFieldName(argIndex: number) {
121return `arg${argIndex}_inseparable_value`
122}
123
124onVisitInseparableArg(argIndex: number): void {
125super.onVisitInseparableArg(argIndex)
126const argChain = this.accessChain[argIndex]
127const arg = argChain[argChain.length - 1]
128const type = this.declarationTable.computeTargetName(arg.type, false)
129const maybePointer = arg.isPointerType
130? '*'
131: arg.type !== PrimitiveType.Undefined ? '&' : ''
132this.printer.print(`const ${type} ${maybePointer}${this.generateInseparableFieldName(argIndex)} = ${this.generateAccessTo(argIndex)};`)
133}
134
135onVisitInseparable(): void {
136super.onVisitInseparable()
137const delegateIdentifier = this.delegateSignatureBuilder.buildIdentifier()
138let delegateArgs = Array.from({length: this.method.argConvertors.length}, (_, argIndex) => {
139return this.generateInseparableFieldName(argIndex)
140})
141if (this.method.hasReceiver())
142delegateArgs = [this.method.generateReceiver()!.argName, ...delegateArgs]
143this.printer.print(`${delegateIdentifier}(${delegateArgs.join(', ')});`)
144}
145}
146
147export class ModifierVisitor {
148dummy = createLanguageWriter(Language.CPP)
149real = createLanguageWriter(Language.CPP)
150modifiers = createLanguageWriter(Language.CPP)
151getterDeclarations = createLanguageWriter(Language.CPP)
152modifierList = createLanguageWriter(Language.CPP)
153
154constructor(
155protected library: PeerLibrary,
156) { }
157
158printDummyImplFunctionBody(method: PeerMethod) {
159let _ = this.dummy
160_.writeStatement(
161_.makeCondition(
162_.makeString("!needGroupedLog(1)"),
163_.makeReturn(
164method.retConvertor.isVoid ? undefined : _.makeString(method.dummyReturnValue ?? "0"))))
165_.print(`string out("${method.toStringName}(");`)
166method.argConvertors.forEach((argConvertor, index) => {
167if (index > 0) this.dummy.print(`out.append(", ");`)
168_.print(`WriteToString(&out, ${argConvertor.param});`)
169})
170_.print(`out.append(")");`)
171const retVal = method.dummyReturnValue
172if (retVal !== undefined) {
173_.print(`out.append("[return ${retVal}]");`)
174}
175_.print(`appendGroupedLog(1, out);`)
176this.printReturnStatement(this.dummy, method, retVal)
177}
178
179printModifierImplFunctionBody(method: PeerMethod) {
180const visitor = new MethodSeparatorPrinter(
181this.library.declarationTable,
182method
183)
184visitor.visit()
185// This is the entry point to delegate print.
186// visitor.printer.getOutput().forEach(it => this.real.print(it))
187this.printReturnStatement(this.real, method)
188}
189
190private printReturnStatement(printer: LanguageWriter, method: PeerMethod, returnValue: string | undefined = undefined) {
191if (!method.retConvertor.isVoid) {
192printer.print(`return ${returnValue ?? "0"};`)
193}
194}
195
196printMethodProlog(printer: LanguageWriter, method: PeerMethod) {
197const apiParameters = method.generateAPIParameters().join(", ")
198const signature = `${method.retType} ${method.implName}(${apiParameters}) {`
199printer.print(signature)
200printer.pushIndent()
201}
202
203printMethodEpilog(printer: LanguageWriter) {
204printer.popIndent()
205printer.print(`}`)
206}
207
208printRealAndDummyModifier(method: PeerMethod) {
209this.printMethodProlog(this.dummy, method)
210this.printMethodProlog(this.real, method)
211this.printDummyImplFunctionBody(method)
212this.printModifierImplFunctionBody(method)
213this.printMethodEpilog(this.dummy)
214this.printMethodEpilog(this.real)
215
216this.modifiers.print(`${method.implNamespaceName}::${method.implName},`)
217}
218
219printClassProlog(clazz: PeerClass) {
220const component = clazz.componentName
221const modifierStructImpl = `ArkUI${component}ModifierImpl`
222
223this.modifiers.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${component}Modifier* Get${component}Modifier() {`)
224this.modifiers.pushIndent()
225this.modifiers.print(`static const ${PeerGeneratorConfig.cppPrefix}ArkUI${component}Modifier ${modifierStructImpl} {`)
226this.modifiers.pushIndent()
227
228this.modifierList.print(`Get${component}Modifier,`)
229}
230
231printClassEpilog(clazz: PeerClass) {
232const name = clazz.componentName
233const modifierStructImpl = `ArkUI${name}ModifierImpl`
234
235this.modifiers.popIndent()
236this.modifiers.print(`};`)
237this.modifiers.print(`return &${modifierStructImpl};`)
238this.modifiers.popIndent()
239this.modifiers.print(`}\n`)
240
241this.getterDeclarations.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${name}Modifier* Get${name}Modifier();`)
242}
243
244pushNamespace(namespaceName: string) {
245this.real.print(`namespace ${namespaceName} {`)
246this.dummy.print(`namespace ${namespaceName} {`)
247this.real.pushIndent()
248this.dummy.pushIndent()
249}
250
251popNamespace(namespaceName: string) {
252this.real.popIndent()
253this.dummy.popIndent()
254this.real.print(`} // ${namespaceName}`)
255this.dummy.print(`} // ${namespaceName}`)
256}
257
258printPeerClassModifiers(clazz: PeerClass) {
259this.printClassProlog(clazz)
260// TODO: move to Object.groupBy when move to nodejs 21
261const namespaces: Map<string, PeerMethod[]> = groupBy(clazz.methods, it => it.implNamespaceName)
262Array.from(namespaces.keys()).forEach (namespaceName => {
263this.pushNamespace(namespaceName)
264namespaces.get(namespaceName)?.forEach(
265method => this.printRealAndDummyModifier(method)
266)
267this.popNamespace(namespaceName)
268})
269this.printClassEpilog(clazz)
270}
271
272// TODO: have a proper Peer module visitor
273printRealAndDummyModifiers() {
274this.library.files.forEach(file => {
275file.peers.forEach(clazz => this.printPeerClassModifiers(clazz))
276})
277}
278}
279
280class AccessorVisitor extends ModifierVisitor {
281accessors = createLanguageWriter(Language.CPP)
282accessorList = createLanguageWriter(Language.CPP)
283
284constructor(library: PeerLibrary) {
285super(library)
286}
287
288override printRealAndDummyModifiers() {
289super.printRealAndDummyModifiers()
290this.library.materializedClasses.forEach(c => this.printRealAndDummyAccessor(c))
291}
292
293printRealAndDummyAccessor(clazz: MaterializedClass) {
294this.printMaterializedClassProlog(clazz)
295// Materialized class methods share the same namespace
296// so take the first one.
297const namespaceName = clazz.methods[0].implNamespaceName
298this.pushNamespace(namespaceName);
299[clazz.ctor, clazz.finalizer].concat(clazz.methods).forEach(method => {
300this.printMaterializedMethod(this.dummy, method, m => this.printDummyImplFunctionBody(m))
301this.printMaterializedMethod(this.real, method, m => this.printModifierImplFunctionBody(m))
302this.accessors.print(`${method.implNamespaceName}::${method.implName},`)
303})
304this.popNamespace(namespaceName)
305this.printMaterializedClassEpilog(clazz)
306}
307
308printMaterializedClassProlog(clazz: MaterializedClass) {
309const accessor = `${clazz.className}Accessor`
310this.accessors.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${accessor}* Get${accessor}() {`)
311this.accessors.pushIndent()
312this.accessors.print(`static const ${PeerGeneratorConfig.cppPrefix}ArkUI${accessor} ${accessor}Impl {`)
313this.accessors.pushIndent()
314this.accessorList.print(`Get${accessor},`)
315}
316
317printMaterializedClassEpilog(clazz: MaterializedClass) {
318const accessor = `${clazz.className}Accessor`
319this.accessors.popIndent()
320this.accessors.print(`};`)
321this.accessors.print(`return &${accessor}Impl;`)
322this.accessors.popIndent()
323this.accessors.print(`}\n`)
324this.getterDeclarations.print(`const ${PeerGeneratorConfig.cppPrefix}ArkUI${accessor}* Get${accessor}();`)
325}
326
327printMaterializedMethod(printer: LanguageWriter, method: MaterializedMethod, printBody: (m: MaterializedMethod) => void) {
328this.printMethodProlog(printer, method)
329printBody(method)
330this.printMethodEpilog(printer)
331}
332}
333
334class MultiFileModifiersVisitorState {
335dummy = createLanguageWriter(Language.CPP)
336real = createLanguageWriter(Language.CPP)
337accessorList = createLanguageWriter(Language.CPP)
338accessors = createLanguageWriter(Language.CPP)
339modifierList = createLanguageWriter(Language.CPP)
340modifiers = createLanguageWriter(Language.CPP)
341getterDeclarations = createLanguageWriter(Language.CPP)
342}
343
344class MultiFileModifiersVisitor extends AccessorVisitor {
345private stateByFile = new Map<string, MultiFileModifiersVisitorState>()
346
347printPeerClassModifiers(clazz: PeerClass): void {
348this.onFileStart(clazz.componentName)
349super.printPeerClassModifiers(clazz)
350this.onFileEnd()
351}
352
353onFileStart(className: string) {
354const slug = makeFileNameFromClassName(className)
355let state = this.stateByFile.get(slug)
356if (!state) {
357state = new MultiFileModifiersVisitorState()
358this.stateByFile.set(slug, state)
359}
360this.dummy = state.dummy
361this.real = state.real
362this.accessors = state.accessors
363this.accessorList = state.accessorList
364this.modifiers = state.modifiers
365this.modifierList = state.modifierList
366this.getterDeclarations = state.getterDeclarations
367}
368
369onFileEnd() {
370}
371
372printRealAndDummyAccessor(clazz: MaterializedClass): void {
373this.onFileStart(clazz.className)
374super.printRealAndDummyAccessor(clazz)
375this.onFileEnd()
376}
377
378emitRealSync(libace: LibaceInstall, options: ModifierFileOptions): void {
379const modifierList = createLanguageWriter(Language.CPP)
380const accessorList = createLanguageWriter(Language.CPP)
381const getterDeclarations = createLanguageWriter(Language.CPP)
382
383for (const [slug, state] of this.stateByFile) {
384const filePath = libace.modifierCpp(slug)
385printModifiersImplFile(filePath, slug, state, options)
386modifierList.concat(state.modifierList)
387accessorList.concat(state.accessorList)
388getterDeclarations.concat(state.getterDeclarations)
389}
390
391const commonFilePath = libace.allModifiers
392const commonFileContent = getterDeclarations
393.concat(modifierStructList(modifierList))
394.concat(accessorStructList(accessorList))
395
396printModifiersCommonImplFile(commonFilePath, commonFileContent, options)
397printApiImplFile(libace.viewModelBridge, options)
398}
399}
400
401export function printRealAndDummyModifiers(peerLibrary: PeerLibrary): {dummy: LanguageWriter, real: LanguageWriter} {
402const visitor = new ModifierVisitor(peerLibrary)
403visitor.printRealAndDummyModifiers()
404const dummy =
405visitor.dummy.concat(visitor.modifiers).concat(modifierStructList(visitor.modifierList))
406const real =
407visitor.real.concat(visitor.modifiers).concat(modifierStructList(visitor.modifierList))
408return {dummy, real}
409}
410
411export function printRealAndDummyAccessors(peerLibrary: PeerLibrary): {dummy: LanguageWriter, real: LanguageWriter} {
412const visitor = new AccessorVisitor(peerLibrary)
413peerLibrary.materializedClasses.forEach(c => visitor.printRealAndDummyAccessor(c))
414
415const dummy =
416visitor.dummy.concat(visitor.accessors).concat(accessorStructList(visitor.accessorList))
417
418const real =
419visitor.real.concat(visitor.accessors).concat(accessorStructList(visitor.accessorList))
420return {dummy, real}
421}
422
423export interface Namespaces {
424generated: string,
425base: string
426}
427
428export interface ModifierFileOptions {
429basicVersion: number;
430fullVersion: number;
431extendedVersion: number;
432
433namespaces?: Namespaces
434}
435
436export function printRealModifiersAsMultipleFiles(library: PeerLibrary, libace: LibaceInstall, options: ModifierFileOptions) {
437const visitor = new MultiFileModifiersVisitor(library)
438visitor.printRealAndDummyModifiers()
439visitor.emitRealSync(libace, options)
440}
441
442function printModifiersImplFile(filePath: string, slug: string, state: MultiFileModifiersVisitorState, options: ModifierFileOptions) {
443const writer = new CppLanguageWriter(new IndentedPrinter())
444writer.writeLines(cStyleCopyright)
445
446writer.writeInclude(`arkoala_api_generated.h`)
447writer.print("")
448
449if (options.namespaces) {
450writer.pushNamespace(options.namespaces.generated)
451}
452
453writer.concat(state.real)
454writer.concat(state.modifiers)
455writer.concat(state.accessors)
456
457if (options.namespaces) {
458writer.popNamespace()
459}
460
461writer.print("")
462writer.printTo(filePath)
463}
464
465function printModifiersCommonImplFile(filePath: string, content: LanguageWriter, options: ModifierFileOptions) {
466const writer = new CppLanguageWriter(new IndentedPrinter())
467writer.writeLines(cStyleCopyright)
468writer.writeMultilineCommentBlock(warning)
469writer.print("")
470
471writer.writeInclude('arkoala-macros.h')
472writer.writeInclude('core/interfaces/arkoala/arkoala_api.h')
473writer.writeInclude('node_api.h')
474writer.print("")
475
476if (options.namespaces) {
477writer.pushNamespace(options.namespaces.base)
478}
479writer.concat(appendModifiersCommonPrologue())
480
481if (options.namespaces) {
482writer.popNamespace()
483}
484
485writer.print("")
486
487if (options.namespaces) {
488writer.pushNamespace(options.namespaces.generated)
489}
490
491writer.concat(completeModifiersContent(content, options.basicVersion, options.fullVersion, options.extendedVersion))
492
493if (options.namespaces) {
494writer.popNamespace()
495}
496
497writer.print("")
498writer.printTo(filePath)
499}
500
501function printApiImplFile(filePath: string, options: ModifierFileOptions) {
502const writer = new CppLanguageWriter(new IndentedPrinter())
503writer.writeLines(cStyleCopyright)
504writer.writeMultilineCommentBlock(warning)
505writer.print("")
506
507writer.writeInclude('core/interfaces/arkoala/arkoala_api.h')
508writer.writeInclude('arkoala_api_generated.h')
509writer.writeInclude('base/utils/utils.h')
510writer.writeInclude('core/pipeline/base/element_register.h')
511writer.print("")
512
513if (options.namespaces) {
514writer.pushNamespace(options.namespaces.base)
515}
516writer.concat(appendViewModelBridge())
517
518if (options.namespaces) {
519writer.popNamespace()
520}
521
522writer.printTo(filePath)
523}
524