~starkingdoms/starkingdoms

6922bff15844056844e1d738494ed7b70def1fef — ghostlyzsh 1 year, 4 months ago e291ccb
call, member access, declaration, and assignment
4 files changed, 216 insertions(+), 18 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 +13 -5
@@ 2,19 2,23 @@ program = { statement } ;

statement = if | while | ( expression , ";" ) ;

while = "while" , expression , block ;
function = "function" , identifier , "(" , { identifier , "," , } ")" , block

if = "if" , expression , block ;
loop = "loop" , block ;

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

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

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

(* implemented *)
expression = assignment | declaration ;

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

assignment = { identifier , "=" , } logical_or ;
assignment = ( identifier , "=" , assignment ) | logical_or;

(* implemented *)
logical_or = logical_and { , "||" , logical_and } ;

logical_and = equality { , "&&" , equality } ;


@@ 29,7 33,11 @@ factor = unary { , ( "*" | "/" ) , unary } ;

unary = ( ( "!" | "-" ) , unary ) | primary ;

primary = identifier | number | string | group ;
primary = identifier | member | call | number | string | group ;

member = identifier , "." ,  { ( identifier | call ) , "." ? } ;

call = ( identifier , "(" , { expression, "," ? } , ")" ) ;

group = "(" , expression , ")" ;


