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  }