From f702f4771422ac30733989d885daaedf9e59ac5d Mon Sep 17 00:00:00 2001 From: Shadow Cat Date: Sun, 12 Apr 2026 17:26:39 -0400 Subject: [PATCH] gaming --- [ | 5 +++++ src/parser/cursor/mod.rs | 13 +++++-------- src/parser/node/parse.rs | 21 +++++++++++++++++++-- src/parser/nodes/body.rs | 26 ++++++++++---------------- src/parser/nodes/expr.rs | 39 +++++++++++++++++++++++++++------------ src/parser/nodes/func.rs | 23 ++++++++++++++++++----- src/parser/nodes/mod.rs | 3 +++ src/parser/nodes/param.rs | 27 +++++++++++++++++++++++++++ test/main.lang | 13 +++++++------ 9 files changed, 121 insertions(+), 49 deletions(-) create mode 100644 [ create mode 100644 src/parser/nodes/param.rs diff --git a/[ b/[ new file mode 100644 index 0000000..129a495 --- /dev/null +++ b/[ @@ -0,0 +1,5 @@ +x :i32 = 3; +y := fn(a: i32, b, c) x = 3; +while true { + print("hello"); +} diff --git a/src/parser/cursor/mod.rs b/src/parser/cursor/mod.rs index 7b1da30..e9fc466 100644 --- a/src/parser/cursor/mod.rs +++ b/src/parser/cursor/mod.rs @@ -1,3 +1,5 @@ +use std::borrow::Borrow; + use crate::io::{CompilerMsg, Span, Spanned}; mod lit; @@ -35,8 +37,8 @@ impl<'a> Cursor<'a> { }) } - pub fn next_if(&mut self, token: &Token) -> bool { - if self.peek().is_some_and(|t| t == token) { + pub fn next_if(&mut self, token: impl Borrow) -> bool { + if self.peek().is_some_and(|t| t == token.borrow()) { self.next(); true } else { @@ -52,11 +54,6 @@ impl<'a> Cursor<'a> { self.next().ok_or_else(CompilerMsg::unexpected_eof) } - pub fn expect_peek(&self) -> Result<&Token, CompilerMsg> { - self.peek().ok_or_else(CompilerMsg::unexpected_eof) - // Ok(self.peek().unwrap()) - } - pub fn expect(&mut self, token: Token) -> Result { let next = self.expect_next()?; if next == token { @@ -87,7 +84,7 @@ impl CompilerMsg { pub fn unexpected_token(token: &Token, span: Span, expected: &str) -> Self { Self { spans: vec![span], - msg: format!("Unexpected token '{}'; expected {expected}", token), + msg: format!("Unexpected token '{}', expected {expected}", token), } } diff --git a/src/parser/node/parse.rs b/src/parser/node/parse.rs index bfa5c69..7f26562 100644 --- a/src/parser/node/parse.rs +++ b/src/parser/node/parse.rs @@ -1,3 +1,5 @@ +use std::ops::Index; + use crate::{ io::{CompilerMsg, Span}, parser::{ @@ -25,10 +27,17 @@ impl<'a> ParseCtx<'a> { } } - pub fn parse(&mut self) -> Result, CompilerMsg> { + pub fn parse(&mut self) -> Result, CompilerMsg> { + self.parse_with(N::parse) + } + + pub fn parse_with( + &mut self, + f: impl FnOnce(&mut Self) -> Result, + ) -> Result, CompilerMsg> { let old_start = self.start; self.start = self.cursor.peek_start(); - let res = P::parse(self).map(|r| self.push(r)); + let res = f(self).map(|r| self.push(r)); self.start = old_start; res } @@ -92,3 +101,11 @@ impl<'a> std::ops::DerefMut for ParseCtx<'a> { &mut self.cursor } } + +impl Index> for ParseCtx<'_> { + type Output = N; + + fn index(&self, index: Id) -> &Self::Output { + &self.nodes[index] + } +} diff --git a/src/parser/nodes/body.rs b/src/parser/nodes/body.rs index d9998db..cd4d8ba 100644 --- a/src/parser/nodes/body.rs +++ b/src/parser/nodes/body.rs @@ -8,25 +8,19 @@ pub struct Body { impl Parsable for Body { fn parse(ctx: &mut ParseCtx) -> Result { let mut exprs = Vec::new(); - let mut final_semicolon = false; - match ctx.peek() { - None | Some(Token::CloseCurly) => { - return Ok(Self { - exprs, - final_semicolon, - }); - } - _ => (), + fn at_end(ctx: &mut ParseCtx) -> bool { + ctx.peek().is_none_or(|t| *t == Token::CloseCurly) } - exprs.push(ctx.parse()?); - while ctx.next_if(&Token::Semicolon) { - final_semicolon = true; - if ctx.peek().is_none_or(|t| *t == Token::CloseCurly) { - break; + let final_semicolon = loop { + if at_end(ctx) { + break true; } exprs.push(ctx.parse()?); - final_semicolon = false; - } + if at_end(ctx) { + break false; + } + ctx.expect(Token::Semicolon)?; + }; Ok(Self { exprs, final_semicolon, diff --git a/src/parser/nodes/expr.rs b/src/parser/nodes/expr.rs index 8ec0959..d0efc45 100644 --- a/src/parser/nodes/expr.rs +++ b/src/parser/nodes/expr.rs @@ -37,22 +37,22 @@ pub enum Expr { impl Parsable for Expr { fn parse(ctx: &mut ParseCtx) -> Result { - let mut res = Self::parse_unit(ctx)?; + let mut res = Self::unit(ctx)?; while let Some(next) = ctx.peek() { res = match next { Token::Equal => { let target = ctx.push_adv(res); - let val = Self::push_unit(ctx)?; + let val = ctx.parse_with(Self::unit)?; Expr::Assign { target, val } } Token::Colon => { let target = ctx.push_adv(res); let mut ty = None; - if !ctx.next_if(&Token::Equal) { + if !ctx.next_if(Token::Equal) { ty = Some(ctx.parse()?); ctx.expect(Token::Equal)?; } - let val = Self::push_unit(ctx)?; + let val = ctx.parse_with(Self::unit)?; Expr::Define { target, ty, val } } Token::OpenParen => { @@ -68,11 +68,7 @@ impl Parsable for Expr { } impl Expr { - fn push_unit(ctx: &mut ParseCtx) -> Result, CompilerMsg> { - let res = Self::parse_unit(ctx)?; - Ok(ctx.push(res)) - } - fn parse_unit(ctx: &mut ParseCtx) -> Result { + fn unit(ctx: &mut ParseCtx) -> Result { Ok(match ctx.expect_next()? { Token::Dash => Self::Negate(ctx.parse()?), Token::Ident(s) => Self::Ident(ctx.ident(s)), @@ -80,12 +76,12 @@ impl Expr { Token::Fn => Self::Fn(ctx.parse()?), Token::If => { let cond = ctx.parse()?; - let body = ctx.parse()?; + let body = cond_body(cond, ctx)?; Self::If { cond, body } } Token::While => { let cond = ctx.parse()?; - let body = ctx.parse()?; + let body = cond_body(cond, ctx)?; Self::While { cond, body } } Token::Loop => { @@ -93,7 +89,7 @@ impl Expr { Self::Loop { body } } Token::OpenParen => { - if ctx.next_if(&Token::CloseParen) { + if ctx.next_if(Token::CloseParen) { Self::Lit(ctx.push(Lit::Unit)) } else { let inner = ctx.parse()?; @@ -109,6 +105,25 @@ impl Expr { other => return ctx.unexpected(&other, "an expression"), }) } + + pub fn is_group(&self) -> bool { + matches!(self, Expr::Group(_)) + } + + pub fn block(ctx: &mut ParseCtx) -> Result { + ctx.expect(Token::OpenCurly)?; + let id = ctx.parse()?; + ctx.expect(Token::CloseCurly)?; + Ok(Expr::Block(id)) + } +} + +fn cond_body(cond: Id, ctx: &mut ParseCtx) -> Result, CompilerMsg> { + if ctx[cond].is_group() { + ctx.parse() + } else { + ctx.parse_with(Expr::block) + } } impl FmtNode for Expr { diff --git a/src/parser/nodes/func.rs b/src/parser/nodes/func.rs index be307b5..aaa004c 100644 --- a/src/parser/nodes/func.rs +++ b/src/parser/nodes/func.rs @@ -1,7 +1,8 @@ use super::*; pub struct Func { - args: Vec>, + args: Vec>, + ret: Option>, body: Id, } @@ -9,21 +10,33 @@ impl Parsable for Func { fn parse(ctx: &mut ParseCtx) -> Result { ctx.expect(Token::OpenParen)?; let args = ctx.list(Token::Comma, Token::CloseParen)?; - let body = ctx.parse()?; - Ok(Self { args, body }) + let mut ret = None; + if ctx.next_if(Token::Arrow) { + ret = Some(ctx.parse()?); + } + let body = if ret.is_some() { + ctx.parse_with(Expr::block) + } else { + ctx.parse() + }?; + Ok(Self { args, ret, body }) } } impl FmtNode for Func { fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { - write!(f, "(")?; + write!(f, "fn(")?; if let Some((last, rest)) = self.args.split_last() { for arg in rest { write!(f, "{}, ", arg.dsp(ctx))?; } write!(f, "{}", last.dsp(ctx))?; } - write!(f, ") {}", self.body.dsp(ctx))?; + write!(f, ") ")?; + if let Some(ret) = self.ret { + write!(f, "-> {} ", ret.dsp(ctx))?; + } + self.body.fmt(f, ctx)?; Ok(()) } } diff --git a/src/parser/nodes/mod.rs b/src/parser/nodes/mod.rs index 7785978..585a687 100644 --- a/src/parser/nodes/mod.rs +++ b/src/parser/nodes/mod.rs @@ -2,11 +2,13 @@ mod body; mod expr; mod func; mod ident; +mod param; mod ty; pub use body::*; pub use expr::*; pub use func::*; pub use ident::*; +pub use param::*; pub use ty::*; use super::{DisplayCtx, FmtNode, Id, Lit, Node, NodeVec, Parsable, ParseCtx, Token}; @@ -19,6 +21,7 @@ def_nodes! { lits: Lit, types: Type, funcs: Func, + params: Param, } macro_rules! def_nodes { diff --git a/src/parser/nodes/param.rs b/src/parser/nodes/param.rs new file mode 100644 index 0000000..9d0de41 --- /dev/null +++ b/src/parser/nodes/param.rs @@ -0,0 +1,27 @@ +use super::*; + +pub struct Param { + name: Id, + ty: Option>, +} + +impl Parsable for Param { + fn parse(ctx: &mut ParseCtx) -> Result { + let name = ctx.parse()?; + let mut ty = None; + if ctx.next_if(Token::Colon) { + ty = Some(ctx.parse()?); + } + Ok(Self { name, ty }) + } +} + +impl FmtNode for Param { + fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { + self.name.fmt(f, ctx)?; + if let Some(ty) = self.ty { + write!(f, ": {}", ty.dsp(ctx))?; + } + Ok(()) + } +} diff --git a/test/main.lang b/test/main.lang index 9352fac..cbd678e 100644 --- a/test/main.lang +++ b/test/main.lang @@ -1,6 +1,7 @@ -x: i32 = 3; -y := fn(a, b, c) {}; -while Some(a) := b { - print("hello"); - f(x, y, z) -} +x :i32 = 3; +while true { + print("hello"); + print(x); +}; + +y := fn(x: i32) -> i32 {x};