github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/compiler/ast/ast.go (about) 1 // Original: src/go/ast/ast.go 2 // 3 // Copyright 2009 The Go Authors. All rights reserved. 4 // Portions Copyright 2016 Hiroshi Ioka. All rights reserved. 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Google Inc. nor the names of its 17 // contributors may be used to endorse or promote products derived from 18 // this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32 package ast 33 34 import ( 35 "strings" 36 37 "github.com/hirochachacha/plua/compiler/token" 38 "github.com/hirochachacha/plua/position" 39 ) 40 41 // ---------------------------------------------------------------------------- 42 // Interfaces 43 // 44 45 // All node types implement the Node interface. 46 type Node interface { 47 Type() Type 48 Pos() position.Position // position of first character belonging to the node 49 End() position.Position // position of first character immediately after the node 50 } 51 52 // All expression nodes implement the Expr interface. 53 type Expr interface { 54 Node 55 56 exprNode() 57 } 58 59 // All statement nodes implement the Stmt interface. 60 type Stmt interface { 61 Node 62 63 stmtNode() 64 } 65 66 // ---------------------------------------------------------------------------- 67 // Expressions 68 69 // An expression is represented by a tree consisting of one 70 // or more of the following concrete expression nodes. 71 // 72 type ( 73 // A BadExpr node is a placeholder for expressions containing 74 // syntax errors for which no correct expression nodes can be 75 // created. 76 // 77 BadExpr struct { 78 From, To position.Position // position range of bad expression 79 } 80 81 // An Name node represents an identifier. 82 Name struct { 83 NamePos position.Position // identifier position 84 Name string // identifier name 85 } 86 87 Vararg struct { 88 Ellipsis position.Position // position of "..." 89 } 90 91 // A BasicLit node represents a literal of basic type. 92 BasicLit struct { 93 token.Token 94 } 95 96 // A FuncLit node represents a function literal. 97 FuncLit struct { 98 Func position.Position // position of "function" keyword 99 Body *FuncBody // function body 100 EndPos position.Position 101 } 102 103 // A TableLit node represents a composite literal. 104 TableLit struct { 105 Lbrace position.Position // position of "{" 106 Fields []Expr // fields 107 Rbrace position.Position // position of "}" 108 } 109 110 // A ParenExpr node represents a parenthesized expression. 111 ParenExpr struct { 112 Lparen position.Position // position of "(" 113 X Expr // parenthesized expression 114 Rparen position.Position // position of ")" 115 } 116 117 // A SelectorExpr node represents an expression followed by a selector. 118 SelectorExpr struct { 119 X Expr // expression 120 Period position.Position // position of "." 121 Sel *Name // field selector 122 } 123 124 // An IndexExpr node represents an expression followed by an index. 125 IndexExpr struct { 126 X Expr // expression 127 Lbrack position.Position // position of "[" 128 Index Expr // index expression 129 Rbrack position.Position // position of "]" 130 } 131 132 // A CallExpr node represents an expression followed by an argument list. 133 CallExpr struct { 134 X Expr // function expression 135 Colon position.Position // position of ":" or position.NoPos 136 Name *Name // method name; or nil 137 Lparen position.Position // position of "(" or position.NoPos 138 Args []Expr // function arguments; or nil 139 Rparen position.Position // position of ")" or position.NoPos 140 } 141 142 // A UnaryExpr node represents a unary expression. 143 UnaryExpr struct { 144 OpPos position.Position // position of Op 145 Op token.Type // operator 146 X Expr // operand 147 } 148 149 // A BinaryExpr node represents a binary expression. 150 BinaryExpr struct { 151 X Expr // left operand 152 OpPos position.Position // position of Op 153 Op token.Type // operator 154 Y Expr // right operand 155 } 156 157 // A KeyValueExpr node represents (key = value) pairs or (value) 158 // in table literals. 159 // 160 KeyValueExpr struct { 161 Lbrack position.Position // position of "["; or position.NoPos 162 Key Expr // key; or nil 163 Rbrack position.Position // position of "]"; or position.NoPos 164 Equal position.Position // position of "="; or position.NoPos 165 Value Expr 166 } 167 ) 168 169 func (*BadExpr) Type() Type { return BAD_EXPR } 170 func (*Name) Type() Type { return NAME } 171 func (*Vararg) Type() Type { return VARARG } 172 func (*BasicLit) Type() Type { return BASIC_LIT } 173 func (*FuncLit) Type() Type { return FUNC_LIT } 174 func (*TableLit) Type() Type { return TABLE_LIT } 175 func (*ParenExpr) Type() Type { return PAREN_EXPR } 176 func (*SelectorExpr) Type() Type { return SELECTOR_EXPR } 177 func (*IndexExpr) Type() Type { return INDEX_EXPR } 178 func (*CallExpr) Type() Type { return CALL_EXPR } 179 func (*UnaryExpr) Type() Type { return UNARY_EXPR } 180 func (*BinaryExpr) Type() Type { return BINARY_EXPR } 181 func (*KeyValueExpr) Type() Type { return KEY_VALUE_EXPR } 182 183 // Pos and End implementations for expression/type nodes. 184 // 185 func (x *BadExpr) Pos() position.Position { return x.From } 186 func (x *Name) Pos() position.Position { return x.NamePos } 187 func (x *Vararg) Pos() position.Position { return x.Ellipsis } 188 func (x *BasicLit) Pos() position.Position { return x.Token.Pos } 189 func (x *FuncLit) Pos() position.Position { return x.Func } 190 func (x *TableLit) Pos() position.Position { 191 return x.Lbrace 192 } 193 func (x *ParenExpr) Pos() position.Position { return x.Lparen } 194 func (x *SelectorExpr) Pos() position.Position { return x.X.Pos() } 195 func (x *IndexExpr) Pos() position.Position { return x.X.Pos() } 196 func (x *CallExpr) Pos() position.Position { return x.X.Pos() } 197 func (x *UnaryExpr) Pos() position.Position { return x.OpPos } 198 func (x *BinaryExpr) Pos() position.Position { return x.X.Pos() } 199 func (x *KeyValueExpr) Pos() position.Position { 200 if x.Lbrack.IsValid() { 201 return x.Lbrack 202 } 203 204 return x.Key.Pos() 205 } 206 207 func (x *BadExpr) End() position.Position { return x.To } 208 func (x *Name) End() position.Position { return x.NamePos.Offset(x.Name) } 209 func (x *Vararg) End() position.Position { return x.Ellipsis.OffsetColumn(3) } 210 func (x *BasicLit) End() position.Position { return x.Token.Pos.Offset(x.Token.Lit) } 211 func (x *FuncLit) End() position.Position { return x.EndPos.OffsetColumn(3) } 212 func (x *TableLit) End() position.Position { return x.Rbrace.OffsetColumn(1) } 213 func (x *ParenExpr) End() position.Position { return x.Rparen.OffsetColumn(1) } 214 func (x *SelectorExpr) End() position.Position { return x.Sel.End() } 215 func (x *IndexExpr) End() position.Position { return x.Rbrack.OffsetColumn(1) } 216 func (x *CallExpr) End() position.Position { 217 if x.Rparen.IsValid() { 218 return x.Rparen.OffsetColumn(1) 219 } 220 if len(x.Args) > 0 { 221 return x.Args[len(x.Args)-1].End() 222 } 223 return position.NoPos 224 } 225 func (x *UnaryExpr) End() position.Position { return x.X.End() } 226 func (x *BinaryExpr) End() position.Position { return x.Y.End() } 227 func (x *KeyValueExpr) End() position.Position { return x.Value.End() } 228 229 // exprNode() ensures that only expression/type nodes can be 230 // assigned to an ExprNode. 231 // 232 func (*BadExpr) exprNode() {} 233 func (*Name) exprNode() {} 234 func (*Vararg) exprNode() {} 235 func (*BasicLit) exprNode() {} 236 func (*FuncLit) exprNode() {} 237 func (*TableLit) exprNode() {} 238 func (*ParenExpr) exprNode() {} 239 func (*SelectorExpr) exprNode() {} 240 func (*IndexExpr) exprNode() {} 241 func (*CallExpr) exprNode() {} 242 func (*UnaryExpr) exprNode() {} 243 func (*BinaryExpr) exprNode() {} 244 func (*KeyValueExpr) exprNode() {} 245 246 // ---------------------------------------------------------------------------- 247 // Statements 248 249 // A statement is represented by a tree consisting of one 250 // or more of the following concrete statement nodes. 251 // 252 type ( 253 // A BadStmt node is a placeholder for statements containing 254 // syntax errors for which no correct statement nodes can be 255 // created. 256 // 257 BadStmt struct { 258 From, To position.Position // position range of bad statement 259 } 260 261 // An EmptyStmt node represents an empty statement. 262 // The "position" of the empty statement is the position 263 // of the immediately preceding semicolon. 264 // 265 EmptyStmt struct { 266 Semicolon position.Position // position of preceding ";" 267 } 268 269 LocalAssignStmt struct { 270 Local position.Position // position of "local" keyword 271 LHS []*Name 272 Equal position.Position // position of Tok 273 RHS []Expr 274 } 275 276 LocalFuncStmt struct { 277 Local position.Position // position of "local" keyword 278 Func position.Position // position of "function" keyword 279 Name *Name 280 Body *FuncBody // function body 281 EndPos position.Position 282 } 283 284 // A FuncStmt node represents a function statement. 285 FuncStmt struct { 286 Func position.Position // position of "function" keyword 287 PathList []*Name 288 AccessTok token.Type // "." or ":" 289 AccessPos position.Position // position of AccessTok 290 Name *Name 291 Body *FuncBody // function body 292 EndPos position.Position 293 } 294 295 // A LabelStmt node represents a label statement. 296 LabelStmt struct { 297 Label position.Position // position of "::" 298 Name *Name 299 EndLabel position.Position // position of "::" 300 } 301 302 // An ExprStmt node represents a (stand-alone) expression 303 // in a statement list. 304 // 305 ExprStmt struct { 306 X *CallExpr // expression 307 } 308 309 // An AssignStmt node represents an assignment statement. 310 AssignStmt struct { 311 LHS []Expr 312 Equal position.Position // position of "=" 313 RHS []Expr 314 } 315 316 // A GotoStmt node represents a goto statement. 317 GotoStmt struct { 318 Goto position.Position 319 Label *Name // label name 320 } 321 322 // A BreakStmt represents a break statement. 323 BreakStmt struct { 324 Break position.Position // position of "break" 325 } 326 327 // An IfStmt node represents an if statement. 328 IfStmt struct { 329 If position.Position // position of "if" 330 Cond Expr // condition 331 Then position.Position // position of "then" 332 Body *Block 333 ElseIfList []struct { // elseif branches; or nil 334 If position.Position // position of "elseif" 335 Cond Expr // condition 336 Then position.Position // position of "then" 337 Body *Block 338 } 339 Else position.Position // position of "else" or position.NoPos 340 ElseBody *Block // else branch; or nil 341 EndPos position.Position 342 } 343 344 // A DoStmt represents a do statement. 345 DoStmt struct { 346 Do position.Position 347 Body *Block 348 EndPos position.Position 349 } 350 351 // A WhileStmt represents a while statement. 352 WhileStmt struct { 353 While position.Position // position of "while" keyword 354 Cond Expr // condition 355 Do position.Position // position of "do" keyword 356 Body *Block 357 EndPos position.Position 358 } 359 360 // A RepeatStmt represents a repeat statement. 361 RepeatStmt struct { 362 Repeat position.Position // position of "repeat" keyword 363 Body *Block 364 Until position.Position // position of "until" keyword 365 Cond Expr // condition 366 } 367 368 // A ReturnStmt represents a return statement. 369 ReturnStmt struct { 370 Return position.Position // position of "return" keyword 371 Results []Expr 372 Semicolon position.Position // position of ";" if exist 373 } 374 375 // A ForStmt represents a for statement. 376 ForStmt struct { 377 For position.Position // position of "for" keyword 378 Name *Name 379 Equal position.Position // position of "=" 380 Start Expr 381 Finish Expr 382 Step Expr // or nil 383 Do position.Position 384 Body *Block 385 EndPos position.Position 386 } 387 388 // A ForEachStmt represents a for statement with a range clause. 389 ForEachStmt struct { 390 For position.Position // position of "for" keyword 391 Names []*Name // Key, Value may be nil 392 In position.Position // position of "in" keyword 393 Exprs []Expr // value to range over 394 Do position.Position 395 Body *Block 396 EndPos position.Position 397 } 398 ) 399 400 func (*BadStmt) Type() Type { return BAD_STMT } 401 func (*EmptyStmt) Type() Type { return EMPTY_STMT } 402 func (*LocalAssignStmt) Type() Type { return LOCAL_ASSIGN_STMT } 403 func (*LocalFuncStmt) Type() Type { return LOCAL_FUNC_STMT } 404 func (*FuncStmt) Type() Type { return FUNC_STMT } 405 func (*LabelStmt) Type() Type { return LABEL_STMT } 406 func (*ExprStmt) Type() Type { return EXPR_STMT } 407 func (*AssignStmt) Type() Type { return ASSIGN_STMT } 408 func (*GotoStmt) Type() Type { return GOTO_STMT } 409 func (*IfStmt) Type() Type { return IF_STMT } 410 func (*DoStmt) Type() Type { return DO_STMT } 411 func (*WhileStmt) Type() Type { return WHILE_STMT } 412 func (*RepeatStmt) Type() Type { return REPEAT_STMT } 413 func (*BreakStmt) Type() Type { return BREAK_STMT } 414 func (*ReturnStmt) Type() Type { return RETURN_STMT } 415 func (*ForStmt) Type() Type { return FOR_STMT } 416 func (*ForEachStmt) Type() Type { return FOR_EACH_STMT } 417 418 // Pos and End implementations for statement nodes. 419 // 420 func (s *BadStmt) Pos() position.Position { return s.From } 421 func (s *EmptyStmt) Pos() position.Position { return s.Semicolon } 422 func (s *LocalAssignStmt) Pos() position.Position { return s.Local } 423 func (s *LocalFuncStmt) Pos() position.Position { return s.Local } 424 func (s *FuncStmt) Pos() position.Position { return s.Func } 425 func (s *LabelStmt) Pos() position.Position { return s.Label } 426 func (s *ExprStmt) Pos() position.Position { return s.X.Pos() } 427 func (s *AssignStmt) Pos() position.Position { 428 if len(s.LHS) > 0 { 429 return s.LHS[0].Pos() 430 } 431 return position.NoPos 432 } 433 func (s *GotoStmt) Pos() position.Position { return s.Goto } 434 func (s *IfStmt) Pos() position.Position { return s.If } 435 func (s *DoStmt) Pos() position.Position { return s.Do } 436 func (s *WhileStmt) Pos() position.Position { return s.While } 437 func (s *RepeatStmt) Pos() position.Position { return s.Repeat } 438 func (s *BreakStmt) Pos() position.Position { return s.Break } 439 func (s *ReturnStmt) Pos() position.Position { return s.Return } 440 func (s *ForStmt) Pos() position.Position { return s.For } 441 func (s *ForEachStmt) Pos() position.Position { return s.For } 442 443 func (s *BadStmt) End() position.Position { return s.To } 444 func (s *EmptyStmt) End() position.Position { return s.Semicolon.OffsetColumn(1) } 445 func (s *LocalAssignStmt) End() position.Position { 446 if s.Equal.IsValid() { 447 if len(s.RHS) > 0 { 448 return s.RHS[len(s.RHS)-1].End() 449 } 450 return position.NoPos 451 } 452 if len(s.LHS) > 0 { 453 return s.LHS[len(s.LHS)-1].End() 454 } 455 return position.NoPos 456 } 457 func (s *LocalFuncStmt) End() position.Position { return s.EndPos.OffsetColumn(3) } 458 func (s *FuncStmt) End() position.Position { return s.EndPos.OffsetColumn(3) } 459 func (s *LabelStmt) End() position.Position { return s.EndLabel.OffsetColumn(2) } 460 func (s *ExprStmt) End() position.Position { return s.X.End() } 461 func (s *AssignStmt) End() position.Position { 462 if len(s.RHS) > 0 { 463 return s.RHS[len(s.RHS)-1].End() 464 } 465 return position.NoPos 466 } 467 func (s *GotoStmt) End() position.Position { 468 return s.Label.End() 469 } 470 func (s *IfStmt) End() position.Position { return s.EndPos.OffsetColumn(3) } 471 func (s *DoStmt) End() position.Position { return s.EndPos.OffsetColumn(3) } 472 func (s *WhileStmt) End() position.Position { return s.EndPos.OffsetColumn(3) } 473 func (s *RepeatStmt) End() position.Position { return s.Cond.End() } 474 func (s *BreakStmt) End() position.Position { return s.Break.OffsetColumn(5) } 475 func (s *ReturnStmt) End() position.Position { 476 if s.Semicolon.IsValid() { 477 return s.Semicolon.OffsetColumn(1) 478 } 479 if len(s.Results) > 0 { 480 return s.Results[len(s.Results)-1].End() 481 } 482 return s.Return.OffsetColumn(6) 483 } 484 func (s *ForStmt) End() position.Position { return s.EndPos.OffsetColumn(3) } 485 func (s *ForEachStmt) End() position.Position { return s.EndPos.OffsetColumn(3) } 486 487 // stmtNode() ensures that only statement nodes can be 488 // assigned to a StmtNode. 489 // 490 func (*BadStmt) stmtNode() {} 491 func (*EmptyStmt) stmtNode() {} 492 func (*LocalAssignStmt) stmtNode() {} 493 func (*LocalFuncStmt) stmtNode() {} 494 func (*FuncStmt) stmtNode() {} 495 func (*LabelStmt) stmtNode() {} 496 func (*ExprStmt) stmtNode() {} 497 func (*AssignStmt) stmtNode() {} 498 func (*GotoStmt) stmtNode() {} 499 func (*IfStmt) stmtNode() {} 500 func (*DoStmt) stmtNode() {} 501 func (*WhileStmt) stmtNode() {} 502 func (*RepeatStmt) stmtNode() {} 503 func (*BreakStmt) stmtNode() {} 504 func (*ReturnStmt) stmtNode() {} 505 func (*ForStmt) stmtNode() {} 506 func (*ForEachStmt) stmtNode() {} 507 508 // ---------------------------------------------------------------------------- 509 // Other Nodes 510 511 // ---------------------------------------------------------------------------- 512 // File 513 514 // A File node represents a Lua source file. 515 // 516 // The Comments list contains all comments in the source file in order of 517 // appearance, including the comments that are pointed to from other nodes. 518 type File struct { 519 Filename string 520 Shebang string 521 Chunk []Stmt 522 Comments []*CommentGroup // list of all comments in the source file 523 } 524 525 func (f *File) Type() Type { return FILE } 526 func (f *File) Pos() position.Position { return position.Position{Line: 1, Column: 1} } 527 func (f *File) End() position.Position { 528 var pos position.Position 529 if len(f.Chunk) > 0 { 530 pos = f.Chunk[len(f.Chunk)-1].End() 531 } 532 if len(f.Comments) > 0 { 533 cpos := f.Comments[len(f.Comments)-1].End() 534 if pos.LessThan(cpos) { 535 pos = cpos 536 } 537 } 538 return pos 539 } 540 541 // ---------------------------------------------------------------------------- 542 // Block 543 544 // A Block node represents a scoped statement list. 545 type Block struct { 546 Opening position.Position // end of "do", "then", "repeat", ... 547 List []Stmt 548 Closing position.Position // start of "end", "elseif", "until", ... 549 } 550 551 func (b *Block) Type() Type { return BLOCK } 552 553 func (b *Block) Pos() position.Position { 554 return b.Opening 555 } 556 557 func (b *Block) End() position.Position { 558 return b.Closing 559 } 560 561 // ---------------------------------------------------------------------------- 562 // Function Block 563 564 // A Function Block node represents a function implementation. 565 type FuncBody struct { 566 Params *ParamList 567 Body *Block 568 } 569 570 func (f *FuncBody) Type() Type { return FUNC_BODY } 571 572 func (f *FuncBody) Pos() position.Position { return f.Params.Pos() } 573 574 func (f *FuncBody) End() position.Position { return f.Body.End() } 575 576 // ---------------------------------------------------------------------------- 577 // Param List 578 579 // A ParamList represents a list of Names, enclosed by parentheses or braces. 580 type ParamList struct { 581 Lparen position.Position // position of "(" 582 List []*Name // field list; or nil 583 Ellipsis position.Position 584 Rparen position.Position // position of ")" 585 } 586 587 func (f *ParamList) Type() Type { 588 return PARAM_LIST 589 } 590 591 func (f *ParamList) Pos() position.Position { 592 if f.Lparen.IsValid() { 593 return f.Lparen 594 } 595 // the list should not be empty in this case; 596 // be conservative and guard against bad ASTs 597 if len(f.List) > 0 { 598 return f.List[0].Pos() 599 } 600 return position.NoPos 601 } 602 603 func (f *ParamList) End() position.Position { 604 if f.Rparen.IsValid() { 605 return f.Rparen.OffsetColumn(1) 606 } 607 // the list should not be empty in this case; 608 // be conservative and guard against bad ASTs 609 if n := len(f.List); n > 0 { 610 return f.List[n-1].End() 611 } 612 return position.NoPos 613 } 614 615 // ---------------------------------------------------------------------------- 616 // Comments 617 618 // A Comment node represents a single --style or --[[style comment. 619 type Comment struct { 620 Hyphen position.Position // position of "-" starting the comment 621 Text string // comment text (excluding '\n' for --style comments) 622 } 623 624 func (c *Comment) Type() Type { return COMMENT } 625 func (c *Comment) Pos() position.Position { return c.Hyphen } 626 func (c *Comment) End() position.Position { return c.Hyphen.Offset(c.Text) } 627 628 // A CommentGroup represents a sequence of comments 629 // with no other tokens and no empty lines between. 630 // 631 type CommentGroup struct { 632 List []*Comment // len(List) > 0 633 } 634 635 func (g *CommentGroup) Type() Type { return COMMENT_GROUP } 636 func (g *CommentGroup) Pos() position.Position { 637 if len(g.List) > 0 { 638 return g.List[0].Pos() 639 } 640 return position.NoPos 641 } 642 func (g *CommentGroup) End() position.Position { 643 if len(g.List) > 0 { 644 return g.List[len(g.List)-1].End() 645 } 646 return position.NoPos 647 } 648 649 func isSpace(c byte) bool { 650 return c == ' ' || uint(c)-'\t' < 5 651 } 652 653 func stripTrailingSpace(s string) string { 654 i := len(s) 655 for i > 0 && isSpace(s[i-1]) { 656 i-- 657 } 658 return s[0:i] 659 } 660 661 // Text returns the text of the comment. 662 // Comment markers (//, /*, and */), the first space of a line comment, and 663 // leading and trailing empty lines are removed. Multiple empty lines are 664 // reduced to one, and trailing space on lines is trimmed. Unless the result 665 // is empty, it is newline-terminated. 666 // 667 func (g *CommentGroup) Text() string { 668 if g == nil { 669 return "" 670 } 671 672 lines := make([]string, 0, len(g.List)) 673 for _, c := range g.List { 674 text := c.Text 675 if len(text) > 0 && text[0] == ' ' { 676 text = text[1:] 677 } 678 679 // Split on newlines. 680 tl := strings.Split(text, "\n") 681 682 // Walk lines, stripping trailing white space and adding to list. 683 for _, l := range tl { 684 lines = append(lines, stripTrailingSpace(l)) 685 } 686 } 687 688 // Remove leading blank lines; convert runs of 689 // interior blank lines to a single blank line. 690 n := 0 691 for _, line := range lines { 692 if line != "" || n > 0 && lines[n-1] != "" { 693 lines[n] = line 694 n++ 695 } 696 } 697 lines = lines[0:n] 698 699 // Add final "" entry to get trailing newline from Join. 700 if n > 0 && lines[n-1] != "" { 701 lines = append(lines, "") 702 } 703 704 return strings.Join(lines, "\n") 705 }