idlize

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

16
import { IndentedPrinter } from "../../IndentedPrinter";
17
import { Language, renameClassToMaterialized, capitalize } from "../../util";
18
import { PeerLibrary } from "../PeerLibrary";
19
import { writePeerMethod } from "./PeersPrinter"
20
import { LanguageWriter, MethodModifier, NamedMethodSignature, Method, Type, createLanguageWriter, FieldModifier, MethodSignature } from "../LanguageWriters";
21
import { MaterializedClass, MaterializedMethod } from "../Materialized"
22
import { makeMaterializedPrologue, tsCopyrightAndWarning } from "../FileGenerators";
23
import { OverloadsPrinter, groupOverloads } from "./OverloadsPrinter";
24

25
import { printPeerFinalizer } from "./PeersPrinter"
26
import { ImportsCollector } from "../ImportsCollector";
27

28
class MaterializedFileVisitor {
29

30
    readonly printer: LanguageWriter = createLanguageWriter(this.language)
31
    private overloadsPrinter = new OverloadsPrinter(this.printer, this.library, false)
32

33
    constructor(
34
        private readonly language: Language,
35
        private readonly library: PeerLibrary,
36
        private readonly clazz: MaterializedClass,
37
        private readonly dumpSerialized: boolean,
38
    ) {}
39

40
    private printImports() {
41
        const imports = new ImportsCollector()
42
        imports.addFilterByBasename(renameClassToMaterialized(this.clazz.className, this.library.declarationTable.language))
43
        this.clazz.importFeatures.forEach(it => imports.addFeature(it.feature, it.module))
44
        imports.print(this.printer)
45
    }
46

47
    private printMaterializedClass(clazz: MaterializedClass) {
48
        this.printImports()
49
        const printer = this.printer
50
        printer.print(makeMaterializedPrologue(this.language))
51

52
        const superClass = clazz.superClass
53
        let superClassName = superClass ? `${superClass.name}${superClass.generics ? `<${superClass.generics.join(", ")}>` : ""}` : undefined
54
        const selfInterface = clazz.isInterface ? `${clazz.className}${clazz.generics ? `<${clazz.generics.join(", ")}>` : `` }` : undefined
55

56
        const interfaces: string[] = []
57
        if (clazz.isInterface) {
58
            if (selfInterface) interfaces.push(selfInterface)
59
            if (superClassName && !this.library.materializedClasses.has(superClassName)) {
60
                interfaces.push(superClassName)
61
                superClassName = undefined
62
            }
63
        }
64

65
        printer.writeClass(clazz.className, writer => {
66

67
            const finalizableType = new Type("Finalizable")
68
            writer.writeFieldDeclaration("peer", finalizableType, undefined, true)
69

70
            let fieldAccessors: MaterializedMethod[] = []
71

72
            // getters and setters for fields
73
            clazz.fields.forEach(f => {
74

75
                const field = f.field
76

77
                // TBD: use deserializer to get complex type from native
78
                const isSimpleType = !f.argConvertor.useArray // type needs to be deserialized from the native
79
                if (isSimpleType) {
80
                    const getSignature = new MethodSignature(field.type, [])
81
                    writer.writeGetterImplementation(new Method(field.name, getSignature), writer => {
82
                        writer.writeStatement(
83
                            writer.makeReturn(
84
                                writer.makeMethodCall("this", `get${capitalize(field.name)}`, [])))
85
                    });
86

87
                    const getAccessor = new MaterializedMethod(clazz.className, [], [], f.retConvertor, false,
88
                        new Method(`get${capitalize(field.name)}`, new NamedMethodSignature(field.type, [], []))
89
                    )
90

91
                    fieldAccessors = fieldAccessors.concat(getAccessor)
92
                }
93

94
                const isReadOnly = field.modifiers.includes(FieldModifier.READONLY)
95
                if (!isReadOnly) {
96
                    const setSignature = new NamedMethodSignature(Type.Void, [field.type], [field.name])
97
                    writer.writeSetterImplementation(new Method(field.name, setSignature), writer => {
98
                        writer.writeMethodCall("this", `set${capitalize(field.name)}`, [field.name])
99
                    });
100

101
                    const retConvertor = { isVoid: true, nativeType: () => Type.Void.name, macroSuffixPart: () => "V" }
102
                    const setAccessor = new MaterializedMethod(clazz.className, [f.declarationTarget], [f.argConvertor], retConvertor, false,
103
                        new Method(`set${capitalize(field.name)}`, setSignature)
104
                    )
105
                    fieldAccessors = fieldAccessors.concat(setAccessor)
106
                }
107
            })
108

109
            clazz.methods = fieldAccessors.concat(clazz.methods)
110

111
            const pointerType = Type.Pointer
112
            // makePrivate(clazz.ctor.method)
113
            this.library.declarationTable.setCurrentContext(`${clazz.className}.constructor`)
114
            writePeerMethod(writer, clazz.ctor, this.dumpSerialized, "", "", pointerType)
115
            this.library.declarationTable.setCurrentContext(undefined)
116

117
            const ctorSig = clazz.ctor.method.signature as NamedMethodSignature
118
            const sigWithPointer = new NamedMethodSignature(
119
                ctorSig.returnType,
120
                ctorSig.args.map(it => new Type(it.name, true)),
121
                ctorSig.argsNames,
122
                ctorSig.defaults)
123

124
            writer.writeConstructorImplementation(clazz.className, sigWithPointer, writer => {
125

126
                if (superClassName) {
127
                    writer.writeSuperCall([]);
128
                }
129

130
                const allOptional = ctorSig.args.every(it => it.nullable)
131
                const hasStaticMethods = clazz.methods.some(it => it.method.modifiers?.includes(MethodModifier.STATIC))
132
                const allUndefined = ctorSig.argsNames.map(it => `${it} === undefined`).join(` && `)
133

134
                if (hasStaticMethods) {
135
                    if (allOptional) {
136
                        if (ctorSig.args.length == 0) {
137
                            writer.print(`// Constructor does not have parameters.`)
138
                        } else {
139
                            writer.print(`// All constructor parameters are optional.`)
140
                        }
141
                        writer.print(`// It means that the static method call invokes ctor method as well`)
142
                        writer.print(`// when all arguments are undefined.`)
143
                    } else {
144
                        writer.writeStatement(
145
                            writer.makeCondition(
146
                                writer.makeString(ctorSig.args.length === 0 ? "true" : allUndefined),
147
                                writer.makeReturn()
148
                            )
149
                        )
150
                    }
151
                }
152

153
                const args = ctorSig.args.map((it, index) => writer.makeString(`${ctorSig.argsNames[index]}${it.nullable ? "" : "!"}`))
154
                writer.writeStatement(
155
                    writer.makeAssign("ctorPtr", Type.Pointer,
156
                        writer.makeMethodCall(clazz.className, "ctor", args),
157
                        true))
158

159
                writer.writeStatement(writer.makeAssign(
160
                    "this.peer",
161
                    finalizableType,
162
                    writer.makeString(`new Finalizable(ctorPtr, ${clazz.className}.getFinalizer())`),
163
                    false
164
                ))
165
            })
166

167
            printPeerFinalizer(clazz, writer)
168

169
            for (const grouped of groupOverloads(clazz.methods)) {
170
                this.overloadsPrinter.printGroupedComponentOverloads(clazz, grouped)
171
            }
172

173
            clazz.methods.forEach(method => {
174
                makePrivate(method.method)
175
                const returnType = method.tsReturnType()
176
                this.library.declarationTable.setCurrentContext(`${method.originalParentName}.${method.overloadedName}`)
177
                writePeerMethod(writer, method, this.dumpSerialized, "_serialize", "this.peer!.ptr", returnType)
178
                this.library.declarationTable.setCurrentContext(undefined)
179
            })
180
        }, superClassName, interfaces.length === 0 ? undefined : interfaces, clazz.generics)
181
    }
182

183
    printFile(): void {
184
        this.printMaterializedClass(this.clazz)
185
    }
186

187
    private getReturnValue(className: string, retType: string| undefined): string| undefined {
188
        if (retType === undefined || retType === "void") {
189
            return ""
190
        } else if(retType === className) {
191
            return (`this`)
192
        } else if (retType === "boolean") {
193
            return `true`
194
        } else {
195
            return undefined
196
        }
197
    }
198
}
199

