diff --git a/src/ast.rs b/src/ast.rs index 775e956..058ccd4 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,12 +1,17 @@ //! //! The AST module contains all structs and enums for the abstract syntax tree generated by the parser -#![allow(dead_code)] use crate::errors::Span; /// imagine interning or something here pub type Symbol = String; +#[derive(Debug, Clone, PartialEq)] +pub struct Ident { + pub name: Symbol, + pub span: Span, +} + #[derive(Debug, Clone, PartialEq)] pub struct Program(pub Vec); @@ -30,42 +35,25 @@ pub enum Stmt { Expr(Expr), } -impl Stmt { - pub fn span(&self) -> Span { - match self { - Stmt::Declaration(decl) => decl.span, - Stmt::Assignment(assign) => assign.span, - Stmt::FnDecl(decl) => decl.span, - Stmt::If(if_stmt) => if_stmt.span, - Stmt::Loop(_, span) => *span, - Stmt::While(while_stmt) => while_stmt.span, - Stmt::Break(span) => *span, - Stmt::Return(_, span) => *span, - Stmt::Block(block) => block.span, - Stmt::Expr(expr) => expr.span(), - } - } -} - #[derive(Debug, Clone, PartialEq)] pub struct Declaration { pub span: Span, - name: Symbol, - init: Expr, + pub name: Ident, + pub init: Expr, } #[derive(Debug, Clone, PartialEq)] pub struct Assignment { pub span: Span, - pub lhs: Symbol, + pub lhs: Expr, pub rhs: Expr, } #[derive(Debug, Clone, PartialEq)] pub struct FnDecl { pub span: Span, - pub name: Symbol, - pub params: Vec, + pub name: Ident, + pub params: Vec, pub body: Block, } @@ -101,7 +89,7 @@ pub struct WhileStmt { #[derive(Debug, Clone, PartialEq)] pub enum Expr { - Ident(Symbol, Span), + Ident(Ident), Literal(Literal), UnaryOp(Box), BinaryOp(Box), @@ -113,7 +101,7 @@ impl Expr { Expr::Literal(lit) => lit.span(), Expr::UnaryOp(unary) => unary.span, Expr::BinaryOp(binary) => binary.span, - Expr::Ident(_, span) => *span, + Expr::Ident(Ident { span, .. }) => *span, } } } diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 02fb139..5fdafc7 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - #[cfg(test)] mod test; @@ -86,15 +84,47 @@ impl<'code> Parser<'code> { } fn declaration(&mut self) -> ParseResult<'code, Stmt> { - todo!() + let keyword_span = self.expect(TokenType::Let)?.span; + let name = self.ident()?; + self.expect(TokenType::Equal)?; + let init = self.expression()?; + self.expect(TokenType::Semi)?; + Ok(Stmt::Declaration(Declaration { + span: keyword_span.extend(init.span()), + name, + init, + })) } fn assignment(&mut self) -> ParseResult<'code, Stmt> { - todo!() + todo!("oh god no") } fn fn_decl(&mut self) -> ParseResult<'code, Stmt> { - todo!() + let keyword_span = self.expect(TokenType::Fn)?.span; + let name = self.ident()?; + let args = self.fn_args()?; + let body = self.block()?; + Ok(Stmt::FnDecl(FnDecl { + span: keyword_span.extend(body.span), + name, + params: args, + body, + })) + } + + fn fn_args(&mut self) -> ParseResult<'code, Vec> { + self.expect(TokenType::ParenO)?; + let mut params = Vec::new(); + while self.peek_kind().ok_or(ParseErr::EOF("function argument"))? != &TokenType::ParenC { + let ident = self.ident()?; + params.push(ident); + + // todo (ident ident) would be allowed here, but should not + self.maybe_consume(TokenType::Comma); + } + self.expect(TokenType::ParenC)?; + Ok(params) } fn if_stmt(&mut self) -> ParseResult<'code, IfStmt> { @@ -276,7 +306,7 @@ impl<'code> Parser<'code> { } } - fn primary(&mut self) -> ParseResult<'code, Expr> { + fn primary<'parser>(&'parser mut self) -> ParseResult<'code, Expr> { let next = self.next().ok_or(ParseErr::EOF("primary"))?; match next.kind { TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal, next.span))), @@ -293,12 +323,34 @@ impl<'code> Parser<'code> { } TokenType::Ident(name) => { let name_owned = name.to_owned(); - Ok(Expr::Ident(name_owned, next.span)) + Ok(Expr::Ident(Ident { + name: name_owned, + span: next.span, + })) } _ => Err(ParseErr::InvalidTokenPrimary(next)), } } + fn ident(&mut self) -> ParseResult<'code, Ident> { + let Token { kind, span } = self.next().ok_or(ParseErr::EOF("identifier"))?; + match kind { + TokenType::Ident(name) => { + let name_owned = name.to_owned(); + Ok(Ident { + name: name_owned, + span, + }) + } + _ => { + return Err(ParseErr::MismatchedKind { + expected: TokenType::Ident(""), + actual: Token { span, kind }, + }) + } + } + } + fn object_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> { let close_span = self.expect(TokenType::BraceC)?.span; Ok(Expr::Literal(Literal::Object(open_span.extend(close_span)))) @@ -307,14 +359,14 @@ impl<'code> Parser<'code> { fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> { let mut elements = Vec::new(); while self - .peek() + .peek_kind() .ok_or(ParseErr::EOFExpecting(TokenType::BracketC))? - .kind - != TokenType::BracketC + != &TokenType::BracketC { let expr = self.expression()?; elements.push(expr); - self.expect(TokenType::Comma)?; + // todo [expr expr] would be allowed here, but should not + self.maybe_consume(TokenType::Comma); } let closing_bracket = self.expect(TokenType::BracketC)?; Ok(Expr::Literal(Literal::Array( @@ -340,6 +392,14 @@ impl<'code> Parser<'code> { self.peek().map(|token| &token.kind) } + fn maybe_consume(&mut self, kind: TokenType<'code>) -> Option { + if self.peek_kind() == Some(&kind) { + self.next() + } else { + None + } + } + fn expect(&mut self, kind: TokenType<'code>) -> ParseResult<'code, Token> { if let Some(token) = self.next() { if token.kind == kind { diff --git a/src/parse/test.rs b/src/parse/test.rs index b795ff0..b3a4b7f 100644 --- a/src/parse/test.rs +++ b/src/parse/test.rs @@ -4,9 +4,12 @@ use prelude::*; mod prelude { pub(super) use super::{parser, test_literal_bin_op, test_number_literal, token}; - pub(super) use crate::ast::{BinaryOp, BinaryOpKind, Expr, Literal}; + pub(super) use crate::ast::*; pub(super) use crate::errors::Span; - pub(super) use crate::lex::{Token, TokenType}; + pub(super) use crate::lex::{ + Token, + TokenType::{self, *}, + }; } fn token(kind: TokenType) -> Token { @@ -50,10 +53,34 @@ fn test_number_literal>) -> Expr>(parser: F) { assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), unary); } +mod r#loop { + use super::prelude::*; + + fn parse_loop(tokens: Vec) -> Stmt { + let mut parser = parser(tokens); + parser.loop_stmt().unwrap() + } + + #[test] + fn empty() { + let tokens = [Loop, BraceO, BraceC].map(token).into(); + let ast = parse_loop(tokens); + assert_eq!( + Stmt::Loop( + Block { + stmts: vec![], + span: Span::dummy() + }, + Span::dummy() + ), + ast + ); + } +} + mod expr { use super::prelude::*; use crate::ast::{UnaryOp, UnaryOpKind}; - use TokenType::*; fn parse_expr(tokens: Vec) -> Expr { let mut parser = parser(tokens); @@ -357,7 +384,13 @@ mod primary { fn ident() { let tokens = [TokenType::Ident("tokens")].map(token).into(); let literal = parse_primary(tokens); - assert_eq!(Expr::Ident("tokens".to_string(), Span::dummy()), literal); + assert_eq!( + Expr::Ident(Ident { + name: "tokens".to_string(), + span: Span::dummy() + }), + literal + ); } #[test] diff --git a/test.sl b/test.sl index 23da65c..948aa36 100644 --- a/test.sl +++ b/test.sl @@ -1 +1,6 @@ -(1 + 5 and 5) / 2; \ No newline at end of file +fn test() { + let uwu = 2; + if uwu { + print; + } +} \ No newline at end of file