Home | History | Annotate | Download | only in parser
      1 // Copyright 2014 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package parser
     16 
     17 import (
     18 	"errors"
     19 	"fmt"
     20 	"io"
     21 	"sort"
     22 	"strconv"
     23 	"strings"
     24 	"text/scanner"
     25 )
     26 
     27 var errTooManyErrors = errors.New("too many errors")
     28 
     29 const maxErrors = 1
     30 
     31 type ParseError struct {
     32 	Err error
     33 	Pos scanner.Position
     34 }
     35 
     36 func (e *ParseError) Error() string {
     37 	return fmt.Sprintf("%s: %s", e.Pos, e.Err)
     38 }
     39 
     40 type File struct {
     41 	Name     string
     42 	Defs     []Definition
     43 	Comments []Comment
     44 }
     45 
     46 func parse(p *parser) (file *File, errs []error) {
     47 	defer func() {
     48 		if r := recover(); r != nil {
     49 			if r == errTooManyErrors {
     50 				errs = p.errors
     51 				return
     52 			}
     53 			panic(r)
     54 		}
     55 	}()
     56 
     57 	defs := p.parseDefinitions()
     58 	p.accept(scanner.EOF)
     59 	errs = p.errors
     60 	comments := p.comments
     61 
     62 	return &File{
     63 		Name:     p.scanner.Filename,
     64 		Defs:     defs,
     65 		Comments: comments,
     66 	}, errs
     67 
     68 }
     69 
     70 func ParseAndEval(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
     71 	p := newParser(r, scope)
     72 	p.eval = true
     73 	p.scanner.Filename = filename
     74 
     75 	return parse(p)
     76 }
     77 
     78 func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
     79 	p := newParser(r, scope)
     80 	p.scanner.Filename = filename
     81 
     82 	return parse(p)
     83 }
     84 
     85 type parser struct {
     86 	scanner  scanner.Scanner
     87 	tok      rune
     88 	errors   []error
     89 	scope    *Scope
     90 	comments []Comment
     91 	eval     bool
     92 }
     93 
     94 func newParser(r io.Reader, scope *Scope) *parser {
     95 	p := &parser{}
     96 	p.scope = scope
     97 	p.scanner.Init(r)
     98 	p.scanner.Error = func(sc *scanner.Scanner, msg string) {
     99 		p.errorf(msg)
    100 	}
    101 	p.scanner.Mode = scanner.ScanIdents | scanner.ScanStrings |
    102 		scanner.ScanRawStrings | scanner.ScanComments
    103 	p.next()
    104 	return p
    105 }
    106 
    107 func (p *parser) error(err error) {
    108 	pos := p.scanner.Position
    109 	if !pos.IsValid() {
    110 		pos = p.scanner.Pos()
    111 	}
    112 	err = &ParseError{
    113 		Err: err,
    114 		Pos: pos,
    115 	}
    116 	p.errors = append(p.errors, err)
    117 	if len(p.errors) >= maxErrors {
    118 		panic(errTooManyErrors)
    119 	}
    120 }
    121 
    122 func (p *parser) errorf(format string, args ...interface{}) {
    123 	p.error(fmt.Errorf(format, args...))
    124 }
    125 
    126 func (p *parser) accept(toks ...rune) bool {
    127 	for _, tok := range toks {
    128 		if p.tok != tok {
    129 			p.errorf("expected %s, found %s", scanner.TokenString(tok),
    130 				scanner.TokenString(p.tok))
    131 			return false
    132 		}
    133 		p.next()
    134 	}
    135 	return true
    136 }
    137 
    138 func (p *parser) next() {
    139 	if p.tok != scanner.EOF {
    140 		p.tok = p.scanner.Scan()
    141 		for p.tok == scanner.Comment {
    142 			lines := strings.Split(p.scanner.TokenText(), "\n")
    143 			p.comments = append(p.comments, Comment{lines, p.scanner.Position})
    144 			p.tok = p.scanner.Scan()
    145 		}
    146 	}
    147 	return
    148 }
    149 
    150 func (p *parser) parseDefinitions() (defs []Definition) {
    151 	for {
    152 		switch p.tok {
    153 		case scanner.Ident:
    154 			ident := p.scanner.TokenText()
    155 			pos := p.scanner.Position
    156 
    157 			p.accept(scanner.Ident)
    158 
    159 			switch p.tok {
    160 			case '+':
    161 				p.accept('+')
    162 				defs = append(defs, p.parseAssignment(ident, pos, "+="))
    163 			case '=':
    164 				defs = append(defs, p.parseAssignment(ident, pos, "="))
    165 			case '{', '(':
    166 				defs = append(defs, p.parseModule(ident, pos))
    167 			default:
    168 				p.errorf("expected \"=\" or \"+=\" or \"{\" or \"(\", found %s",
    169 					scanner.TokenString(p.tok))
    170 			}
    171 		case scanner.EOF:
    172 			return
    173 		default:
    174 			p.errorf("expected assignment or module definition, found %s",
    175 				scanner.TokenString(p.tok))
    176 			return
    177 		}
    178 	}
    179 }
    180 
    181 func (p *parser) parseAssignment(name string,
    182 	namePos scanner.Position, assigner string) (assignment *Assignment) {
    183 
    184 	assignment = new(Assignment)
    185 
    186 	pos := p.scanner.Position
    187 	if !p.accept('=') {
    188 		return
    189 	}
    190 	value := p.parseExpression()
    191 
    192 	assignment.Name = Ident{name, namePos}
    193 	assignment.Value = value
    194 	assignment.OrigValue = value
    195 	assignment.Pos = pos
    196 	assignment.Assigner = assigner
    197 
    198 	if p.scope != nil {
    199 		if assigner == "+=" {
    200 			if old, local := p.scope.Get(assignment.Name.Name); old == nil {
    201 				p.errorf("modified non-existent variable %q with +=", assignment.Name.Name)
    202 			} else if !local {
    203 				p.errorf("modified non-local variable %q with +=", assignment.Name.Name)
    204 			} else if old.Referenced {
    205 				p.errorf("modified variable %q with += after referencing",
    206 					assignment.Name.Name)
    207 			} else {
    208 				val, err := p.evaluateOperator(old.Value, assignment.Value, '+', assignment.Pos)
    209 				if err != nil {
    210 					p.error(err)
    211 				} else {
    212 					old.Value = val
    213 				}
    214 			}
    215 		} else {
    216 			err := p.scope.Add(assignment)
    217 			if err != nil {
    218 				p.error(err)
    219 			}
    220 		}
    221 	}
    222 
    223 	return
    224 }
    225 
    226 func (p *parser) parseModule(typ string,
    227 	typPos scanner.Position) (module *Module) {
    228 
    229 	module = new(Module)
    230 	compat := false
    231 	lbracePos := p.scanner.Position
    232 	if p.tok == '{' {
    233 		compat = true
    234 	}
    235 
    236 	if !p.accept(p.tok) {
    237 		return
    238 	}
    239 	properties := p.parsePropertyList(true, compat)
    240 	rbracePos := p.scanner.Position
    241 	if !compat {
    242 		p.accept(')')
    243 	} else {
    244 		p.accept('}')
    245 	}
    246 
    247 	module.Type = Ident{typ, typPos}
    248 	module.Properties = properties
    249 	module.LbracePos = lbracePos
    250 	module.RbracePos = rbracePos
    251 	return
    252 }
    253 
    254 func (p *parser) parsePropertyList(isModule, compat bool) (properties []*Property) {
    255 	for p.tok == scanner.Ident {
    256 		property := p.parseProperty(isModule, compat)
    257 		properties = append(properties, property)
    258 
    259 		if p.tok != ',' {
    260 			// There was no comma, so the list is done.
    261 			break
    262 		}
    263 
    264 		p.accept(',')
    265 	}
    266 
    267 	return
    268 }
    269 
    270 func (p *parser) parseProperty(isModule, compat bool) (property *Property) {
    271 	property = new(Property)
    272 
    273 	name := p.scanner.TokenText()
    274 	namePos := p.scanner.Position
    275 	p.accept(scanner.Ident)
    276 	pos := p.scanner.Position
    277 
    278 	if isModule {
    279 		if compat && p.tok == ':' {
    280 			p.accept(':')
    281 		} else {
    282 			if !p.accept('=') {
    283 				return
    284 			}
    285 		}
    286 	} else {
    287 		if !p.accept(':') {
    288 			return
    289 		}
    290 	}
    291 
    292 	value := p.parseExpression()
    293 
    294 	property.Name = Ident{name, namePos}
    295 	property.Value = value
    296 	property.Pos = pos
    297 
    298 	return
    299 }
    300 
    301 func (p *parser) parseExpression() (value Value) {
    302 	value = p.parseValue()
    303 	switch p.tok {
    304 	case '+':
    305 		return p.parseOperator(value)
    306 	default:
    307 		return value
    308 	}
    309 }
    310 
    311 func (p *parser) evaluateOperator(value1, value2 Value, operator rune,
    312 	pos scanner.Position) (Value, error) {
    313 
    314 	value := Value{}
    315 
    316 	if p.eval {
    317 		if value1.Type != value2.Type {
    318 			return Value{}, fmt.Errorf("mismatched type in operator %c: %s != %s", operator,
    319 				value1.Type, value2.Type)
    320 		}
    321 
    322 		value = value1
    323 		value.Variable = ""
    324 
    325 		switch operator {
    326 		case '+':
    327 			switch value1.Type {
    328 			case String:
    329 				value.StringValue = value1.StringValue + value2.StringValue
    330 			case List:
    331 				value.ListValue = append([]Value{}, value1.ListValue...)
    332 				value.ListValue = append(value.ListValue, value2.ListValue...)
    333 			case Map:
    334 				var err error
    335 				value.MapValue, err = p.addMaps(value.MapValue, value2.MapValue, pos)
    336 				if err != nil {
    337 					return Value{}, err
    338 				}
    339 			default:
    340 				return Value{}, fmt.Errorf("operator %c not supported on type %s", operator,
    341 					value1.Type)
    342 			}
    343 		default:
    344 			panic("unknown operator " + string(operator))
    345 		}
    346 	}
    347 
    348 	value.Expression = &Expression{
    349 		Args:     [2]Value{value1, value2},
    350 		Operator: operator,
    351 		Pos:      pos,
    352 	}
    353 
    354 	return value, nil
    355 }
    356 
    357 func (p *parser) addMaps(map1, map2 []*Property, pos scanner.Position) ([]*Property, error) {
    358 	ret := make([]*Property, 0, len(map1))
    359 
    360 	inMap1 := make(map[string]*Property)
    361 	inMap2 := make(map[string]*Property)
    362 	inBoth := make(map[string]*Property)
    363 
    364 	for _, prop1 := range map1 {
    365 		inMap1[prop1.Name.Name] = prop1
    366 	}
    367 
    368 	for _, prop2 := range map2 {
    369 		inMap2[prop2.Name.Name] = prop2
    370 		if _, ok := inMap1[prop2.Name.Name]; ok {
    371 			inBoth[prop2.Name.Name] = prop2
    372 		}
    373 	}
    374 
    375 	for _, prop1 := range map1 {
    376 		if prop2, ok := inBoth[prop1.Name.Name]; ok {
    377 			var err error
    378 			newProp := *prop1
    379 			newProp.Value, err = p.evaluateOperator(prop1.Value, prop2.Value, '+', pos)
    380 			if err != nil {
    381 				return nil, err
    382 			}
    383 			ret = append(ret, &newProp)
    384 		} else {
    385 			ret = append(ret, prop1)
    386 		}
    387 	}
    388 
    389 	for _, prop2 := range map2 {
    390 		if _, ok := inBoth[prop2.Name.Name]; !ok {
    391 			ret = append(ret, prop2)
    392 		}
    393 	}
    394 
    395 	return ret, nil
    396 }
    397 
    398 func (p *parser) parseOperator(value1 Value) Value {
    399 	operator := p.tok
    400 	pos := p.scanner.Position
    401 	p.accept(operator)
    402 
    403 	value2 := p.parseExpression()
    404 
    405 	value, err := p.evaluateOperator(value1, value2, operator, pos)
    406 	if err != nil {
    407 		p.error(err)
    408 		return Value{}
    409 	}
    410 
    411 	return value
    412 }
    413 
    414 func (p *parser) parseValue() (value Value) {
    415 	switch p.tok {
    416 	case scanner.Ident:
    417 		return p.parseVariable()
    418 	case scanner.String:
    419 		return p.parseStringValue()
    420 	case '[':
    421 		return p.parseListValue()
    422 	case '{':
    423 		return p.parseMapValue()
    424 	default:
    425 		p.errorf("expected bool, list, or string value; found %s",
    426 			scanner.TokenString(p.tok))
    427 		return
    428 	}
    429 }
    430 
    431 func (p *parser) parseVariable() (value Value) {
    432 	switch text := p.scanner.TokenText(); text {
    433 	case "true":
    434 		value.Type = Bool
    435 		value.BoolValue = true
    436 	case "false":
    437 		value.Type = Bool
    438 		value.BoolValue = false
    439 	default:
    440 		variable := p.scanner.TokenText()
    441 		if p.eval {
    442 			if assignment, local := p.scope.Get(variable); assignment == nil {
    443 				p.errorf("variable %q is not set", variable)
    444 			} else {
    445 				if local {
    446 					assignment.Referenced = true
    447 				}
    448 				value = assignment.Value
    449 			}
    450 		}
    451 		value.Variable = variable
    452 	}
    453 	value.Pos = p.scanner.Position
    454 
    455 	p.accept(scanner.Ident)
    456 	return
    457 }
    458 
    459 func (p *parser) parseStringValue() (value Value) {
    460 	value.Type = String
    461 	value.Pos = p.scanner.Position
    462 	str, err := strconv.Unquote(p.scanner.TokenText())
    463 	if err != nil {
    464 		p.errorf("couldn't parse string: %s", err)
    465 		return
    466 	}
    467 	value.StringValue = str
    468 	p.accept(scanner.String)
    469 	return
    470 }
    471 
    472 func (p *parser) parseListValue() (value Value) {
    473 	value.Type = List
    474 	value.Pos = p.scanner.Position
    475 	if !p.accept('[') {
    476 		return
    477 	}
    478 
    479 	var elements []Value
    480 	for p.tok != ']' {
    481 		element := p.parseExpression()
    482 		if p.eval && element.Type != String {
    483 			p.errorf("Expected string in list, found %s", element.String())
    484 			return
    485 		}
    486 		elements = append(elements, element)
    487 
    488 		if p.tok != ',' {
    489 			// There was no comma, so the list is done.
    490 			break
    491 		}
    492 
    493 		p.accept(',')
    494 	}
    495 
    496 	value.ListValue = elements
    497 	value.EndPos = p.scanner.Position
    498 
    499 	p.accept(']')
    500 	return
    501 }
    502 
    503 func (p *parser) parseMapValue() (value Value) {
    504 	value.Type = Map
    505 	value.Pos = p.scanner.Position
    506 	if !p.accept('{') {
    507 		return
    508 	}
    509 
    510 	properties := p.parsePropertyList(false, false)
    511 	value.MapValue = properties
    512 
    513 	value.EndPos = p.scanner.Position
    514 	p.accept('}')
    515 	return
    516 }
    517 
    518 type Expression struct {
    519 	Args     [2]Value
    520 	Operator rune
    521 	Pos      scanner.Position
    522 }
    523 
    524 func (e *Expression) Copy() *Expression {
    525 	ret := *e
    526 	ret.Args[0] = e.Args[0].Copy()
    527 	ret.Args[1] = e.Args[1].Copy()
    528 	return &ret
    529 }
    530 
    531 func (e *Expression) String() string {
    532 	return fmt.Sprintf("(%s %c %s)@%d:%s", e.Args[0].String(), e.Operator, e.Args[1].String(),
    533 		e.Pos.Offset, e.Pos)
    534 }
    535 
    536 type ValueType int
    537 
    538 const (
    539 	Bool ValueType = iota
    540 	String
    541 	List
    542 	Map
    543 )
    544 
    545 func (p ValueType) String() string {
    546 	switch p {
    547 	case Bool:
    548 		return "bool"
    549 	case String:
    550 		return "string"
    551 	case List:
    552 		return "list"
    553 	case Map:
    554 		return "map"
    555 	default:
    556 		panic(fmt.Errorf("unknown value type: %d", p))
    557 	}
    558 }
    559 
    560 type Definition interface {
    561 	String() string
    562 	definitionTag()
    563 }
    564 
    565 type Assignment struct {
    566 	Name       Ident
    567 	Value      Value
    568 	OrigValue  Value
    569 	Pos        scanner.Position
    570 	Assigner   string
    571 	Referenced bool
    572 }
    573 
    574 func (a *Assignment) String() string {
    575 	return fmt.Sprintf("%s@%d:%s %s %s", a.Name, a.Pos.Offset, a.Pos, a.Assigner, a.Value)
    576 }
    577 
    578 func (a *Assignment) definitionTag() {}
    579 
    580 type Module struct {
    581 	Type       Ident
    582 	Properties []*Property
    583 	LbracePos  scanner.Position
    584 	RbracePos  scanner.Position
    585 }
    586 
    587 func (m *Module) Copy() *Module {
    588 	ret := *m
    589 	ret.Properties = make([]*Property, len(m.Properties))
    590 	for i := range m.Properties {
    591 		ret.Properties[i] = m.Properties[i].Copy()
    592 	}
    593 	return &ret
    594 }
    595 
    596 func (m *Module) String() string {
    597 	propertyStrings := make([]string, len(m.Properties))
    598 	for i, property := range m.Properties {
    599 		propertyStrings[i] = property.String()
    600 	}
    601 	return fmt.Sprintf("%s@%d:%s-%d:%s{%s}", m.Type,
    602 		m.LbracePos.Offset, m.LbracePos,
    603 		m.RbracePos.Offset, m.RbracePos,
    604 		strings.Join(propertyStrings, ", "))
    605 }
    606 
    607 func (m *Module) definitionTag() {}
    608 
    609 type Property struct {
    610 	Name  Ident
    611 	Value Value
    612 	Pos   scanner.Position
    613 }
    614 
    615 func (p *Property) Copy() *Property {
    616 	ret := *p
    617 	ret.Value = p.Value.Copy()
    618 	return &ret
    619 }
    620 
    621 func (p *Property) String() string {
    622 	return fmt.Sprintf("%s@%d:%s: %s", p.Name, p.Pos.Offset, p.Pos, p.Value)
    623 }
    624 
    625 type Ident struct {
    626 	Name string
    627 	Pos  scanner.Position
    628 }
    629 
    630 func (i Ident) String() string {
    631 	return fmt.Sprintf("%s@%d:%s", i.Name, i.Pos.Offset, i.Pos)
    632 }
    633 
    634 type Value struct {
    635 	Type        ValueType
    636 	BoolValue   bool
    637 	StringValue string
    638 	ListValue   []Value
    639 	MapValue    []*Property
    640 	Expression  *Expression
    641 	Variable    string
    642 	Pos         scanner.Position
    643 	EndPos      scanner.Position
    644 }
    645 
    646 func (p Value) Copy() Value {
    647 	ret := p
    648 	if p.MapValue != nil {
    649 		ret.MapValue = make([]*Property, len(p.MapValue))
    650 		for i := range p.MapValue {
    651 			ret.MapValue[i] = p.MapValue[i].Copy()
    652 		}
    653 	}
    654 	if p.ListValue != nil {
    655 		ret.ListValue = make([]Value, len(p.ListValue))
    656 		for i := range p.ListValue {
    657 			ret.ListValue[i] = p.ListValue[i].Copy()
    658 		}
    659 	}
    660 	if p.Expression != nil {
    661 		ret.Expression = p.Expression.Copy()
    662 	}
    663 	return ret
    664 }
    665 
    666 func (p Value) String() string {
    667 	var s string
    668 	if p.Variable != "" {
    669 		s += p.Variable + " = "
    670 	}
    671 	if p.Expression != nil {
    672 		s += p.Expression.String()
    673 	}
    674 	switch p.Type {
    675 	case Bool:
    676 		s += fmt.Sprintf("%t@%d:%s", p.BoolValue, p.Pos.Offset, p.Pos)
    677 	case String:
    678 		s += fmt.Sprintf("%q@%d:%s", p.StringValue, p.Pos.Offset, p.Pos)
    679 	case List:
    680 		valueStrings := make([]string, len(p.ListValue))
    681 		for i, value := range p.ListValue {
    682 			valueStrings[i] = value.String()
    683 		}
    684 		s += fmt.Sprintf("@%d:%s-%d:%s[%s]", p.Pos.Offset, p.Pos, p.EndPos.Offset, p.EndPos,
    685 			strings.Join(valueStrings, ", "))
    686 	case Map:
    687 		propertyStrings := make([]string, len(p.MapValue))
    688 		for i, property := range p.MapValue {
    689 			propertyStrings[i] = property.String()
    690 		}
    691 		s += fmt.Sprintf("@%d:%s-%d:%s{%s}", p.Pos.Offset, p.Pos, p.EndPos.Offset, p.EndPos,
    692 			strings.Join(propertyStrings, ", "))
    693 	default:
    694 		panic(fmt.Errorf("bad property type: %d", p.Type))
    695 	}
    696 
    697 	return s
    698 }
    699 
    700 type Scope struct {
    701 	vars          map[string]*Assignment
    702 	inheritedVars map[string]*Assignment
    703 }
    704 
    705 func NewScope(s *Scope) *Scope {
    706 	newScope := &Scope{
    707 		vars:          make(map[string]*Assignment),
    708 		inheritedVars: make(map[string]*Assignment),
    709 	}
    710 
    711 	if s != nil {
    712 		for k, v := range s.vars {
    713 			newScope.inheritedVars[k] = v
    714 		}
    715 		for k, v := range s.inheritedVars {
    716 			newScope.inheritedVars[k] = v
    717 		}
    718 	}
    719 
    720 	return newScope
    721 }
    722 
    723 func (s *Scope) Add(assignment *Assignment) error {
    724 	if old, ok := s.vars[assignment.Name.Name]; ok {
    725 		return fmt.Errorf("variable already set, previous assignment: %s", old)
    726 	}
    727 
    728 	if old, ok := s.inheritedVars[assignment.Name.Name]; ok {
    729 		return fmt.Errorf("variable already set in inherited scope, previous assignment: %s", old)
    730 	}
    731 
    732 	s.vars[assignment.Name.Name] = assignment
    733 
    734 	return nil
    735 }
    736 
    737 func (s *Scope) Remove(name string) {
    738 	delete(s.vars, name)
    739 	delete(s.inheritedVars, name)
    740 }
    741 
    742 func (s *Scope) Get(name string) (*Assignment, bool) {
    743 	if a, ok := s.vars[name]; ok {
    744 		return a, true
    745 	}
    746 
    747 	if a, ok := s.inheritedVars[name]; ok {
    748 		return a, false
    749 	}
    750 
    751 	return nil, false
    752 }
    753 
    754 func (s *Scope) String() string {
    755 	vars := []string{}
    756 
    757 	for k := range s.vars {
    758 		vars = append(vars, k)
    759 	}
    760 	for k := range s.inheritedVars {
    761 		vars = append(vars, k)
    762 	}
    763 
    764 	sort.Strings(vars)
    765 
    766 	ret := []string{}
    767 	for _, v := range vars {
    768 		if assignment, ok := s.vars[v]; ok {
    769 			ret = append(ret, assignment.String())
    770 		} else {
    771 			ret = append(ret, s.inheritedVars[v].String())
    772 		}
    773 	}
    774 
    775 	return strings.Join(ret, "\n")
    776 }
    777 
    778 type Comment struct {
    779 	Comment []string
    780 	Pos     scanner.Position
    781 }
    782 
    783 func (c Comment) String() string {
    784 	l := 0
    785 	for _, comment := range c.Comment {
    786 		l += len(comment) + 1
    787 	}
    788 	buf := make([]byte, 0, l)
    789 	for _, comment := range c.Comment {
    790 		buf = append(buf, comment...)
    791 		buf = append(buf, '\n')
    792 	}
    793 
    794 	return string(buf)
    795 }
    796 
    797 // Return the text of the comment with // or /* and */ stripped
    798 func (c Comment) Text() string {
    799 	l := 0
    800 	for _, comment := range c.Comment {
    801 		l += len(comment) + 1
    802 	}
    803 	buf := make([]byte, 0, l)
    804 
    805 	blockComment := false
    806 	if strings.HasPrefix(c.Comment[0], "/*") {
    807 		blockComment = true
    808 	}
    809 
    810 	for i, comment := range c.Comment {
    811 		if blockComment {
    812 			if i == 0 {
    813 				comment = strings.TrimPrefix(comment, "/*")
    814 			}
    815 			if i == len(c.Comment)-1 {
    816 				comment = strings.TrimSuffix(comment, "*/")
    817 			}
    818 		} else {
    819 			comment = strings.TrimPrefix(comment, "//")
    820 		}
    821 		buf = append(buf, comment...)
    822 		buf = append(buf, '\n')
    823 	}
    824 
    825 	return string(buf)
    826 }
    827 
    828 // Return the line number that the comment ends on
    829 func (c Comment) EndLine() int {
    830 	return c.Pos.Line + len(c.Comment) - 1
    831 }
    832