| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 1 | // Copyright 2017 The Bazel 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 provides a Skylark parser and abstract syntax tree. | 
 | 6 | package syntax | 
 | 7 |  | 
 | 8 | // A Node is a node in a Skylark syntax tree. | 
 | 9 | type Node interface { | 
 | 10 | 	// Span returns the start and end position of the expression. | 
 | 11 | 	Span() (start, end Position) | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 12 |  | 
 | 13 | 	// Comments returns the comments associated with this node. | 
 | 14 | 	// It returns nil if RetainComments was not specified during parsing, | 
 | 15 | 	// or if AllocComments was not called. | 
 | 16 | 	Comments() *Comments | 
 | 17 |  | 
 | 18 | 	// AllocComments allocates a new Comments node if there was none. | 
 | 19 | 	// This makes possible to add new comments using Comments() method. | 
 | 20 | 	AllocComments() | 
 | 21 | } | 
 | 22 |  | 
 | 23 | // A Comment represents a single # comment. | 
 | 24 | type Comment struct { | 
 | 25 | 	Start Position | 
 | 26 | 	Text  string // without trailing newline | 
 | 27 | } | 
 | 28 |  | 
 | 29 | // Comments collects the comments associated with an expression. | 
 | 30 | type Comments struct { | 
 | 31 | 	Before []Comment // whole-line comments before this expression | 
 | 32 | 	Suffix []Comment // end-of-line comments after this expression (up to 1) | 
 | 33 |  | 
 | 34 | 	// For top-level expressions only, After lists whole-line | 
 | 35 | 	// comments following the expression. | 
 | 36 | 	After []Comment | 
 | 37 | } | 
 | 38 |  | 
 | 39 | // A commentsRef is a possibly-nil reference to a set of comments. | 
 | 40 | // A commentsRef is embedded in each type of syntax node, | 
 | 41 | // and provides its Comments and AllocComments methods. | 
 | 42 | type commentsRef struct{ ref *Comments } | 
 | 43 |  | 
 | 44 | // Comments returns the comments associated with a syntax node, | 
 | 45 | // or nil if AllocComments has not yet been called. | 
 | 46 | func (cr commentsRef) Comments() *Comments { return cr.ref } | 
 | 47 |  | 
 | 48 | // AllocComments enables comments to be associated with a syntax node. | 
 | 49 | func (cr *commentsRef) AllocComments() { | 
 | 50 | 	if cr.ref == nil { | 
 | 51 | 		cr.ref = new(Comments) | 
 | 52 | 	} | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 53 | } | 
 | 54 |  | 
 | 55 | // Start returns the start position of the expression. | 
 | 56 | func Start(n Node) Position { | 
 | 57 | 	start, _ := n.Span() | 
 | 58 | 	return start | 
 | 59 | } | 
 | 60 |  | 
 | 61 | // End returns the end position of the expression. | 
 | 62 | func End(n Node) Position { | 
 | 63 | 	_, end := n.Span() | 
 | 64 | 	return end | 
 | 65 | } | 
 | 66 |  | 
 | 67 | // A File represents a Skylark file. | 
 | 68 | type File struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 69 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 70 | 	Path  string | 
 | 71 | 	Stmts []Stmt | 
 | 72 |  | 
 | 73 | 	// set by resolver: | 
 | 74 | 	Locals []*Ident // this file's (comprehension-)local variables | 
 | 75 | } | 
 | 76 |  | 
 | 77 | func (x *File) Span() (start, end Position) { | 
 | 78 | 	if len(x.Stmts) == 0 { | 
 | 79 | 		return | 
 | 80 | 	} | 
 | 81 | 	start, _ = x.Stmts[0].Span() | 
 | 82 | 	_, end = x.Stmts[len(x.Stmts)-1].Span() | 
 | 83 | 	return start, end | 
 | 84 | } | 
 | 85 |  | 
 | 86 | // A Stmt is a Skylark statement. | 
 | 87 | type Stmt interface { | 
 | 88 | 	Node | 
 | 89 | 	stmt() | 
 | 90 | } | 
 | 91 |  | 
 | 92 | func (*AssignStmt) stmt() {} | 
 | 93 | func (*BranchStmt) stmt() {} | 
 | 94 | func (*DefStmt) stmt()    {} | 
 | 95 | func (*ExprStmt) stmt()   {} | 
 | 96 | func (*ForStmt) stmt()    {} | 
 | 97 | func (*IfStmt) stmt()     {} | 
 | 98 | func (*LoadStmt) stmt()   {} | 
 | 99 | func (*ReturnStmt) stmt() {} | 
 | 100 |  | 
 | 101 | // An AssignStmt represents an assignment: | 
 | 102 | //	x = 0 | 
 | 103 | //	x, y = y, x | 
 | 104 | // 	x += 1 | 
 | 105 | type AssignStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 106 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 107 | 	OpPos Position | 
 | 108 | 	Op    Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ | 
 | 109 | 	LHS   Expr | 
 | 110 | 	RHS   Expr | 
 | 111 | } | 
 | 112 |  | 
 | 113 | func (x *AssignStmt) Span() (start, end Position) { | 
 | 114 | 	start, _ = x.LHS.Span() | 
 | 115 | 	_, end = x.RHS.Span() | 
 | 116 | 	return | 
 | 117 | } | 
 | 118 |  | 
 | 119 | // A Function represents the common parts of LambdaExpr and DefStmt. | 
 | 120 | type Function struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 121 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 122 | 	StartPos Position // position of DEF or LAMBDA token | 
 | 123 | 	Params   []Expr   // param = ident | ident=expr | *ident | **ident | 
 | 124 | 	Body     []Stmt | 
 | 125 |  | 
 | 126 | 	// set by resolver: | 
 | 127 | 	HasVarargs bool     // whether params includes *args (convenience) | 
 | 128 | 	HasKwargs  bool     // whether params includes **kwargs (convenience) | 
 | 129 | 	Locals     []*Ident // this function's local variables, parameters first | 
 | 130 | 	FreeVars   []*Ident // enclosing local variables to capture in closure | 
 | 131 | } | 
 | 132 |  | 
 | 133 | func (x *Function) Span() (start, end Position) { | 
 | 134 | 	_, end = x.Body[len(x.Body)-1].Span() | 
 | 135 | 	return x.StartPos, end | 
 | 136 | } | 
 | 137 |  | 
 | 138 | // A DefStmt represents a function definition. | 
 | 139 | type DefStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 140 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 141 | 	Def  Position | 
 | 142 | 	Name *Ident | 
 | 143 | 	Function | 
 | 144 | } | 
 | 145 |  | 
 | 146 | func (x *DefStmt) Span() (start, end Position) { | 
 | 147 | 	_, end = x.Function.Body[len(x.Body)-1].Span() | 
 | 148 | 	return x.Def, end | 
 | 149 | } | 
 | 150 |  | 
 | 151 | // An ExprStmt is an expression evaluated for side effects. | 
 | 152 | type ExprStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 153 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 154 | 	X Expr | 
 | 155 | } | 
 | 156 |  | 
 | 157 | func (x *ExprStmt) Span() (start, end Position) { | 
 | 158 | 	return x.X.Span() | 
 | 159 | } | 
 | 160 |  | 
 | 161 | // An IfStmt is a conditional: If Cond: True; else: False. | 
 | 162 | // 'elseif' is desugared into a chain of IfStmts. | 
 | 163 | type IfStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 164 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 165 | 	If      Position // IF or ELIF | 
 | 166 | 	Cond    Expr | 
 | 167 | 	True    []Stmt | 
 | 168 | 	ElsePos Position // ELSE or ELIF | 
 | 169 | 	False   []Stmt   // optional | 
 | 170 | } | 
 | 171 |  | 
 | 172 | func (x *IfStmt) Span() (start, end Position) { | 
 | 173 | 	body := x.False | 
 | 174 | 	if body == nil { | 
 | 175 | 		body = x.True | 
 | 176 | 	} | 
 | 177 | 	_, end = body[len(body)-1].Span() | 
 | 178 | 	return x.If, end | 
 | 179 | } | 
 | 180 |  | 
 | 181 | // A LoadStmt loads another module and binds names from it: | 
 | 182 | // load(Module, "x", y="foo"). | 
 | 183 | // | 
 | 184 | // The AST is slightly unfaithful to the concrete syntax here because | 
 | 185 | // Skylark's load statement, so that it can be implemented in Python, | 
 | 186 | // binds some names (like y above) with an identifier and some (like x) | 
 | 187 | // without.  For consistency we create fake identifiers for all the | 
 | 188 | // strings. | 
 | 189 | type LoadStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 190 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 191 | 	Load   Position | 
 | 192 | 	Module *Literal // a string | 
 | 193 | 	From   []*Ident // name defined in loading module | 
 | 194 | 	To     []*Ident // name in loaded module | 
 | 195 | 	Rparen Position | 
 | 196 | } | 
 | 197 |  | 
 | 198 | func (x *LoadStmt) Span() (start, end Position) { | 
 | 199 | 	return x.Load, x.Rparen | 
 | 200 | } | 
 | 201 |  | 
