idlize

Форк
0
/
deserialize.ts 
287 строк · 9.4 Кб
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 * as webidl2 from "webidl2"
17
import {
18
    isAttribute, isCallback, isClass, isConstructor, isDictionary, isEnum, isInterface, isOperation, isOptional,
19
    isPromiseTypeDescription,
20
    isRecordTypeDescription,
21
    isSequenceTypeDescription,
22
    isSingleTypeDescription, isTypedef, isUnionTypeDescription
23
} from "./webidl2-utils"
24
import { toString } from "./toString"
25
import {
26
    createContainerType, createNumberType, createUnionType, hasExtAttribute, IDLCallback, IDLConstructor, IDLEntry, IDLEnum, IDLEnumMember, IDLExtendedAttribute, IDLInterface, IDLKind,
27
    IDLMethod, IDLModuleType, IDLParameter, IDLPrimitiveType, IDLProperty, IDLType, IDLTypedef
28
} from "../idl"
29
import { isDefined, stringOrNone } from "../util"
30

31
export function toIDLNode(file: string, node: webidl2.IDLRootType): IDLEntry {
32
    if (isEnum(node)) {
33
        return toIDLEnum(file, node)
34
    }
35
    if (isClass(node)) {
36
        return toIDLInterface(file, node)
37
    }
38
    if (isInterface(node)) {
39
        return toIDLInterface(file, node)
40
    }
41
    if (isCallback(node)) {
42
        return toIDLCallback(file, node)
43
    }
44
    if (isTypedef(node)) {
45
        return toIDLTypedef(file, node)
46
    }
47
    if (isDictionary(node)) {
48
        return toIDLDictionary(file, node)
49
    }
50
    if (isNamespace(node)) {
51
        return toIDLNamespcae(file, node)
52
    }
53

54
    throw new Error(`unexpected node type: ${toString(node)}`)
55
}
56

57

58
function isNamespace(node: webidl2.IDLRootType): node is webidl2.NamespaceType {
59
    return node.type === 'namespace'
60
}
61
function isCallable(node: webidl2.IDLInterfaceMemberType): boolean {
62
    return node.extAttrs.some(it => it.name == "Invoke")
63
}
64

65
function toIDLInterface(file: string, node: webidl2.InterfaceType): IDLInterface {
66
    return {
67
        kind: isClass(node) ? IDLKind.Class : IDLKind.Interface,
68
        name: node.name,
69
        fileName: file,
70
        documentation: makeDocs(node),
71
        inheritance: [node.inheritance]
72
            .filter(isDefined)
73
            .map(it => toIDLType(file, it)),
74
        constructors: node.members
75
            .filter(isConstructor)
76
            .map(it => toIDLConstructor(file, it)),
77
        constants: [],
78
        properties: node.members
79
            .filter(isAttribute)
80
            .map(it => toIDLProperty(file, it)),
81
        methods: node.members
82
            .filter(isOperation)
83
            .filter(it => !isCallable(it))
84
            .map(it => toIDLMethod(file, it)),
85
        extendedAttributes: toExtendedAttributes(node.extAttrs),
86
        callables: node.members
87
            .filter(isOperation)
88
            .filter(it => isCallable(it))
89
            .map(it => toIDLMethod(file, it)),
90
    }
91
}
92

93
function toTypeParams(extAttrs: webidl2.ExtendedAttribute[] | undefined) {
94
    let result = undefined
95
    extAttrs?.forEach(it => {
96
        if (it.name === "TypeParameters") result = toExtendedAttributeValue(it)
97
    })
98
    return result
99
}
100

101
function toIDLType(file: string, type: webidl2.IDLTypeDescription | string, extAttrs?: webidl2.ExtendedAttribute[]): IDLType {
102
    if (typeof type === "string") {
103
        const typeParams = toTypeParams(extAttrs)
104
        return {
105
            name: type,
106
            fileName: file,
107
            kind: IDLKind.ReferenceType,
108
            extendedAttributes: typeParams ? [{ "name": "TypeParameters", value: typeParams }] : []
109
        }
110
    }
111
    if (isUnionTypeDescription(type)) {
112
        const unionTypes = type.idlType
113
        return createUnionType(unionTypes
114
            .map(it => toIDLType(file, it))
115
            .filter(isDefined))
116
    }
117
    if (isSingleTypeDescription(type)) {
118
        return {
119
            name: type.idlType,
120
            fileName: file,
121
            kind: IDLKind.ReferenceType,
122
            extendedAttributes: toExtendedAttributes(type.extAttrs)?.concat(
123
                toExtendedAttributes(extAttrs ?? []) ?? [])
124
        }
125
    }
126
    if (isSequenceTypeDescription(type) || isPromiseTypeDescription(type) || isRecordTypeDescription(type)) {
127
        return createContainerType(
128
            type.generic,
129
            type.idlType.map(it => toIDLType(file, it))
130
        )
131
    }
132

133
    throw new Error(`unexpected type: ${toString(type)}`)
134
}
135

136

137
function toIDLMethod(file: string, node: webidl2.OperationMemberType): IDLMethod {
138
    if (!node.idlType) {
139
        throw new Error(`method with no type ${toString(node)}`)
140
    }
141
    return {
142
        name: node.name ?? "",
143
        isStatic: node.special === "static",
144
        parameters: node.arguments.map(it => toIDLParameter(file, it)),
145
        documentation: makeDocs(node),
146
        returnType: toIDLType(file, node.idlType, node.extAttrs),
147
        extendedAttributes: toExtendedAttributes(node.extAttrs),
148
        kind: IDLKind.Method,
149
        isOptional: isOptional(node)
150
    }
151
}
152

