~starkingdoms/starkingdoms

d593bc7063de0d9edc1353c7718050598966602e — ghostlyzsh 1 year, 4 months ago 6922bff
if statement
4 files changed, 206 insertions(+), 8 deletions(-)

M kabel/grammar.ebnf
M kabel/src/lexer.rs
M kabel/src/macros.rs
M kabel/src/parser.rs
M kabel/grammar.ebnf => kabel/grammar.ebnf +1 -1
@@ 8,11 8,11 @@ loop = "loop" , block ;

while = "while" , "(" , expression , ")" , block ;

(* implemented *)
if = "if" , "(" , expression , ")" , block [ , "else" , ( if | block ) ] ;

block = "{" , { statement } , "}" ;

(* implemented *)
expression = assignment | declaration ;

declaration = "var" , identifier , "=" , expression ;

M kabel/src/lexer.rs => kabel/src/lexer.rs +16 -0
@@ 59,6 59,14 @@ impl Lexer {
                self.output.push(token!(self, TokenType::RightParen));
                self.start = self.current;
            }
            b'{' => {
                self.output.push(token!(self, TokenType::LeftBrace));
                self.start = self.current;
            }
            b'}' => {
                self.output.push(token!(self, TokenType::RightBrace));
                self.start = self.current;
            }
            b'.' => {
                self.output.push(token!(self, TokenType::Period));
                self.start = self.current;


@@ 67,6 75,10 @@ impl Lexer {
                self.output.push(token!(self, TokenType::Comma));
                self.start = self.current;
            }
            b';' => {
                self.output.push(token!(self, TokenType::Semicolon));
                self.start = self.current;
            }
            b'|' => {
                if self.peek() == b'|' {
                    self.read_char();


@@ 151,6 163,7 @@ impl Lexer {
                self.line += 1;
                self.line_start = self.current;
                self.column = 0;
                self.start = self.current;
            }
            b' ' | b'\r' | b'\t' => {
                self.start = self.current;


@@ 234,8 247,11 @@ pub enum TokenType {
    Minus,
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Period,
    Comma,
    Semicolon,
    Equal,
    EqualEqual,
    Bang,

M kabel/src/macros.rs => kabel/src/macros.rs +1 -1
@@ 22,5 22,5 @@ macro_rules! lit {
            line: $token.line,
            column: $token.column,
        }
    }
    };
}

M kabel/src/parser.rs => kabel/src/parser.rs +188 -6
@@ 1,6 1,7 @@
use crate::{
    error::{ErrorKind, KabelError},
    lexer::{Token, TokenType}, lit,
    lexer::{Token, TokenType},
    lit,
};

pub struct Parser {


@@ 30,7 31,7 @@ impl Parser {
            if self.current >= self.input.len() {
                break;
            }
            match self.expression() {
            match self.statement() {
                Ok(ast) => program.push(ast),
                Err(e) => self.errors.push(e),
            }


@@ 44,6 45,171 @@ impl Parser {
        }
    }

    pub fn statement(&mut self) -> Result<AST, KabelError> {
        match self.peek()?.token_type {
            TokenType::Ident(ident) => {
                match ident.as_str() {
                    "if" => self.if_statement(),
                    _ => self.expression_statement()
                }
            }
            _ => self.expression_statement()
        }
    }

    pub fn if_statement(&mut self) -> Result<AST, KabelError> {
        let if_ident = self.read_token()?;
        let left_paren = self.read_token()?;
        if let TokenType::LeftParen = left_paren.token_type {
            let condition = self.expression()?;
            let right_paren = self.read_token()?;
            if let TokenType::RightParen = right_paren.token_type {
                let block = self.block()?;
                if self.current < self.input.len() {
                    let else_ident = self.read_token()?;
                    if let TokenType::Ident(content) = else_ident.token_type {
                        if content == "else" {
                            if let TokenType::LeftBrace = self.peek()?.token_type {
                                let else_block = self.block()?;
                                return Ok(AST {
                                    ast_type: ASTType::If(Box::new(condition), Box::new(block.clone()), Some(Box::new(else_block.clone()))),
                                    start: if_ident.start,
                                    end: else_block.end,
                                    line: if_ident.line,
                                    column: if_ident.column,
                                });
                            }
                            let else_if_ident = self.peek()?;
                            if let TokenType::Ident(content) = else_if_ident.token_type {
                                if content == "if" {
                                    let else_if = self.if_statement()?;
                                    return Ok(AST {
                                        ast_type: ASTType::If(Box::new(condition), Box::new(block.clone()), Some(Box::new(else_if.clone()))),
                                        start: if_ident.start,
                                        end: else_if.end,
                                        line: if_ident.line,
                                        column: if_ident.column,
                                    });
                                } else {
                                    return Err(KabelError::new(
                                        ErrorKind::UnexpectedToken,
                                        format!(
                                            "Expected if found {}",
                                            self.text[else_if_ident.start..else_if_ident.end].to_string()
                                        ),
                                        else_if_ident.line,
                                        else_if_ident.column,
                                        self.text[else_if_ident.line_start..else_if_ident.end].to_string(),
                                    ));
                                }
                            }
                            return Err(KabelError::new(
                                ErrorKind::UnexpectedToken,
                                format!(
                                    "Unexpected token {}",
                                    self.text[else_ident.start..else_ident.end].to_string()
                                ),
                                else_ident.line,
                                else_ident.column,
                                self.text[else_ident.line_start..else_ident.end].to_string(),
                            ));
                        } else {
                            self.current -= 1;
                        }
                    }
                }
                return Ok(AST {
                    ast_type: ASTType::If(Box::new(condition), Box::new(block.clone()), None),
                    start: if_ident.start,
                    end: block.end,
                    line: if_ident.line,
                    column: if_ident.column,
                });
            } else {
                return Err(KabelError::new(
                    ErrorKind::UnexpectedToken,
                    format!(
                        "Expected ) found {}",
                        self.text[right_paren.start..right_paren.end].to_string()
                    ),
                    right_paren.line,
                    right_paren.column,
                    self.text[right_paren.line_start..right_paren.end].to_string(),
                ));
            }
        } else {
            return Err(KabelError::new(
                ErrorKind::UnexpectedToken,
                format!(
                    "Expected ( found {}",
                    self.text[left_paren.start..left_paren.end].to_string()
                ),
                left_paren.line,
                left_paren.column,
                self.text[left_paren.line_start..left_paren.end].to_string(),
            ));
        }
    }

    pub fn block(&mut self) -> Result<AST, KabelError> {
        let left_brace = self.read_token()?;
        if let TokenType::LeftBrace = left_brace.token_type {
            let mut stmts = Vec::new();
            while self.peek()?.token_type != TokenType::RightBrace {
                stmts.push(self.statement()?);
            }
            let right_brace = self.read_token()?;
            return Ok(AST {
                ast_type: ASTType::Block(stmts),
                start: left_brace.start,
                end: right_brace.end,
                line: left_brace.line,
                column: left_brace.column,
            });
        } else {
            return Err(KabelError::new(
                ErrorKind::UnexpectedToken,
                format!(
                    "Expected {{ found {}",
                    self.text[left_brace.start..left_brace.end].to_string()
                ),
                left_brace.line,
                left_brace.column,
                self.text[left_brace.line_start..left_brace.end].to_string(),
            ));
        }
    }

    pub fn expression_statement(&mut self) -> Result<AST, KabelError> {
        let expression = self.expression()?;
        if self.current >= self.input.len() {
            let last = self.input.last().unwrap();
            return Err(KabelError::new(
                ErrorKind::UnexpectedEof,
                "Unexpected end of file, expected ;".to_string(),
                expression.line,
                last.column,
                self.text[last.line_start..expression.end].to_string(),
            ));
        }
        let semicolon = self.read_token()?;
        if let TokenType::Semicolon = semicolon.token_type {
            return Ok(expression);
        } else {
            self.current -= 1;
            return Err(KabelError::new(
                ErrorKind::UnexpectedToken,
                format!(
                    "Expected ; found {}",
                    self.text[semicolon.start..semicolon.end].to_string()
                ),
                semicolon.line,
                semicolon.column,
                self.text[semicolon.line_start..semicolon.end].to_string(),
            ));
        }
    }

    pub fn expression(&mut self) -> Result<AST, KabelError> {
        if let TokenType::Ident(name) = self.peek()?.token_type {
            if name == "var" {


@@ 62,7 228,10 @@ impl Parser {
            if let TokenType::Equal = equal.token_type {
                let expr = self.expression()?;
                return Ok(AST {
                    ast_type: ASTType::Decl(Box::new(lit!(Ident, name, ident)), Box::new(expr.clone())),
                    ast_type: ASTType::Decl(
                        Box::new(lit!(Ident, name, ident)),
                        Box::new(expr.clone()),
                    ),
                    start: var.start,
                    end: expr.end,
                    line: var.line,


@@ 105,7 274,11 @@ impl Parser {
                self.read_token()?;
                let expr = self.assignment()?;
                return Ok(AST {
                    ast_type: ASTType::Binary(Box::new(lit!(Ident, name, ident)), BinOp::Assign, Box::new(expr.clone())),
                    ast_type: ASTType::Binary(
                        Box::new(lit!(Ident, name, ident)),
                        BinOp::Assign,
                        Box::new(expr.clone()),
                    ),
                    start: ident.start,
                    end: expr.end,
                    line: ident.line,


@@ 434,7 607,10 @@ impl Parser {
                        if let TokenType::LeftParen = self.peek()?.token_type {
                            let call = self.call(child)?;
                            expr = AST {
                                ast_type: ASTType::Member(Box::new(expr.clone()), Box::new(call.clone())),
                                ast_type: ASTType::Member(
                                    Box::new(expr.clone()),
                                    Box::new(call.clone()),
                                ),
                                start: expr.start,
                                end: call.end,
                                line: expr.line,


@@ 447,7 623,10 @@ impl Parser {
                        }
                    }
                    expr = AST {
                        ast_type: ASTType::Member(Box::new(expr.clone()), Box::new(lit!(Ident, child_str, child))),
                        ast_type: ASTType::Member(
                            Box::new(expr.clone()),
                            Box::new(lit!(Ident, child_str, child)),
                        ),
                        start: expr.start,
                        end: child.end,
                        line: expr.line,


@@ 573,6 752,9 @@ pub struct AST {
pub enum ASTType {
    Program(Vec<AST>),

    If(Box<AST>, Box<AST>, Option<Box<AST>>),
    Block(Vec<AST>),

    Decl(Box<AST>, Box<AST>),
    Binary(Box<AST>, BinOp, Box<AST>),
    Unary(UnOp, Box<AST>),