| alandonovan | ab191a0 | 2018-03-02 10:20:44 -0500 | [diff] [blame^] | 202 | // ModuleName returns the name of the module loaded by this statement. | 
 | 203 | func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) } | 
 | 204 |  | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 205 | // A BranchStmt changes the flow of control: break, continue, pass. | 
 | 206 | type BranchStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 207 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 208 | 	Token    Token // = BREAK | CONTINUE | PASS | 
 | 209 | 	TokenPos Position | 
 | 210 | } | 
 | 211 |  | 
 | 212 | func (x *BranchStmt) Span() (start, end Position) { | 
 | 213 | 	return x.TokenPos, x.TokenPos.add(x.Token.String()) | 
 | 214 | } | 
 | 215 |  | 
 | 216 | // A ReturnStmt returns from a function. | 
 | 217 | type ReturnStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 218 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 219 | 	Return Position | 
 | 220 | 	Result Expr // may be nil | 
 | 221 | } | 
 | 222 |  | 
 | 223 | func (x *ReturnStmt) Span() (start, end Position) { | 
 | 224 | 	if x.Result == nil { | 
 | 225 | 		return x.Return, x.Return.add("return") | 
 | 226 | 	} | 
 | 227 | 	_, end = x.Result.Span() | 
 | 228 | 	return x.Return, end | 
 | 229 | } | 
 | 230 |  | 
 | 231 | // An Expr is a Skylark expression. | 
 | 232 | type Expr interface { | 
 | 233 | 	Node | 
 | 234 | 	expr() | 
 | 235 | } | 
 | 236 |  | 
 | 237 | func (*BinaryExpr) expr()    {} | 
 | 238 | func (*CallExpr) expr()      {} | 
 | 239 | func (*Comprehension) expr() {} | 
 | 240 | func (*CondExpr) expr()      {} | 
 | 241 | func (*DictEntry) expr()     {} | 
 | 242 | func (*DictExpr) expr()      {} | 
 | 243 | func (*DotExpr) expr()       {} | 
 | 244 | func (*Ident) expr()         {} | 
 | 245 | func (*IndexExpr) expr()     {} | 
 | 246 | func (*LambdaExpr) expr()    {} | 
 | 247 | func (*ListExpr) expr()      {} | 
 | 248 | func (*Literal) expr()       {} | 
