diff --git a/src/v1/mod.rs b/src/v1/mod.rs index 47057e3..69a0f3f 100644 --- a/src/v1/mod.rs +++ b/src/v1/mod.rs @@ -2,12 +2,27 @@ use std::io::{stdout, BufRead, BufReader}; mod parser; -use parser::{Module, Statement, TokenCursor}; +use parser::{Module, Node, NodeContainer, Statement, TokenCursor}; pub fn parse_file(file: &str) { - match Module::parse(&mut TokenCursor::from(file)) { + let node = Node::::parse(&mut TokenCursor::from(file)); + match node.inner { Err(err) => err.write_for(&mut stdout(), file).unwrap(), - Ok(module) => println!("{module:#?}"), + Ok(module) => { + println!("{module:#?}"); + print_errors(module.children(), file) + }, + }; +} + +pub fn print_errors(nodes: Vec>>, file: &str) { + for node in &nodes { + if let Err(err) = &node.inner { + err.write_for(&mut stdout(), file).unwrap(); + } + } + for node in nodes { + print_errors(node.children(), file) } } @@ -16,7 +31,7 @@ pub fn run_stdin() { let str = &line.expect("failed to read line"); let mut cursor = TokenCursor::from(&str[..]); let out = &mut stdout(); - match Statement::parse(&mut cursor) { + match Node::::parse(&mut cursor).inner { Ok(expr) => println!("{:?}", expr), Err(err) => err.write_for(out, str).unwrap(), } diff --git a/src/v1/parser/body.rs b/src/v1/parser/body.rs index 06d9265..c42e5c8 100644 --- a/src/v1/parser/body.rs +++ b/src/v1/parser/body.rs @@ -1,65 +1,81 @@ use std::fmt::{Debug, Write}; -use super::token::{Keyword, Symbol, Token}; +use super::{ + token::{Keyword, Symbol, Token}, Node, NodeContainer, Parsable +}; use crate::util::Padder; use super::{Expr, ParserError, TokenCursor}; +#[derive(Clone)] pub struct Body { - statements: Vec, + statements: Vec>, } +#[derive(Clone)] pub enum Statement { - Let(String, Expr), - Return(Expr), - Expr(Expr), + Let(String, Node), + Return(Node), + Expr(Node), } -impl Body { - pub fn parse(cursor: &mut TokenCursor) -> Result { +impl Parsable for Body { + fn parse(cursor: &mut TokenCursor) -> Result { let mut statements = Vec::new(); + let statement_end = &[Symbol::Semicolon, Symbol::CloseCurly]; cursor.expect_sym(Symbol::OpenCurly)?; + if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) { + cursor.next(); + return Ok(Self { statements }); + } loop { let next = cursor.expect_peek()?; if next.is_symbol(Symbol::CloseCurly) { cursor.next(); return Ok(Self { statements }); } - statements.push(Statement::parse(cursor)?); + statements.push(Node::parse(cursor)); + let next = cursor.expect_next()?; + match next.token { + Token::Symbol(Symbol::Semicolon) => continue, + Token::Symbol(Symbol::CloseCurly) => return Ok(Self { statements }), + _ => { + let start = next.span.start; + cursor + .seek(|t| t.is_symbol_and(|s| statement_end.contains(&s))) + .ok_or(ParserError::unexpected_end())?; + let end = cursor.prev_end(); + let next = cursor.expect_next()?; + let span = start.to(end); + statements.push(Node::err(ParserError { + msg: "Unexpected tokens".to_string(), + spans: vec![span], + }, span)); + if next.is_symbol(Symbol::CloseCurly) { + return Ok(Self { statements }); + } + } + } } } } -impl Statement { - pub fn parse(cursor: &mut TokenCursor) -> Result { +impl Parsable for Statement { + fn parse(cursor: &mut TokenCursor) -> Result { let next = cursor.expect_peek()?; Ok(match next.token { Token::Keyword(Keyword::Let) => { cursor.next(); let name = cursor.expect_ident()?; cursor.expect_sym(Symbol::Equals)?; - let expr = Expr::parse(cursor)?; - cursor.expect_sym(Symbol::Semicolon)?; + let expr = Node::parse(cursor); Self::Let(name, expr) } Token::Keyword(Keyword::Return) => { cursor.next(); - let expr = Expr::parse(cursor)?; - cursor.expect_sym(Symbol::Semicolon)?; - Self::Return(expr) - } - _ => { - let expr = Expr::parse(cursor)?; - let next = cursor.expect_peek()?; - if next.is_symbol(Symbol::Semicolon) { - cursor.next(); - Self::Expr(expr) - } else if next.is_symbol(Symbol::CloseCurly) { - Self::Return(expr) - } else { - return Err(ParserError::unexpected_token(next, "a ';' or '}'")); - } + Self::Return(Node::parse(cursor)) } + _ => Self::Expr(Node::parse(cursor)), }) } } @@ -104,3 +120,19 @@ impl Debug for Body { Ok(()) } } + +impl NodeContainer for Body { + fn children(&self) -> Vec>> { + self.statements.iter().map(|f| f.containerr()).collect() + } +} + +impl NodeContainer for Statement { + fn children(&self) -> Vec>> { + match self { + Statement::Let(_, e) => vec![e.containerr()], + Statement::Return(e) => vec![e.containerr()], + Statement::Expr(e) => vec![e.containerr()], + } + } +} diff --git a/src/v1/parser/cursor.rs b/src/v1/parser/cursor.rs index 2fe1ebc..b0008e8 100644 --- a/src/v1/parser/cursor.rs +++ b/src/v1/parser/cursor.rs @@ -1,19 +1,23 @@ -use std::ops::{Deref, DerefMut}; - use super::error::ParserError; use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance}; +use super::FilePos; pub struct TokenCursor<'a> { cursor: CharCursor<'a>, next: Option, + next_pos: FilePos, + prev_end: FilePos, } impl<'a> TokenCursor<'a> { pub fn next(&mut self) -> Option { + self.prev_end = self.cursor.prev_pos(); + self.next_pos = self.cursor.next_pos(); std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor)) } pub fn expect_next(&mut self) -> Result { - self.next().ok_or(ParserError::unexpected_end()) + self.peek().ok_or(ParserError::unexpected_end())?; + Ok(self.next().unwrap()) } pub fn expect_token(&mut self, t: Token) -> Result<(), ParserError> { let next = self.expect_next()?; @@ -26,6 +30,20 @@ impl<'a> TokenCursor<'a> { pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> { self.expect_token(Token::Symbol(symbol)) } + pub fn seek_sym(&mut self, symbol: Symbol) { + while self + .next() + .is_some_and(|n| n.token != Token::Symbol(symbol)) + {} + } + pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> { + loop { + if f(self.peek()?) { + return self.peek(); + } + self.next(); + } + } pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserError> { self.expect_token(Token::Keyword(kw)) } @@ -45,6 +63,12 @@ impl<'a> TokenCursor<'a> { pub fn chars(&mut self) -> &mut CharCursor<'a> { &mut self.cursor } + pub fn prev_end(&self) -> FilePos { + self.prev_end + } + pub fn next_pos(&self) -> FilePos { + self.next_pos + } } impl<'a> From<&'a str> for TokenCursor<'a> { @@ -56,6 +80,11 @@ impl<'a> From<&'a str> for TokenCursor<'a> { impl<'a> From> for TokenCursor<'a> { fn from(mut cursor: CharCursor<'a>) -> Self { let cur = TokenInstance::parse(&mut cursor); - Self { cursor, next: cur } + Self { + cursor, + next: cur, + next_pos: FilePos::start(), + prev_end: FilePos::start(), + } } } diff --git a/src/v1/parser/error.rs b/src/v1/parser/error.rs index a5709ac..3a6e44a 100644 --- a/src/v1/parser/error.rs +++ b/src/v1/parser/error.rs @@ -1,31 +1,35 @@ -use super::{token::{FileRegion, TokenInstance}, FilePos}; +use super::{ + token::{FileSpan, TokenInstance}, + FilePos, +}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ParserError { pub msg: String, - pub regions: Vec, + pub spans: Vec, +} + +pub struct ParserErrors { + pub errs: Vec, } impl ParserError { pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self { ParserError { msg, - regions: instances.iter().map(|i| i.region).collect(), + spans: instances.iter().map(|i| i.span).collect(), } } pub fn from_msg(msg: String) -> Self { Self { msg, - regions: Vec::new(), + spans: Vec::new(), } } pub fn at(pos: FilePos, msg: String) -> Self { Self { msg, - regions: vec![FileRegion { - start: pos, - end: pos, - }], + spans: vec![FileSpan::at(pos)], } } pub fn unexpected_end() -> Self { @@ -39,12 +43,17 @@ impl ParserError { ) } pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { - let after = if self.regions.is_empty() { "" } else { ":" }; + let after = if self.spans.is_empty() { "" } else { ":" }; writeln!(writer, "error: {}{}", self.msg, after)?; - for reg in &self.regions { - reg.write_for(writer, file)?; + for span in &self.spans { + span.write_for(writer, file)?; } Ok(()) } } +impl ParserErrors { + pub fn add(&mut self, err: ParserError) { + self.errs.push(err); + } +} diff --git a/src/v1/parser/expr.rs b/src/v1/parser/expr.rs index 65384fa..acaabb4 100644 --- a/src/v1/parser/expr.rs +++ b/src/v1/parser/expr.rs @@ -1,14 +1,15 @@ use std::fmt::{Debug, Write}; use super::token::{Symbol, Token}; -use super::{Body, Number, ParserError, TokenCursor, Val}; +use super::{Body, Node, NodeContainer, Parsable, ParserError, TokenCursor, Val}; +#[derive(Clone)] pub enum Expr { - Val(Val), + Val(Node), Ident(String), - BinaryOp(Operator, Box, Box), - Block(Body), - Call(Box, Vec), + BinaryOp(Operator, Node>, Node>), + Block(Node), + Call(Node>, Vec>), } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -22,64 +23,78 @@ pub enum Operator { Access, } -impl Expr { - pub fn parse(cursor: &mut TokenCursor) -> Result { +impl Parsable for Expr { + fn parse(cursor: &mut TokenCursor) -> Result { + let start = cursor.next_pos(); let Some(next) = cursor.peek() else { - return Ok(Expr::Val(Val::Unit)); + return Ok(Expr::Val(Node::new( + Val::Unit, + cursor.next_pos().char_span(), + ))); }; let mut e1 = if next.is_symbol(Symbol::OpenParen) { cursor.next(); - let expr = Self::parse(cursor)?; - cursor.expect_sym(Symbol::CloseParen)?; - expr + let expr = Node::parse(cursor); + if expr.is_ok() { + cursor.expect_sym(Symbol::CloseParen)?; + } else { + cursor.seek_sym(Symbol::CloseParen); + } + expr.take()? } else if next.is_symbol(Symbol::OpenCurly) { - let expr = Body::parse(cursor)?; - Expr::Block(expr) + Self::Block(Node::parse(cursor)) + } else if let Some(val) = Node::maybe_parse(cursor) { + Self::Val(val) } else { - Self::parse_unit(cursor)? + let next = cursor.peek().unwrap(); + match &next.token { + Token::Ident(name) => { + let name = name.to_string(); + cursor.next(); + Self::Ident(name) + } + _ => { + return Ok(Expr::Val(Node::new( + Val::Unit, + cursor.next_pos().char_span(), + ))) + } + } }; let Some(mut next) = cursor.peek() else { return Ok(e1); }; while next.is_symbol(Symbol::OpenParen) { cursor.next(); - let inner = Self::parse(cursor)?; + let inner = Node::parse(cursor); cursor.expect_sym(Symbol::CloseParen)?; - e1 = Self::Call(Box::new(e1), vec![inner]); + let end = cursor.prev_end(); + e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), vec![inner]); let Some(next2) = cursor.peek() else { return Ok(e1); }; next = next2 } - Ok(if let Some(op) = Operator::from_token(&next.token) { + let end = cursor.prev_end(); + Ok(if let Some(mut op) = Operator::from_token(&next.token) { cursor.next(); - let e2 = Self::parse(cursor)?; - if let Self::BinaryOp(op_next, e3, e4) = e2 { - if op.presedence() > op_next.presedence() { - Self::BinaryOp(op_next, Box::new(Self::BinaryOp(op, Box::new(e1), e3)), e4) - } else { - Self::BinaryOp(op, Box::new(e1), Box::new(Self::BinaryOp(op_next, e3, e4))) + let mut n1 = Node::new(Box::new(e1), start.to(end)); + let mut n2 = Node::::parse(cursor); + if let Ok(Self::BinaryOp(op2, n21, n22)) = &*n2 { + if op.presedence() > op2.presedence() { + n1 = Node::new( + Box::new(Self::BinaryOp(op, n1, n21.clone())), + start.to(n21.span.end), + ); + op = *op2; + n2 = n22.clone().unbx(); } - } else { - Self::BinaryOp(op, Box::new(e1), Box::new(e2)) } + Self::BinaryOp(op, n1, n2.bx()) } else { e1 }) } - fn parse_unit(cursor: &mut TokenCursor) -> Result { - if let Some(val) = Val::parse(cursor)? { - return Ok(Self::Val(val)); - } - let inst = cursor.expect_next()?; - match &inst.token { - Token::Ident(name) => Ok(Self::Ident(name.to_string())), - _ => Err(ParserError::unexpected_token( - &inst, - "an identifier or value", - )), - } - } } impl Operator { @@ -166,3 +181,18 @@ impl Debug for Expr { Ok(()) } } + +impl NodeContainer for Expr { + fn children(&self) -> Vec>> { + match self { + Expr::Val(_) => Vec::new(), + Expr::Ident(_) => Vec::new(), + Expr::BinaryOp(_, e1, e2) => vec![e1.container(), e2.container()], + Expr::Block(b) => vec![b.containerr()], + Expr::Call(e1, rest) => [e1.container()] + .into_iter() + .chain(rest.iter().map(|e| e.containerr())) + .collect(), + } + } +} diff --git a/src/v1/parser/mod.rs b/src/v1/parser/mod.rs index 76eda86..a9cd93a 100644 --- a/src/v1/parser/mod.rs +++ b/src/v1/parser/mod.rs @@ -6,34 +6,37 @@ mod error; mod expr; mod token; mod val; +mod node; pub use body::*; pub use cursor::*; pub use error::*; pub use expr::*; pub use val::*; +pub use node::*; use token::*; #[derive(Debug)] pub struct Module { - functions: Vec, + functions: Vec>, } +#[derive(Clone)] pub struct Function { pub name: String, - pub body: Body, + pub body: Node, } -impl Module { - pub fn parse(cursor: &mut TokenCursor) -> Result { +impl Parsable for Module { + fn parse(cursor: &mut TokenCursor) -> Result { let mut functions = Vec::new(); loop { let Some(next) = cursor.peek() else { return Ok(Self { functions }); }; if next.is_keyword(Keyword::Fn) { - functions.push(Function::parse(cursor)?); + functions.push(Node::parse(cursor)); } else { return Err(ParserError::unexpected_token(next, "fn")); } @@ -41,13 +44,13 @@ impl Module { } } -impl Function { - pub fn parse(cursor: &mut TokenCursor) -> Result { +impl Parsable for Function { + fn parse(cursor: &mut TokenCursor) -> Result { cursor.expect_kw(Keyword::Fn)?; let name = cursor.expect_ident()?; cursor.expect_sym(Symbol::OpenParen)?; cursor.expect_sym(Symbol::CloseParen)?; - let body = Body::parse(cursor)?; + let body = Node::parse(cursor); Ok(Self { name, body }) } } @@ -61,3 +64,15 @@ impl Debug for Function { Ok(()) } } + +impl NodeContainer for Module { + fn children(&self) -> Vec>> { + self.functions.iter().map(|f| f.containerr()).collect() + } +} + +impl NodeContainer for Function { + fn children(&self) -> Vec>> { + vec![self.body.containerr()] + } +} diff --git a/src/v1/parser/node.rs b/src/v1/parser/node.rs new file mode 100644 index 0000000..9009377 --- /dev/null +++ b/src/v1/parser/node.rs @@ -0,0 +1,132 @@ +use std::{ + fmt::Debug, + ops::{Deref, DerefMut}, +}; + +use super::{FileSpan, ParserError, TokenCursor}; + +#[derive(Clone)] +pub struct Node { + pub inner: Result, + pub span: FileSpan, +} + +pub trait Parsable: Sized { + fn parse(cursor: &mut TokenCursor) -> Result; +} + +pub trait MaybeParsable: Sized { + fn maybe_parse(cursor: &mut TokenCursor) -> Result, ParserError>; +} + +pub trait NodeContainer { + fn children(&self) -> Vec>>; +} + +impl NodeContainer for Node> { + fn children(&self) -> Vec>> { + match &self.inner { + Ok(v) => v.children(), + Err(_) => Vec::new(), + } + } +} + +impl Node { + pub fn parse(cursor: &mut TokenCursor) -> Self { + let start = cursor.next_pos(); + let inner = T::parse(cursor); + let end = cursor.prev_end(); + Self { + inner, + span: start.to(end), + } + } +} + +impl Node { + pub fn maybe_parse(cursor: &mut TokenCursor) -> Option { + let start = cursor.next_pos(); + let inner = match T::maybe_parse(cursor) { + Ok(v) => Ok(v?), + Err(e) => Err(e), + }; + let end = cursor.prev_end(); + Some(Self { + inner, + span: start.to(end), + }) + } +} + +impl Node { + pub fn new(inner: T, span: FileSpan) -> Self { + Self { + inner: Ok(inner), + span, + } + } + pub fn err(inner: ParserError, span: FileSpan) -> Self { + Self { + inner: Err(inner), + span, + } + } + pub fn take(self) -> Result { + self.inner + } + pub fn bx(self) -> Node> { + Node { + inner: self.inner.map(|v| Box::new(v)), + span: self.span, + } + } +} + +impl Node { + pub fn containerr(&self) -> Node> { + Node { + inner: self.clone().inner.map(|v| Box::new(v) as Box), + span: self.span, + } + } +} + +impl Node> { + pub fn unbx(self) -> Node { + Node { + inner: self.inner.map(|v| *v), + span: self.span, + } + } +} +impl Node> { + pub fn container(&self) -> Node> { + Node { + inner: self.clone().inner.map(|v| v as Box), + span: self.span, + } + } +} + +impl Deref for Node { + type Target = Result; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Node { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Debug for Node { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.inner { + Ok(v) => v.fmt(f), + Err(_) => f.write_str("{error}"), + } + } +} diff --git a/src/v1/parser/token/cursor.rs b/src/v1/parser/token/cursor.rs index 0ff09cb..45eb503 100644 --- a/src/v1/parser/token/cursor.rs +++ b/src/v1/parser/token/cursor.rs @@ -1,12 +1,11 @@ use std::{iter::Peekable, str::Chars}; -use crate::v1::parser::ParserError; - +use super::super::ParserError; use super::FilePos; pub struct CharCursor<'a> { chars: Peekable>, - pos: FilePos, + next_pos: FilePos, prev_pos: FilePos, } @@ -39,12 +38,12 @@ impl CharCursor<'_> { let Some(next) = self.chars.next() else { return; }; - self.prev_pos = self.pos; + self.prev_pos = self.next_pos; if next == '\n' { - self.pos.col = 0; - self.pos.line += 1; + self.next_pos.col = 0; + self.next_pos.line += 1; } else { - self.pos.col += 1; + self.next_pos.col += 1; } } pub fn advance_if(&mut self, c: char) -> bool { @@ -57,11 +56,10 @@ impl CharCursor<'_> { false } pub fn expect_next(&mut self) -> Result { - self.next() - .ok_or(ParserError::from_msg("Unexpected end of input".to_string())) + self.next().ok_or(ParserError::unexpected_end()) } - pub fn pos(&self) -> FilePos { - self.pos + pub fn next_pos(&self) -> FilePos { + self.next_pos } pub fn prev_pos(&self) -> FilePos { self.prev_pos @@ -72,7 +70,7 @@ impl<'a> From<&'a str> for CharCursor<'a> { fn from(value: &'a str) -> Self { Self { chars: value.chars().peekable(), - pos: FilePos::start(), + next_pos: FilePos::start(), prev_pos: FilePos::start(), } } diff --git a/src/v1/parser/token/file.rs b/src/v1/parser/token/file.rs index 762af9f..7bbcc97 100644 --- a/src/v1/parser/token/file.rs +++ b/src/v1/parser/token/file.rs @@ -5,7 +5,7 @@ pub struct FilePos { } #[derive(Debug, Clone, Copy)] -pub struct FileRegion { +pub struct FileSpan { pub start: FilePos, pub end: FilePos, } @@ -16,10 +16,25 @@ impl FilePos { } } +impl FilePos { + pub fn to(self, end: FilePos) -> FileSpan { + FileSpan { start: self, end } + } + pub fn char_span(self) -> FileSpan { + FileSpan::at(self) + } +} + const BEFORE: usize = 1; const AFTER: usize = 1; -impl FileRegion { +impl FileSpan { + pub fn at(pos: FilePos) -> Self { + Self { + start: pos, + end: pos, + } + } pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { let start = self.start.line.saturating_sub(BEFORE); let num_before = self.start.line - start; diff --git a/src/v1/parser/token/mod.rs b/src/v1/parser/token/mod.rs index 8f03556..6b489a4 100644 --- a/src/v1/parser/token/mod.rs +++ b/src/v1/parser/token/mod.rs @@ -3,6 +3,8 @@ mod file; mod keyword; mod symbol; +use std::ops::Deref; + pub use cursor::*; pub use file::*; pub use keyword::*; @@ -15,17 +17,17 @@ pub enum Token { Keyword(Keyword), } -#[derive(Debug)] +#[derive(Clone)] pub struct TokenInstance { pub token: Token, - pub region: FileRegion, + pub span: FileSpan, } impl TokenInstance { pub fn parse(cursor: &mut CharCursor) -> Option { cursor.skip_whitespace(); cursor.peek()?; - let start = cursor.pos(); + let start = cursor.next_pos(); if let Some(s) = Symbol::parse(cursor) { if s == Symbol::DoubleSlash { while cursor.next() != Some('\n') {} @@ -34,7 +36,7 @@ impl TokenInstance { let end = cursor.prev_pos(); return Some(Self { token: Token::Symbol(s), - region: FileRegion { start, end }, + span: FileSpan { start, end }, }); } let mut word = String::new(); @@ -53,7 +55,7 @@ impl TokenInstance { }; Some(Self { token, - region: FileRegion { start, end }, + span: FileSpan { start, end }, }) } } @@ -65,6 +67,12 @@ impl Token { _ => false, } } + pub fn is_symbol_and(&self, f: impl Fn(Symbol) -> bool) -> bool { + match self { + Token::Symbol(s) => f(*s), + _ => false, + } + } pub fn is_keyword(&self, kw: Keyword) -> bool { match self { Token::Keyword(k) => *k == kw, @@ -73,11 +81,10 @@ impl Token { } } -impl TokenInstance { - pub fn is_keyword(&self, kw: Keyword) -> bool { - self.token.is_keyword(kw) - } - pub fn is_symbol(&self, symbol: Symbol) -> bool { - self.token.is_symbol(symbol) +impl Deref for TokenInstance { + type Target = Token; + + fn deref(&self) -> &Self::Target { + &self.token } } diff --git a/src/v1/parser/val.rs b/src/v1/parser/val.rs index 3a4a2f6..1674478 100644 --- a/src/v1/parser/val.rs +++ b/src/v1/parser/val.rs @@ -1,7 +1,7 @@ -use super::{CharCursor, ParserError, Symbol, Token, TokenCursor}; +use super::{CharCursor, MaybeParsable, NodeContainer, ParserError, Symbol, Token, TokenCursor}; use std::fmt::Debug; -#[derive(PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub enum Val { String(String), Char(char), @@ -9,15 +9,15 @@ pub enum Val { Unit, } -#[derive(PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct Number { pub whole: String, pub decimal: Option, pub ty: Option, } -impl Val { - pub fn parse(cursor: &mut TokenCursor) -> Result, ParserError> { +impl MaybeParsable for Val { + fn maybe_parse(cursor: &mut TokenCursor) -> Result, ParserError> { let inst = cursor.expect_peek()?; let mut res = match &inst.token { Token::Symbol(Symbol::SingleQuote) => { @@ -108,3 +108,4 @@ impl Debug for Number { Ok(()) } } + diff --git a/src/v2/parser/body.rs b/src/v2/parser/body.rs index c01d05f..1e25afc 100644 --- a/src/v2/parser/body.rs +++ b/src/v2/parser/body.rs @@ -109,7 +109,7 @@ impl Debug for Body { let mut padder = Padder::new(f); for s in &self.statements { // they don't expose wrap_buf :grief: - write!(padder, "{s:?}\n")?; + writeln!(padder, "{s:?}")?; } write!(f, "}}")?; } else { diff --git a/test.lang b/test.lang index 43c4940..6cfc18a 100644 --- a/test.lang +++ b/test.lang @@ -3,7 +3,7 @@ fn main() { let y = 4 + 4 + 5; let z = 1 * 2 - 3 / test * 4; let r = 1-2.5 + 3; - let w = 1 * (2 - 3) / "test" - 7; + let w = 1 * (2 - 3) / "test" - 7 let a = test('3'); let c = '3' ; test(5);