srcfile.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package goja
  2. import (
  3. "fmt"
  4. "sort"
  5. "strings"
  6. "github.com/go-sourcemap/sourcemap"
  7. )
  8. type Position struct {
  9. Line, Col int
  10. }
  11. type SrcFile struct {
  12. name string
  13. src string
  14. lineOffsets []int
  15. lastScannedOffset int
  16. sourceMap *sourcemap.Consumer
  17. }
  18. func NewSrcFile(name, src string, sourceMap *sourcemap.Consumer) *SrcFile {
  19. return &SrcFile{
  20. name: name,
  21. src: src,
  22. sourceMap: sourceMap,
  23. }
  24. }
  25. func (f *SrcFile) Position(offset int) Position {
  26. var line int
  27. if offset > f.lastScannedOffset {
  28. line = f.scanTo(offset)
  29. } else {
  30. line = sort.Search(len(f.lineOffsets), func(x int) bool { return f.lineOffsets[x] > offset }) - 1
  31. }
  32. var lineStart int
  33. if line >= 0 {
  34. lineStart = f.lineOffsets[line]
  35. }
  36. row := line + 2
  37. col := offset - lineStart + 1
  38. if f.sourceMap != nil {
  39. if _, _, row, col, ok := f.sourceMap.Source(row, col); ok {
  40. return Position{
  41. Line: row,
  42. Col: col,
  43. }
  44. }
  45. }
  46. return Position{
  47. Line: row,
  48. Col: col,
  49. }
  50. }
  51. func (f *SrcFile) scanTo(offset int) int {
  52. o := f.lastScannedOffset
  53. for o < offset {
  54. p := strings.Index(f.src[o:], "\n")
  55. if p == -1 {
  56. f.lastScannedOffset = len(f.src)
  57. return len(f.lineOffsets) - 1
  58. }
  59. o = o + p + 1
  60. f.lineOffsets = append(f.lineOffsets, o)
  61. }
  62. f.lastScannedOffset = o
  63. if o == offset {
  64. return len(f.lineOffsets) - 1
  65. }
  66. return len(f.lineOffsets) - 2
  67. }
  68. func (p Position) String() string {
  69. return fmt.Sprintf("%d:%d", p.Line, p.Col)
  70. }