...

Source file src/github.com/golang/protobuf/protoc-gen-go/generator/internal/remap/remap.go

Documentation: github.com/golang/protobuf/protoc-gen-go/generator/internal/remap

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package remap handles tracking the locations of Go tokens in a source text
     6  // across a rewrite by the Go formatter.
     7  package remap
     8  
     9  import (
    10  	"fmt"
    11  	"go/scanner"
    12  	"go/token"
    13  )
    14  
    15  // A Location represents a span of byte offsets in the source text.
    16  type Location struct {
    17  	Pos, End int // End is exclusive
    18  }
    19  
    20  // A Map represents a mapping between token locations in an input source text
    21  // and locations in the correspnding output text.
    22  type Map map[Location]Location
    23  
    24  // Find reports whether the specified span is recorded by m, and if so returns
    25  // the new location it was mapped to. If the input span was not found, the
    26  // returned location is the same as the input.
    27  func (m Map) Find(pos, end int) (Location, bool) {
    28  	key := Location{
    29  		Pos: pos,
    30  		End: end,
    31  	}
    32  	if loc, ok := m[key]; ok {
    33  		return loc, true
    34  	}
    35  	return key, false
    36  }
    37  
    38  func (m Map) add(opos, oend, npos, nend int) {
    39  	m[Location{Pos: opos, End: oend}] = Location{Pos: npos, End: nend}
    40  }
    41  
    42  // Compute constructs a location mapping from input to output.  An error is
    43  // reported if any of the tokens of output cannot be mapped.
    44  func Compute(input, output []byte) (Map, error) {
    45  	itok := tokenize(input)
    46  	otok := tokenize(output)
    47  	if len(itok) != len(otok) {
    48  		return nil, fmt.Errorf("wrong number of tokens, %d ≠ %d", len(itok), len(otok))
    49  	}
    50  	m := make(Map)
    51  	for i, ti := range itok {
    52  		to := otok[i]
    53  		if ti.Token != to.Token {
    54  			return nil, fmt.Errorf("token %d type mismatch: %s ≠ %s", i+1, ti, to)
    55  		}
    56  		m.add(ti.pos, ti.end, to.pos, to.end)
    57  	}
    58  	return m, nil
    59  }
    60  
    61  // tokinfo records the span and type of a source token.
    62  type tokinfo struct {
    63  	pos, end int
    64  	token.Token
    65  }
    66  
    67  func tokenize(src []byte) []tokinfo {
    68  	fs := token.NewFileSet()
    69  	var s scanner.Scanner
    70  	s.Init(fs.AddFile("src", fs.Base(), len(src)), src, nil, scanner.ScanComments)
    71  	var info []tokinfo
    72  	for {
    73  		pos, next, lit := s.Scan()
    74  		switch next {
    75  		case token.SEMICOLON:
    76  			continue
    77  		}
    78  		info = append(info, tokinfo{
    79  			pos:   int(pos - 1),
    80  			end:   int(pos + token.Pos(len(lit)) - 1),
    81  			Token: next,
    82  		})
    83  		if next == token.EOF {
    84  			break
    85  		}
    86  	}
    87  	return info
    88  }
    89  

View as plain text