16
import { IDLEntry, forEachChild, isCallback, isClass, isEnum, isInterface, isTypedef } from "./idl"
30
export class TypeInfo {
32
public kind: TypeKind,
33
public declaration: IDLEntry|undefined,
34
public location: string|undefined = undefined
38
function createPrimitiveType(): TypeInfo {
39
return new TypeInfo(TypeKind.Primitive, undefined, undefined)
42
function createContainerType(): TypeInfo {
43
return new TypeInfo(TypeKind.Container, undefined, undefined)
46
function createReferenceType(idl: IDLEntry, kind: TypeKind): TypeInfo {
47
return new TypeInfo(TypeKind.Interface, idl, idl.fileName)
50
export class TypeTable {
51
table = new Map<string, TypeInfo[]>([
52
["undefined", [new TypeInfo(TypeKind.Primitive, undefined, undefined)]],
53
["boolean", [new TypeInfo(TypeKind.Primitive, undefined, undefined)]],
54
["DOMString", [new TypeInfo(TypeKind.String, undefined, undefined)]],
55
["number", [new TypeInfo(TypeKind.Primitive, undefined, undefined)]],
56
["Object", [new TypeInfo(TypeKind.Interface, undefined, undefined)]],
57
["Promise", [new TypeInfo(TypeKind.Interface, undefined, undefined)]],
58
["Date", [new TypeInfo(TypeKind.Interface, undefined, undefined)]],
59
["Function", [new TypeInfo(TypeKind.Interface, undefined, undefined)]],
60
["this", [new TypeInfo(TypeKind.Interface, undefined, undefined)]],
61
["sequence", [new TypeInfo(TypeKind.Container, undefined, undefined)]],
62
["record", [new TypeInfo(TypeKind.Container, undefined, undefined)]]
65
put(name: string, typeInfo: TypeInfo) {
66
const alreadyKnown = this.table.get(name)
68
this.table.set(name, [typeInfo])
71
if (alreadyKnown.length > 0) {
74
alreadyKnown.push(typeInfo)
76
get(name: string): TypeInfo[] {
77
return this.table.get(name) ?? []
81
export class TypeChecker {
83
constructor(idls?: IDLEntry[], typeTable?: TypeTable) {
84
this.typeTable = typeTable ?? new TypeTable()
85
idls?.forEach(idl => this.typecheck(idl))
88
typecheck(idl: IDLEntry) {
89
forEachChild(idl, it => this.recordType(it))
92
private createTypeInfo(idl: IDLEntry, typeKind: TypeKind) {
94
console.log("Trying to record type for an unnamed IDL entry: ", idl)
96
this.typeTable.put(idl.name!, new TypeInfo(typeKind, idl, idl.fileName))
99
find(name: string): TypeInfo[] {
100
return this.typeTable.get(name)
103
recordType(idl: IDLEntry) {
104
if (isInterface(idl)) {
105
this.createTypeInfo(idl, TypeKind.Interface)
109
this.createTypeInfo(idl, TypeKind.Enum)
113
this.createTypeInfo(idl, TypeKind.Class)
116
if (isCallback(idl)) {
117
this.createTypeInfo(idl, TypeKind.Callback)
120
if (isTypedef(idl)) {
121
this.createTypeInfo(idl, TypeKind.Typedef)
127
export function testTypecheck(entries: IDLEntry[]) {
128
const typeChecker = new TypeChecker(entries)
129
typeChecker.typeTable.table.forEach((types, name) => {
130
console.log(`${name}:`)
131
types.forEach(type =>
132
console.log(`\t${TypeKind[type.kind]} ${type.declaration ? `IDLEntry name is ${type.declaration.name}` : `NO DECL`} in ${type.location}`)