Merge pull request #11 from colincross/bpfmt

bpfmt fixes
diff --git a/context.go b/context.go
index ac4fbe6..e576331 100644
--- a/context.go
+++ b/context.go
@@ -430,7 +430,7 @@
 
 	scope = parser.NewScope(scope)
 	scope.Remove("subdirs")
-	file, errs := parser.Parse(filename, r, scope)
+	file, errs := parser.ParseAndEval(filename, r, scope)
 	if len(errs) > 0 {
 		for i, err := range errs {
 			if parseErr, ok := err.(*parser.ParseError); ok {
diff --git a/parser/parser.go b/parser/parser.go
index 0031547..498bdcb 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -42,11 +42,7 @@
 	Comments []Comment
 }
 
-func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
-
-	p := newParser(r, scope)
-	p.scanner.Filename = filename
-
+func parse(p *parser) (file *File, errs []error) {
 	defer func() {
 		if r := recover(); r != nil {
 			if r == errTooManyErrors {
@@ -66,30 +62,42 @@
 		Defs:     defs,
 		Comments: comments,
 	}, errs
+
+}
+
+func ParseAndEval(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
+	p := newParser(r, scope)
+	p.eval = true
+	p.scanner.Filename = filename
+
+	return parse(p)
+}
+
+func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
+	p := newParser(r, scope)
+	p.scanner.Filename = filename
+
+	return parse(p)
 }
 
 type parser struct {
-	scanner       scanner.Scanner
-	tok           rune
-	errors        []error
-	scope         *Scope
-	parseComments bool
-	comments      []Comment
+	scanner  scanner.Scanner
+	tok      rune
+	errors   []error
+	scope    *Scope
+	comments []Comment
+	eval     bool
 }
 
 func newParser(r io.Reader, scope *Scope) *parser {
 	p := &parser{}
 	p.scope = scope
-	p.parseComments = true
 	p.scanner.Init(r)
 	p.scanner.Error = func(sc *scanner.Scanner, msg string) {
 		p.errorf(msg)
 	}
 	p.scanner.Mode = scanner.ScanIdents | scanner.ScanStrings |
 		scanner.ScanRawStrings | scanner.ScanComments
-	if !p.parseComments {
-		p.scanner.Mode |= scanner.SkipComments
-	}
 	p.next()
 	return p
 }
@@ -125,7 +133,8 @@
 	if p.tok != scanner.EOF {
 		p.tok = p.scanner.Scan()
 		for p.tok == scanner.Comment {
-			p.comments = append(p.comments, Comment{p.scanner.TokenText(), p.scanner.Position})
+			lines := strings.Split(p.scanner.TokenText(), "\n")
+			p.comments = append(p.comments, Comment{lines, p.scanner.Position})
 			p.tok = p.scanner.Scan()
 		}
 	}
@@ -182,13 +191,19 @@
 
 	if p.scope != nil {
 		if assigner == "+=" {
-			p.scope.Append(assignment)
-		} else {
-			err := p.scope.Add(assignment)
-			if err != nil {
-				p.errorf("%s", err.Error())
+			if old, err := p.scope.Get(assignment.Name.Name); err == nil {
+				if old.Referenced {
+					p.errorf("modified variable with += after referencing")
+				}
+				old.Value, err = p.evaluateOperator(old.Value, assignment.Value, '+', assignment.Pos)
+				return
 			}
 		}
+
+		err := p.scope.Add(assignment)
+		if err != nil {
+			p.errorf("%s", err.Error())
+		}
 	}
 
 	return
@@ -279,35 +294,41 @@
 	}
 }
 
-func evaluateOperator(value1, value2 Value, operator rune, pos scanner.Position) (Value, error) {
-	if value1.Type != value2.Type {
-		return Value{}, fmt.Errorf("mismatched type in operator %c: %s != %s", operator,
-			value1.Type, value2.Type)
-	}
+func (p *parser) evaluateOperator(value1, value2 Value, operator rune,
+	pos scanner.Position) (Value, error) {
 
-	value := value1
-	value.Variable = ""
+	value := Value{}
 
-	switch operator {
-	case '+':
-		switch value1.Type {
-		case String:
-			value.StringValue = value1.StringValue + value2.StringValue
-		case List:
-			value.ListValue = append([]Value{}, value1.ListValue...)
-			value.ListValue = append(value.ListValue, value2.ListValue...)
-		case Map:
-			var err error
-			value.MapValue, err = addMaps(value.MapValue, value2.MapValue, pos)
-			if err != nil {
-				return Value{}, err
+	if p.eval {
+		if value1.Type != value2.Type {
+			return Value{}, fmt.Errorf("mismatched type in operator %c: %s != %s", operator,
+				value1.Type, value2.Type)
+		}
+
+		value = value1
+		value.Variable = ""
+
+		switch operator {
+		case '+':
+			switch value1.Type {
+			case String:
+				value.StringValue = value1.StringValue + value2.StringValue
+			case List:
+				value.ListValue = append([]Value{}, value1.ListValue...)
+				value.ListValue = append(value.ListValue, value2.ListValue...)
+			case Map:
+				var err error
+				value.MapValue, err = p.addMaps(value.MapValue, value2.MapValue, pos)
+				if err != nil {
+					return Value{}, err
+				}
+			default:
+				return Value{}, fmt.Errorf("operator %c not supported on type %s", operator,
+					value1.Type)
 			}
 		default:
-			return Value{}, fmt.Errorf("operator %c not supported on type %s", operator,
-				value1.Type)
+			panic("unknown operator " + string(operator))
 		}
-	default:
-		panic("unknown operator " + string(operator))
 	}
 
 	value.Expression = &Expression{
@@ -319,7 +340,7 @@
 	return value, nil
 }
 
-func addMaps(map1, map2 []*Property, pos scanner.Position) ([]*Property, error) {
+func (p *parser) addMaps(map1, map2 []*Property, pos scanner.Position) ([]*Property, error) {
 	ret := make([]*Property, 0, len(map1))
 
 	inMap1 := make(map[string]*Property)
@@ -341,7 +362,7 @@
 		if prop2, ok := inBoth[prop1.Name.Name]; ok {
 			var err error
 			newProp := *prop1
-			newProp.Value, err = evaluateOperator(prop1.Value, prop2.Value, '+', pos)
+			newProp.Value, err = p.evaluateOperator(prop1.Value, prop2.Value, '+', pos)
 			if err != nil {
 				return nil, err
 			}
@@ -367,7 +388,7 @@
 
 	value2 := p.parseExpression()
 
-	value, err := evaluateOperator(value1, value2, operator, pos)
+	value, err := p.evaluateOperator(value1, value2, operator, pos)
 	if err != nil {
 		p.errorf(err.Error())
 		return Value{}
@@ -403,11 +424,14 @@
 		value.BoolValue = false
 	default:
 		variable := p.scanner.TokenText()
-		assignment, err := p.scope.Get(variable)
-		if err != nil {
-			p.errorf(err.Error())
+		if p.eval {
+			assignment, err := p.scope.Get(variable)
+			if err != nil {
+				p.errorf(err.Error())
+			}
+			assignment.Referenced = true
+			value = assignment.Value
 		}
-		value = assignment.Value
 		value.Variable = variable
 	}
 	value.Pos = p.scanner.Position
@@ -439,7 +463,7 @@
 	var elements []Value
 	for p.tok != ']' {
 		element := p.parseExpression()
-		if element.Type != String {
+		if p.eval && element.Type != String {
 			p.errorf("Expected string in list, found %s", element.String())
 			return
 		}
@@ -643,27 +667,12 @@
 	return nil
 }
 
-func (s *Scope) Append(assignment *Assignment) error {
-	var err error
-	if old, ok := s.vars[assignment.Name.Name]; ok {
-		if old.Referenced {
-			return fmt.Errorf("modified variable with += after referencing")
-		}
-		old.Value, err = evaluateOperator(old.Value, assignment.Value, '+', assignment.Pos)
-	} else {
-		err = s.Add(assignment)
-	}
-
-	return err
-}
-
 func (s *Scope) Remove(name string) {
 	delete(s.vars, name)
 }
 
 func (s *Scope) Get(name string) (*Assignment, error) {
 	if a, ok := s.vars[name]; ok {
-		a.Referenced = true
 		return a, nil
 	}
 
@@ -688,6 +697,6 @@
 }
 
 type Comment struct {
-	Comment string
+	Comment []string
 	Pos     scanner.Position
 }
diff --git a/parser/parser_test.go b/parser/parser_test.go
index f1e99c7..8925684 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -229,15 +229,15 @@
 		},
 		[]Comment{
 			Comment{
-				Comment: "// comment1",
+				Comment: []string{"// comment1"},
 				Pos:     mkpos(3, 2, 3),
 			},
 			Comment{
-				Comment: "// comment2",
+				Comment: []string{"// comment2"},
 				Pos:     mkpos(26, 4, 4),
 			},
 			Comment{
-				Comment: "// comment3",
+				Comment: []string{"// comment3"},
 				Pos:     mkpos(56, 5, 19),
 			},
 		},
@@ -477,7 +477,7 @@
 func TestParseValidInput(t *testing.T) {
 	for _, testCase := range validParseTestCases {
 		r := bytes.NewBufferString(testCase.input)
-		file, errs := Parse("", r, NewScope(nil))
+		file, errs := ParseAndEval("", r, NewScope(nil))
 		if len(errs) != 0 {
 			t.Errorf("test case: %s", testCase.input)
 			t.Errorf("unexpected errors:")
diff --git a/parser/printer.go b/parser/printer.go
index 53fbbcc..b27f5e0 100644
--- a/parser/printer.go
+++ b/parser/printer.go
@@ -19,36 +19,21 @@
 	"strconv"
 	"strings"
 	"text/scanner"
+	"unicode"
 )
 
 var noPos = scanner.Position{}
 
-type whitespace int
-
-const (
-	wsDontCare whitespace = iota
-	wsBoth
-	wsAfter
-	wsBefore
-	wsCanBreak     // allow extra line breaks or comments
-	wsBothCanBreak // wsBoth plus allow extra line breaks or comments
-	wsForceBreak
-	wsForceDoubleBreak
-)
-
-type tokenState struct {
-	ws     whitespace
-	token  string
-	pos    scanner.Position
-	indent int
-}
-
 type printer struct {
 	defs     []Definition
 	comments []Comment
 
 	curComment int
-	prev       tokenState
+
+	pos scanner.Position
+
+	pendingSpace   bool
+	pendingNewline int
 
 	output []byte
 
@@ -63,8 +48,12 @@
 		defs:       file.Defs,
 		comments:   file.Comments,
 		indentList: []int{0},
-		prev: tokenState{
-			ws: wsCanBreak,
+
+		// pendingNewLine is initialized to -1 to eat initial spaces if the first token is a comment
+		pendingNewline: -1,
+
+		pos: scanner.Position{
+			Line: 1,
 		},
 	}
 }
@@ -75,7 +64,6 @@
 	for _, def := range p.defs {
 		p.printDef(def)
 	}
-	p.prev.ws = wsDontCare
 	p.flush()
 	return p.output, nil
 }
@@ -99,21 +87,23 @@
 }
 
 func (p *printer) printAssignment(assignment *Assignment) {
-	p.printToken(assignment.Name.Name, assignment.Name.Pos, wsDontCare)
-	p.printToken(assignment.Assigner, assignment.Pos, wsBoth)
+	p.printToken(assignment.Name.Name, assignment.Name.Pos)
+	p.requestSpace()
+	p.printToken(assignment.Assigner, assignment.Pos)
+	p.requestSpace()
 	p.printValue(assignment.OrigValue)
-	p.prev.ws = wsForceBreak
+	p.requestNewline()
 }
 
 func (p *printer) printModule(module *Module) {
-	p.printToken(module.Type.Name, module.Type.Pos, wsDontCare)
+	p.printToken(module.Type.Name, module.Type.Pos)
 	p.printMap(module.Properties, module.LbracePos, module.RbracePos)
-	p.prev.ws = wsForceDoubleBreak
+	p.requestDoubleNewline()
 }
 
 func (p *printer) printValue(value Value) {
 	if value.Variable != "" {
-		p.printToken(value.Variable, value.Pos, wsDontCare)
+		p.printToken(value.Variable, value.Pos)
 	} else if value.Expression != nil {
 		p.printExpression(*value.Expression)
 	} else {
@@ -125,9 +115,9 @@
 			} else {
 				s = "false"
 			}
-			p.printToken(s, value.Pos, wsDontCare)
+			p.printToken(s, value.Pos)
 		case String:
-			p.printToken(strconv.Quote(value.StringValue), value.Pos, wsDontCare)
+			p.printToken(strconv.Quote(value.StringValue), value.Pos)
 		case List:
 			p.printList(value.ListValue, value.Pos, value.EndPos)
 		case Map:
@@ -139,184 +129,219 @@
 }
 
 func (p *printer) printList(list []Value, pos, endPos scanner.Position) {
-	p.printToken("[", pos, wsBefore)
+	p.requestSpace()
+	p.printToken("[", pos)
 	if len(list) > 1 || pos.Line != endPos.Line {
-		p.prev.ws = wsForceBreak
+		p.requestNewline()
 		p.indent(p.curIndent() + 4)
 		for _, value := range list {
 			p.printValue(value)
-			p.printToken(",", noPos, wsForceBreak)
+			p.printToken(",", noPos)
+			p.requestNewline()
 		}
-		p.unindent()
+		p.unindent(endPos)
 	} else {
 		for _, value := range list {
 			p.printValue(value)
 		}
 	}
-	p.printToken("]", endPos, wsDontCare)
+	p.printToken("]", endPos)
 }
 
 func (p *printer) printMap(list []*Property, pos, endPos scanner.Position) {
-	p.printToken("{", pos, wsBefore)
+	p.requestSpace()
+	p.printToken("{", pos)
 	if len(list) > 0 || pos.Line != endPos.Line {
-		p.prev.ws = wsForceBreak
+		p.requestNewline()
 		p.indent(p.curIndent() + 4)
 		for _, prop := range list {
 			p.printProperty(prop)
-			p.printToken(",", noPos, wsForceBreak)
+			p.printToken(",", noPos)
+			p.requestNewline()
 		}
-		p.unindent()
+		p.unindent(endPos)
 	}
-	p.printToken("}", endPos, wsDontCare)
+	p.printToken("}", endPos)
 }
 
 func (p *printer) printExpression(expression Expression) {
 	p.printValue(expression.Args[0])
-	p.printToken(string(expression.Operator), expression.Pos, wsBothCanBreak)
+	p.requestSpace()
+	p.printToken(string(expression.Operator), expression.Pos)
+	if expression.Args[0].Pos.Line == expression.Args[1].Pos.Line {
+		p.requestSpace()
+	} else {
+		p.requestNewline()
+	}
 	p.printValue(expression.Args[1])
 }
 
 func (p *printer) printProperty(property *Property) {
-	p.printToken(property.Name.Name, property.Name.Pos, wsDontCare)
-	p.printToken(":", property.Pos, wsAfter)
+	p.printToken(property.Name.Name, property.Name.Pos)
+	p.printToken(":", property.Pos)
+	p.requestSpace()
 	p.printValue(property.Value)
 }
 
 // Print a single token, including any necessary comments or whitespace between
 // this token and the previously printed token
-func (p *printer) printToken(s string, pos scanner.Position, ws whitespace) {
-	this := tokenState{
-		token:  s,
-		pos:    pos,
-		ws:     ws,
-		indent: p.curIndent(),
+func (p *printer) printToken(s string, pos scanner.Position) {
+	newline := p.pendingNewline != 0
+
+	if pos == noPos {
+		pos = p.pos
 	}
 
-	if this.pos == noPos {
-		this.pos = p.prev.pos
+	if newline {
+		p.printEndOfLineCommentsBefore(pos)
+		p.requestNewlinesForPos(pos)
 	}
 
-	// Print the previously stored token
-	allowLineBreak := false
-	lineBreak := 0
+	p.printInLineCommentsBefore(pos)
 
-	switch p.prev.ws {
-	case wsBothCanBreak, wsCanBreak, wsForceBreak, wsForceDoubleBreak:
-		allowLineBreak = true
-	}
+	p.flushSpace()
 
-	p.output = append(p.output, p.prev.token...)
+	p.output = append(p.output, s...)
 
-	commentIndent := max(p.prev.indent, this.indent)
-	p.printComments(this.pos, allowLineBreak, commentIndent)
-
-	switch p.prev.ws {
-	case wsForceBreak:
-		lineBreak = 1
-	case wsForceDoubleBreak:
-		lineBreak = 2
-	}
-
-	if allowLineBreak && p.prev.pos.IsValid() &&
-		pos.Line-p.prev.pos.Line > lineBreak {
-		lineBreak = pos.Line - p.prev.pos.Line
-	}
-
-	if lineBreak > 0 {
-		p.printLineBreak(lineBreak, this.indent)
-	} else {
-		p.printWhitespace(this.ws)
-	}
-
-	p.prev = this
+	p.pos = pos
 }
 
-func (p *printer) printWhitespace(ws whitespace) {
-	if p.prev.ws == wsBoth || ws == wsBoth ||
-		p.prev.ws == wsBothCanBreak || ws == wsBothCanBreak ||
-		p.prev.ws == wsAfter || ws == wsBefore {
-		p.output = append(p.output, ' ')
-	}
-}
-
-// Pr int all comments that occur before position pos
-func (p *printer) printComments(pos scanner.Position, allowLineBreak bool, indent int) {
-	if allowLineBreak {
-		for _, c := range p.skippedComments {
-			p.printComment(c, indent)
-		}
-		p.skippedComments = []Comment{}
-	}
+// Print any in-line (single line /* */) comments that appear _before_ pos
+func (p *printer) printInLineCommentsBefore(pos scanner.Position) {
 	for p.curComment < len(p.comments) && p.comments[p.curComment].Pos.Offset < pos.Offset {
-		if !allowLineBreak && p.comments[p.curComment].Comment[0:2] == "//" {
-			p.skippedComments = append(p.skippedComments, p.comments[p.curComment])
+		c := p.comments[p.curComment]
+		if c.Comment[0][0:2] == "//" || len(c.Comment) > 1 {
+			p.skippedComments = append(p.skippedComments, c)
 		} else {
-			p.printComment(p.comments[p.curComment], indent)
+			p.flushSpace()
+			p.printComment(c)
+			p.requestSpace()
 		}
 		p.curComment++
 	}
 }
 
-// Print a single comment, which may be a multi-line comment
-func (p *printer) printComment(comment Comment, indent int) {
-	commentLines := strings.Split(comment.Comment, "\n")
-	pos := comment.Pos
-	for _, line := range commentLines {
-		if p.prev.pos.IsValid() && pos.Line > p.prev.pos.Line {
-			// Comment is on the next line
-			if p.prev.ws == wsForceDoubleBreak {
-				p.printLineBreak(2, indent)
-				p.prev.ws = wsForceBreak
-			} else {
-				p.printLineBreak(pos.Line-p.prev.pos.Line, indent)
-			}
-		} else if p.prev.pos.IsValid() {
-			// Comment is on the current line
-			p.printWhitespace(wsBoth)
+// Print any comments, including end of line comments, that appear _before_ the line specified
+// by pos
+func (p *printer) printEndOfLineCommentsBefore(pos scanner.Position) {
+	for _, c := range p.skippedComments {
+		if !p.requestNewlinesForPos(c.Pos) {
+			p.requestSpace()
 		}
-		p.output = append(p.output, strings.TrimSpace(line)...)
-		p.prev.pos = pos
-		pos.Line++
+		p.printComment(c)
+		p._requestNewline()
 	}
-	if comment.Comment[0:2] == "//" {
-		if p.prev.ws != wsForceDoubleBreak {
-			p.prev.ws = wsForceBreak
+	p.skippedComments = []Comment{}
+	for p.curComment < len(p.comments) && p.comments[p.curComment].Pos.Line < pos.Line {
+		c := p.comments[p.curComment]
+		if !p.requestNewlinesForPos(c.Pos) {
+			p.requestSpace()
 		}
-	} else {
-		p.prev.ws = wsBothCanBreak
+		p.printComment(c)
+		p._requestNewline()
+		p.curComment++
 	}
 }
 
-// Print one or two line breaks.  n <= 0 is only valid if forceLineBreak is set,
-// n > 2 is collapsed to a single blank line.
-func (p *printer) printLineBreak(n, indent int) {
-	if n > 2 {
-		n = 2
+// Compare the line numbers of the previous and current positions to determine whether extra
+// newlines should be inserted.  A second newline is allowed anywhere requestNewline() is called.
+func (p *printer) requestNewlinesForPos(pos scanner.Position) bool {
+	if pos.Line > p.pos.Line {
+		p._requestNewline()
+		if pos.Line > p.pos.Line+1 {
+			p.pendingNewline = 2
+		}
+		return true
 	}
 
-	for i := 0; i < n; i++ {
+	return false
+}
+
+func (p *printer) requestSpace() {
+	p.pendingSpace = true
+}
+
+// Ask for a newline to be inserted before the next token, but do not insert any comments.  Used
+// by the comment printers.
+func (p *printer) _requestNewline() {
+	if p.pendingNewline == 0 {
+		p.pendingNewline = 1
+	}
+}
+
+// Ask for a newline to be inserted before the next token.  Also inserts any end-of line comments
+// for the current line
+func (p *printer) requestNewline() {
+	pos := p.pos
+	pos.Line++
+	p.printEndOfLineCommentsBefore(pos)
+	p._requestNewline()
+}
+
+// Ask for two newlines to be inserted before the next token.  Also inserts any end-of line comments
+// for the current line
+func (p *printer) requestDoubleNewline() {
+	p.requestNewline()
+	p.pendingNewline = 2
+}
+
+// Flush any pending whitespace, ignoring pending spaces if there is a pending newline
+func (p *printer) flushSpace() {
+	if p.pendingNewline == 1 {
 		p.output = append(p.output, '\n')
+		p.pad(p.curIndent())
+	} else if p.pendingNewline == 2 {
+		p.output = append(p.output, "\n\n"...)
+		p.pad(p.curIndent())
+	} else if p.pendingSpace == true && p.pendingNewline != -1 {
+		p.output = append(p.output, ' ')
 	}
 
-	p.pad(0, indent)
+	p.pendingSpace = false
+	p.pendingNewline = 0
+}
+
+// Print a single comment, which may be a multi-line comment
+func (p *printer) printComment(comment Comment) {
+	pos := comment.Pos
+	for i, line := range comment.Comment {
+		line = strings.TrimRightFunc(line, unicode.IsSpace)
+		p.flushSpace()
+		if i != 0 {
+			lineIndent := strings.IndexFunc(line, func(r rune) bool { return !unicode.IsSpace(r) })
+			lineIndent = max(lineIndent, p.curIndent())
+			p.pad(lineIndent - p.curIndent())
+			pos.Line++
+		}
+		p.output = append(p.output, strings.TrimSpace(line)...)
+		if i < len(comment.Comment)-1 {
+			p._requestNewline()
+		}
+	}
+	p.pos = pos
 }
 
 // Print any comments that occur after the last token, and a trailing newline
 func (p *printer) flush() {
 	for _, c := range p.skippedComments {
-		p.printComment(c, p.curIndent())
+		if !p.requestNewlinesForPos(c.Pos) {
+			p.requestSpace()
+		}
+		p.printComment(c)
 	}
-	p.printToken("", noPos, wsDontCare)
 	for p.curComment < len(p.comments) {
-		p.printComment(p.comments[p.curComment], p.curIndent())
+		c := p.comments[p.curComment]
+		if !p.requestNewlinesForPos(c.Pos) {
+			p.requestSpace()
+		}
+		p.printComment(c)
 		p.curComment++
 	}
 	p.output = append(p.output, '\n')
 }
 
 // Print whitespace to pad from column l to column max
-func (p *printer) pad(l, max int) {
-	l = max - l
+func (p *printer) pad(l int) {
 	if l > len(p.wsBuf) {
 		p.wsBuf = make([]byte, l)
 		for i := range p.wsBuf {
@@ -330,7 +355,8 @@
 	p.indentList = append(p.indentList, i)
 }
 
-func (p *printer) unindent() {
+func (p *printer) unindent(pos scanner.Position) {
+	p.printEndOfLineCommentsBefore(pos)
 	p.indentList = p.indentList[0 : len(p.indentList)-1]
 }
 
diff --git a/parser/printer_test.go b/parser/printer_test.go
index 9f26230..20fb747 100644
--- a/parser/printer_test.go
+++ b/parser/printer_test.go
@@ -195,9 +195,64 @@
     ],
     //test
 }
+
 //test2
 `,
 	},
+	{
+		input: `
+/*test {
+    test: true,
+}*/
+
+test {
+/*test: true,*/
+}
+
+// This
+/* Is */
+// A
+
+// Multiline
+// Comment
+
+test {}
+
+// This
+/* Is */
+// A
+// Trailing
+
+// Multiline
+// Comment
+`,
+		output: `
+/*test {
+    test: true,
+}*/
+
+test {
+    /*test: true,*/
+}
+
+// This
+/* Is */
+// A
+
+// Multiline
+// Comment
+
+test {}
+
+// This
+/* Is */
+// A
+// Trailing
+
+// Multiline
+// Comment
+`,
+	},
 }
 
 func TestPrinter(t *testing.T) {