package parser import ( "fmt" "jinx/pkg/lang/ast" "jinx/pkg/lang/scanner/token" ) func (p *Parser) parseStmt() (ast.Stmt, error) { switch p.peek().Kind { case token.KwUse: return p.parseUseStmt() case token.KwFn: return p.parseFnDeclStmt() case token.KwObject: return p.parseObjectDeclStmt() case token.KwVar: return p.parseVarDeclStmt() case token.KwIf: return p.parseIfStmt() case token.KwFor: return p.parseForStmt() case token.KwTry: return p.parseTryStmt() case token.KwReturn: return p.parseReturnStmt() case token.KwContinue: return p.parseContinueStmt() case token.KwBreak: return p.parseBreakStmt() case token.KwThrow: return p.parseThrowStmt() default: if p.peek().CanEndStmt() { return p.parseEmptyStmt() } else { return p.parseExprStmt() } } } func (p *Parser) parseUseStmt() (ast.Stmt, error) { panic("not implemented") } func (p *Parser) parseFnDeclStmt() (ast.Stmt, error) { fnTok, err := p.expect(token.KwFn) if err != nil { return ast.Stmt{}, err } name, err := p.parseIdent() if err != nil { return ast.Stmt{}, err } params, err := p.parseFnParams() if err != nil { return ast.Stmt{}, err } block, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: fnTok.At, Kind: ast.StmtKindFnDecl, Value: ast.StmtFnDecl{ Name: name, Args: params, Body: block, }, }, nil } func (p *Parser) parseFnParams() ([]ast.IdentNode, error) { // FnParams = "(" ( IDENT ("," IDENT)* )? ")" if _, err := p.expect(token.LParen); err != nil { return nil, err } params := []ast.IdentNode{} if p.peek().Kind != token.RParen { for { param, err := p.parseIdent() if err != nil { return nil, err } params = append(params, param) if p.peek().Kind == token.RParen { break } if _, err := p.expect(token.Comma); err != nil { return nil, err } } } if _, err := p.expect(token.RParen); err != nil { return nil, err } return params, nil } func (p *Parser) parseObjectDeclStmt() (ast.Stmt, error) { panic("not implemented") } func (p *Parser) parseVarDeclStmt() (ast.Stmt, error) { // VarDeclStmt = "var" IDENT "=" Expr varTok, err := p.expect(token.KwVar) if err != nil { return ast.Stmt{}, err } name, err := p.parseIdent() if err != nil { return ast.Stmt{}, err } if _, err := p.expect(token.Assign); err != nil { return ast.Stmt{}, err } expr, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: varTok.At, Kind: ast.StmtKindVarDecl, Value: ast.StmtVarDecl{ Name: name, Value: expr, }, }, nil } func (p *Parser) parseIfStmt() (ast.Stmt, error) { // IfStmt = "if" Expr Block ("elif" Expr Block)* ("else" Block)? ifTok, err := p.expect(token.KwIf) if err != nil { return ast.Stmt{}, err } conds := []ast.CondNode{} ifCond, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } then, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } conds = append(conds, ast.CondNode{ At: ifTok.At, Cond: ifCond, Then: then, }) for p.peek().Kind == token.KwElif { elifTok, err := p.expect(token.KwElif) if err != nil { return ast.Stmt{}, err } elifCond, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } elifThen, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } conds = append(conds, ast.CondNode{ At: elifTok.At, Cond: elifCond, Then: elifThen, }) } if p.peek().Kind == token.KwElse { elseTok, err := p.expect(token.KwElse) if err != nil { return ast.Stmt{}, err } elseThen, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } conds = append(conds, ast.CondNode{ At: elseTok.At, Cond: ast.Expr{}, Then: elseThen, }) } return ast.Stmt{ At: ifTok.At, Kind: ast.StmtKindIf, Value: ast.StmtIf{ Conds: conds, }, }, nil } func (p *Parser) parseForStmt() (ast.Stmt, error) { // ForStmt = ForCondStmt | ForInStmt // ForCondStmt = "for" Expr? Block // ForInStmt = "for" Ident "in" Expr Block forTok, err := p.expect(token.KwFor) if err != nil { return ast.Stmt{}, err } expr, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } // ForInStmt if expr.Kind == ast.ExprKindIdent && p.peek().Kind == token.KwIn { _, err := p.expect(token.KwIn) if err != nil { return ast.Stmt{}, err } collection, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } do, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: forTok.At, Kind: ast.StmtKindForIn, Value: ast.StmtForIn{ Name: expr.Value.(ast.ExprIdent).Value, Collection: collection, Do: do, }, }, nil } // ForCondStmt cond := expr do, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: forTok.At, Kind: ast.StmtKindForCond, Value: ast.StmtForCond{ Cond: cond, Do: do, }, }, nil } func (p *Parser) parseTryStmt() (ast.Stmt, error) { // TryStmt = "try" Block "catch" Ident ("finally" Block)? tryTok, err := p.expect(token.KwTry) if err != nil { return ast.Stmt{}, err } tryBlock, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } if _, err = p.expect(token.KwCatch); err != nil { return ast.Stmt{}, err } catchName, err := p.parseIdent() if err != nil { return ast.Stmt{}, err } catchBlock, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } finallyBlock := ast.BlockNode{} if p.peek().Kind == token.KwFinally { _, err := p.expect(token.KwFinally) if err != nil { return ast.Stmt{}, err } finallyBlock, err = p.parseBlock() if err != nil { return ast.Stmt{}, err } } return ast.Stmt{ At: tryTok.At, Kind: ast.StmtKindTry, Value: ast.StmtTry{ Try: tryBlock, CatchedName: catchName, Catch: catchBlock, Finally: finallyBlock, }, }, nil } func (p *Parser) parseReturnStmt() (ast.Stmt, error) { // ReturnStmt = "return" (Expr)? returnTok, err := p.expect(token.KwReturn) if err != nil { return ast.Stmt{}, err } expr := ast.Expr{} if !p.peek().CanEndStmt() { expr, err = p.parseExpr() if err != nil { return ast.Stmt{}, err } } return ast.Stmt{ At: returnTok.At, Kind: ast.StmtKindReturn, Value: ast.StmtReturn{ Value: expr, }, }, nil } func (p *Parser) parseContinueStmt() (ast.Stmt, error) { // ContinueStmt = "continue" continueTok, err := p.expect(token.KwContinue) if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: continueTok.At, Kind: ast.StmtKindContinue, Value: ast.StmtContinue{}, }, nil } func (p *Parser) parseBreakStmt() (ast.Stmt, error) { // BreakStmt = "break" breakTok, err := p.expect(token.KwBreak) if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: breakTok.At, Kind: ast.StmtKindBreak, Value: ast.StmtBreak{}, }, nil } func (p *Parser) parseThrowStmt() (ast.Stmt, error) { // ThrowStmt = "throw" Expr throwTok, err := p.expect(token.KwThrow) if err != nil { return ast.Stmt{}, err } expr, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: throwTok.At, Kind: ast.StmtKindThrow, Value: ast.StmtThrow{ Value: expr, }, }, nil } func (p *Parser) parseExprStmt() (ast.Stmt, error) { expr, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } return ast.Stmt{ At: expr.At, Kind: ast.StmtKindExpr, Value: ast.StmtExpr{ Value: expr, }, }, nil } func (p *Parser) parseEmptyStmt() (ast.Stmt, error) { return ast.Stmt{ At: p.peek().At, Kind: ast.StmtKindEmpty, Value: ast.StmtEmpty{}, }, nil } func (p *Parser) parseStmtEnd() error { tok := p.peek() if !tok.CanEndStmt() { panic(fmt.Errorf("wanted statement end, received: %+v", tok)) } p.next() return nil }