Files
CodeMapper/Sources/CodeMapper/SymbolTable.swift
T
2026-05-28 22:03:43 -04:00

97 lines
2.9 KiB
Swift

import Foundation
enum SymbolKind: String {
case `class`, `struct`, `enum`, `protocol`, actor
case `extension` = "ext"
case function = "func"
case initializer = "init"
case property = "prop"
case unknown = "?"
}
struct SymbolInfo {
var qualifiedName: String // "Application.addWindow" or "Application"
var typeName: String // parent type ("Application"), empty for top-level types
var name: String // simple name
var kind: SymbolKind
var signature: String // sliced source text from decl start to `{`
var filePath: String
var targetName: String
var isExtensionDecl: Bool
var accessLevel: String // "pub", "priv", or "" (internal)
var isAsync: Bool
var isThrows: Bool
var returnType: String?
var superclass: String?
var conformances: [String]
var selectionLine: Int
var selectionChar: Int
}
struct CallEdge {
var callerQualified: String
var calleeQualified: String // "" if external
var calleeDisplay: String // "~name" prefix if external
var isExternal: Bool
}
struct ExtensionInfo {
var baseType: String
var conformances: [String]
}
class SymbolTable {
var symbols: [String: SymbolInfo] = [:]
var fileSymbols: [String: [SymbolInfo]] = [:]
var fileExtensions: [String: [ExtensionInfo]] = [:]
var fileTargets: [String: String] = [:]
var callEdges: [String: [CallEdge]] = [:]
var reverseEdges: [String: [String]] = [:]
var conformanceMap: [String: Set<String>] = [:]
var implementorMap: [String: [String]] = [:]
func registerSymbol(_ sym: SymbolInfo) {
if sym.kind != .extension {
symbols[sym.qualifiedName] = sym
}
fileSymbols[sym.filePath, default: []].append(sym)
let owner = sym.typeName.isEmpty ? sym.name : sym.typeName
for proto in sym.conformances {
conformanceMap[owner, default: []].insert(proto)
}
}
func registerExtension(_ ext: ExtensionInfo, filePath: String) {
fileExtensions[filePath, default: []].append(ext)
for proto in ext.conformances {
conformanceMap[ext.baseType, default: []].insert(proto)
}
}
func addCallEdge(_ edge: CallEdge) {
callEdges[edge.callerQualified, default: []].append(edge)
}
func buildReverseIndex() {
reverseEdges = [:]
for (caller, edges) in callEdges {
for edge in edges where !edge.isExternal {
reverseEdges[edge.calleeQualified, default: []].append(caller)
}
}
}
func buildImplementorMap() {
implementorMap = [:]
for (typeName, protos) in conformanceMap {
for proto in protos {
implementorMap[proto, default: []].append(typeName)
}
}
for key in implementorMap.keys {
implementorMap[key]?.sort()
}
}
}