| Laurent Le Brun | 28ceca7 | 2018-02-26 15:01:53 +0100 | [diff] [blame] | 249 | func (*ParenExpr) expr()     {} | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 250 | func (*SliceExpr) expr()     {} | 
 | 251 | func (*TupleExpr) expr()     {} | 
 | 252 | func (*UnaryExpr) expr()     {} | 
 | 253 |  | 
 | 254 | // An Ident represents an identifier. | 
 | 255 | type Ident struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 256 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 257 | 	NamePos Position | 
 | 258 | 	Name    string | 
 | 259 |  | 
 | 260 | 	// set by resolver: | 
 | 261 |  | 
 | 262 | 	Scope uint8 // one of resolve.{Undefined,Local,Free,Global,Builtin} | 
 | 263 | 	Index int   // index into enclosing {DefStmt,File}.Locals (if scope==Local) or DefStmt.FreeVars (if scope==Free) | 
 | 264 | } | 
 | 265 |  | 
 | 266 | func (x *Ident) Span() (start, end Position) { | 
 | 267 | 	return x.NamePos, x.NamePos.add(x.Name) | 
 | 268 | } | 
 | 269 |  | 
 | 270 | // A Literal represents a literal string or number. | 
 | 271 | type Literal struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 272 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 273 | 	Token    Token // = STRING | INT | 
 | 274 | 	TokenPos Position | 
 | 275 | 	Raw      string      // uninterpreted text | 
