From cfac708644d002cbd01cba538607104a3b225246 Mon Sep 17 00:00:00 2001 From: Jooris Hadeler Date: Fri, 16 Jan 2026 21:17:53 +0100 Subject: [PATCH] feat: Add support for function declarations. --- .gitignore | 7 ---- example/simple.bky | 5 ++- src/ast.rs | 18 ++++++++++ src/main.rs | 4 +-- src/parser.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index a5ff07f..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1 @@ /target - - -# Added by cargo -# -# already existing elements were commented out - -#/target diff --git a/example/simple.bky b/example/simple.bky index e1b7dd6..e78fafd 100644 --- a/example/simple.bky +++ b/example/simple.bky @@ -1,4 +1,3 @@ -fn main(): i32 { - let return_code: i32 = 12; - return return_code; +fn add(a: i32, b: i32): i32 { + return a + b; } \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index cced20e..24b7984 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -103,3 +103,21 @@ pub enum Type { Named { name: Box, name_span: Span }, } + +#[derive(Debug, PartialEq, Eq)] +pub enum Declaration { + Function { + name: Box, + name_span: Span, + parameters: Vec, + return_type: Option, + body: Option, + }, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Parameter { + pub name: Box, + pub name_span: Span, + pub type_: Type, +} diff --git a/src/main.rs b/src/main.rs index bd8f197..af83521 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ pub mod parser; pub mod token; fn main() { - let mut parser = Parser::new("{ let return_code: i32 = 12; return return_code; }"); + let mut parser = Parser::new(include_str!("../example/simple.bky")); - println!("{:#?}", parser.parse_statement()); + println!("{:#?}", parser.parse_declaration()); } diff --git a/src/parser.rs b/src/parser.rs index 8268876..9a4896d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -56,6 +56,90 @@ impl<'src> Parser<'src> { } } + pub fn parse_declaration(&mut self) -> ParserResult { + let peek_tok = self.peek_no_eof()?; + + match peek_tok.kind { + TokenKind::KwFn => self.parse_function_declaration(), + + found => Err(ParserError::UnexpectedToken { + expected: &[TokenKind::KwFn], + found, + span: peek_tok.span, + }), + } + } + + fn parse_function_declaration(&mut self) -> ParserResult { + self.expect(&[TokenKind::KwFn])?; + + let (name, name_span) = { + let token = self.expect(&[TokenKind::Identifier])?; + + (token.text.to_string().into_boxed_str(), token.span) + }; + + self.expect(&[TokenKind::LeftParen])?; + + let parameters = self.parse_function_parameters()?; + + self.expect(&[TokenKind::RightParen])?; + + let return_type = if self.is_peek(TokenKind::Colon) { + self.consume(); + Some(self.parse_type()?) + } else { + None + }; + + let body = if self.is_peek(TokenKind::LeftBrace) { + Some(self.parse_compound_statement()?) + } else { + self.expect(&[TokenKind::Semicolon])?; + None + }; + + Ok(Declaration::Function { + name, + name_span, + parameters, + return_type, + body, + }) + } + + fn parse_function_parameters(&mut self) -> ParserResult> { + let mut parameters = Vec::new(); + + loop { + if self.is_peek(TokenKind::RightParen) { + break; + } + + if !parameters.is_empty() { + self.expect(&[TokenKind::Comma])?; + } + + let (name, name_span) = { + let token = self.expect(&[TokenKind::Identifier])?; + + (token.text.to_string().into_boxed_str(), token.span) + }; + + self.expect(&[TokenKind::Colon])?; + + let type_ = self.parse_type()?; + + parameters.push(Parameter { + name, + name_span, + type_, + }); + } + + Ok(parameters) + } + pub fn parse_type(&mut self) -> ParserResult { let name_tok = self.expect(&[TokenKind::Identifier])?;