...

Source file src/pkg/cmd/compile/internal/syntax/pos.go

     1	// Copyright 2018 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 syntax
     6	
     7	import "fmt"
     8	
     9	// PosMax is the largest line or column value that can be represented without loss.
    10	// Incoming values (arguments) larger than PosMax will be set to PosMax.
    11	const PosMax = 1 << 30
    12	
    13	// A Pos represents an absolute (line, col) source position
    14	// with a reference to position base for computing relative
    15	// (to a file, or line directive) position information.
    16	// Pos values are intentionally light-weight so that they
    17	// can be created without too much concern about space use.
    18	type Pos struct {
    19		base      *PosBase
    20		line, col uint32
    21	}
    22	
    23	// MakePos returns a new Pos for the given PosBase, line and column.
    24	func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line), sat32(col)} }
    25	
    26	// TODO(gri) IsKnown makes an assumption about linebase < 1.
    27	//           Maybe we should check for Base() != nil instead.
    28	
    29	func (pos Pos) IsKnown() bool  { return pos.line > 0 }
    30	func (pos Pos) Base() *PosBase { return pos.base }
    31	func (pos Pos) Line() uint     { return uint(pos.line) }
    32	func (pos Pos) Col() uint      { return uint(pos.col) }
    33	
    34	func (pos Pos) RelFilename() string { return pos.base.Filename() }
    35	
    36	func (pos Pos) RelLine() uint {
    37		b := pos.base
    38		if b.Line() == 0 {
    39			// base line is unknown => relative line is unknown
    40			return 0
    41		}
    42		return b.Line() + (pos.Line() - b.Pos().Line())
    43	}
    44	
    45	func (pos Pos) RelCol() uint {
    46		b := pos.base
    47		if b.Col() == 0 {
    48			// base column is unknown => relative column is unknown
    49			// (the current specification for line directives requires
    50			// this to apply until the next PosBase/line directive,
    51			// not just until the new newline)
    52			return 0
    53		}
    54		if pos.Line() == b.Pos().Line() {
    55			// pos on same line as pos base => column is relative to pos base
    56			return b.Col() + (pos.Col() - b.Pos().Col())
    57		}
    58		return pos.Col()
    59	}
    60	
    61	func (pos Pos) String() string {
    62		rel := position_{pos.RelFilename(), pos.RelLine(), pos.RelCol()}
    63		abs := position_{pos.Base().Pos().RelFilename(), pos.Line(), pos.Col()}
    64		s := rel.String()
    65		if rel != abs {
    66			s += "[" + abs.String() + "]"
    67		}
    68		return s
    69	}
    70	
    71	// TODO(gri) cleanup: find better name, avoid conflict with position in error_test.go
    72	type position_ struct {
    73		filename  string
    74		line, col uint
    75	}
    76	
    77	func (p position_) String() string {
    78		if p.line == 0 {
    79			if p.filename == "" {
    80				return "<unknown position>"
    81			}
    82			return p.filename
    83		}
    84		if p.col == 0 {
    85			return fmt.Sprintf("%s:%d", p.filename, p.line)
    86		}
    87		return fmt.Sprintf("%s:%d:%d", p.filename, p.line, p.col)
    88	}
    89	
    90	// A PosBase represents the base for relative position information:
    91	// At position pos, the relative position is filename:line:col.
    92	type PosBase struct {
    93		pos       Pos
    94		filename  string
    95		line, col uint32
    96	}
    97	
    98	// NewFileBase returns a new PosBase for the given filename.
    99	// A file PosBase's position is relative to itself, with the
   100	// position being filename:1:1.
   101	func NewFileBase(filename string) *PosBase {
   102		base := &PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase}
   103		base.pos.base = base
   104		return base
   105	}
   106	
   107	// NewLineBase returns a new PosBase for a line directive "line filename:line:col"
   108	// relative to pos, which is the position of the character immediately following
   109	// the comment containing the line directive. For a directive in a line comment,
   110	// that position is the beginning of the next line (i.e., the newline character
   111	// belongs to the line comment).
   112	func NewLineBase(pos Pos, filename string, line, col uint) *PosBase {
   113		return &PosBase{pos, filename, sat32(line), sat32(col)}
   114	}
   115	
   116	func (base *PosBase) IsFileBase() bool {
   117		if base == nil {
   118			return false
   119		}
   120		return base.pos.base == base
   121	}
   122	
   123	func (base *PosBase) Pos() (_ Pos) {
   124		if base == nil {
   125			return
   126		}
   127		return base.pos
   128	}
   129	
   130	func (base *PosBase) Filename() string {
   131		if base == nil {
   132			return ""
   133		}
   134		return base.filename
   135	}
   136	
   137	func (base *PosBase) Line() uint {
   138		if base == nil {
   139			return 0
   140		}
   141		return uint(base.line)
   142	}
   143	
   144	func (base *PosBase) Col() uint {
   145		if base == nil {
   146			return 0
   147		}
   148		return uint(base.col)
   149	}
   150	
   151	func sat32(x uint) uint32 {
   152		if x > PosMax {
   153			return PosMax
   154		}
   155		return uint32(x)
   156	}
   157	

View as plain text