153
function toIDLConstructor(file: string, node: webidl2.ConstructorMemberType): IDLConstructor {
154
    return {
155
        parameters: node.arguments.map(it => toIDLParameter(file, it)),
156
        documentation: makeDocs(node),
157
        kind: IDLKind.Constructor
158
    }
159
}
160

161
function toIDLParameter(file: string, node: webidl2.Argument): IDLParameter {
162
    return {
163
        kind: IDLKind.Parameter,
164
        fileName: file,
165
        isVariadic: node.variadic,
166
        isOptional: node.optional,
167
        type: toIDLType(file, node.idlType, node.extAttrs),
168
        name: node.name
169
    }
170
}
171

172
function toIDLCallback(file: string, node: webidl2.CallbackType): IDLCallback {
173
    return {
174
        kind: IDLKind.Callback,
175
        name: node.name,
176
        fileName: file,
177
        parameters: node.arguments.map(it => toIDLParameter(file, it)),
178
        extendedAttributes: toExtendedAttributes(node.extAttrs),
179
        documentation: makeDocs(node),
180
        returnType: toIDLType(file, node.idlType)
181
    }
182
}
183

184
function toIDLTypedef(file: string, node: webidl2.TypedefType): IDLTypedef {
185
    return {
186
        kind: IDLKind.Typedef,
187
        type: toIDLType(file, node.idlType),
188
        extendedAttributes: toExtendedAttributes(node.extAttrs),
189
        documentation: makeDocs(node),
190
        fileName: file,
191
        name: node.name
192
    }
193
}
194

195
function toIDLDictionary(file: string, node: webidl2.DictionaryType): IDLEnum {
196
    return {
197
        kind: IDLKind.Enum,
198
        name: node.name,
199
        documentation: makeDocs(node),
200
        extendedAttributes: toExtendedAttributes(node.extAttrs),
201
        fileName: file,
202
        elements: node.members.map(it => toIDLEnumMember(file, it))
203
    }
204
}
205

206
function toIDLNamespcae(file: string, node: webidl2.NamespaceType): IDLModuleType {
207

208
    return {
209
        kind: IDLKind.ModuleType,
210
        name: node.name,
211
        extendedAttributes: toExtendedAttributes(node.extAttrs),
212
        fileName: file
213
    }
214
}
215

216
function toIDLProperty(file: string, node: webidl2.AttributeMemberType): IDLProperty {
217
    return {
218
        kind: IDLKind.Property,
219
        name: node.name,
220
        documentation: makeDocs(node),
221
        fileName: file,
222
        type: toIDLType(file, node.idlType),
223
        isReadonly: node.readonly,
224
        isStatic: node.special === "static",
225
        isOptional: isOptional(node),
226
        extendedAttributes: toExtendedAttributes(node.extAttrs)
227
    }
228
}
229

230
function toIDLEnumMember(file: string, node: webidl2.DictionaryMemberType): IDLEnumMember {
231
    let initializer = undefined
232
    if (node.default?.type == "string") {
233
        initializer = node.default?.value
234
    } else if (node.default?.type == "number") {
235
        initializer = +(node.default?.value)
236
    } else if (node.default == null) {
237
        initializer = undefined
238
    } else {
239
        throw new Error(`Not representable enum initializer: ${node.default}`)
240
    }
241
    return {
242
        kind: IDLKind.EnumMember,
243
        name: node.name,
244
        type: toIDLType(file, node.idlType) as IDLPrimitiveType,
245
        extendedAttributes: toExtendedAttributes(node.extAttrs),
246
        initializer: initializer
247
    }
248
}
249

250
function toExtendedAttributes(extAttrs: webidl2.ExtendedAttribute[]): IDLExtendedAttribute[]|undefined {
251
    return extAttrs.map(it => {
252
        return { name: it.name, value: toExtendedAttributeValue(it) }
253
    })
254
}
255

256
function toExtendedAttributeValue(attr: webidl2.ExtendedAttribute): stringOrNone {
257
    // TODO: be smarter about RHS.
258
    return attr.rhs?.value instanceof Array
259
            ? attr.rhs.value.map(v => v.value).join(",")
260
            : attr.rhs?.value
261
}
262

263
function makeDocs(node: webidl2.AbstractBase): stringOrNone {
264
    let docs = undefined
265
    node.extAttrs.forEach(it => {
266
        if (it.name == "Documentation") docs = it.rhs?.value
267
    })
268
    return docs
269
}
270

271
function toIDLEnum(file: string, node: webidl2.EnumType): IDLEnum {
272
    return {
273
        kind: IDLKind.Enum,
274
        name: node.name,
275
        fileName: file,
276
        documentation: makeDocs(node),
277
        extendedAttributes: toExtendedAttributes(node.extAttrs),
278
        elements: node.values.map((it: { value: string }) => {
279
            return {
280
                kind: IDLKind.EnumMember,
281
                name: it.value,
282
                type: createNumberType(),
283
                initializer: undefined
284
            }
285
        })
286
    }
287
}
288

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

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

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

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