github.com/algorand/go-algorand-sdk@v1.24.0/logic/source_map.go (about) 1 package logic 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strings" 7 ) 8 9 // SourceMap provides a mapping of the source to assembled program 10 type SourceMap struct { 11 Version int `json:"version"` 12 File string `json:"file,omitempty"` 13 SourceRoot string `json:"sourceRoot,omitempty"` 14 Sources []string `json:"sources"` 15 Names []string `json:"names"` 16 Mappings string `json:"mappings"` 17 // Decoded mapping results 18 LineToPc map[int][]int 19 PcToLine map[int]int 20 } 21 22 func DecodeSourceMap(ism map[string]interface{}) (SourceMap, error) { 23 var sm SourceMap 24 25 buff, err := json.Marshal(ism) 26 if err != nil { 27 return sm, err 28 } 29 30 err = json.Unmarshal(buff, &sm) 31 if err != nil { 32 return sm, err 33 } 34 35 if sm.Version != 3 { 36 return sm, fmt.Errorf("only version 3 is supported") 37 } 38 39 if sm.Mappings == "" { 40 return sm, fmt.Errorf("no mappings defined") 41 } 42 43 sm.PcToLine = map[int]int{} 44 sm.LineToPc = map[int][]int{} 45 46 lastLine := 0 47 for idx, chunk := range strings.Split(sm.Mappings, ";") { 48 vals := decodeSourceMapLine(chunk) 49 // If the vals length >= 3 the lineDelta 50 if len(vals) >= 3 { 51 lastLine = lastLine + vals[2] // Add the line delta 52 } 53 54 if _, ok := sm.LineToPc[lastLine]; !ok { 55 sm.LineToPc[lastLine] = []int{} 56 } 57 58 sm.LineToPc[lastLine] = append(sm.LineToPc[lastLine], idx) 59 sm.PcToLine[idx] = lastLine 60 } 61 62 return sm, nil 63 } 64 65 func (s *SourceMap) GetLineForPc(pc int) (int, bool) { 66 line, ok := s.PcToLine[pc] 67 return line, ok 68 } 69 70 func (s *SourceMap) GetPcsForLine(line int) []int { 71 return s.LineToPc[line] 72 } 73 74 const ( 75 // consts used for vlq encoding/decoding 76 b64table string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" 77 vlqShiftSize = 5 78 vlqFlag = 1 << vlqShiftSize 79 vlqMask = vlqFlag - 1 80 ) 81 82 func decodeSourceMapLine(vlq string) []int { 83 84 var ( 85 results []int 86 value, shift int 87 ) 88 89 for i := 0; i < len(vlq); i++ { 90 digit := strings.Index(b64table, string(vlq[i])) 91 92 value |= (digit & int(vlqMask)) << shift 93 94 if digit&vlqFlag > 0 { 95 shift += vlqShiftSize 96 continue 97 } 98 99 if value&1 > 0 { 100 value = (value >> 1) * -1 101 } else { 102 value = value >> 1 103 } 104 105 results = append(results, value) 106 107 // Reset 108 value, shift = 0, 0 109 } 110 111 return results 112 }