| Mohamed Elqdusy | 69e9615 | 2018-01-22 20:00:29 +0100 | [diff] [blame] | 276 | 	Value    interface{} // = string | int64 | *big.Int | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 277 | } | 
 | 278 |  | 
 | 279 | func (x *Literal) Span() (start, end Position) { | 
 | 280 | 	return x.TokenPos, x.TokenPos.add(x.Raw) | 
 | 281 | } | 
 | 282 |  | 
| Laurent Le Brun | 28ceca7 | 2018-02-26 15:01:53 +0100 | [diff] [blame] | 283 | // A ParenExpr represents a parenthesized expression: (X). | 
 | 284 | type ParenExpr struct { | 
 | 285 | 	commentsRef | 
 | 286 | 	Lparen Position | 
 | 287 | 	X      Expr | 
 | 288 | 	Rparen Position | 
 | 289 | } | 
 | 290 |  | 
 | 291 | func (x *ParenExpr) Span() (start, end Position) { | 
 | 292 | 	return x.Lparen, x.Rparen.add(")") | 
 | 293 | } | 
 | 294 |  | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 295 | // A CallExpr represents a function call expression: Fn(Args). | 
 | 296 | type CallExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 297 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 298 | 	Fn     Expr | 
 | 299 | 	Lparen Position | 
 | 300 | 	Args   []Expr | 
 | 301 | 	Rparen Position | 
 | 302 | } | 
 | 303 |  | 
 | 304 | func (x *CallExpr) Span() (start, end Position) { | 
 | 305 | 	start, _ = x.Fn.Span() | 
 | 306 | 	return start, x.Rparen.add(")") | 
 | 307 | } | 
 | 308 |  | 
 | 309 | // A DotExpr represents a field or method selector: X.Name. | 
 | 310 | type DotExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 311 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 312 | 	X       Expr | 
 | 313 | 	Dot     Position | 
 | 314 | 	NamePos Position | 
 | 315 | 	Name    *Ident | 
 | 316 | } | 
 | 317 |  | 
 | 318 | func (x *DotExpr) Span() (start, end Position) { | 
 | 319 | 	start, _ = x.X.Span() | 
 | 320 | 	_, end = x.Name.Span() | 
 | 321 | 	return | 
 | 322 | } | 
 | 323 |  | 
 | 324 | // A Comprehension represents a list or dict comprehension: | 
 | 325 | // [Body for ... if ...] or {Body for ... if ...} | 
 | 326 | type Comprehension struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 327 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 328 | 	Curly   bool // {x:y for ...} or {x for ...}, not [x for ...] | 
 | 329 | 	Lbrack  Position | 
 | 330 | 	Body    Expr | 
 | 331 | 	Clauses []Node // = *ForClause | *IfClause | 
 | 332 | 	Rbrack  Position | 
 | 333 | } | 
 | 334 |  | 
 | 335 | func (x *Comprehension) Span() (start, end Position) { | 
 | 336 | 	return x.Lbrack, x.Rbrack.add("]") | 
 | 337 | } | 
 | 338 |  | 
 | 339 | // A ForStmt represents a loop: for Vars in X: Body. | 
 | 340 | type ForStmt struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 341 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 342 | 	For  Position | 
 | 343 | 	Vars Expr // name, or tuple of names | 
 | 344 | 	X    Expr | 
 | 345 | 	Body []Stmt | 
 | 346 | } | 
 | 347 |  | 
 | 348 | func (x *ForStmt) Span() (start, end Position) { | 
 | 349 | 	_, end = x.Body[len(x.Body)-1].Span() | 
 | 350 | 	return x.For, end | 
 | 351 | } | 
 | 352 |  | 
 | 353 | // A ForClause represents a for clause in a list comprehension: for Vars in X. | 
 | 354 | type ForClause struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 355 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 356 | 	For  Position | 
 | 357 | 	Vars Expr // name, or tuple of names | 
 | 358 | 	In   Position | 
 | 359 | 	X    Expr | 
 | 360 | } | 
 | 361 |  | 
 | 362 | func (x *ForClause) Span() (start, end Position) { | 
 | 363 | 	_, end = x.X.Span() | 
 | 364 | 	return x.For, end | 
 | 365 | } | 
 | 366 |  | 
 | 367 | // An IfClause represents an if clause in a list comprehension: if Cond. | 
 | 368 | type IfClause struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 369 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 370 | 	If   Position | 
 | 371 | 	Cond Expr | 
 | 372 | } | 
 | 373 |  | 
 | 374 | func (x *IfClause) Span() (start, end Position) { | 
 | 375 | 	_, end = x.Cond.Span() | 
 | 376 | 	return x.If, end | 
 | 377 | } | 
 | 378 |  | 
 | 379 | // A DictExpr represents a dictionary literal: { List }. | 
 | 380 | type DictExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 381 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 382 | 	Lbrace Position | 
 | 383 | 	List   []Expr // all *DictEntrys | 
 | 384 | 	Rbrace Position | 
 | 385 | } | 
 | 386 |  | 
 | 387 | func (x *DictExpr) Span() (start, end Position) { | 
 | 388 | 	return x.Lbrace, x.Rbrace.add("}") | 
 | 389 | } | 
 | 390 |  | 
 | 391 | // A DictEntry represents a dictionary entry: Key: Value. | 
 | 392 | // Used only within a DictExpr. | 
 | 393 | type DictEntry struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 394 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 395 | 	Key   Expr | 
 | 396 | 	Colon Position | 
 | 397 | 	Value Expr | 
 | 398 | } | 
 | 399 |  | 
 | 400 | func (x *DictEntry) Span() (start, end Position) { | 
 | 401 | 	start, _ = x.Key.Span() | 
 | 402 | 	_, end = x.Value.Span() | 
 | 403 | 	return start, end | 
 | 404 | } | 
 | 405 |  | 
 | 406 | // A LambdaExpr represents an inline function abstraction. | 
 | 407 | // | 
 | 408 | // Although they may be added in future, lambda expressions are not | 
 | 409 | // currently part of the Skylark spec, so their use is controlled by the | 
 | 410 | // resolver.AllowLambda flag. | 
 | 411 | type LambdaExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 412 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 413 | 	Lambda Position | 
 | 414 | 	Function | 
 | 415 | } | 
 | 416 |  | 
 | 417 | func (x *LambdaExpr) Span() (start, end Position) { | 
 | 418 | 	_, end = x.Function.Body[len(x.Body)-1].Span() | 
 | 419 | 	return x.Lambda, end | 
 | 420 | } | 
 | 421 |  | 
 | 422 | // A ListExpr represents a list literal: [ List ]. | 
 | 423 | type ListExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 424 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 425 | 	Lbrack Position | 
 | 426 | 	List   []Expr | 
 | 427 | 	Rbrack Position | 
 | 428 | } | 
 | 429 |  | 
 | 430 | func (x *ListExpr) Span() (start, end Position) { | 
 | 431 | 	return x.Lbrack, x.Rbrack.add("]") | 
 | 432 | } | 
 | 433 |  | 
 | 434 | // CondExpr represents the conditional: X if COND else ELSE. | 
 | 435 | type CondExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 436 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 437 | 	If      Position | 
 | 438 | 	Cond    Expr | 
 | 439 | 	True    Expr | 
 | 440 | 	ElsePos Position | 
 | 441 | 	False   Expr | 
 | 442 | } | 
 | 443 |  | 
 | 444 | func (x *CondExpr) Span() (start, end Position) { | 
 | 445 | 	start, _ = x.True.Span() | 
 | 446 | 	_, end = x.False.Span() | 
 | 447 | 	return start, end | 
 | 448 | } | 
 | 449 |  | 
 | 450 | // A TupleExpr represents a tuple literal: (List). | 
 | 451 | type TupleExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 452 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 453 | 	Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty | 
 | 454 | 	List   []Expr | 
 | 455 | 	Rparen Position | 
 | 456 | } | 
 | 457 |  | 
 | 458 | func (x *TupleExpr) Span() (start, end Position) { | 
 | 459 | 	if x.Lparen.IsValid() { | 
 | 460 | 		return x.Lparen, x.Rparen | 
 | 461 | 	} else { | 
 | 462 | 		return Start(x.List[0]), End(x.List[len(x.List)-1]) | 
 | 463 | 	} | 
 | 464 | } | 
 | 465 |  | 
 | 466 | // A UnaryExpr represents a unary expression: Op X. | 
 | 467 | type UnaryExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 468 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 469 | 	OpPos Position | 
 | 470 | 	Op    Token | 
 | 471 | 	X     Expr | 
 | 472 | } | 
 | 473 |  | 
 | 474 | func (x *UnaryExpr) Span() (start, end Position) { | 
 | 475 | 	_, end = x.X.Span() | 
 | 476 | 	return x.OpPos, end | 
 | 477 | } | 
 | 478 |  | 
 | 479 | // A BinaryExpr represents a binary expression: X Op Y. | 
 | 480 | type BinaryExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 481 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 482 | 	X     Expr | 
 | 483 | 	OpPos Position | 
 | 484 | 	Op    Token | 
 | 485 | 	Y     Expr | 
 | 486 | } | 
 | 487 |  | 
 | 488 | func (x *BinaryExpr) Span() (start, end Position) { | 
 | 489 | 	start, _ = x.X.Span() | 
 | 490 | 	_, end = x.Y.Span() | 
 | 491 | 	return start, end | 
 | 492 | } | 
 | 493 |  | 
 | 494 | // A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step]. | 
 | 495 | type SliceExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 496 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 497 | 	X            Expr | 
 | 498 | 	Lbrack       Position | 
 | 499 | 	Lo, Hi, Step Expr // all optional | 
 | 500 | 	Rbrack       Position | 
 | 501 | } | 
 | 502 |  | 
 | 503 | func (x *SliceExpr) Span() (start, end Position) { | 
 | 504 | 	start, _ = x.X.Span() | 
 | 505 | 	return start, x.Rbrack | 
 | 506 | } | 
 | 507 |  | 
 | 508 | // An IndexExpr represents an index expression: X[Y]. | 
 | 509 | type IndexExpr struct { | 
| Laurent Le Brun | 689fc22 | 2018-02-22 19:37:18 +0100 | [diff] [blame] | 510 | 	commentsRef | 
| Alan Donovan | 312d1a5 | 2017-10-02 10:10:28 -0400 | [diff] [blame] | 511 | 	X      Expr | 
 | 512 | 	Lbrack Position | 
 | 513 | 	Y      Expr | 
 | 514 | 	Rbrack Position | 
 | 515 | } | 
 | 516 |  | 
 | 517 | func (x *IndexExpr) Span() (start, end Position) { | 
 | 518 | 	start, _ = x.X.Span() | 
 | 519 | 	return start, x.Rbrack | 
 | 520 | } |