diff --git a/src/main.rs b/src/main.rs index 7902060..0f6d2ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ fn main() { let mut output = CompilerOutput::new(); let nodes = Nodes::parse_root(&path, &mut output); if let Some((nodes, root)) = nodes { - println!("{}", root.dsp(&nodes)); + print!("{}", root.dsp(&nodes)); } output.write(&mut std::io::stdout()); } diff --git a/src/parser/cursor/lit.rs b/src/parser/cursor/lit.rs index fc424e8..ae16f79 100644 --- a/src/parser/cursor/lit.rs +++ b/src/parser/cursor/lit.rs @@ -5,6 +5,7 @@ pub enum Lit { Number(String), Bool(bool), String(String), + Unit, } impl From for Token { @@ -18,8 +19,8 @@ impl std::fmt::Display for Lit { match self { Lit::Number(n) => write!(f, "{n}"), Lit::Bool(b) => write!(f, "{b}"), - Lit::String(s) => write!(f, "{s}"), + Lit::String(s) => write!(f, "\"{s}\""), + Lit::Unit => write!(f, "()"), } } } - diff --git a/src/parser/cursor/mod.rs b/src/parser/cursor/mod.rs index 0161661..7b1da30 100644 --- a/src/parser/cursor/mod.rs +++ b/src/parser/cursor/mod.rs @@ -35,8 +35,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: &Token) -> bool { + if self.peek().is_some_and(|t| t == token) { self.next(); true } else { @@ -54,6 +54,7 @@ impl<'a> Cursor<'a> { 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 { diff --git a/src/parser/cursor/token.rs b/src/parser/cursor/token.rs index 29b126e..6c3b7bc 100644 --- a/src/parser/cursor/token.rs +++ b/src/parser/cursor/token.rs @@ -3,6 +3,8 @@ use std::{iter::Peekable, str::CharIndices}; def_tokens! { symbol { + Dot: ".", + Comma: ",", Equal: "=", Colon: ":", Semicolon: ";", @@ -23,9 +25,9 @@ def_tokens! { AsteriskEqual: "*=", SlashEqual: "/=", DoubleColon: "::", + Hash: "#", } keyword { - Let: "let", Fn: "fn", If: "if", Loop: "loop", @@ -80,12 +82,15 @@ impl Iterator for Tokens<'_> { }; } let inner = match c { + '.' => Token::Dot, + ',' => Token::Comma, '(' => Token::OpenParen, ')' => Token::CloseParen, '[' => Token::OpenSquare, ']' => Token::CloseSquare, '{' => Token::OpenCurly, '}' => Token::CloseCurly, + '#' => Token::Hash, '+' => then! { _ => Token::Plus, '=' => Token::PlusEqual, @@ -124,15 +129,13 @@ impl Iterator for Tokens<'_> { Lit::Number(s).into() } '"' => { - let mut s = c.to_string(); - while let Some((i, c)) = self.chars.peek() + let mut s = String::new(); + while let Some((i, c)) = self.chars.next() && !matches!(c, '"') { - s.push(*c); - span.end = *i; - self.chars.next(); + s.push(c); + span.end = i; } - self.chars.next(); Lit::String(s).into() } _ => { diff --git a/src/parser/node/id.rs b/src/parser/node/id.rs index e160fc8..560df4f 100644 --- a/src/parser/node/id.rs +++ b/src/parser/node/id.rs @@ -38,8 +38,7 @@ pub struct DisplayCtx<'a> { pub struct IdDisplay<'a, N> { id: Id, - nodes: &'a Nodes, - indent: usize, + ctx: DisplayCtx<'a>, } pub trait FmtNode: Node { @@ -48,13 +47,7 @@ pub trait FmtNode: Node { impl std::fmt::Display for IdDisplay<'_, N> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.nodes[self.id].fmt( - f, - DisplayCtx { - nodes: self.nodes, - indent: self.indent, - }, - ) + self.ctx.nodes[self.id].fmt(f, self.ctx) } } @@ -76,11 +69,7 @@ impl Id { 'a: 'b, { let ctx = ctx.into(); - IdDisplay { - id: *self, - nodes: ctx.nodes, - indent: ctx.indent, - } + IdDisplay { id: *self, ctx } } } @@ -92,3 +81,36 @@ impl<'a> From<&'a Nodes> for DisplayCtx<'a> { } } } + +pub struct VecDsp<'a, N> { + list: &'a Vec>, + ctx: DisplayCtx<'a>, +} + +impl std::fmt::Display for VecDsp<'_, N> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some((last, rest)) = self.list.split_last() { + for arg in rest { + write!(f, "{}, ", arg.dsp(self.ctx))?; + } + write!(f, "{}", last.dsp(self.ctx))?; + } + Ok(()) + } +} + +pub trait VecDspT { + fn dsp<'a, 'b>(&'a self, ctx: impl Into>) -> VecDsp<'b, N> + where + 'a: 'b; +} + +impl VecDspT for Vec> { + fn dsp<'a, 'b>(&'a self, ctx: impl Into>) -> VecDsp<'b, N> + where + 'a: 'b, + { + let ctx = ctx.into(); + VecDsp { list: self, ctx } + } +} diff --git a/src/parser/node/mod.rs b/src/parser/node/mod.rs index 729f631..78430cb 100644 --- a/src/parser/node/mod.rs +++ b/src/parser/node/mod.rs @@ -9,7 +9,7 @@ pub use id::*; pub use parse::*; impl Nodes { - pub fn parse_root(path: &str, output: &mut CompilerOutput) -> Option<(Self, Id)> { + pub fn parse_root(path: &str, output: &mut CompilerOutput) -> Option<(Self, Id)> { let root_code = match std::fs::read_to_string(path) { Ok(code) => code, Err(err) => { diff --git a/src/parser/node/parse.rs b/src/parser/node/parse.rs index 8e86db8..bfa5c69 100644 --- a/src/parser/node/parse.rs +++ b/src/parser/node/parse.rs @@ -2,7 +2,7 @@ use crate::{ io::{CompilerMsg, Span}, parser::{ Id, Ident, Node, Nodes, - cursor::{Cursor, Lit}, + cursor::{Cursor, Lit, Token}, }, }; @@ -10,16 +10,6 @@ pub trait Parsable: Sized + Node { fn parse(ctx: &mut ParseCtx) -> Result; } -pub trait ParsableWith: Sized + Node { - fn parse_with(ctx: &mut ParseCtx, input: Input) -> Result; -} - -impl ParsableWith<()> for P { - fn parse_with(ctx: &mut ParseCtx, _: ()) -> Result { - P::parse(ctx) - } -} - pub struct ParseCtx<'a> { start: usize, cursor: Cursor<'a>, @@ -36,16 +26,9 @@ impl<'a> ParseCtx<'a> { } pub fn parse(&mut self) -> Result, CompilerMsg> { - self.parse_with(()) - } - - pub fn parse_with, Input>( - &mut self, - input: Input, - ) -> Result, CompilerMsg> { let old_start = self.start; self.start = self.cursor.peek_start(); - let res = P::parse_with(self, input).map(|r| self.push(r)); + let res = P::parse(self).map(|r| self.push(r)); self.start = old_start; res } @@ -54,15 +37,18 @@ impl<'a> ParseCtx<'a> { let span = self.cursor.span; self.nodes.idents.add(Ident { inner: s }, span) } + pub fn lit(&mut self, lit: Lit) -> Id { let span = self.cursor.span; self.nodes.lits.add(lit, span) } + pub fn push_adv(&mut self, node: N) -> Id { let res = self.push(node); self.cursor.next(); res } + pub fn push(&mut self, node: N) -> Id { let end = self.cursor.cur_end(); N::vec_mut(&mut self.nodes).add( @@ -74,6 +60,20 @@ impl<'a> ParseCtx<'a> { }, ) } + + pub fn list(&mut self, sep: Token, end: Token) -> Result>, CompilerMsg> { + let mut list = Vec::new(); + if self.next_if(&end) { + return Ok(list); + } + list.push(self.parse()?); + while self.next_if(&sep) { + list.push(self.parse()?); + } + self.expect(end)?; + Ok(list) + } + pub fn finish(self) -> Nodes { self.nodes } diff --git a/src/parser/nodes/body.rs b/src/parser/nodes/body.rs new file mode 100644 index 0000000..d9998db --- /dev/null +++ b/src/parser/nodes/body.rs @@ -0,0 +1,52 @@ +use super::*; + +pub struct Body { + pub exprs: Vec>, + pub final_semicolon: bool, +} + +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, + }); + } + _ => (), + } + exprs.push(ctx.parse()?); + while ctx.next_if(&Token::Semicolon) { + final_semicolon = true; + if ctx.peek().is_none_or(|t| *t == Token::CloseCurly) { + break; + } + exprs.push(ctx.parse()?); + final_semicolon = false; + } + Ok(Self { + exprs, + final_semicolon, + }) + } +} + +impl FmtNode for Body { + fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { + // surely there's a better way to do this + if let Some((last, rest)) = self.exprs.split_last() { + for &i in rest { + writeln!(f, "{}{};", " ".repeat(ctx.indent), i.dsp(ctx))?; + } + if self.final_semicolon { + writeln!(f, "{}{};", " ".repeat(ctx.indent), last.dsp(ctx))?; + } else { + writeln!(f, "{}{}", " ".repeat(ctx.indent), last.dsp(ctx))?; + } + } + Ok(()) + } +} diff --git a/src/parser/nodes/expr.rs b/src/parser/nodes/expr.rs index e778d81..8ec0959 100644 --- a/src/parser/nodes/expr.rs +++ b/src/parser/nodes/expr.rs @@ -1,44 +1,159 @@ +use crate::parser::VecDspT; + pub use super::*; pub enum Expr { + Block(Id), + Group(Id), Ident(Id), Lit(Id), Negate(Id), - Assign(Id, Id), + Call { + target: Id, + args: Vec>, + }, + Assign { + target: Id, + val: Id, + }, + Define { + target: Id, + ty: Option>, + val: Id, + }, + If { + cond: Id, + body: Id, + }, + Loop { + body: Id, + }, + While { + cond: Id, + body: Id, + }, + Fn(Id), } impl Parsable for Expr { fn parse(ctx: &mut ParseCtx) -> Result { - let e1 = match ctx.expect_next()? { + let mut res = Self::parse_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)?; + Expr::Assign { target, val } + } + Token::Colon => { + let target = ctx.push_adv(res); + let mut ty = None; + if !ctx.next_if(&Token::Equal) { + ty = Some(ctx.parse()?); + ctx.expect(Token::Equal)?; + } + let val = Self::push_unit(ctx)?; + Expr::Define { target, ty, val } + } + Token::OpenParen => { + let target = ctx.push_adv(res); + let args = ctx.list(Token::Comma, Token::CloseParen)?; + Expr::Call { target, args } + } + _ => break, + } + } + Ok(res) + } +} + +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 { + Ok(match ctx.expect_next()? { Token::Dash => Self::Negate(ctx.parse()?), Token::Ident(s) => Self::Ident(ctx.ident(s)), Token::Lit(l) => Self::Lit(ctx.lit(l)), - other => return ctx.unexpected(&other, "an expression"), - }; - let Some(next) = ctx.peek() else { - return Ok(e1); - }; - Ok(match next { - Token::Equal => { - let e1 = ctx.push_adv(e1); - let e2: Id = ctx.parse()?; - Expr::Assign(e1, e2) + Token::Fn => Self::Fn(ctx.parse()?), + Token::If => { + let cond = ctx.parse()?; + let body = ctx.parse()?; + Self::If { cond, body } } - _ => e1, + Token::While => { + let cond = ctx.parse()?; + let body = ctx.parse()?; + Self::While { cond, body } + } + Token::Loop => { + let body = ctx.parse()?; + Self::Loop { body } + } + Token::OpenParen => { + if ctx.next_if(&Token::CloseParen) { + Self::Lit(ctx.push(Lit::Unit)) + } else { + let inner = ctx.parse()?; + ctx.expect(Token::CloseParen)?; + Self::Group(inner) + } + } + Token::OpenCurly => { + let body = ctx.parse()?; + ctx.expect(Token::CloseCurly)?; + Self::Block(body) + } + other => return ctx.unexpected(&other, "an expression"), }) } } impl FmtNode for Expr { - fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter, mut ctx: DisplayCtx) -> std::fmt::Result { match *self { - Expr::Ident(id) => id.fmt(f, ctx), - Expr::Lit(id) => id.fmt(f, ctx), - Expr::Negate(id) => { + Self::Ident(id) => id.fmt(f, ctx), + Self::Group(id) => write!(f, "({})", id.dsp(ctx)), + Self::Fn(id) => id.fmt(f, ctx), + Self::Lit(id) => id.fmt(f, ctx), + Self::Negate(id) => { write!(f, "-{}", id.dsp(ctx)) } - Expr::Assign(id1, id2) => { - write!(f, "{} = {}", id1.dsp(ctx), id2.dsp(ctx)) + Self::Call { target, ref args } => { + write!(f, "{}({})", target.dsp(ctx), args.dsp(ctx)) + } + Self::Assign { target, val } => { + write!(f, "{} = {}", target.dsp(ctx), val.dsp(ctx)) + } + Self::Define { target, ty, val } => { + target.fmt(f, ctx)?; + if let Some(ty) = ty { + write!(f, ": {} ", ty.dsp(ctx))?; + } else { + write!(f, " :")?; + } + write!(f, "= {}", val.dsp(ctx)) + } + Self::If { cond, body } => { + write!(f, "if {} {}", cond.dsp(ctx), body.dsp(ctx)) + } + Self::While { cond, body } => { + write!(f, "while {} {}", cond.dsp(ctx), body.dsp(ctx)) + } + Self::Loop { body } => { + write!(f, "loop {}", body.dsp(ctx)) + } + Self::Block(body) => { + write!(f, "{{")?; + if !ctx.nodes[body].exprs.is_empty() { + writeln!(f)?; + ctx.indent += 3; + body.fmt(f, ctx)?; + } + write!(f, "}}")?; + Ok(()) } } } @@ -46,10 +161,6 @@ impl FmtNode for Expr { impl FmtNode for Lit { fn fmt(&self, f: &mut std::fmt::Formatter, _: DisplayCtx) -> std::fmt::Result { - match self { - Lit::Number(v) => write!(f, "{v}"), - Lit::Bool(v) => write!(f, "{v}"), - Lit::String(v) => write!(f, "{v}"), - } + write!(f, "{self}") } } diff --git a/src/parser/nodes/func.rs b/src/parser/nodes/func.rs new file mode 100644 index 0000000..be307b5 --- /dev/null +++ b/src/parser/nodes/func.rs @@ -0,0 +1,29 @@ +use super::*; + +pub struct Func { + args: Vec>, + body: Id, +} + +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 }) + } +} + +impl FmtNode for Func { + fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { + write!(f, "(")?; + 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))?; + Ok(()) + } +} diff --git a/src/parser/nodes/item.rs b/src/parser/nodes/item.rs deleted file mode 100644 index 5c75366..0000000 --- a/src/parser/nodes/item.rs +++ /dev/null @@ -1,24 +0,0 @@ -use super::*; - -pub enum Item { - Module(Id), - Statement(Id), -} - -impl Parsable for Item { - fn parse(ctx: &mut ParseCtx) -> Result { - Ok(match ctx.expect_peek()? { - Token::Fn => Self::Module(ctx.parse()?), - _ => Self::Statement(ctx.parse()?), - }) - } -} - -impl FmtNode for Item { - fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { - match self { - Item::Module(id) => write!(f, "{}", id.dsp(ctx)), - Item::Statement(id) => write!(f, "{}", id.dsp(ctx)), - } - } -} diff --git a/src/parser/nodes/mod.rs b/src/parser/nodes/mod.rs index a19e1e9..7785978 100644 --- a/src/parser/nodes/mod.rs +++ b/src/parser/nodes/mod.rs @@ -1,14 +1,12 @@ +mod body; mod expr; +mod func; mod ident; -mod item; -mod module; -mod statement; mod ty; +pub use body::*; pub use expr::*; +pub use func::*; pub use ident::*; -pub use item::*; -pub use module::*; -pub use statement::*; pub use ty::*; use super::{DisplayCtx, FmtNode, Id, Lit, Node, NodeVec, Parsable, ParseCtx, Token}; @@ -17,11 +15,10 @@ use crate::io::CompilerMsg; def_nodes! { exprs: Expr, idents: Ident, - statements: Statement, - blocks: Module, + blocks: Body, lits: Lit, types: Type, - items: Item, + funcs: Func, } macro_rules! def_nodes { diff --git a/src/parser/nodes/module.rs b/src/parser/nodes/module.rs deleted file mode 100644 index f704a64..0000000 --- a/src/parser/nodes/module.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::*; - -pub struct Module { - items: Vec>, -} - -impl Parsable for Module { - fn parse(ctx: &mut ParseCtx) -> Result { - let mut items = Vec::new(); - if ctx.peek().is_none() { - return Ok(Self { items }); - } - items.push(ctx.parse()?); - while *ctx.expect_peek()? == Token::Semicolon { - ctx.next(); - items.push(ctx.parse()?); - } - Ok(Self { items }) - } -} - -impl FmtNode for Module { - fn fmt(&self, f: &mut std::fmt::Formatter, mut ctx: DisplayCtx) -> std::fmt::Result { - ctx.indent += 3; - write!(f, "{{")?; - if !self.items.is_empty() { - writeln!(f)?; - } - for &i in &self.items { - writeln!(f, "{}{};", " ".repeat(ctx.indent), i.dsp(ctx))?; - } - write!(f, "}}")?; - Ok(()) - } -} diff --git a/src/parser/nodes/statement.rs b/src/parser/nodes/statement.rs deleted file mode 100644 index 5bca4e6..0000000 --- a/src/parser/nodes/statement.rs +++ /dev/null @@ -1,60 +0,0 @@ -pub use super::*; - -pub enum Statement { - Let { - name: Id, - ty: Option>, - val: Id, - }, - If { - cond: Id, - body: Id, - }, - Expr(Id), -} - -impl Parsable for Statement { - fn parse(ctx: &mut ParseCtx) -> Result { - Ok(match ctx.expect_peek()? { - Token::Let => { - ctx.next(); - let name = ctx.parse()?; - let mut ty = None; - if ctx.next_if(Token::Colon) { - ty = Some(ctx.parse()?); - } - ctx.expect(Token::Equal)?; - Self::Let { - name, - ty, - val: ctx.parse()?, - } - } - Token::If => { - ctx.next(); - let cond = ctx.parse()?; - let body = ctx.parse()?; - Self::If { cond, body } - } - _ => Self::Expr(ctx.parse()?), - }) - } -} - -impl FmtNode for Statement { - fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result { - match *self { - Self::If { cond, body } => { - write!(f, "if {} {}", cond.dsp(ctx), body.dsp(ctx)) - } - Self::Let { name, ty, val } => { - write!(f, "let {}", name.dsp(ctx))?; - if let Some(ty) = ty { - write!(f, ": {}", ty.dsp(ctx))?; - } - write!(f, " = {}", val.dsp(ctx)) - } - Self::Expr(expr) => expr.fmt(f, ctx), - } - } -} diff --git a/test/main.lang b/test/main.lang index 6ef13e4..9352fac 100644 --- a/test/main.lang +++ b/test/main.lang @@ -1 +1,6 @@ -let x: i32 = arst -3 +x: i32 = 3; +y := fn(a, b, c) {}; +while Some(a) := b { + print("hello"); + f(x, y, z) +}