200
class MaterializedVisitor {
201
    readonly materialized: Map<string, string[]> = new Map()
202

203
    constructor(
204
        private readonly library: PeerLibrary,
205
        private readonly dumpSerialized: boolean,
206
    ) {}
207

208
    printMaterialized(): void {
209
        console.log(`Materialized classes: ${this.library.materializedClasses.size}`)
210
        for (const clazz of this.library.materializedClasses.values()) {
211
            const visitor = new MaterializedFileVisitor(
212
                this.library.declarationTable.language, this.library, clazz, this.dumpSerialized)
213
            visitor.printFile()
214
            const fileName = renameClassToMaterialized(clazz.className, this.library.declarationTable.language)
215
            this.materialized.set(fileName, visitor.printer.getOutput())
216
        }
217
    }
218
}
219

220
export function printMaterialized(peerLibrary: PeerLibrary, dumpSerialized: boolean): Map<string, string> {
221

222
    // TODO: support other output languages
223
    if (peerLibrary.declarationTable.language != Language.TS)
224
        return new Map()
225

226
    const visitor = new MaterializedVisitor(peerLibrary, dumpSerialized)
227
    visitor.printMaterialized()
228
    const result = new Map<string, string>()
229
    for (const [key, content] of visitor.materialized) {
230
        if (content.length === 0) continue
231
        const text = tsCopyrightAndWarning(content.join('\n'))
232
        result.set(key, text)
233
    }
234
    return result
235
}
236

237
function makePrivate(method: Method) {
238
    method.modifiers?.unshift(MethodModifier.PRIVATE)
239
}

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

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

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

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