func processFile(filename string, out io.Writer, config Config) error {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	text := string(content)
	inputStream := antlr.NewInputStream(text)
	lexer := parser.NewModelicaLexer(inputStream)
	stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
	tokenSource := newCommentCollector(lexer)
	stream.SetTokenSource(&tokenSource)
	p := parser.NewModelicaParser(stream)
	sd := p.Stored_definition()
	listener := newListener(out, tokenSource.commentTokens, config)
	defer listener.close()
	antlr.ParseTreeWalkerDefault.Walk(listener, sd)
	for _, comment := range listener.commentTokens {
		listener.writeComment(comment)
	}
	if !listener.onNewLine {
		listener.writeNewline()
	}
	return nil
}
processFile formats a file
package main
import (
	"bufio"
	"io"
	"io/ioutil"
	"strings"
	"github.com/antlr/antlr4/runtime/Go/antlr"
	"github.com/urbanopt/modelica-fmt/thirdparty/parser"
)
type Config struct {
	maxLineLength int
	emptyLines    bool
}
const (
	spaceIndent = "  "
)
func (l *modelicaListener) insertIndentBefore(rule antlr.ParserRuleContext) bool {
	switch rule.(type) {
	case
		parser.IElementContext,
		parser.IEquationsContext,
		parser.IAlgorithm_statementsContext,
		parser.IControl_structure_bodyContext,
		parser.IAnnotationContext,
		parser.IExpression_listContext,
		parser.IConstraining_clauseContext,
		parser.IIf_expressionContext,
		parser.IIf_expression_bodyContext,
		parser.IExternal_function_call_argumentContext:
		return true
	case parser.IString_commentContext:
		return 0 == l.inAnnotation
	case
		parser.IArgumentContext,
		parser.INamed_argumentContext:
		return 0 == l.inAnnotation || 0 < l.inModelAnnotation
	case parser.IExpressionContext:
		if len(l.modelAnnotationVectorStack) == 0 {
			return false
		}
		arrayArgumentsNode, ok := rule.GetParent().(*parser.Array_argumentsContext)
		if !ok {
			return false
		}
		thisVectorInterval := arrayArgumentsNode.GetParent().(*parser.VectorContext).GetSourceInterval()
		stackVectorInterval := l.modelAnnotationVectorStack[len(l.modelAnnotationVectorStack)-1].GetSourceInterval()
		if thisVectorInterval.Start == stackVectorInterval.Start && thisVectorInterval.Stop == stackVectorInterval.Stop {
			return true
		}
		return false
	case parser.IFunction_argumentContext:
		return 0 == l.inNamedArgument && 0 == l.inVector && (0 == l.inAnnotation || 0 < l.inModelAnnotation)
	default:
		return false
	}
}
func insertSpaceBeforeToken(currentTokenText, previousTokenText string) bool {
	switch currentTokenText {
	case "(":
		if previousTokenText == "annotation" {
			return true
		}
		fallthrough
	default:
		return !tokenInGroup(previousTokenText, noSpaceAfterTokens) &&
			!tokenInGroup(currentTokenText, noSpaceBeforeTokens)
	}
}
func insertNewlineBefore(rule antlr.ParserRuleContext) bool {
	switch rule.(type) {
	case
		parser.ICompositionContext,
		parser.IEquationsContext,
		parser.IIf_expression_conditionContext,
		parser.IElseif_expression_conditionContext,
		parser.IElse_expression_conditionContext:
		return true
	default:
		return false
	}
}
var (
	noSpaceAfterTokens = []string{
		"(",
		"=",
		".",
		"[",
		"{",
		"-", "+", "^", "*", "/",
		";",
		",",
		":",  
	}
	noSpaceBeforeTokens = []string{
		"(", ")",
		"[", "]",
		"}",
		";",
		"=",
		",",
		".",
		"-", "+", "^", "*", "/",
		":",  
	}
	allowBreakAfterTokens = []string{
		"=",
		",",
		"(",
	}
)
func tokenInGroup(token string, group []string) bool {
	for _, other := range group {
		if token == other {
			return true
		}
	}
	return false
}
type indent int
const (
	renderIndent indent = iota
	ignoreIndent
)
type modelicaListener struct {
	*parser.BaseModelicaListener                
	writer                       *bufio.Writer  
	indentationStack             []indent       
	onNewLine                    bool           
	withinOnCurrentLine          bool           
	insideBracket                bool           
	lineIndentIncreased          bool           
	previousTokenText            string         
	previousTokenIdx             int            
	commentTokens                []antlr.Token  
	maxLineLength                int            
	currentLineLength            int            
	modelAnnotationVectorStack []antlr.RuleContext
	inAnnotation      int   
	inModelAnnotation int   
	inNamedArgument   int   
	inVector          int   
	inLastSemicolon   bool  
	config Config
}
func newListener(out io.Writer, commentTokens []antlr.Token, config Config) *modelicaListener {
	return &modelicaListener{
		BaseModelicaListener: &parser.BaseModelicaListener{},
		writer:               bufio.NewWriter(out),
		onNewLine:            true,
		withinOnCurrentLine:  false,
		insideBracket:        false,
		lineIndentIncreased:  false,
		inLastSemicolon:      false,
		inAnnotation:         0,
		inModelAnnotation:    0,
		inVector:             0,
		inNamedArgument:      0,
		previousTokenText:    "",
		previousTokenIdx:     -1,
		commentTokens:        commentTokens,
		currentLineLength:    0,
		config:               config,
	}
}
func (l *modelicaListener) close() {
	err := l.writer.Flush()
	if err != nil {
		panic(err)
	}
}
func (l *modelicaListener) indentation() int {
	nRenderIndents := 0
	for _, indentType := range l.indentationStack {
		if indentType == renderIndent {
			nRenderIndents++
		}
	}
	return nRenderIndents
}
func (l *modelicaListener) maybeIndent() {
	if !l.lineIndentIncreased {
		l.indentationStack = append(l.indentationStack, renderIndent)
		l.lineIndentIncreased = true
	} else {
		l.indentationStack = append(l.indentationStack, ignoreIndent)
	}
}
func (l *modelicaListener) maybeDedent() {
	l.indentationStack = l.indentationStack[:len(l.indentationStack)-1]
}
func (l *modelicaListener) writeString(str string) {
	originalSpacePrefix := l.getSpaceBefore(str, true)
	charsOnFirstLine := len(originalSpacePrefix)
	firstNewlineIndex := strings.Index(str, "\n")
	if firstNewlineIndex < 0 {
		charsOnFirstLine += len(str)
	} else {
		charsOnFirstLine += firstNewlineIndex
	}
	var actualSpacePrefix string
	if l.config.maxLineLength > 0 &&
		l.currentLineLength+charsOnFirstLine > l.config.maxLineLength &&
		tokenInGroup(l.previousTokenText, allowBreakAfterTokens) {
		l.writeNewline()
		l.maybeIndent()
		actualSpacePrefix = l.getSpaceBefore(str, false)
		l.writer.WriteString(actualSpacePrefix + str)
		l.maybeDedent()
	} else {
		actualSpacePrefix = l.getSpaceBefore(str, false)
		l.writer.WriteString(actualSpacePrefix + str)
	}
	lastNewlineIndex := strings.LastIndex(str, "\n")
	var charsOnLastLine int
	if lastNewlineIndex < 0 {
		charsOnLastLine = len(actualSpacePrefix) + len(str)
	} else {
		charsOnLastLine = len(str) - (lastNewlineIndex + 1)
	}
	l.currentLineLength += charsOnLastLine
}
func (l *modelicaListener) writeNewline() {
	l.writer.WriteString("\n")
	l.onNewLine = true
	l.currentLineLength = 0
	l.lineIndentIncreased = false
}
func (l *modelicaListener) writeComment(comment antlr.Token) {
	l.writeString(comment.GetText())
	if comment.GetTokenType() == parser.ModelicaLexerLINE_COMMENT {
		l.writeNewline()
	}
}
func (l *modelicaListener) getSpaceBefore(str string, dryRun bool) string {
	if l.onNewLine {
		if !dryRun {
			l.onNewLine = false
		}
		if l.indentation() > 0 {
			indentation := l.indentation()
			return strings.Repeat(spaceIndent, indentation)
		}
	} else if insertSpaceBeforeToken(str, l.previousTokenText) {
		return " "
	}
	return ""
}
func (l *modelicaListener) insertBlankLine() bool {
	if !l.config.emptyLines {
		return false
	}
	if l.inLastSemicolon {
		return len(l.commentTokens) > 0
	}
	return !l.withinOnCurrentLine && !l.insideBracket
}
func (l *modelicaListener) VisitTerminal(node antlr.TerminalNode) {
	tokenIdx := node.GetSymbol().GetTokenIndex()
	for len(l.commentTokens) > 0 && tokenIdx > l.commentTokens[0].GetTokenIndex() && l.commentTokens[0].GetTokenIndex() > l.previousTokenIdx {
		commentToken := l.commentTokens[0]
		l.commentTokens = l.commentTokens[1:]
		l.writeComment(commentToken)
	}
	l.writeString(node.GetText())
	if l.previousTokenText == "within" {
		l.withinOnCurrentLine = true
	}
	if l.previousTokenText == "[" {
		l.insideBracket = true
	} else if l.previousTokenText == "]" {
		l.insideBracket = false
	}
	if node.GetText() == ";" {
		l.writeNewline()
		if l.insertBlankLine() {
			l.writeNewline()
		} else {
			l.withinOnCurrentLine = false
		}
	}
	l.previousTokenText = node.GetText()
	l.previousTokenIdx = node.GetSymbol().GetTokenIndex()
}
func (l *modelicaListener) EnterEveryRule(node antlr.ParserRuleContext) {
	if insertNewlineBefore(node) && !l.onNewLine {
		l.writeNewline()
	}
	if l.insertIndentBefore(node) {
		if !l.onNewLine {
			l.writeNewline()
		}
		l.maybeIndent()
	}
}
func (l *modelicaListener) ExitEveryRule(node antlr.ParserRuleContext) {
	if l.insertIndentBefore(node) {
		l.maybeDedent()
	}
}
func (l *modelicaListener) EnterAnnotation(node *parser.AnnotationContext) {
	l.inAnnotation++
}
func (l *modelicaListener) ExitAnnotation(node *parser.AnnotationContext) {
	l.inAnnotation--
}
func (l *modelicaListener) EnterModel_annotation(node *parser.Model_annotationContext) {
	l.inModelAnnotation++
}
func (l *modelicaListener) ExitModel_annotation(node *parser.Model_annotationContext) {
	l.inModelAnnotation--
}
func (l *modelicaListener) EnterVector(node *parser.VectorContext) {
	l.inVector++
	if l.inModelAnnotation > 0 {
		if _, ok := node.GetChild(0).(parser.Array_iterator_constructorContext); ok {
			return
		}
		for _, child := range node.Array_arguments().GetChildren() {
			expressionNode, ok := child.(*parser.ExpressionContext)
			if !ok {
				continue
			}
			startToken := expressionNode.GetStart()
			if startToken.GetTokenType() == parser.ModelicaLexerIDENT {
				l.modelAnnotationVectorStack = append(l.modelAnnotationVectorStack, node)
				break
			}
		}
	}
}
func (l *modelicaListener) ExitVector(node *parser.VectorContext) {
	l.inVector--
	if len(l.modelAnnotationVectorStack) > 0 {
		annotationVectorInterval := l.modelAnnotationVectorStack[len(l.modelAnnotationVectorStack)-1].GetSourceInterval()
		thisVectorInterval := node.GetSourceInterval()
		if annotationVectorInterval.Start == thisVectorInterval.Start && annotationVectorInterval.Stop == thisVectorInterval.Stop {
			l.modelAnnotationVectorStack = l.modelAnnotationVectorStack[:len(l.modelAnnotationVectorStack)-1]
		}
	}
}
func (l *modelicaListener) EnterNamed_argument(node *parser.Named_argumentContext) {
	l.inNamedArgument++
}
func (l *modelicaListener) ExitNamed_argument(node *parser.Named_argumentContext) {
	l.inNamedArgument--
}
func (l *modelicaListener) EnterLast_semicolon(node *parser.Last_semicolonContext) {
	l.inLastSemicolon = true
}
func (l *modelicaListener) ExitLast_semicolon(node *parser.Last_semicolonContext) {
	l.inLastSemicolon = false
}
type commentCollector struct {
	antlr.TokenSource
	commentTokens []antlr.Token
}
func newCommentCollector(source antlr.TokenSource) commentCollector {
	return commentCollector{
		source,
		[]antlr.Token{},
	}
}
func (c *commentCollector) NextToken() antlr.Token {
	token := c.TokenSource.NextToken()
	tokenType := token.GetTokenType()
	if tokenType == parser.ModelicaLexerCOMMENT || tokenType == parser.ModelicaLexerLINE_COMMENT {
		c.commentTokens = append(c.commentTokens, token)
	}
	return token
}