package iskra import "bytes" // FindBySignature scans all meta entries at the given stage using the // 24-bit signature hash for fast rejection, then verifying with full // IsIsomorphic on the content. Returns recIdxs of matching entries. func FindBySignature(t *Tree, sig *BindingSignature, stage uint8) []uint32 { targetHash := SignatureHash24(sig) var matches []uint32 for recIdx := range t.RecMeta { meta := &t.RecMeta[recIdx] if meta.StageTag != stage { continue } if meta.SigHash() != targetHash { continue } content := t.GetContent(uint32(recIdx)) if len(content) == 0 { continue } cst := ExtractSymbols(string(content)) candidateSig := SignatureWithTypes(cst) if sig.IsIsomorphic(candidateSig) { matches = append(matches, uint32(recIdx)) } } return matches } // FindBySignatureFromAST extracts symbols from an AST dump and finds // matching entries in the lattice. Convenience wrapper. func FindBySignatureFromAST(t *Tree, astDump string) []uint32 { st := ExtractSymbols(astDump) sig := SignatureWithTypes(st) return FindBySignature(t, sig, StageAST) } // FindBySignatureInPkg is like FindBySignature but only considers entries // whose IR representation (at the same name hash, StageIR) contains pkgPrefix. // Cross-stage adjacency is now key-implicit: same hash, different stage prefix. func FindBySignatureInPkg(t *Tree, sig *BindingSignature, stage uint8, pkgPrefix string) []uint32 { targetHash := SignatureHash24(sig) prefix := []byte(pkgPrefix) var matches []uint32 for recIdx := range t.RecMeta { meta := &t.RecMeta[recIdx] if meta.StageTag != stage { continue } if meta.SigHash() != targetHash { continue } if len(pkgPrefix) > 0 { // Look up IR version of this entry: same name hash, StageIR, same branch. key, ok := t.db.RecKey[uint32(recIdx)] if !ok { continue } branch := KindToBranch(meta.Kind) irKey := MakeCodeKey(StageIR, KeyHash(key)) irRecIdx := t.db.LookupRecIdx(branch, irKey) if irRecIdx == NullLatticeRec { continue } ir := t.GetContent(irRecIdx) if !bytes.Contains(ir, prefix) { continue } } content := t.GetContent(uint32(recIdx)) if len(content) == 0 { continue } cst := ExtractSymbols(string(content)) candidateSig := SignatureWithTypes(cst) if sig.IsIsomorphic(candidateSig) { matches = append(matches, uint32(recIdx)) } } return matches } func FindBySignatureFromASTInPkg(t *Tree, astDump string, pkgPrefix string) []uint32 { st := ExtractSymbols(astDump) sig := SignatureWithTypes(st) return FindBySignatureInPkg(t, sig, StageAST, pkgPrefix) } // RankMatches reorders matches: self first, then name match, then lowest cost. func RankMatches(t *Tree, matches []uint32, selfIdx uint32, queryName string) { if len(matches) < 2 { return } qMethod := unqualifiedName(queryName) for j, mi := range matches { if mi == selfIdx && j != 0 { matches[0], matches[j] = matches[j], matches[0] return } } if matches[0] == selfIdx { return } for j := 0; j < len(matches); j++ { rec := t.db.GetRecord(matches[j]) if rec == nil { continue } mName := FormFromRecord(rec, t.StringPool) if unqualifiedName(mName) == qMethod { if j != 0 { matches[0], matches[j] = matches[j], matches[0] } return } } RankByCost(t, matches) } // RankByCost sorts matches by ascending CostMap cost. func RankByCost(t *Tree, matches []uint32) { if len(t.CostMap) == 0 || len(matches) < 2 { return } for i := 1; i < len(matches); i++ { key := matches[i] kCost, kHas := t.CostMap[key] j := i - 1 for j >= 0 { jCost, jHas := t.CostMap[matches[j]] if !costLess(kCost, kHas, jCost, jHas) { break } matches[j+1] = matches[j] j-- } matches[j+1] = key } } func costLess(a CostEntry, aHas bool, b CostEntry, bHas bool) bool { if aHas && !bHas { return true } if !aHas { return false } return a.NsOp100 < b.NsOp100 } func unqualifiedName(name string) string { for i := len(name) - 1; i >= 0; i-- { if name[i] == '.' { return name[i+1:] } } return name }