func (p *Parser) varAssignment() ast.Node {
	var assignNode ast.Node
	assignNode.Type = ast.VARASSIGN
	assignNode.Symbols = p.curSymTable
	for p.curTokenIs(token.IDENT) {
		assignNode.Children = append(assignNode.Children, p.varRef())
		if !p.curTokenIs(token.COMMA) {
			break
		}
		p.consume(token.COMMA)
	}
	p.consume(token.ASSIGN)
	assignNode.Children = append(assignNode.Children, p.expr())
	return assignNode
}
varAssignment = varRef assignOp expr
package parser
import (
	"fmt"
	"knox/ast"
	"knox/lexer"
	"knox/token"
)
type Parser struct {
	l         *lexer.Lexer
	curToken  token.Token
	peekToken token.Token
	curSymTable *ast.SymTable
}
func New(l *lexer.Lexer) *Parser {
	p := &Parser{l: l}
	p.nextToken()
	p.nextToken()  
	return p
}
func (p *Parser) abort(t token.TokenType) {
	fmt.Printf("Expected %s, got %s instead. Line %v.\n", t, p.curToken.Type, p.curToken.Line)
	panic("Aborted.\n")
}
func (p *Parser) abortMsg(msg string) {
	fmt.Printf("%v. Line %v.\n", msg, p.curToken.Line)
	panic("Aborted.\n")
}
func (p *Parser) nextToken() {
	p.curToken = p.peekToken
	p.peekToken = p.l.NextToken()
}
func (p *Parser) curTokenIs(t token.TokenType) bool {
	return p.curToken.Type == t
}
func (p *Parser) peekTokenIs(t token.TokenType) bool {
	return p.peekToken.Type == t
}
func (p *Parser) consume(t token.TokenType) bool {
	if p.curTokenIs(t) {
		p.nextToken()
		return true
	}
	p.abort(t)
	return false  
}
func (p *Parser) Program() ast.Node {
	var progNode ast.Node
	progNode.Type = ast.PROGRAM
	st := ast.NewSymTable()
	st.Parent = nil
	p.curSymTable = st
	progNode.Symbols = st
	for !p.curTokenIs(token.EOF) {
		if p.curTokenIs(token.FUNCTION) {
			progNode.Children = append(progNode.Children, p.funcDecl())
		} else if p.curTokenIs(token.CLASS) {
			progNode.Children = append(progNode.Children, p.classDecl())
		} else {
			p.abortMsg("Expected function or class.")
		}
	}
	return progNode
}
func (p *Parser) classDecl() ast.Node {
	var classNode ast.Node
	classNode.Type = ast.CLASS
	p.consume(token.CLASS)
	var identNode ast.Node
	identNode.Type = ast.IDENT
	identNode.TokenStart = p.curToken
	classNode.Children = append(classNode.Children, identNode)
	success := p.curSymTable.InsertSymbol(p.curToken.Literal, &classNode)
	if !success {
		p.abortMsg("Class already exists.")
	}
	p.consume(token.IDENT)
	classNode.Children = append(classNode.Children, p.classBlock())
	return classNode
}
func (p *Parser) classBlock() ast.Node {
	var blockNode ast.Node
	blockNode.Type = ast.BLOCK
	st := ast.NewSymTable()
	st.Parent = p.curSymTable
	p.curSymTable = st
	blockNode.Symbols = st
	p.consume(token.LBRACE)
	for !p.curTokenIs(token.RBRACE) {
		if p.curTokenIs(token.VAR) {
			blockNode.Children = append(blockNode.Children, p.varDecl())
			p.consume(token.SEMICOLON)
		} else if p.curTokenIs(token.FUNCTION) {
			blockNode.Children = append(blockNode.Children, p.funcDecl())
		} else {
			p.abortMsg("Unexpected token in class block.")
		}
	}
	p.consume(token.RBRACE)
	p.curSymTable = st.Parent
	return blockNode
}
func (p *Parser) funcDecl() ast.Node {
	var funcNode ast.Node
	funcNode.Type = ast.FUNCDECL
	p.consume(token.FUNCTION)
	var identNode ast.Node
	identNode.Type = ast.IDENT
	identNode.TokenStart = p.curToken
	funcNode.Children = append(funcNode.Children, identNode)
	success := p.curSymTable.InsertSymbol(p.curToken.Literal, &funcNode)
	if !success {
		p.abortMsg("Function already exists.")
	}
	p.consume(token.IDENT)
	funcNode.Children = append(funcNode.Children, p.paramList())
	funcNode.Children = append(funcNode.Children, p.returnList())
	funcNode.Children = append(funcNode.Children, p.block())
	for _, param := range funcNode.Children[1].Children {
		param.Symbols = funcNode.Children[3].Symbols
		success := funcNode.Children[3].Symbols.InsertSymbol(param.Children[0].TokenStart.Literal, &param)
		if !success {
			p.abortMsg("Variable already exists.")
		}
	}
	return funcNode
}
func (p *Parser) paramList() ast.Node {
	var paramNode ast.Node
	paramNode.Type = ast.PARAMLIST
	p.consume(token.LPAREN)
	for !p.curTokenIs(token.RPAREN) {
		var varNode ast.Node
		varNode.Type = ast.VARDECL
		var identNode ast.Node
		identNode.Type = ast.IDENT
		identNode.TokenStart = p.curToken
		p.consume(token.IDENT)
		p.consume(token.COLON)
		varNode.Children = append(varNode.Children, identNode)
		varNode.Children = append(varNode.Children, p.varType())
		paramNode.Children = append(paramNode.Children, varNode)
		if p.curTokenIs(token.COMMA) {
			p.consume(token.COMMA)
			if p.curTokenIs(token.RPAREN) {  
				p.abort(token.IDENT)
			}
		}
	}
	p.consume(token.RPAREN)
	return paramNode
}
func (p *Parser) returnList() ast.Node {
	var returnNode ast.Node
	returnNode.Type = ast.RETURNLIST
	if p.curTokenIs(token.LBRACE) {
		p.abortMsg("Expected return type.")
	} else if !p.curTokenIs(token.LPAREN) {
		returnNode.Children = append(returnNode.Children, p.varType())
	} else {
		p.consume(token.LPAREN)
		returnNode.Children = append(returnNode.Children, p.varType())
		for !p.curTokenIs(token.RPAREN) {
			p.consume(token.COMMA)
			returnNode.Children = append(returnNode.Children, p.varType())
		}
		p.nextToken()
	}
	return returnNode
}
func (p *Parser) block() ast.Node {
	var blockNode ast.Node
	blockNode.Type = ast.BLOCK
	st := ast.NewSymTable()
	st.Parent = p.curSymTable
	p.curSymTable = st
	blockNode.Symbols = st
	p.consume(token.LBRACE)
	for !p.curTokenIs(token.RBRACE) {
		blockNode.Children = append(blockNode.Children, p.statement())
	}
	p.consume(token.RBRACE)
	p.curSymTable = st.Parent
	return blockNode
}
func (p *Parser) statement() ast.Node {
	var statementNode ast.Node
	if p.curTokenIs(token.VAR) {
		statementNode = p.varDecl()
		p.consume(token.SEMICOLON)
	} else if p.curTokenIs(token.IF) {
		statementNode = p.ifStatement()
	} else if p.curTokenIs(token.FOR) {
		statementNode = p.forStatement()
	} else if p.curTokenIs(token.WHILE) {
		statementNode = p.whileStatement()
	} else if p.curTokenIs(token.RETURN) || p.curTokenIs(token.CONTINUE) || p.curTokenIs(token.BREAK) {
		statementNode = p.jumpStatement()
		p.consume(token.SEMICOLON)
	} else {
		exprNode := p.expr()
		for p.curTokenIs(token.COMMA) {
		}
		if p.curTokenIs(token.ASSIGN) {  
			var assignNode ast.Node
			assignNode.Type = ast.VARASSIGN
			assignNode.Symbols = p.curSymTable
			assignNode.Children = append(assignNode.Children, exprNode)
			p.consume(token.ASSIGN)
			assignNode.Children = append(assignNode.Children, p.expr())
			statementNode = assignNode
		} else {  
			var leftNode ast.Node
			leftNode.Type = ast.LEFTEXPR
			leftNode.Children = append(leftNode.Children, exprNode)
			statementNode = leftNode
		}
		p.consume(token.SEMICOLON)
	}
	return statementNode
}
func (p *Parser) varDeclPiece() ast.Node {
	var varNode ast.Node
	varNode.Type = ast.VARDECL
	varNode.Symbols = p.curSymTable
	for p.curTokenIs(token.IDENT) {
		var identNode ast.Node
		identNode.Type = ast.IDENT
		identNode.TokenStart = p.curToken
		success := p.curSymTable.InsertSymbol(p.curToken.Literal, &varNode)
		if !success {
			p.abortMsg("Variable already exists.")
		}
		p.consume(token.IDENT)
		p.consume(token.COLON)
		varNode.Children = append(varNode.Children, identNode)
		varNode.Children = append(varNode.Children, p.varType())
		if !p.curTokenIs(token.COMMA) {
			break
		}
		p.consume(token.COMMA)
	}
	return varNode
}
func (p *Parser) varDecl() ast.Node {
	var varNode ast.Node
	varNode.Type = ast.VARDECL
	varNode.Symbols = p.curSymTable
	p.consume(token.VAR)
	for p.curTokenIs(token.IDENT) {
		var identNode ast.Node
		identNode.Type = ast.IDENT
		identNode.TokenStart = p.curToken
		success := p.curSymTable.InsertSymbol(p.curToken.Literal, &varNode)
		if !success {
			p.abortMsg("Variable already exists.")
		}
		p.consume(token.IDENT)
		p.consume(token.COLON)
		varNode.Children = append(varNode.Children, identNode)
		varNode.Children = append(varNode.Children, p.varType())
		if !p.curTokenIs(token.COMMA) {
			break
		}
		p.consume(token.COMMA)
	}
	p.consume(token.ASSIGN)
	varNode.Children = append(varNode.Children, p.expr())
	return varNode
}
func (p *Parser) funcCall() ast.Node {
	var funcNode ast.Node
	funcNode.Type = ast.FUNCCALL
	var identNode ast.Node
	identNode.Type = ast.IDENT
	identNode.TokenStart = p.curToken
	p.consume(token.IDENT)
	funcNode.Children = append(funcNode.Children, identNode)
	var nodes = p.argList()
	funcNode.Children = append(funcNode.Children, nodes...)
	return funcNode
}
func (p *Parser) argList() []ast.Node {
	var argNodes []ast.Node
	p.consume(token.LPAREN)
	for !p.curTokenIs(token.RPAREN) {
		argNodes = append(argNodes, p.expr())
		if p.curTokenIs(token.COMMA) {
			p.consume(token.COMMA)
			if p.curTokenIs(token.RPAREN) {  
				p.abort(token.IDENT)
			}
		}
	}
	p.nextToken()
	return argNodes
}
func (p *Parser) varType() ast.Node {
	var typeNode ast.Node
	typeNode.Type = ast.VARTYPE
	var identNode ast.Node
	identNode.Type = ast.IDENT
	identNode.TokenStart = p.curToken
	typeNode.Children = append(typeNode.Children, identNode)
	if p.curTokenIs(token.IDENT) && !p.peekTokenIs(token.LBRACKET) {  
		p.consume(token.IDENT)
	} else if p.curTokenIs(token.IDENT) && p.peekTokenIs(token.LBRACKET) {  
		p.consume(token.IDENT)
		p.consume(token.LBRACKET)
		typeNode.Children = append(typeNode.Children, p.varType())
		for !p.curTokenIs(token.RBRACKET) {
			p.consume(token.COMMA)
			typeNode.Children = append(typeNode.Children, p.varType())
		}
		p.consume(token.RBRACKET)
	} else if p.curTokenIs(token.LBRACKET) {  
		p.consume(token.LBRACKET)
		typeNode.Children = append(typeNode.Children, p.varType())
		p.consume(token.RBRACKET)
	}
	return typeNode
}
func (p *Parser) varRef() ast.Node {
	var refNode ast.Node
	refNode.Type = ast.VARREF
	refNode.Symbols = p.curSymTable
	var identNode ast.Node
	identNode.Type = ast.IDENT
	identNode.TokenStart = p.curToken
	refNode.Children = append(refNode.Children, identNode)
	p.consume(token.IDENT)
	for p.curTokenIs(token.LBRACKET) {
		p.nextToken()
		refNode.Children = append(refNode.Children, p.expr())
		p.consume(token.RBRACKET)
	}
	return refNode
}