idlize
172 строки · 5.8 Кб
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
17import { capitalize } from "../util"
18import { ArgConvertor, OptionConvertor, RetConvertor } from "./Convertors"
19import { Method, MethodModifier, mangleMethodName } from "./LanguageWriters"
20import { DeclarationTable, DeclarationTarget, FieldRecord, PrimitiveType, StructVisitor } from "./DeclarationTable"
21
22export class PeerMethod {
23constructor(
24public originalParentName: string,
25public declarationTargets: DeclarationTarget[],
26public argConvertors: ArgConvertor[],
27public retConvertor: RetConvertor,
28public isCallSignature: boolean,
29public isOverloaded: boolean,
30public method: Method
31) { }
32
33public hasReceiver(): boolean {
34return !this.method.modifiers?.includes(MethodModifier.STATIC)
35}
36
37get overloadedName(): string {
38return this.isOverloaded ? mangleMethodName(this.method) : this.method.name
39}
40
41get fullMethodName(): string {
42return this.isCallSignature ? this.overloadedName : this.peerMethodName
43}
44
45get peerMethodName() {
46const name = this.overloadedName
47if (!this.hasReceiver()) return name
48if (name.startsWith("set") ||
49name.startsWith("get") ||
50name.startsWith("_set")
51) return name
52return `set${capitalize(name)}`
53}
54
55get implNamespaceName(): string {
56return `${capitalize(this.originalParentName)}Modifier`
57}
58
59get implName(): string {
60return `${capitalize(this.overloadedName)}Impl`
61}
62
63get toStringName(): string {
64return this.method.name
65}
66
67get dummyReturnValue(): string | undefined {
68return undefined
69}
70
71get retType(): string {
72return this.maybeCRetType(this.retConvertor) ?? "void"
73}
74
75get receiverType(): string {
76return "Ark_NodeHandle"
77}
78
79get apiCall(): string {
80return "GetNodeModifiers()"
81}
82
83get apiKind(): string {
84return "Modifier"
85}
86
87maybeCRetType(retConvertor: RetConvertor): string | undefined {
88if (retConvertor.isVoid) return undefined
89return retConvertor.nativeType()
90}
91
92generateAPIParameters(): string[] {
93const args = this.argConvertors.map(it => {
94let isPointer = it.isPointerType()
95return `${isPointer ? "const ": ""}${it.nativeType(false)}${isPointer ? "*": ""} ${it.param}`
96})
97const receiver = this.generateReceiver()
98if (receiver) return [`${receiver.argType} ${receiver.argName}`, ...args]
99return args
100}
101
102generateReceiver(): {argName: string, argType: string} | undefined {
103if (!this.hasReceiver()) return undefined
104return {
105argName: "node",
106argType: PrimitiveType.NativePointer.getText()
107}
108}
109
110static markOverloads(methods: PeerMethod[]): void {
111for (const peerMethod of methods)
112peerMethod.isOverloaded = false
113
114for (const peerMethod of methods) {
115if (peerMethod.isOverloaded) continue
116const sameNamedMethods = methods.filter(it => it.method.name === peerMethod.method.name)
117if (sameNamedMethods.length <= 1) continue
118sameNamedMethods.forEach((method) => method.isOverloaded = true)
119}
120}
121}
122
123export class MethodSeparatorVisitor {
124constructor(
125protected readonly declarationTable: DeclarationTable,
126protected readonly method: PeerMethod,
127) {}
128
129protected onPushUnionScope(argIndex: number, field: FieldRecord, selectorValue: number): void {}
130protected onPopUnionScope(argIndex: number) {}
131protected onPushOptionScope(argIndex: number, target: DeclarationTarget, exists: boolean): void {}
132protected onPopOptionScope(argIndex: number): void {}
133protected onVisitInseparableArg(argIndex: number) {}
134protected onVisitInseparable() {}
135
136private visitArg(argIndex: number): void {
137if (argIndex >= this.method.argConvertors.length) {
138this.onVisitInseparable()
139return
140}
141
142const visitor: StructVisitor = {
143visitUnionField: (field: FieldRecord, selectorValue: number) => {
144this.onPushUnionScope(argIndex, field, selectorValue)
145this.declarationTable.visitDeclaration(field.declaration, visitor)
146this.onPopUnionScope(argIndex)
147},
148visitInseparable: () => {
149this.onVisitInseparableArg(argIndex)
150this.visitArg(argIndex + 1)
151}
152}
153if (this.method.argConvertors[argIndex] instanceof OptionConvertor) {
154// todo does we have optionals only on root?
155const conv = this.method.argConvertors[argIndex] as OptionConvertor
156const target = this.declarationTable.toTarget(conv.type)
157
158this.onPushOptionScope(argIndex, target, true)
159this.declarationTable.visitDeclaration(target, visitor)
160this.onPopOptionScope(argIndex)
161
162this.onPushOptionScope(argIndex, target, false)
163visitor.visitInseparable()
164this.onPopOptionScope(argIndex)
165} else
166this.declarationTable.visitDeclaration(this.method.declarationTargets[argIndex], visitor)
167}
168
169visit(): void {
170this.visitArg(0)
171}
172}