idlize
239 строк · 10.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 { Language, renameClassToMaterialized, capitalize } from "../../util";
18import { PeerLibrary } from "../PeerLibrary";
19import { writePeerMethod } from "./PeersPrinter"
20import { LanguageWriter, MethodModifier, NamedMethodSignature, Method, Type, createLanguageWriter, FieldModifier, MethodSignature } from "../LanguageWriters";
21import { MaterializedClass, MaterializedMethod } from "../Materialized"
22import { makeMaterializedPrologue, tsCopyrightAndWarning } from "../FileGenerators";
23import { OverloadsPrinter, groupOverloads } from "./OverloadsPrinter";
24
25import { printPeerFinalizer } from "./PeersPrinter"
26import { ImportsCollector } from "../ImportsCollector";
27
28class MaterializedFileVisitor {
29
30readonly printer: LanguageWriter = createLanguageWriter(this.language)
31private overloadsPrinter = new OverloadsPrinter(this.printer, this.library, false)
32
33constructor(
34private readonly language: Language,
35private readonly library: PeerLibrary,
36private readonly clazz: MaterializedClass,
37private readonly dumpSerialized: boolean,
38) {}
39
40private printImports() {
41const imports = new ImportsCollector()
42imports.addFilterByBasename(renameClassToMaterialized(this.clazz.className, this.library.declarationTable.language))
43this.clazz.importFeatures.forEach(it => imports.addFeature(it.feature, it.module))
44imports.print(this.printer)
45}
46
47private printMaterializedClass(clazz: MaterializedClass) {
48this.printImports()
49const printer = this.printer
50printer.print(makeMaterializedPrologue(this.language))
51
52const superClass = clazz.superClass
53let superClassName = superClass ? `${superClass.name}${superClass.generics ? `<${superClass.generics.join(", ")}>` : ""}` : undefined
54const selfInterface = clazz.isInterface ? `${clazz.className}${clazz.generics ? `<${clazz.generics.join(", ")}>` : `` }` : undefined
55
56const interfaces: string[] = []
57if (clazz.isInterface) {
58if (selfInterface) interfaces.push(selfInterface)
59if (superClassName && !this.library.materializedClasses.has(superClassName)) {
60interfaces.push(superClassName)
61superClassName = undefined
62}
63}
64
65printer.writeClass(clazz.className, writer => {
66
67const finalizableType = new Type("Finalizable")
68writer.writeFieldDeclaration("peer", finalizableType, undefined, true)
69
70let fieldAccessors: MaterializedMethod[] = []
71
72// getters and setters for fields
73clazz.fields.forEach(f => {
74
75const field = f.field
76
77// TBD: use deserializer to get complex type from native
78const isSimpleType = !f.argConvertor.useArray // type needs to be deserialized from the native
79if (isSimpleType) {
80const getSignature = new MethodSignature(field.type, [])
81writer.writeGetterImplementation(new Method(field.name, getSignature), writer => {
82writer.writeStatement(
83writer.makeReturn(
84writer.makeMethodCall("this", `get${capitalize(field.name)}`, [])))
85});
86
87const getAccessor = new MaterializedMethod(clazz.className, [], [], f.retConvertor, false,
88new Method(`get${capitalize(field.name)}`, new NamedMethodSignature(field.type, [], []))
89)
90
91fieldAccessors = fieldAccessors.concat(getAccessor)
92}
93
94const isReadOnly = field.modifiers.includes(FieldModifier.READONLY)
95if (!isReadOnly) {
96const setSignature = new NamedMethodSignature(Type.Void, [field.type], [field.name])
97writer.writeSetterImplementation(new Method(field.name, setSignature), writer => {
98writer.writeMethodCall("this", `set${capitalize(field.name)}`, [field.name])
99});
100
101const retConvertor = { isVoid: true, nativeType: () => Type.Void.name, macroSuffixPart: () => "V" }
102const setAccessor = new MaterializedMethod(clazz.className, [f.declarationTarget], [f.argConvertor], retConvertor, false,
103new Method(`set${capitalize(field.name)}`, setSignature)
104)
105fieldAccessors = fieldAccessors.concat(setAccessor)
106}
107})
108
109clazz.methods = fieldAccessors.concat(clazz.methods)
110
111const pointerType = Type.Pointer
112// makePrivate(clazz.ctor.method)
113this.library.declarationTable.setCurrentContext(`${clazz.className}.constructor`)
114writePeerMethod(writer, clazz.ctor, this.dumpSerialized, "", "", pointerType)
115this.library.declarationTable.setCurrentContext(undefined)
116
117const ctorSig = clazz.ctor.method.signature as NamedMethodSignature
118const sigWithPointer = new NamedMethodSignature(
119ctorSig.returnType,
120ctorSig.args.map(it => new Type(it.name, true)),
121ctorSig.argsNames,
122ctorSig.defaults)
123
124writer.writeConstructorImplementation(clazz.className, sigWithPointer, writer => {
125
126if (superClassName) {
127writer.writeSuperCall([]);
128}
129
130const allOptional = ctorSig.args.every(it => it.nullable)
131const hasStaticMethods = clazz.methods.some(it => it.method.modifiers?.includes(MethodModifier.STATIC))
132const allUndefined = ctorSig.argsNames.map(it => `${it} === undefined`).join(` && `)
133
134if (hasStaticMethods) {
135if (allOptional) {
136if (ctorSig.args.length == 0) {
137writer.print(`// Constructor does not have parameters.`)
138} else {
139writer.print(`// All constructor parameters are optional.`)
140}
141writer.print(`// It means that the static method call invokes ctor method as well`)
142writer.print(`// when all arguments are undefined.`)
143} else {
144writer.writeStatement(
145writer.makeCondition(
146writer.makeString(ctorSig.args.length === 0 ? "true" : allUndefined),
147writer.makeReturn()
148)
149)
150}
151}
152
153const args = ctorSig.args.map((it, index) => writer.makeString(`${ctorSig.argsNames[index]}${it.nullable ? "" : "!"}`))
154writer.writeStatement(
155writer.makeAssign("ctorPtr", Type.Pointer,
156writer.makeMethodCall(clazz.className, "ctor", args),
157true))
158
159writer.writeStatement(writer.makeAssign(
160"this.peer",
161finalizableType,
162writer.makeString(`new Finalizable(ctorPtr, ${clazz.className}.getFinalizer())`),
163false
164))
165})
166
167printPeerFinalizer(clazz, writer)
168
169for (const grouped of groupOverloads(clazz.methods)) {
170this.overloadsPrinter.printGroupedComponentOverloads(clazz, grouped)
171}
172
173clazz.methods.forEach(method => {
174makePrivate(method.method)
175const returnType = method.tsReturnType()
176this.library.declarationTable.setCurrentContext(`${method.originalParentName}.${method.overloadedName}`)
177writePeerMethod(writer, method, this.dumpSerialized, "_serialize", "this.peer!.ptr", returnType)
178this.library.declarationTable.setCurrentContext(undefined)
179})
180}, superClassName, interfaces.length === 0 ? undefined : interfaces, clazz.generics)
181}
182
183printFile(): void {
184this.printMaterializedClass(this.clazz)
185}
186
187private getReturnValue(className: string, retType: string| undefined): string| undefined {
188if (retType === undefined || retType === "void") {
189return ""
190} else if(retType === className) {
191return (`this`)
192} else if (retType === "boolean") {
193return `true`
194} else {
195return undefined
196}
197}
198}
199
200class MaterializedVisitor {
201readonly materialized: Map<string, string[]> = new Map()
202
203constructor(
204private readonly library: PeerLibrary,
205private readonly dumpSerialized: boolean,
206) {}
207
208printMaterialized(): void {
209console.log(`Materialized classes: ${this.library.materializedClasses.size}`)
210for (const clazz of this.library.materializedClasses.values()) {
211const visitor = new MaterializedFileVisitor(
212this.library.declarationTable.language, this.library, clazz, this.dumpSerialized)
213visitor.printFile()
214const fileName = renameClassToMaterialized(clazz.className, this.library.declarationTable.language)
215this.materialized.set(fileName, visitor.printer.getOutput())
216}
217}
218}
219
220export function printMaterialized(peerLibrary: PeerLibrary, dumpSerialized: boolean): Map<string, string> {
221
222// TODO: support other output languages
223if (peerLibrary.declarationTable.language != Language.TS)
224return new Map()
225
226const visitor = new MaterializedVisitor(peerLibrary, dumpSerialized)
227visitor.printMaterialized()
228const result = new Map<string, string>()
229for (const [key, content] of visitor.materialized) {
230if (content.length === 0) continue
231const text = tsCopyrightAndWarning(content.join('\n'))
232result.set(key, text)
233}
234return result
235}
236
237function makePrivate(method: Method) {
238method.modifiers?.unshift(MethodModifier.PRIVATE)
239}