cue/ast: add API for setting a position
Ideally, the Pos and End methods would go
from Node, but this may be a bit intrusive.
Change-Id: I5a01c202f661f5a67818fa175f1001e9b22dd9b9
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3222
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast/ast.go b/cue/ast/ast.go
index 01f16c4..8e7ec79 100644
--- a/cue/ast/ast.go
+++ b/cue/ast/ast.go
@@ -42,7 +42,9 @@
Pos() token.Pos // position of first character belonging to the node
End() token.Pos // position of first character immediately after the node
- // TODO: SetPos(p token.RelPos)
+ // pos reports the pointer to the position of first character belonging to
+ // the node or nil if there is no such position.
+ pos() *token.Pos
// Deprecated: use ast.Comments
Comments() []*CommentGroup
@@ -52,6 +54,35 @@
commentInfo() *comments
}
+func getPos(n Node) token.Pos {
+ p := n.pos()
+ if p == nil {
+ return token.NoPos
+ }
+ return *p
+}
+
+// SetPos sets a node to the given position, if possible.
+func SetPos(n Node, p token.Pos) {
+ ptr := n.pos()
+ if ptr == nil {
+ return
+ }
+ *ptr = p
+}
+
+// SetRelPos sets the relative position of a node without modifying its
+// file position. Setting it to token.NoRelPos allows a node to adopt default
+// formatting.
+func SetRelPos(n Node, p token.RelPos) {
+ ptr := n.pos()
+ if ptr == nil {
+ return
+ }
+ pos := *ptr
+ *ptr = pos.WithRel(p)
+}
+
// An Expr is implemented by all expression nodes.
type Expr interface {
Node
@@ -164,8 +195,9 @@
func (c *Comment) AddComment(*CommentGroup) {}
func (c *Comment) commentInfo() *comments { return nil }
-func (c *Comment) Pos() token.Pos { return c.Slash }
-func (c *Comment) End() token.Pos { return c.Slash.Add(len(c.Text)) }
+func (c *Comment) Pos() token.Pos { return c.Slash }
+func (c *Comment) pos() *token.Pos { return &c.Slash }
+func (c *Comment) End() token.Pos { return c.Slash.Add(len(c.Text)) }
// A CommentGroup represents a sequence of comments
// with no other tokens and no empty lines between.
@@ -182,8 +214,9 @@
List []*Comment // len(List) > 0
}
-func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }
-func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
+func (g *CommentGroup) Pos() token.Pos { return getPos(g) }
+func (g *CommentGroup) pos() *token.Pos { return g.List[0].pos() }
+func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
func (g *CommentGroup) Comments() []*CommentGroup { return nil }
func (g *CommentGroup) AddComment(*CommentGroup) {}
@@ -265,8 +298,9 @@
Text string // must be a valid attribute format.
}
-func (a *Attribute) Pos() token.Pos { return a.At }
-func (a *Attribute) End() token.Pos { return a.At.Add(len(a.Text)) }
+func (a *Attribute) Pos() token.Pos { return a.At }
+func (a *Attribute) pos() *token.Pos { return &a.At }
+func (a *Attribute) End() token.Pos { return a.At.Add(len(a.Text)) }
// A Field represents a field declaration in a struct.
type Field struct {
@@ -283,7 +317,8 @@
Attrs []*Attribute
}
-func (d *Field) Pos() token.Pos { return d.Label.Pos() }
+func (d *Field) Pos() token.Pos { return d.Label.Pos() }
+func (d *Field) pos() *token.Pos { return d.Label.pos() }
func (d *Field) End() token.Pos {
if len(d.Attrs) > 0 {
return d.Attrs[len(d.Attrs)-1].End()
@@ -302,8 +337,9 @@
Expr Expr // An Ident or SelectorExpr
}
-func (a *Alias) Pos() token.Pos { return a.Ident.Pos() }
-func (a *Alias) End() token.Pos { return a.Expr.End() }
+func (a *Alias) Pos() token.Pos { return a.Ident.Pos() }
+func (a *Alias) pos() *token.Pos { return a.Ident.pos() }
+func (a *Alias) End() token.Pos { return a.Expr.End() }
// A Comprehension node represents a comprehension declaration.
type Comprehension struct {
@@ -312,7 +348,8 @@
Value Expr // Must be a struct
}
-func (x *Comprehension) Pos() token.Pos { return x.Clauses[0].Pos() }
+func (x *Comprehension) Pos() token.Pos { return getPos(x) }
+func (x *Comprehension) pos() *token.Pos { return x.Clauses[0].pos() }
func (x *Comprehension) End() token.Pos {
return x.Value.End()
}
@@ -491,31 +528,50 @@
// token.Pos and End implementations for expression/type nodes.
-func (x *BadExpr) Pos() token.Pos { return x.From }
-func (x *Ident) Pos() token.Pos { return x.NamePos }
-func (x *TemplateLabel) Pos() token.Pos { return x.Langle }
-func (x *BasicLit) Pos() token.Pos { return x.ValuePos }
-func (x *Interpolation) Pos() token.Pos { return x.Elts[0].Pos() }
-func (x *StructLit) Pos() token.Pos {
+func (x *BadExpr) Pos() token.Pos { return x.From }
+func (x *BadExpr) pos() *token.Pos { return &x.From }
+func (x *Ident) Pos() token.Pos { return x.NamePos }
+func (x *Ident) pos() *token.Pos { return &x.NamePos }
+func (x *TemplateLabel) Pos() token.Pos { return x.Langle }
+func (x *TemplateLabel) pos() *token.Pos { return &x.Langle }
+func (x *BasicLit) Pos() token.Pos { return x.ValuePos }
+func (x *BasicLit) pos() *token.Pos { return &x.ValuePos }
+func (x *Interpolation) Pos() token.Pos { return x.Elts[0].Pos() }
+func (x *Interpolation) pos() *token.Pos { return x.Elts[0].pos() }
+func (x *StructLit) Pos() token.Pos { return getPos(x) }
+func (x *StructLit) pos() *token.Pos {
if x.Lbrace == token.NoPos && len(x.Elts) > 0 {
- return x.Elts[0].Pos()
+ return x.Elts[0].pos()
}
- return x.Lbrace
+ return &x.Lbrace
}
-func (x *ListLit) Pos() token.Pos { return x.Lbrack }
-func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
-func (x *ListComprehension) Pos() token.Pos { return x.Lbrack }
-func (x *ForClause) Pos() token.Pos { return x.For }
-func (x *IfClause) Pos() token.Pos { return x.If }
-func (x *ParenExpr) Pos() token.Pos { return x.Lparen }
-func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() }
-func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() }
-func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() }
-func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() }
-func (x *UnaryExpr) Pos() token.Pos { return x.OpPos }
-func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() }
-func (x *BottomLit) Pos() token.Pos { return x.Bottom }
+func (x *ListLit) Pos() token.Pos { return x.Lbrack }
+func (x *ListLit) pos() *token.Pos { return &x.Lbrack }
+func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
+func (x *Ellipsis) pos() *token.Pos { return &x.Ellipsis }
+func (x *ListComprehension) Pos() token.Pos { return x.Lbrack }
+func (x *ListComprehension) pos() *token.Pos { return &x.Lbrack }
+func (x *ForClause) Pos() token.Pos { return x.For }
+func (x *ForClause) pos() *token.Pos { return &x.For }
+func (x *IfClause) Pos() token.Pos { return x.If }
+func (x *IfClause) pos() *token.Pos { return &x.If }
+func (x *ParenExpr) Pos() token.Pos { return x.Lparen }
+func (x *ParenExpr) pos() *token.Pos { return &x.Lparen }
+func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *SelectorExpr) pos() *token.Pos { return x.X.pos() }
+func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *IndexExpr) pos() *token.Pos { return x.X.pos() }
+func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *SliceExpr) pos() *token.Pos { return x.X.pos() }
+func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() }
+func (x *CallExpr) pos() *token.Pos { return x.Fun.pos() }
+func (x *UnaryExpr) Pos() token.Pos { return x.OpPos }
+func (x *UnaryExpr) pos() *token.Pos { return &x.OpPos }
+func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *BinaryExpr) pos() *token.Pos { return x.X.pos() }
+func (x *BottomLit) Pos() token.Pos { return x.Bottom }
+func (x *BottomLit) pos() *token.Pos { return &x.Bottom }
func (x *BadExpr) End() token.Pos { return x.To }
func (x *Ident) End() token.Pos {
@@ -579,11 +635,12 @@
// Pos and End implementations for spec nodes.
-func (s *ImportSpec) Pos() token.Pos {
+func (s *ImportSpec) Pos() token.Pos { return getPos(s) }
+func (s *ImportSpec) pos() *token.Pos {
if s.Name != nil {
- return s.Name.Pos()
+ return s.Name.pos()
}
- return s.Path.Pos()
+ return s.Path.pos()
}
// func (s *AliasSpec) Pos() token.Pos { return s.Name.Pos() }
@@ -636,9 +693,12 @@
// Pos and End implementations for declaration nodes.
-func (d *BadDecl) Pos() token.Pos { return d.From }
-func (d *ImportDecl) Pos() token.Pos { return d.Import }
-func (d *EmbedDecl) Pos() token.Pos { return d.Expr.Pos() }
+func (d *BadDecl) Pos() token.Pos { return d.From }
+func (d *BadDecl) pos() *token.Pos { return &d.From }
+func (d *ImportDecl) Pos() token.Pos { return d.Import }
+func (d *ImportDecl) pos() *token.Pos { return &d.Import }
+func (d *EmbedDecl) Pos() token.Pos { return d.Expr.Pos() }
+func (d *EmbedDecl) pos() *token.Pos { return d.Expr.pos() }
func (d *BadDecl) End() token.Pos { return d.To }
func (d *ImportDecl) End() token.Pos {
@@ -680,6 +740,16 @@
return token.NoPos
}
+func (f *File) pos() *token.Pos {
+ if len(f.Decls) > 0 {
+ return f.Decls[0].pos()
+ }
+ if f.Filename != "" {
+ return nil
+ }
+ return nil
+}
+
func (f *File) End() token.Pos {
if n := len(f.Decls); n > 0 {
return f.Decls[n-1].End()
@@ -694,14 +764,15 @@
Name *Ident // package name
}
-func (p *Package) Pos() token.Pos {
+func (p *Package) Pos() token.Pos { return getPos(p) }
+func (p *Package) pos() *token.Pos {
if p.PackagePos != token.NoPos {
- return p.PackagePos
+ return &p.PackagePos
}
if p.Name != nil {
- return p.Name.Pos()
+ return p.Name.pos()
}
- return token.NoPos
+ return nil
}
func (p *Package) End() token.Pos {