M kabel/src/lexer.rs => kabel/src/lexer.rs +10 -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::Period));
                self.start = self.current;
            }
            b',' => {
                self.output.push(token!(self, TokenType::Comma));
                self.start = self.current;
            }
            b'|' => {
                if self.peek() == b'|' {
                    self.read_char();


@@ 226,6 234,8 @@ pub enum TokenType {
    Minus,
    LeftParen,
    RightParen,
    Period,
    Comma,
    Equal,
    EqualEqual,
    Bang,

M kabel/src/macros.rs => kabel/src/macros.rs +13 -0
@@ 11,3 11,16 @@ macro_rules! token {
        }
    };
}

#[macro_export]
macro_rules! lit {
    ($type:ident, $data:expr, $token:expr) => {
        $crate::parser::AST {
            ast_type: $crate::parser::ASTType::Lit($crate::parser::Lit::$type($data)),
            start: $token.start,
            end: $token.end,
            line: $token.line,
            column: $token.column,
        }
    }
}

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

pub struct Parser {


@@ 45,19 45,92 @@ impl Parser {
    }

    pub fn expression(&mut self) -> Result<AST, KabelError> {
        let equality = self.logical_or()?;
        Ok(equality)
        if let TokenType::Ident(name) = self.peek()?.token_type {
            if name == "var" {
                return self.declaration();
            }
        }
        let assignment = self.assignment()?;
        Ok(assignment)
    }

    pub fn declaration(&mut self) -> Result<AST, KabelError> {
        let var = self.read_token()?;
        let ident = self.read_token()?;
        if let TokenType::Ident(name) = ident.token_type {
            let equal = self.read_token()?;
            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())),
                    start: var.start,
                    end: expr.end,
                    line: var.line,
                    column: var.column,
                });
            } else {
                return Err(KabelError::new(
                    ErrorKind::UnexpectedToken,
                    format!(
                        "Expected equals, found {}",
                        self.text[equal.start..equal.end].to_string()
                    ),
                    equal.line,
                    equal.column,
                    self.text[equal.line_start..equal.end].to_string(),
                ));
            }
        } else {
            return Err(KabelError::new(
                ErrorKind::UnexpectedToken,
                format!(
                    "Expected identifier, found {}",
                    self.text[ident.start..ident.end].to_string()
                ),
                ident.line,
                ident.column,
                self.text[ident.line_start..ident.end].to_string(),
            ));
        }
    }

    pub fn assignment(&mut self) -> Result<AST, KabelError> {
        if let TokenType::Ident(name) = self.peek()?.token_type {
            let ident = self.read_token()?;
            if self.current >= self.input.len() {
                self.current -= 1;
                return self.logical_or();
            }
            if self.peek()?.token_type == TokenType::Equal {
                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())),
                    start: ident.start,
                    end: expr.end,
                    line: ident.line,
                    column: ident.column,
                });
            }
            self.current -= 1;
            return self.logical_or();
        }

        return self.logical_or();
    }

    pub fn logical_or(&mut self) -> Result<AST, KabelError> {
        let mut left = self.logical_and()?;

        while self.current < self.input.len()
            && self.peek()?.token_type == TokenType::OrOr {
        while self.current < self.input.len() && self.peek()?.token_type == TokenType::OrOr {
            self.read_token()?;
            let right = self.logical_and()?;
            left = AST {
                ast_type: ASTType::Binary(Box::new(left.clone()), BinOp::Or, Box::new(right.clone())),
                ast_type: ASTType::Binary(
                    Box::new(left.clone()),
                    BinOp::Or,
                    Box::new(right.clone()),
                ),
                start: left.start,
                end: right.end,
                line: left.line,


@@ 70,12 143,15 @@ impl Parser {
    pub fn logical_and(&mut self) -> Result<AST, KabelError> {
        let mut left = self.equality()?;

        while self.current < self.input.len()
            && self.peek()?.token_type == TokenType::AndAnd {
        while self.current < self.input.len() && self.peek()?.token_type == TokenType::AndAnd {
            self.read_token()?;
            let right = self.equality()?;
            left = AST {
                ast_type: ASTType::Binary(Box::new(left.clone()), BinOp::And, Box::new(right.clone())),
                ast_type: ASTType::Binary(
                    Box::new(left.clone()),
                    BinOp::And,
                    Box::new(right.clone()),
                ),
                start: left.start,
                end: right.end,
                line: left.line,


@@ 294,9 370,17 @@ impl Parser {
        let token = self.read_token()?;

        match token.token_type {
            TokenType::Ident(ident) => {
            TokenType::Ident(ref ident) => {
                if self.current < self.input.len() {
                    if let TokenType::LeftParen = self.peek()?.token_type {
                        return self.call(token);
                    }
                    if let TokenType::Period = self.peek()?.token_type {
                        return self.member(token);
                    }
                }
                return Ok(AST {
                    ast_type: ASTType::Ident(ident),
                    ast_type: ASTType::Lit(Lit::Ident(ident.clone())),
                    start: token.start,
                    end: token.end,
                    line: token.line,


@@ 305,7 389,7 @@ impl Parser {
            }
            TokenType::Num(num) => {
                return Ok(AST {
                    ast_type: ASTType::Num(num),
                    ast_type: ASTType::Lit(Lit::Num(num)),
                    start: token.start,
                    end: token.end,
                    line: token.line,


@@ 314,7 398,7 @@ impl Parser {
            }
            TokenType::Str(string) => {
                return Ok(AST {
                    ast_type: ASTType::Str(string),
                    ast_type: ASTType::Lit(Lit::Str(string)),
                    start: token.start,
                    end: token.end,
                    line: token.line,


@@ 338,6 422,80 @@ impl Parser {
            }
        }
    }

    pub fn member(&mut self, ident: Token) -> Result<AST, KabelError> {
        if let TokenType::Ident(first) = ident.token_type {
            let mut expr: AST = lit!(Ident, first, ident);
            while self.peek()?.token_type == TokenType::Period {
                self.read_token()?;
                let child = self.read_token()?;
                if let TokenType::Ident(child_str) = child.clone().token_type {
                    if self.current < self.input.len() {
                        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())),
                                start: expr.start,
                                end: call.end,
                                line: expr.line,
                                column: expr.column,
                            };
                            if self.current >= self.input.len() {
                                break;
                            }
                            continue;
                        }
                    }
                    expr = AST {
                        ast_type: ASTType::Member(Box::new(expr.clone()), Box::new(lit!(Ident, child_str, child))),
                        start: expr.start,
                        end: child.end,
                        line: expr.line,
                        column: expr.column,
                    };
                } else {
                    return Err(KabelError::new(
                        ErrorKind::UnexpectedToken,
                        format!(
                            "Unexpected token {}",
                            self.text[child.start..child.end].to_string()
                        ),
                        child.line,
                        child.column,
                        self.text[child.line_start..child.end].to_string(),
                    ));
                }
                if self.current >= self.input.len() {
                    break;
                }
            }
            return Ok(expr);
        }
        panic!("Bad member logic");
    }

    pub fn call(&mut self, ident: Token) -> Result<AST, KabelError> {
        self.read_token()?;
        let mut expressions = Vec::new();
        while self.peek()?.token_type != TokenType::RightParen {
            expressions.push(self.expression()?);
            if let TokenType::Comma = self.peek()?.token_type {
                self.read_token()?;
            }
        }
        let right_paren = self.read_token()?;
        if let TokenType::Ident(name) = ident.token_type {
            return Ok(AST {
                ast_type: ASTType::Call(Box::new(lit!(Ident, name, ident)), expressions),
                start: ident.start,
                end: right_paren.end,
                line: ident.start,
                column: ident.column,
            });
        }
        panic!("Call logic broke");
    }

    pub fn group(&mut self, left_paren: Token) -> Result<AST, KabelError> {
        let expr = self.expression()?;
        let right_paren = self.peek();


@@ 415,10 573,18 @@ pub struct AST {
pub enum ASTType {
    Program(Vec<AST>),

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

    Group(Box<AST>),
    Lit(Lit),
    Call(Box<AST>, Vec<AST>),
    Member(Box<AST>, Box<AST>),
}

#[derive(Debug, Clone)]
pub enum Lit {
    Ident(String),
    Num(f32),
    Str(String),


@@ 438,6 604,7 @@ pub enum BinOp {
    Le,
    Or,
    And,
    Assign,
}

#[derive(Debug, Clone, Copy)]