···11+// Copyright 2018 The CUE Authors
22+//
33+// Licensed under the Apache License, Version 2.0 (the "License");
44+// you may not use this file except in compliance with the License.
55+// You may obtain a copy of the License at
66+//
77+// http://www.apache.org/licenses/LICENSE-2.0
88+//
99+// Unless required by applicable law or agreed to in writing, software
1010+// distributed under the License is distributed on an "AS IS" BASIS,
1111+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212+// See the License for the specific language governing permissions and
1313+// limitations under the License.
1414+1515+// Package ast declares the types used to represent syntax trees for CUE
1616+// packages.
1717+package ast // import "cuelang.org/go/cue/ast"
1818+1919+import (
2020+ "strconv"
2121+ "strings"
2222+2323+ "cuelang.org/go/cue/token"
2424+)
2525+2626+// ----------------------------------------------------------------------------
2727+// Interfaces
2828+//
2929+// There are two main classes of nodes: expressions, clauses, and declaration
3030+// nodes. The node names usually match the corresponding CUE spec production
3131+// names to which they correspond. The node fields correspond to the individual
3232+// parts of the respective productions.
3333+//
3434+// All nodes contain position information marking the beginning of the
3535+// corresponding source text segment; it is accessible via the Pos accessor
3636+// method. Nodes may contain additional position info for language constructs
3737+// where comments may be found between parts of the construct (typically any
3838+// larger, parenthesized subpart). That position information is needed to
3939+// properly position comments when printing the construct.
4040+4141+// A Node represents any node in the abstract syntax tree.
4242+type Node interface {
4343+ Pos() token.Pos // position of first character belonging to the node
4444+ End() token.Pos // position of first character immediately after the node
4545+4646+ // TODO: SetPos(p token.RelPos)
4747+4848+ Comments() []*CommentGroup
4949+ AddComment(*CommentGroup)
5050+}
5151+5252+// An Expr is implemented by all expression nodes.
5353+type Expr interface {
5454+ Node
5555+ exprNode()
5656+}
5757+5858+func (*BadExpr) exprNode() {}
5959+func (*Ident) exprNode() {}
6060+func (*Ellipsis) exprNode() {}
6161+func (*BasicLit) exprNode() {}
6262+func (*Interpolation) exprNode() {}
6363+func (*StructLit) exprNode() {}
6464+func (*ListLit) exprNode() {}
6565+func (*LambdaExpr) exprNode() {}
6666+6767+// func (*StructComprehension) exprNode() {}
6868+func (*ListComprehension) exprNode() {}
6969+func (*ParenExpr) exprNode() {}
7070+func (*SelectorExpr) exprNode() {}
7171+func (*IndexExpr) exprNode() {}
7272+func (*SliceExpr) exprNode() {}
7373+func (*CallExpr) exprNode() {}
7474+func (*UnaryExpr) exprNode() {}
7575+func (*BinaryExpr) exprNode() {}
7676+func (*BottomLit) exprNode() {}
7777+7878+// A Decl node is implemented by all declarations.
7979+type Decl interface {
8080+ Node
8181+ declNode()
8282+}
8383+8484+func (*Field) declNode() {}
8585+func (*ComprehensionDecl) declNode() {}
8686+func (*ImportDecl) declNode() {}
8787+func (*BadDecl) declNode() {}
8888+func (*EmitDecl) declNode() {}
8989+func (*Alias) declNode() {}
9090+9191+// A Label is any prduction that can be used as a LHS label.
9292+type Label interface {
9393+ Node
9494+ labelName() (name string, isIdent bool)
9595+}
9696+9797+func (n *Ident) labelName() (string, bool) {
9898+ return n.Name, true
9999+}
100100+101101+func (n *BasicLit) labelName() (string, bool) {
102102+ switch n.Kind {
103103+ case token.STRING:
104104+ // Use strconv to only allow double-quoted, single-line strings.
105105+ if str, err := strconv.Unquote(n.Value); err == nil {
106106+ return str, true
107107+ }
108108+ case token.NULL, token.TRUE, token.FALSE:
109109+ return n.Value, true
110110+111111+ // TODO: allow numbers to be fields?
112112+ }
113113+ return "", false
114114+}
115115+116116+func (n *TemplateLabel) labelName() (string, bool) {
117117+ return n.Ident.Name, false
118118+}
119119+120120+func (n *Interpolation) labelName() (string, bool) {
121121+ return "", false
122122+}
123123+func (n *ExprLabel) labelName() (string, bool) {
124124+ return "", false
125125+}
126126+127127+// LabelName reports the name of a label, if known, and whether it is valid.
128128+func LabelName(x Label) (name string, ok bool) {
129129+ return x.labelName()
130130+}
131131+132132+// As for now, a ExprLabel is not a label, as it can only use used in
133133+// struct comprehensions.
134134+135135+// Clause nodes are part of comprehensions.
136136+type Clause interface {
137137+ Node
138138+ clauseNode()
139139+}
140140+141141+func (x *ForClause) clauseNode() {}
142142+func (x *IfClause) clauseNode() {}
143143+func (x *Alias) clauseNode() {}
144144+145145+// Comments
146146+147147+type comments struct {
148148+ groups *[]*CommentGroup
149149+}
150150+151151+func (c *comments) Comments() []*CommentGroup {
152152+ if c.groups == nil {
153153+ return []*CommentGroup{}
154154+ }
155155+ return *c.groups
156156+}
157157+158158+// // AddComment adds the given comments to the fields.
159159+// // If line is true the comment is inserted at the preceding token.
160160+161161+func (c *comments) AddComment(cg *CommentGroup) {
162162+ if cg == nil {
163163+ return
164164+ }
165165+ if c.groups == nil {
166166+ a := []*CommentGroup{cg}
167167+ c.groups = &a
168168+ return
169169+ }
170170+ *c.groups = append(*c.groups, cg)
171171+}
172172+173173+// A Comment node represents a single //-style or /*-style comment.
174174+type Comment struct {
175175+ Slash token.Pos // position of "/" starting the comment
176176+ Text string // comment text (excluding '\n' for //-style comments)
177177+}
178178+179179+func (g *Comment) Comments() []*CommentGroup { return nil }
180180+func (g *Comment) AddComment(*CommentGroup) {}
181181+182182+func (c *Comment) Pos() token.Pos { return c.Slash }
183183+func (c *Comment) End() token.Pos { return c.Slash.Add(len(c.Text)) }
184184+185185+// A CommentGroup represents a sequence of comments
186186+// with no other tokens and no empty lines between.
187187+type CommentGroup struct {
188188+ // TODO: remove and use the token position of the first commment.
189189+ Doc bool
190190+ Line bool // true if it is on the same line as the node's end pos.
191191+192192+ // Position indicates where a comment should be attached if a node has
193193+ // multiple tokens. 0 means before the first token, 1 means before the
194194+ // second, etc. For instance, for a field, the positions are:
195195+ // <0> Label <1> ":" <2> Expr <3> "," <4>
196196+ Position int8
197197+ List []*Comment // len(List) > 0
198198+}
199199+200200+func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }
201201+func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
202202+203203+func (g *CommentGroup) Comments() []*CommentGroup { return nil }
204204+func (g *CommentGroup) AddComment(*CommentGroup) {}
205205+206206+func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
207207+208208+func stripTrailingWhitespace(s string) string {
209209+ i := len(s)
210210+ for i > 0 && isWhitespace(s[i-1]) {
211211+ i--
212212+ }
213213+ return s[0:i]
214214+}
215215+216216+// Text returns the text of the comment.
217217+// Comment markers (//, /*, and */), the first space of a line comment, and
218218+// leading and trailing empty lines are removed. Multiple empty lines are
219219+// reduced to one, and trailing space on lines is trimmed. Unless the result
220220+// is empty, it is newline-terminated.
221221+func (g *CommentGroup) Text() string {
222222+ if g == nil {
223223+ return ""
224224+ }
225225+ comments := make([]string, len(g.List))
226226+ for i, c := range g.List {
227227+ comments[i] = c.Text
228228+ }
229229+230230+ lines := make([]string, 0, 10) // most comments are less than 10 lines
231231+ for _, c := range comments {
232232+ // Remove comment markers.
233233+ // The parser has given us exactly the comment text.
234234+ switch c[1] {
235235+ case '/':
236236+ //-style comment (no newline at the end)
237237+ c = c[2:]
238238+ // strip first space - required for Example tests
239239+ if len(c) > 0 && c[0] == ' ' {
240240+ c = c[1:]
241241+ }
242242+ case '*':
243243+ /*-style comment */
244244+ c = c[2 : len(c)-2]
245245+ }
246246+247247+ // Split on newlines.
248248+ cl := strings.Split(c, "\n")
249249+250250+ // Walk lines, stripping trailing white space and adding to list.
251251+ for _, l := range cl {
252252+ lines = append(lines, stripTrailingWhitespace(l))
253253+ }
254254+ }
255255+256256+ // Remove leading blank lines; convert runs of
257257+ // interior blank lines to a single blank line.
258258+ n := 0
259259+ for _, line := range lines {
260260+ if line != "" || n > 0 && lines[n-1] != "" {
261261+ lines[n] = line
262262+ n++
263263+ }
264264+ }
265265+ lines = lines[0:n]
266266+267267+ // Add final "" entry to get trailing newline from Join.
268268+ if n > 0 && lines[n-1] != "" {
269269+ lines = append(lines, "")
270270+ }
271271+272272+ return strings.Join(lines, "\n")
273273+}
274274+275275+// A Field represents a field declaration in a struct.
276276+type Field struct {
277277+ comments
278278+ Label Label // must have at least one element.
279279+280280+ // No colon: Value must be an StructLit with one field or a
281281+ // LambdaExpr.
282282+ Colon token.Pos
283283+ Value Expr // the value associated with this field.
284284+}
285285+286286+func (d *Field) Pos() token.Pos { return d.Label.Pos() }
287287+func (d *Field) End() token.Pos { return d.Value.End() }
288288+289289+// An Alias binds another field to the alias name in the current struct.
290290+type Alias struct {
291291+ comments
292292+ Ident *Ident // field name, always an Ident
293293+ Equal token.Pos // position of "="
294294+ Expr Expr // An Ident or SelectorExpr
295295+}
296296+297297+func (a *Alias) Pos() token.Pos { return a.Ident.Pos() }
298298+func (a *Alias) End() token.Pos { return a.Expr.End() }
299299+300300+// A ComprehensionDecl node represents a field comprehension.
301301+type ComprehensionDecl struct {
302302+ comments
303303+ Field *Field
304304+ Select token.Pos
305305+ Clauses []Clause
306306+}
307307+308308+func (x *ComprehensionDecl) Pos() token.Pos { return x.Field.Pos() }
309309+func (x *ComprehensionDecl) End() token.Pos {
310310+ if len(x.Clauses) > 0 {
311311+ return x.Clauses[len(x.Clauses)-1].End()
312312+ }
313313+ return x.Select
314314+}
315315+316316+// ----------------------------------------------------------------------------
317317+// Expressions and types
318318+//
319319+// An expression is represented by a tree consisting of one
320320+// or more of the following concrete expression nodes.
321321+322322+// A LambdaExpr defines a function expression.
323323+//
324324+// Lambdas are only used internally under controlled conditions. Although
325325+// the implementation of lambdas is fully functional, enabling them will
326326+// cause the language to be Turing-complete (if not otherwise limited).
327327+// Also, lambdas would provide yet another way to create structure, and one
328328+// that is known to not work well for declarative configuration languages.
329329+type LambdaExpr struct {
330330+ comments
331331+ Lparen token.Pos // position of "("
332332+ Params []*Field // parameters with possible initializers
333333+ Rparen token.Pos // position of ")"
334334+ Expr Expr
335335+}
336336+337337+func (t *LambdaExpr) Pos() token.Pos { return t.Lparen }
338338+func (t *LambdaExpr) End() token.Pos { return t.Rparen }
339339+340340+// A BadExpr node is a placeholder for expressions containing
341341+// syntax errors for which no correct expression nodes can be
342342+// created. This is different from an ErrorExpr which represents
343343+// an explicitly marked error in the source.
344344+type BadExpr struct {
345345+ comments
346346+ From, To token.Pos // position range of bad expression
347347+}
348348+349349+// A BottomLit indicates an error.
350350+type BottomLit struct {
351351+ comments
352352+ Bottom token.Pos
353353+}
354354+355355+// An Ident node represents an left-hand side identifier.
356356+type Ident struct {
357357+ comments
358358+ NamePos token.Pos // identifier position
359359+360360+ // This LHS path element may be an identifier. Possible forms:
361361+ // foo: a normal identifier
362362+ // "foo": JSON compatible
363363+ // <foo>: a template shorthand
364364+ Name string
365365+366366+ Scope Node // scope in which node was found or nil if referring directly
367367+ Node Node
368368+}
369369+370370+// A TemplateLabel represents a field template declaration in a struct.
371371+type TemplateLabel struct {
372372+ comments
373373+ Langle token.Pos
374374+ Ident *Ident
375375+ Rangle token.Pos
376376+}
377377+378378+// An ExprLabel is an expression to create a label in struct comprehensions.
379379+type ExprLabel struct {
380380+ comments
381381+ Lbrack token.Pos
382382+ Label Expr
383383+ Rbrack token.Pos
384384+}
385385+386386+// An Ellipsis node stands for the "..." type in a
387387+// parameter list or the "..." length in an array type.
388388+type Ellipsis struct {
389389+ comments
390390+ Ellipsis token.Pos // position of "..."
391391+ Elt Expr // ellipsis element type (parameter lists only); or nil
392392+}
393393+394394+// A BasicLit node represents a literal of basic type.
395395+type BasicLit struct {
396396+ comments
397397+ ValuePos token.Pos // literal position
398398+ Kind token.Token // INT, FLOAT, DURATION, or STRING
399399+ Value string // literal string; e.g. 42, 0x7f, 3.14, 1_234_567, 1e-9, 2.4i, 'a', '\x7f', "foo", or '\m\n\o'
400400+}
401401+402402+// A Interpolation node represents a string or bytes interpolation.
403403+type Interpolation struct { // TODO: rename to TemplateLit
404404+ comments
405405+ Elts []Expr // interleaving of strings and expressions.
406406+}
407407+408408+// A StructLit node represents a literal struct.
409409+type StructLit struct {
410410+ comments
411411+ Lbrace token.Pos // position of "{"
412412+ Elts []Decl // list of elements; or nil
413413+ Rbrace token.Pos // position of "}"
414414+}
415415+416416+// A ListLit node represents a literal list.
417417+type ListLit struct {
418418+ comments
419419+ Lbrack token.Pos // position of "["
420420+ Elts []Expr // list of composite elements; or nil
421421+ Ellipsis token.Pos // open list if set
422422+ Type Expr // type for the remaining elements
423423+ Rbrack token.Pos // position of "]"
424424+}
425425+426426+// A ListComprehension node represents as list comprehension.
427427+type ListComprehension struct {
428428+ comments
429429+ Lbrack token.Pos // position of "["
430430+ Expr Expr
431431+ Clauses []Clause // Feed or Guard (TODO let)
432432+ Rbrack token.Pos // position of "]"
433433+}
434434+435435+// A ForClause node represents a for clause in a comprehension.
436436+type ForClause struct {
437437+ comments
438438+ For token.Pos
439439+ Key *Ident // allow pattern matching?
440440+ Colon token.Pos
441441+ Value *Ident // allow pattern matching?
442442+ In token.Pos
443443+ Source Expr
444444+}
445445+446446+// A IfClause node represents an if guard clause in a comprehension.
447447+type IfClause struct {
448448+ comments
449449+ If token.Pos
450450+ Condition Expr
451451+}
452452+453453+// A ParenExpr node represents a parenthesized expression.
454454+type ParenExpr struct {
455455+ comments
456456+ Lparen token.Pos // position of "("
457457+ X Expr // parenthesized expression
458458+ Rparen token.Pos // position of ")"
459459+}
460460+461461+// A SelectorExpr node represents an expression followed by a selector.
462462+type SelectorExpr struct {
463463+ comments
464464+ X Expr // expression
465465+ Sel *Ident // field selector
466466+}
467467+468468+// An IndexExpr node represents an expression followed by an index.
469469+type IndexExpr struct {
470470+ comments
471471+ X Expr // expression
472472+ Lbrack token.Pos // position of "["
473473+ Index Expr // index expression
474474+ Rbrack token.Pos // position of "]"
475475+}
476476+477477+// An SliceExpr node represents an expression followed by slice indices.
478478+type SliceExpr struct {
479479+ comments
480480+ X Expr // expression
481481+ Lbrack token.Pos // position of "["
482482+ Low Expr // begin of slice range; or nil
483483+ High Expr // end of slice range; or nil
484484+ Rbrack token.Pos // position of "]"
485485+}
486486+487487+// A CallExpr node represents an expression followed by an argument list.
488488+type CallExpr struct {
489489+ comments
490490+ Fun Expr // function expression
491491+ Lparen token.Pos // position of "("
492492+ Args []Expr // function arguments; or nil
493493+ Rparen token.Pos // position of ")"
494494+}
495495+496496+// A UnaryExpr node represents a unary expression.
497497+type UnaryExpr struct {
498498+ comments
499499+ OpPos token.Pos // position of Op
500500+ Op token.Token // operator
501501+ X Expr // operand
502502+}
503503+504504+// A BinaryExpr node represents a binary expression.
505505+type BinaryExpr struct {
506506+ comments
507507+ X Expr // left operand
508508+ OpPos token.Pos // position of Op
509509+ Op token.Token // operator
510510+ Y Expr // right operand
511511+}
512512+513513+// token.Pos and End implementations for expression/type nodes.
514514+515515+func (x *BadExpr) Pos() token.Pos { return x.From }
516516+func (x *Ident) Pos() token.Pos { return x.NamePos }
517517+func (x *TemplateLabel) Pos() token.Pos { return x.Langle }
518518+func (x *ExprLabel) Pos() token.Pos { return x.Lbrack }
519519+func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
520520+func (x *BasicLit) Pos() token.Pos { return x.ValuePos }
521521+func (x *Interpolation) Pos() token.Pos { return x.Elts[0].Pos() }
522522+func (x *StructLit) Pos() token.Pos {
523523+ if x.Lbrace == token.NoPos && len(x.Elts) > 0 {
524524+ return x.Elts[0].Pos()
525525+ }
526526+ return x.Lbrace
527527+}
528528+529529+func (x *ListLit) Pos() token.Pos { return x.Lbrack }
530530+func (x *ListComprehension) Pos() token.Pos { return x.Lbrack }
531531+func (x *ForClause) Pos() token.Pos { return x.For }
532532+func (x *IfClause) Pos() token.Pos { return x.If }
533533+func (x *ParenExpr) Pos() token.Pos { return x.Lparen }
534534+func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() }
535535+func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() }
536536+func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() }
537537+func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() }
538538+func (x *UnaryExpr) Pos() token.Pos { return x.OpPos }
539539+func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() }
540540+func (x *BottomLit) Pos() token.Pos { return x.Bottom }
541541+542542+func (x *BadExpr) End() token.Pos { return x.To }
543543+func (x *Ident) End() token.Pos {
544544+ return x.NamePos.Add(len(x.Name))
545545+}
546546+func (x *TemplateLabel) End() token.Pos { return x.Rangle }
547547+func (x *ExprLabel) End() token.Pos { return x.Rbrack }
548548+func (x *Ellipsis) End() token.Pos {
549549+ if x.Elt != nil {
550550+ return x.Elt.End()
551551+ }
552552+ return x.Ellipsis + 3 // len("...")
553553+}
554554+func (x *BasicLit) End() token.Pos { return token.Pos(int(x.ValuePos) + len(x.Value)) }
555555+func (x *Interpolation) End() token.Pos { return x.Elts[len(x.Elts)-1].Pos() }
556556+func (x *StructLit) End() token.Pos {
557557+ if x.Rbrace == token.NoPos && len(x.Elts) > 0 {
558558+ return x.Elts[len(x.Elts)-1].Pos()
559559+ }
560560+ return x.Rbrace.Add(1)
561561+}
562562+func (x *ListLit) End() token.Pos { return x.Rbrack.Add(1) }
563563+func (x *ListComprehension) End() token.Pos { return x.Rbrack }
564564+func (x *ForClause) End() token.Pos { return x.Source.End() }
565565+func (x *IfClause) End() token.Pos { return x.Condition.End() }
566566+func (x *ParenExpr) End() token.Pos { return x.Rparen.Add(1) }
567567+func (x *SelectorExpr) End() token.Pos { return x.Sel.End() }
568568+func (x *IndexExpr) End() token.Pos { return x.Rbrack.Add(1) }
569569+func (x *SliceExpr) End() token.Pos { return x.Rbrack.Add(1) }
570570+func (x *CallExpr) End() token.Pos { return x.Rparen.Add(1) }
571571+func (x *UnaryExpr) End() token.Pos { return x.X.End() }
572572+func (x *BinaryExpr) End() token.Pos { return x.Y.End() }
573573+func (x *BottomLit) End() token.Pos { return x.Bottom.Add(1) }
574574+575575+// ----------------------------------------------------------------------------
576576+// Convenience functions for Idents
577577+578578+// NewIdent creates a new Ident without position.
579579+// Useful for ASTs generated by code other than the Go
580580+func NewIdent(name string) *Ident {
581581+ return &Ident{comments{}, token.NoPos, name, nil, nil}
582582+}
583583+584584+func (id *Ident) String() string {
585585+ if id != nil {
586586+ return id.Name
587587+ }
588588+ return "<nil>"
589589+}
590590+591591+// ----------------------------------------------------------------------------
592592+// Declarations
593593+594594+// An ImportSpec node represents a single package import.
595595+type ImportSpec struct {
596596+ comments
597597+ Name *Ident // local package name (including "."); or nil
598598+ Path *BasicLit // import path
599599+ EndPos token.Pos // end of spec (overrides Path.Pos if nonzero)
600600+}
601601+602602+// Pos and End implementations for spec nodes.
603603+604604+func (s *ImportSpec) Pos() token.Pos {
605605+ if s.Name != nil {
606606+ return s.Name.Pos()
607607+ }
608608+ return s.Path.Pos()
609609+}
610610+611611+// func (s *AliasSpec) Pos() token.Pos { return s.Name.Pos() }
612612+// func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() }
613613+// func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() }
614614+615615+func (s *ImportSpec) End() token.Pos {
616616+ if s.EndPos != 0 {
617617+ return s.EndPos
618618+ }
619619+ return s.Path.End()
620620+}
621621+622622+// specNode() ensures that only spec nodes can be assigned to a Spec.
623623+func (*ImportSpec) specNode() {}
624624+625625+// A declaration is represented by one of the following declaration nodes.
626626+type (
627627+ // A BadDecl node is a placeholder for declarations containing
628628+ // syntax errors for which no correct declaration nodes can be
629629+ // created.
630630+ BadDecl struct {
631631+ comments
632632+ From, To token.Pos // position range of bad declaration
633633+ }
634634+635635+ // A ImportDecl node represents a series of import declarations. A valid
636636+ // Lparen position (Lparen.Line > 0) indicates a parenthesized declaration.
637637+ ImportDecl struct {
638638+ comments
639639+ Import token.Pos
640640+ Lparen token.Pos // position of '(', if any
641641+ Specs []*ImportSpec
642642+ Rparen token.Pos // position of ')', if any
643643+ }
644644+645645+ // An EmitDecl node represents a single expression used as a declaration.
646646+ // The expressions in this declaration is what will be emitted as
647647+ // configuration output.
648648+ //
649649+ // An EmitDecl may only appear at the top level.
650650+ EmitDecl struct {
651651+ comments
652652+ Expr Expr
653653+ }
654654+)
655655+656656+// Pos and End implementations for declaration nodes.
657657+658658+func (d *BadDecl) Pos() token.Pos { return d.From }
659659+func (d *ImportDecl) Pos() token.Pos { return d.Import }
660660+func (d *EmitDecl) Pos() token.Pos { return d.Expr.Pos() }
661661+662662+func (d *BadDecl) End() token.Pos { return d.To }
663663+func (d *ImportDecl) End() token.Pos {
664664+ if d.Rparen.IsValid() {
665665+ return d.Rparen.Add(1)
666666+ }
667667+ return d.Specs[0].End()
668668+}
669669+func (d *EmitDecl) End() token.Pos { return d.Expr.End() }
670670+671671+// ----------------------------------------------------------------------------
672672+// Files and packages
673673+674674+// A File node represents a Go source file.
675675+//
676676+// The Comments list contains all comments in the source file in order of
677677+// appearance, including the comments that are pointed to from other nodes
678678+// via Doc and Comment fields.
679679+type File struct {
680680+ Filename string
681681+ comments
682682+ Package token.Pos // position of "package" pseudo-keyword
683683+ Name *Ident // package names
684684+ // TODO: Change Expr to Decl?
685685+ Imports []*ImportSpec // imports in this file
686686+ Decls []Decl // top-level declarations; or nil
687687+ Unresolved []*Ident // unresolved identifiers in this file
688688+}
689689+690690+func (f *File) Pos() token.Pos {
691691+ if f.Package != token.NoPos {
692692+ return f.Package
693693+ }
694694+ if len(f.Decls) > 0 {
695695+ return f.Decls[0].Pos()
696696+ }
697697+ return token.NoPos
698698+}
699699+func (f *File) End() token.Pos {
700700+ if n := len(f.Decls); n > 0 {
701701+ return f.Decls[n-1].End()
702702+ }
703703+ if f.Name != nil {
704704+ return f.Name.End()
705705+ }
706706+ return token.NoPos
707707+}
+60
cue/ast/ast_test.go
···11+// Copyright 2018 The CUE Authors
22+//
33+// Licensed under the Apache License, Version 2.0 (the "License");
44+// you may not use this file except in compliance with the License.
55+// You may obtain a copy of the License at
66+//
77+// http://www.apache.org/licenses/LICENSE-2.0
88+//
99+// Unless required by applicable law or agreed to in writing, software
1010+// distributed under the License is distributed on an "AS IS" BASIS,
1111+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212+// See the License for the specific language governing permissions and
1313+// limitations under the License.
1414+1515+package ast
1616+1717+import (
1818+ "testing"
1919+)
2020+2121+func TestCommentText(t *testing.T) {
2222+ testCases := []struct {
2323+ list []string
2424+ text string
2525+ }{
2626+ {[]string{"//"}, ""},
2727+ {[]string{"// "}, ""},
2828+ {[]string{"//", "//", "// "}, ""},
2929+ {[]string{"// foo "}, "foo\n"},
3030+ {[]string{"//", "//", "// foo"}, "foo\n"},
3131+ {[]string{"// foo bar "}, "foo bar\n"},
3232+ {[]string{"// foo", "// bar"}, "foo\nbar\n"},
3333+ {[]string{"// foo", "//", "//", "//", "// bar"}, "foo\n\nbar\n"},
3434+ {[]string{"// foo", "/* bar */"}, "foo\n bar\n"},
3535+ {[]string{"//", "//", "//", "// foo", "//", "//", "//"}, "foo\n"},
3636+3737+ {[]string{"/**/"}, ""},
3838+ {[]string{"/* */"}, ""},
3939+ {[]string{"/**/", "/**/", "/* */"}, ""},
4040+ {[]string{"/* Foo */"}, " Foo\n"},
4141+ {[]string{"/* Foo Bar */"}, " Foo Bar\n"},
4242+ {[]string{"/* Foo*/", "/* Bar*/"}, " Foo\n Bar\n"},
4343+ {[]string{"/* Foo*/", "/**/", "/**/", "/**/", "// Bar"}, " Foo\n\nBar\n"},
4444+ {[]string{"/* Foo*/", "/*\n*/", "//", "/*\n*/", "// Bar"}, " Foo\n\nBar\n"},
4545+ {[]string{"/* Foo*/", "// Bar"}, " Foo\nBar\n"},
4646+ {[]string{"/* Foo\n Bar*/"}, " Foo\n Bar\n"},
4747+ }
4848+4949+ for i, c := range testCases {
5050+ list := make([]*Comment, len(c.list))
5151+ for i, s := range c.list {
5252+ list[i] = &Comment{Text: s}
5353+ }
5454+5555+ text := (&CommentGroup{List: list}).Text()
5656+ if text != c.text {
5757+ t.Errorf("case %d: got %q; expected %q", i, text, c.text)
5858+ }
5959+ }
6060+}
+287
cue/ast/walk.go
···11+// Copyright 2018 The CUE Authors
22+//
33+// Licensed under the Apache License, Version 2.0 (the "License");
44+// you may not use this file except in compliance with the License.
55+// You may obtain a copy of the License at
66+//
77+// http://www.apache.org/licenses/LICENSE-2.0
88+//
99+// Unless required by applicable law or agreed to in writing, software
1010+// distributed under the License is distributed on an "AS IS" BASIS,
1111+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212+// See the License for the specific language governing permissions and
1313+// limitations under the License.
1414+1515+package ast
1616+1717+import (
1818+ "fmt"
1919+2020+ "cuelang.org/go/cue/token"
2121+)
2222+2323+// Walk traverses an AST in depth-first order: It starts by calling f(node);
2424+// node must not be nil. If before returns true, Walk invokes f recursively for
2525+// each of the non-nil children of node, followed by a call of after. Both
2626+// functions may be nil. If before is nil, it is assumed to always return true.
2727+//
2828+func Walk(node Node, before func(Node) bool, after func(Node)) {
2929+ walk(&inspector{before: before, after: after}, node)
3030+}
3131+3232+// A visitor's before method is invoked for each node encountered by Walk.
3333+// If the result visitor w is not nil, Walk visits each of the children
3434+// of node with the visitor w, followed by a call of w.After.
3535+type visitor interface {
3636+ Before(node Node) (w visitor)
3737+ After(node Node)
3838+}
3939+4040+// Helper functions for common node lists. They may be empty.
4141+4242+func walkIdentList(v visitor, list []*Ident) {
4343+ for _, x := range list {
4444+ walk(v, x)
4545+ }
4646+}
4747+4848+func walkExprList(v visitor, list []Expr) {
4949+ for _, x := range list {
5050+ walk(v, x)
5151+ }
5252+}
5353+5454+func walkDeclList(v visitor, list []Decl) {
5555+ for _, x := range list {
5656+ walk(v, x)
5757+ }
5858+}
5959+6060+// walk traverses an AST in depth-first order: It starts by calling
6161+// v.Visit(node); node must not be nil. If the visitor w returned by
6262+// v.Visit(node) is not nil, walk is invoked recursively with visitor
6363+// w for each of the non-nil children of node, followed by a call of
6464+// w.Visit(nil).
6565+//
6666+func walk(v visitor, node Node) {
6767+ if v = v.Before(node); v == nil {
6868+ return
6969+ }
7070+7171+ // TODO: record the comment groups and interleave with the values like for
7272+ // parsing and printing?
7373+ for _, c := range node.Comments() {
7474+ walk(v, c)
7575+ }
7676+7777+ // walk children
7878+ // (the order of the cases matches the order
7979+ // of the corresponding node types in go)
8080+ switch n := node.(type) {
8181+ // Comments and fields
8282+ case *Comment:
8383+ // nothing to do
8484+8585+ case *CommentGroup:
8686+ for _, c := range n.List {
8787+ walk(v, c)
8888+ }
8989+9090+ case *Field:
9191+ walk(v, n.Label)
9292+ if n.Value != nil {
9393+ walk(v, n.Value)
9494+ }
9595+9696+ case *LambdaExpr:
9797+ for _, p := range n.Params {
9898+ walk(v, p)
9999+ }
100100+ walk(v, n.Expr)
101101+102102+ case *StructLit:
103103+ for _, f := range n.Elts {
104104+ walk(v, f)
105105+ }
106106+107107+ // Expressions
108108+ case *BottomLit, *BadExpr, *Ident, *BasicLit:
109109+ // nothing to do
110110+111111+ case *ExprLabel:
112112+ walk(v, n.Label)
113113+114114+ case *TemplateLabel:
115115+ walk(v, n.Ident)
116116+117117+ case *Interpolation:
118118+ for _, e := range n.Elts {
119119+ walk(v, e)
120120+ }
121121+122122+ case *Ellipsis:
123123+ if n.Elt != nil {
124124+ walk(v, n.Elt)
125125+ }
126126+127127+ case *ListLit:
128128+ walkExprList(v, n.Elts)
129129+ if n.Type != nil {
130130+ walk(v, n.Type)
131131+ }
132132+133133+ case *ParenExpr:
134134+ walk(v, n.X)
135135+136136+ case *SelectorExpr:
137137+ walk(v, n.X)
138138+ walk(v, n.Sel)
139139+140140+ case *IndexExpr:
141141+ walk(v, n.X)
142142+ walk(v, n.Index)
143143+144144+ case *SliceExpr:
145145+ walk(v, n.X)
146146+ if n.Low != nil {
147147+ walk(v, n.Low)
148148+ }
149149+ if n.High != nil {
150150+ walk(v, n.High)
151151+ }
152152+153153+ case *CallExpr:
154154+ walk(v, n.Fun)
155155+ walkExprList(v, n.Args)
156156+157157+ case *UnaryExpr:
158158+ walk(v, n.X)
159159+160160+ case *BinaryExpr:
161161+ walk(v, n.X)
162162+ walk(v, n.Y)
163163+164164+ // Declarations
165165+ case *ImportSpec:
166166+ if n.Name != nil {
167167+ walk(v, n.Name)
168168+ }
169169+ walk(v, n.Path)
170170+171171+ case *BadDecl:
172172+ // nothing to do
173173+174174+ case *ImportDecl:
175175+ for _, s := range n.Specs {
176176+ walk(v, s)
177177+ }
178178+179179+ case *EmitDecl:
180180+ walk(v, n.Expr)
181181+182182+ case *Alias:
183183+ walk(v, n.Ident)
184184+ walk(v, n.Expr)
185185+186186+ case *ComprehensionDecl:
187187+ walk(v, n.Field)
188188+ for _, c := range n.Clauses {
189189+ walk(v, c)
190190+ }
191191+192192+ // Files and packages
193193+ case *File:
194194+ if n.Name != nil {
195195+ walk(v, n.Name)
196196+ }
197197+ walkDeclList(v, n.Decls)
198198+ // don't walk n.Comments - they have been
199199+ // visited already through the individual
200200+ // nodes
201201+202202+ case *ListComprehension:
203203+ walk(v, n.Expr)
204204+ for _, c := range n.Clauses {
205205+ walk(v, c)
206206+ }
207207+208208+ case *ForClause:
209209+ if n.Key != nil {
210210+ walk(v, n.Key)
211211+ }
212212+ walk(v, n.Value)
213213+ walk(v, n.Source)
214214+215215+ case *IfClause:
216216+ walk(v, n.Condition)
217217+218218+ default:
219219+ panic(fmt.Sprintf("Walk: unexpected node type %T", n))
220220+ }
221221+222222+ v.After(node)
223223+}
224224+225225+type inspector struct {
226226+ before func(Node) bool
227227+ after func(Node)
228228+229229+ commentStack []commentFrame
230230+ current commentFrame
231231+}
232232+233233+type commentFrame struct {
234234+ cg []*CommentGroup
235235+ pos int8
236236+}
237237+238238+func (f *inspector) Before(node Node) visitor {
239239+ if f.before == nil || f.before(node) {
240240+ f.commentStack = append(f.commentStack, f.current)
241241+ f.current = commentFrame{cg: node.Comments()}
242242+ f.visitComments(f.current.pos)
243243+ return f
244244+ }
245245+ return nil
246246+}
247247+248248+func (f *inspector) After(node Node) {
249249+ f.visitComments(127)
250250+ p := len(f.commentStack) - 1
251251+ f.current = f.commentStack[p]
252252+ f.commentStack = f.commentStack[:p]
253253+ f.current.pos++
254254+ if f.after != nil {
255255+ f.after(node)
256256+ }
257257+}
258258+259259+func (f *inspector) Token(t token.Token) {
260260+ f.current.pos++
261261+}
262262+263263+func (f *inspector) setPos(i int8) {
264264+ f.current.pos = i
265265+}
266266+267267+func (f *inspector) visitComments(pos int8) {
268268+ c := &f.current
269269+ for ; len(c.cg) > 0; c.cg = c.cg[1:] {
270270+ cg := c.cg[0]
271271+ if cg.Position == pos {
272272+ continue
273273+ }
274274+ if f.before == nil || f.before(cg) {
275275+ for _, c := range cg.List {
276276+ if f.before == nil || f.before(c) {
277277+ if f.after != nil {
278278+ f.after(c)
279279+ }
280280+ }
281281+ }
282282+ if f.after != nil {
283283+ f.after(cg)
284284+ }
285285+ }
286286+ }
287287+}