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.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 } cond, err := p.parseExpr() if err != nil { return ast.Stmt{}, err } then, err := p.parseBlock() if err != nil { return ast.Stmt{}, err } elifs := []ast.CondNode{} 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 } elifs = append(elifs, ast.CondNode{ At: elifTok.At, Cond: elifCond, Then: elifThen, }) } elseThen := ast.BlockNode{} if p.peek().Kind == token.KwElse { _, err := p.expect(token.KwElse) if err != nil { return ast.Stmt{}, err } elseThen, err = p.parseBlock() if err != nil { return ast.Stmt{}, err } } return ast.Stmt{ At: ifTok.At, Kind: ast.StmtKindIf, Value: ast.StmtIf{ Cond: cond, Then: then, Elifs: elifs, Else: elseThen, }, }, 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 }