glox/parser.go

391 lines
6.5 KiB
Go
Raw Normal View History

2024-10-03 22:12:40 +03:00
package main
import (
"fmt"
2024-10-05 18:58:49 +03:00
"log"
2024-10-03 22:12:40 +03:00
)
type Parser struct {
tokens []Token
current int
2024-10-05 18:58:49 +03:00
errors []error
2024-10-03 22:12:40 +03:00
}
type ParseError struct {
token Token
message string
}
2024-10-05 18:58:49 +03:00
func (pe *ParseError) Error() string {
return fmt.Sprintf("ParseError [%d][%s]: %s", pe.token.line, pe.token.typ, pe.message)
2024-10-03 22:12:40 +03:00
}
func newParser(tokens []Token) *Parser {
return &Parser{
tokens: tokens,
current: 0,
}
}
2024-10-05 18:58:49 +03:00
// program -> declaration* EOF
func (p *Parser) parse() ([]Stmt, []error) {
2024-10-03 22:12:40 +03:00
defer p.recover()
2024-10-05 18:58:49 +03:00
stmts := []Stmt{}
for !p.isAtEnd() {
if stmt := p.declaration(); stmt != nil {
stmts = append(stmts, stmt)
}
}
return stmts, p.errors
2024-10-03 22:12:40 +03:00
}
2024-10-05 18:58:49 +03:00
// declaration -> varDecl | statement
func (p *Parser) declaration() Stmt {
defer p.synchronize()
if p.match(VAR) {
return p.varDecl()
2024-10-03 22:12:40 +03:00
}
2024-10-05 18:58:49 +03:00
return p.statement()
2024-10-03 22:12:40 +03:00
}
2024-10-05 18:58:49 +03:00
// varDecl -> "var" IDENTIFIER ("=" expression)? ";"
func (p *Parser) varDecl() Stmt {
name := p.consume(IDENTIFIER, "expect identifier for variable")
var initializer Expr = nil
if p.match(EQUAL) {
initializer = p.expression()
}
p.consume(SEMICOLON, "Expect ';' after expression.")
return &VarStmt{name, initializer}
}
2024-10-06 16:30:57 +03:00
// statement -> exprStmt | printStmt | block | ifStmt | env
2024-10-05 18:58:49 +03:00
func (p *Parser) statement() Stmt {
if p.match(PRINT) {
return p.printStmt()
}
2024-10-05 23:27:00 +03:00
if p.match(LEFT_BRACE) {
return p.block()
}
2024-10-06 16:30:57 +03:00
if p.match(IF) {
return p.ifStmt()
}
if p.match(ENV) {
return p.envStmt()
}
2024-10-05 18:58:49 +03:00
return p.exprStmt()
}
// exprStmt -> expression ";"
func (p *Parser) exprStmt() Stmt {
expr := p.expression()
p.consume(SEMICOLON, "Expect ';' after expression.")
2024-10-06 16:30:57 +03:00
if expr == nil {
return nil
}
2024-10-05 18:58:49 +03:00
return &ExprStmt{expr}
}
// printStmt -> "print" expression ";"
func (p *Parser) printStmt() Stmt {
expr := p.expression()
2024-10-06 16:30:57 +03:00
if expr == nil {
p.panic(&ParseError{p.previous(), "Expect expression after 'print'"})
}
2024-10-05 18:58:49 +03:00
p.consume(SEMICOLON, "Expect ';' after expression.")
return &PrintStmt{expr}
}
2024-10-05 23:27:00 +03:00
// block -> "{" statement* "}"
func (p *Parser) block() Stmt {
stmts := []Stmt{}
2024-10-06 16:30:57 +03:00
for !p.check(RIGHT_BRACE) && !p.isAtEnd() {
2024-10-05 23:27:00 +03:00
stmts = append(stmts, p.declaration())
}
p.consume(RIGHT_BRACE, "Unclosed block: Expected '}'.")
return &BlockStmt{stmts}
}
2024-10-06 16:30:57 +03:00
// if -> "if" "(" expression ")" statement ("else" statement)?
func (p *Parser) ifStmt() Stmt {
name := p.previous()
p.consume(LEFT_PAREN, "Expect '(' after 'if'.")
expr := p.expression()
p.consume(RIGHT_PAREN, "Expect ')' after 'if' condition.")
then := p.statement()
var or Stmt = nil
if p.match(ELSE) {
or = p.statement()
}
return &IfStmt{name, expr, then, or}
}
// env -> "env" ";"
func (p *Parser) envStmt() Stmt {
p.consume(SEMICOLON, "Expect ';' after 'env'.")
return &EnvStmt{}
}
2024-10-05 18:58:49 +03:00
// expression -> assignment
2024-10-03 22:12:40 +03:00
func (p *Parser) expression() Expr {
2024-10-05 18:58:49 +03:00
return p.assignment()
}
2024-10-06 17:15:50 +03:00
// assignment -> IDENTIFIER "=" assignment | or
2024-10-05 18:58:49 +03:00
func (p *Parser) assignment() Expr {
2024-10-06 17:15:50 +03:00
expr := p.or()
2024-10-05 18:58:49 +03:00
if p.match(EQUAL) {
eq := p.previous()
val := p.assignment()
if variable, ok := expr.(*Variable); ok {
return &Assign{variable.name, val}
}
p.panic(&ParseError{eq, "Invalid assignment target."})
}
return expr
2024-10-03 22:12:40 +03:00
}
2024-10-06 17:15:50 +03:00
// or -> and ( "or" and )*
func (p *Parser) or() Expr {
left := p.and()
2024-10-06 16:30:57 +03:00
for p.match(OR) {
or := p.previous()
2024-10-06 17:15:50 +03:00
right := p.and()
left = &Logical{left, or, right}
2024-10-06 16:30:57 +03:00
}
return left
}
2024-10-06 17:15:50 +03:00
// and -> equality ( "and" equality )*
func (p *Parser) and() Expr {
2024-10-06 16:30:57 +03:00
left := p.equality()
for p.match(AND) {
or := p.previous()
right := p.equality()
2024-10-06 17:15:50 +03:00
left = &Logical{left, or, right}
2024-10-06 16:30:57 +03:00
}
return left
}
2024-10-03 22:12:40 +03:00
// equality -> comparison ( ( "==" | "!=" ) comparison )*
func (p *Parser) equality() Expr {
expr := p.comparison()
for p.match(EQUAL_EQUAL, BANG_EQUAL) {
op := p.previous()
right := p.comparison()
expr = &Binary{expr, op, right}
}
return expr
}
// comparison -> term ( ( ">" | ">=" | "<" | "<=" ) term )*
func (p *Parser) comparison() Expr {
expr := p.term()
for p.match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL) {
op := p.previous()
right := p.term()
expr = &Binary{expr, op, right}
}
return expr
}
// term -> factor ( ( "-" | "+" ) factor )*
func (p *Parser) term() Expr {
expr := p.factor()
for p.match(MINUS, PLUS) {
op := p.previous()
right := p.factor()
expr = &Binary{expr, op, right}
}
return expr
}
// factor -> unary ( ( "/" | "*" ) unary )*
func (p *Parser) factor() Expr {
exp := p.unary()
for p.match(SLASH, STAR) {
op := p.previous()
right := p.unary()
2024-10-04 15:24:01 +03:00
exp = &Binary{exp, op, right}
2024-10-03 22:12:40 +03:00
}
return exp
}
// unary -> ( "!" | "-" ) unary | primary
func (p *Parser) unary() Expr {
if p.match(BANG, MINUS) {
op := p.previous()
right := p.unary()
return &Unary{op, right}
}
return p.primary()
}
2024-10-05 18:58:49 +03:00
// primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER
2024-10-03 22:12:40 +03:00
func (p *Parser) primary() Expr {
switch {
case p.match(FALSE):
return &Literal{false}
case p.match(TRUE):
return &Literal{true}
case p.match(NIL):
return &Literal{nil}
}
if p.match(NUMBER, STRING) {
return &Literal{p.previous().literal}
}
2024-10-05 18:58:49 +03:00
if p.match(IDENTIFIER) {
return &Variable{p.previous()}
}
2024-10-03 22:12:40 +03:00
if p.match(LEFT_PAREN) {
expr := p.expression()
p.consume(RIGHT_PAREN, "Expect ')' after expression")
return &Grouping{expr}
}
2024-10-05 23:27:00 +03:00
// p.panic(&ParseError{p.peek(), "Expect expression"})
2024-10-03 22:12:40 +03:00
return nil
}
func (p *Parser) previous() Token {
return p.tokens[p.current-1]
}
func (p *Parser) peek() Token {
return p.tokens[p.current]
}
func (p *Parser) isAtEnd() bool {
return p.peek().typ == EOF
}
func (p *Parser) advance() Token {
if !p.isAtEnd() {
p.current++
}
return p.previous()
}
func (p *Parser) check(typ TokenType) bool {
if p.isAtEnd() {
return false
}
return p.peek().typ == typ
}
func (p *Parser) match(types ...TokenType) bool {
for _, typ := range types {
if p.check(typ) {
p.advance()
return true
}
}
return false
}
func (p *Parser) consume(typ TokenType, mes string) Token {
if p.check(typ) {
return p.advance()
}
2024-10-05 18:58:49 +03:00
p.panic(&ParseError{p.peek(), mes})
2024-10-03 22:12:40 +03:00
return Token{}
}
func (p *Parser) synchronize() {
2024-10-05 18:58:49 +03:00
err := recover()
pe := p.isParseError(err)
if pe == nil {
return
}
2024-10-03 22:12:40 +03:00
p.advance()
for !p.isAtEnd() {
if p.previous().typ == SEMICOLON {
return
}
switch p.peek().typ {
2024-10-06 16:30:57 +03:00
case CLASS, FOR, FUN, IF, PRINT, RETURN, VAR, WHILE, ENV:
2024-10-03 22:12:40 +03:00
return
}
p.advance()
}
2024-10-05 18:58:49 +03:00
}
func (p *Parser) recover() {
p.isParseError(recover())
}
func (p *Parser) panic(pe *ParseError) {
p.errors = append(p.errors, pe)
log.Println(pe)
panic(pe)
}
func (p *Parser) isParseError(err any) *ParseError {
if err == nil {
return nil
}
pe, ok := err.(*ParseError)
if !ok {
panic(err)
}
return pe
2024-10-03 22:12:40 +03:00
}