From e33420e91f2d0f81483e4891726cd15604c4a145 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Mon, 14 Oct 2024 00:54:27 -0400 Subject: [PATCH] added unary ops and control flow for parser --- data/err.lang | 3 + data/test.lang | 2 +- src/ir/mod.rs | 2 + src/main.rs | 1 + src/parser/v1/mod.rs | 30 ++-- src/parser/v1/node.rs | 59 +------- src/parser/v1/{ => nodes}/body.rs | 31 ++-- src/parser/v1/{ => nodes}/expr.rs | 81 ++++++----- src/parser/v1/{ => nodes}/func.rs | 10 +- src/parser/v1/nodes/mod.rs | 17 +++ src/parser/v1/{ => nodes}/module.rs | 14 +- src/parser/v1/nodes/op.rs | 96 +++++++++++++ src/parser/v1/{ => nodes}/statement.rs | 27 +--- src/parser/v1/{ => nodes}/val.rs | 0 src/parser/v1/op.rs | 71 ---------- src/parser/v1/parse.rs | 189 +++++++++++++++++++++++++ src/parser/v1/token/cursor.rs | 9 -- src/parser/v1/token/keyword.rs | 8 -- src/parser/v1/token/symbol.rs | 20 ++- 19 files changed, 433 insertions(+), 237 deletions(-) rename src/parser/v1/{ => nodes}/body.rs (73%) rename src/parser/v1/{ => nodes}/expr.rs (62%) rename src/parser/v1/{ => nodes}/func.rs (75%) create mode 100644 src/parser/v1/nodes/mod.rs rename src/parser/v1/{ => nodes}/module.rs (69%) create mode 100644 src/parser/v1/nodes/op.rs rename src/parser/v1/{ => nodes}/statement.rs (68%) rename src/parser/v1/{ => nodes}/val.rs (100%) delete mode 100644 src/parser/v1/op.rs create mode 100644 src/parser/v1/parse.rs diff --git a/data/err.lang b/data/err.lang index 426e136..a68d066 100644 --- a/data/err.lang +++ b/data/err.lang @@ -29,3 +29,6 @@ fn test() { fn test2() { let a anerit; } + +fn test3() { + let x = 3 diff --git a/data/test.lang b/data/test.lang index 973a6a3..1cabfb2 100644 --- a/data/test.lang +++ b/data/test.lang @@ -1,4 +1,4 @@ fn main() { - let x = 3; + let x = &"Hello World!"; print(x); } diff --git a/src/ir/mod.rs b/src/ir/mod.rs index e69de29..06d5b0e 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -0,0 +1,2 @@ +pub enum IRInstruction { +} diff --git a/src/main.rs b/src/main.rs index 17da4cb..01cfa51 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![feature(box_patterns)] +#![feature(try_trait_v2)] mod util; mod compiler; diff --git a/src/parser/v1/mod.rs b/src/parser/v1/mod.rs index b3d9ca7..376ba9c 100644 --- a/src/parser/v1/mod.rs +++ b/src/parser/v1/mod.rs @@ -1,33 +1,25 @@ use std::io::{stdout, BufRead, BufReader}; -mod body; mod cursor; mod error; -mod expr; -mod module; mod node; -mod op; +mod nodes; +mod parse; mod token; -mod val; -mod statement; -mod func; -pub use body::*; pub use cursor::*; pub use error::*; -pub use expr::*; -pub use module::*; pub use node::*; -pub use op::*; +pub use nodes::*; +pub use parse::*; use token::*; -pub use val::*; -pub use statement::*; pub fn parse_file(file: &str) { let mut errors = ParserErrors::new(); - let node = Module::parse_node(&mut TokenCursor::from(file), &mut errors); + let res = Module::parse_node(&mut TokenCursor::from(file), &mut errors); + println!("{:?}", res.node); if errors.errs.is_empty() { - let module = node.resolve().expect("what"); + let module = res.node.resolve().expect("what"); } let out = &mut stdout(); for err in errors.errs { @@ -40,8 +32,12 @@ pub fn run_stdin() { let mut errors = ParserErrors::new(); let str = &line.expect("failed to read line"); let mut cursor = TokenCursor::from(&str[..]); - if let Ok(expr) = Statement::parse_node(&mut cursor, &mut errors).as_ref() { - println!("{:?}", expr); + if let Ok(expr) = Statement::parse_node(&mut cursor, &mut errors).node.as_ref() { + if cursor.next().is_none() { + println!("{:?}", expr); + } else { + println!("uhhhh ehehe"); + } } let out = &mut stdout(); for err in errors.errs { diff --git a/src/parser/v1/node.rs b/src/parser/v1/node.rs index 316fa05..d879373 100644 --- a/src/parser/v1/node.rs +++ b/src/parser/v1/node.rs @@ -3,7 +3,7 @@ use std::{ ops::{Deref, DerefMut}, }; -use super::{FileSpan, ParserError, ParserErrors, TokenCursor}; +use super::FileSpan; pub trait MaybeResolved { type Inner; @@ -24,63 +24,8 @@ pub struct Node { pub span: FileSpan, } -pub trait Parsable: Sized { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result; -} - -pub trait MaybeParsable: Sized { - fn maybe_parse( - cursor: &mut TokenCursor, - errors: &mut ParserErrors, - ) -> Result, ParserError>; -} - -impl Node { - pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Self { - let start = cursor.next_pos(); - let inner = T::parse(cursor, errors).map_err(|e| errors.add(e)); - let end = cursor.prev_end(); - Self { - inner, - span: start.to(end), - } - } -} - -impl Node { - pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Option { - let start = cursor.next_pos(); - let inner = match T::maybe_parse(cursor, errors) { - Ok(v) => Ok(v?), - Err(e) => { - errors.add(e); - Err(()) - } - }; - let end = cursor.prev_end(); - Some(Self { - inner, - span: start.to(end), - }) - } -} - -pub trait NodeParsable { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Node - where - Self: Sized; -} -impl NodeParsable for T { - fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Node - where - Self: Sized, - { - Node::::parse(cursor, errors) - } -} - impl Node { - pub fn new_unres(inner: T, span: FileSpan) -> Self { + pub fn new(inner: T, span: FileSpan) -> Self { Self { inner: Ok(inner), span, diff --git a/src/parser/v1/body.rs b/src/parser/v1/nodes/body.rs similarity index 73% rename from src/parser/v1/body.rs rename to src/parser/v1/nodes/body.rs index a7ad8a4..8472a2a 100644 --- a/src/parser/v1/body.rs +++ b/src/parser/v1/nodes/body.rs @@ -1,8 +1,8 @@ use std::fmt::{Debug, Write}; use super::{ - token::Symbol, MaybeResolved, Node, NodeParsable, Parsable, ParserError, ParserErrors, - Resolvable, Resolved, Statement, TokenCursor, Unresolved, + token::Symbol, MaybeResolved, Node, NodeParsable, Parsable, ParseResult, ParserError, + ParserErrors, Resolvable, Resolved, Statement, TokenCursor, Unresolved, }; use crate::util::Padder; @@ -11,20 +11,25 @@ pub struct Body { } impl Parsable for Body { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { 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 }); + return ParseResult::Ok(Self { statements }); } let mut expect_semi = false; + let mut recover = false; loop { - let next = cursor.expect_peek()?; + let Some(next) = cursor.peek() else { + recover = true; + errors.add(ParserError::unexpected_end()); + break; + }; if next.is_symbol(Symbol::CloseCurly) { cursor.next(); - return Ok(Self { statements }); + break; } if next.is_symbol(Symbol::Semicolon) { cursor.next(); @@ -36,15 +41,19 @@ impl Parsable for Body { spans: vec![cursor.next_pos().char_span()], }); } - let statement = Statement::parse_node(cursor, errors); + let res = Statement::parse_node(cursor, errors); + statements.push(res.node); expect_semi = true; - if statement.is_err() || statement.as_ref().is_ok_and(|s| s.ended_with_error()) { - let res = cursor + if res.recover + && cursor .seek(|t| t.is_symbol_and(|s| statement_end.contains(&s))) - .ok_or(ParserError::unexpected_end())?; + .is_none() + { + recover = true; + break; } - statements.push(statement); } + ParseResult::from_recover(Self { statements }, recover) } } diff --git a/src/parser/v1/expr.rs b/src/parser/v1/nodes/expr.rs similarity index 62% rename from src/parser/v1/expr.rs rename to src/parser/v1/nodes/expr.rs index 3efa1c7..b3ec73f 100644 --- a/src/parser/v1/expr.rs +++ b/src/parser/v1/nodes/expr.rs @@ -2,8 +2,8 @@ use std::fmt::{Debug, Write}; use super::token::{Symbol, Token}; use super::{ - Body, Literal, MaybeResolved, Node, Operator, Parsable, ParserError, ParserErrors, Resolvable, - Resolved, TokenCursor, Unresolved, + BinaryOperator, Body, Literal, MaybeResolved, Node, NodeParsable, Parsable, ParseResult, + ParserError, ParserErrors, Resolvable, Resolved, TokenCursor, UnaryOperator, Unresolved, }; type BoxNode = Node>, R>; @@ -11,46 +11,45 @@ type BoxNode = Node>, R>; pub enum Expr { Lit(Node), Ident(String), - BinaryOp(Operator, BoxNode, BoxNode), + BinaryOp(BinaryOperator, BoxNode, BoxNode), + UnaryOp(UnaryOperator, BoxNode), Block(Node, R>), Call(BoxNode, Vec, R>>), Group(BoxNode), } -impl Expr { - pub fn ended_with_error(&self) -> bool { - match self { - Expr::Lit(_) => false, - Expr::Ident(_) => false, - Expr::BinaryOp(_, _, e) => e.is_err() || e.as_ref().is_ok_and(|e| e.ended_with_error()), - Expr::Block(b) => b.is_err(), - Expr::Call(_, _) => false, - Expr::Group(_) => false, - } - } -} - impl Parsable for Expr { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { let start = cursor.next_pos(); let next = cursor.expect_peek()?; let mut e1 = if next.is_symbol(Symbol::OpenParen) { cursor.next(); if cursor.expect_peek()?.is_symbol(Symbol::CloseParen) { cursor.next(); - return Ok(Expr::Lit(Node::new_unres( + return ParseResult::Ok(Expr::Lit(Node::new( Literal::Unit, cursor.next_pos().char_span(), ))); } - let expr = Node::parse(cursor, errors).bx(); - if expr.is_err() { + let res = Node::parse(cursor, errors); + if res.recover { cursor.seek_sym(Symbol::CloseParen); } cursor.expect_sym(Symbol::CloseParen)?; - Self::Group(expr) + Self::Group(res.node.bx()) } else if next.is_symbol(Symbol::OpenCurly) { - Self::Block(Node::parse(cursor, errors)) + Self::Block(Body::parse_node(cursor, errors)?) + } else if let Some(op) = UnaryOperator::from_token(next) { + cursor.next(); + return Node::parse(cursor, errors).map(|n| { + let n = n.bx(); + if let Ok(box Self::BinaryOp(op2, n1, n2)) = n.inner { + let span = start.to(n1.span.end); + Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2) + } else { + Self::UnaryOp(op, n) + } + }); } else if let Some(val) = Node::maybe_parse(cursor, errors) { Self::Lit(val) } else { @@ -62,36 +61,47 @@ impl Parsable for Expr { Self::Ident(name) } _ => { - return Err(ParserError::unexpected_token(next, "an expression")); + return ParseResult::Err(ParserError::unexpected_token(next, "an expression")); } } }; let Some(mut next) = cursor.peek() else { - return Ok(e1); + return ParseResult::Ok(e1); }; while next.is_symbol(Symbol::OpenParen) { cursor.next(); - let inner = Node::parse(cursor, errors); + let mut args = Vec::new(); + while !cursor.expect_peek()?.is_symbol(Symbol::CloseParen) { + let res = Node::, Unresolved>::parse(cursor, errors); + args.push(res.node); + if res.recover { + cursor.seek_sym(Symbol::CloseParen); + break; + } + } cursor.expect_sym(Symbol::CloseParen)?; let end = cursor.prev_end(); - e1 = Self::Call(Node::new_unres(Box::new(e1), start.to(end)), vec![inner]); + e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args); let Some(next2) = cursor.peek() else { - return Ok(e1); + return ParseResult::Ok(e1); }; next = next2 } let end = cursor.prev_end(); - Ok(if let Some(mut op) = Operator::from_token(&next.token) { + let mut recover = false; + let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) { cursor.next(); - let mut n1 = Node::new_unres(e1, start.to(end)).bx(); - let mut n2 = Node::parse(cursor, errors).bx(); + let mut n1 = Node::new(e1, start.to(end)).bx(); + let res = Node::parse(cursor, errors); + let mut n2 = res.node.bx(); + recover = res.recover; if let Ok(box Self::BinaryOp(op2, _, _)) = n2.as_ref() { if op.presedence() > op2.presedence() { let Ok(box Self::BinaryOp(op2, n21, n22)) = n2.inner else { unreachable!(); }; let end = n21.span.end; - n1 = Node::new_unres(Self::BinaryOp(op, n1, n21), start.to(end)).bx(); + n1 = Node::new(Self::BinaryOp(op, n1, n21), start.to(end)).bx(); op = op2; n2 = n22; } @@ -99,7 +109,8 @@ impl Parsable for Expr { Self::BinaryOp(op, n1, n2) } else { e1 - }) + }; + ParseResult::from_recover(res, recover) } } @@ -109,6 +120,7 @@ impl Resolvable> for Expr { Expr::Lit(l) => Expr::Lit(l.resolve()?), Expr::Ident(n) => Expr::Ident(n), Expr::BinaryOp(o, e1, e2) => Expr::BinaryOp(o, e1.resolve()?, e2.resolve()?), + Expr::UnaryOp(o, e) => Expr::UnaryOp(o, e.resolve()?), Expr::Block(b) => Expr::Block(b.resolve()?), Expr::Call(f, args) => Expr::Call( f.resolve()?, @@ -148,6 +160,11 @@ impl Debug for Expr { } f.write_char(')')?; } + Expr::UnaryOp(op, e) => { + write!(f, "(")?; + write!(f, "{}", op.str())?; + write!(f, "{:?})", *e)?; + } Expr::Group(inner) => inner.fmt(f)?, } Ok(()) diff --git a/src/parser/v1/func.rs b/src/parser/v1/nodes/func.rs similarity index 75% rename from src/parser/v1/func.rs rename to src/parser/v1/nodes/func.rs index c2ff857..cc54cf0 100644 --- a/src/parser/v1/func.rs +++ b/src/parser/v1/nodes/func.rs @@ -1,5 +1,6 @@ use super::{ - Body, Keyword, MaybeResolved, Node, Parsable, ParserError, ParserErrors, Resolvable, Resolved, Symbol, TokenCursor, Unresolved + Body, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, + Symbol, TokenCursor, Unresolved, }; use std::fmt::Debug; @@ -9,13 +10,12 @@ pub struct Function { } impl Parsable for Function { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { cursor.expect_kw(Keyword::Fn)?; let name = cursor.expect_ident()?; cursor.expect_sym(Symbol::OpenParen)?; cursor.expect_sym(Symbol::CloseParen)?; - let body = Node::parse(cursor, errors); - Ok(Self { name, body }) + Node::parse(cursor, errors).map(|body| Self {name, body}) } } @@ -33,7 +33,7 @@ impl Resolvable> for Function { fn resolve(self) -> Result, ()> { Ok(Function { name: self.name, - body: self.body.resolve()? + body: self.body.resolve()?, }) } } diff --git a/src/parser/v1/nodes/mod.rs b/src/parser/v1/nodes/mod.rs new file mode 100644 index 0000000..45286e8 --- /dev/null +++ b/src/parser/v1/nodes/mod.rs @@ -0,0 +1,17 @@ +mod body; +mod expr; +mod func; +mod module; +mod op; +mod statement; +mod val; + +pub use body::*; +pub use expr::*; +pub use func::*; +pub use module::*; +pub use op::*; +pub use statement::*; +pub use val::*; + +use super::*; diff --git a/src/parser/v1/module.rs b/src/parser/v1/nodes/module.rs similarity index 69% rename from src/parser/v1/module.rs rename to src/parser/v1/nodes/module.rs index 3c48968..fe8f469 100644 --- a/src/parser/v1/module.rs +++ b/src/parser/v1/nodes/module.rs @@ -1,6 +1,6 @@ use super::{ - func::Function, Keyword, MaybeResolved, Node, Parsable, ParserError, ParserErrors, Resolvable, - Resolved, TokenCursor, Unresolved, + Function, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserError, ParserErrors, + Resolvable, Resolved, TokenCursor, Unresolved, }; use std::fmt::Debug; @@ -9,14 +9,18 @@ pub struct Module { } impl Parsable for Module { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { let mut functions = Vec::new(); loop { let Some(next) = cursor.peek() else { - return Ok(Self { functions }); + return ParseResult::Ok(Self { functions }); }; if next.is_keyword(Keyword::Fn) { - functions.push(Node::parse(cursor, errors)); + let res = Node::parse(cursor, errors); + functions.push(res.node); + if res.recover { + return ParseResult::Recover(Self { functions }); + } } else { errors.add(ParserError::unexpected_token(next, "fn")); cursor.next(); diff --git a/src/parser/v1/nodes/op.rs b/src/parser/v1/nodes/op.rs new file mode 100644 index 0000000..e066530 --- /dev/null +++ b/src/parser/v1/nodes/op.rs @@ -0,0 +1,96 @@ +use super::{Symbol, Token}; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum BinaryOperator { + Add, + Sub, + Mul, + Div, + LessThan, + GreaterThan, + Access, + Assign, +} + +impl BinaryOperator { + pub fn presedence(&self) -> u32 { + match self { + Self::Assign => 0, + Self::LessThan => 1, + Self::GreaterThan => 1, + Self::Add => 2, + Self::Sub => 3, + Self::Mul => 4, + Self::Div => 5, + Self::Access => 6, + } + } + pub fn str(&self) -> &str { + match self { + Self::Add => "+", + Self::Sub => "-", + Self::Mul => "*", + Self::Div => "/", + Self::LessThan => "<", + Self::GreaterThan => ">", + Self::Access => ".", + Self::Assign => "=", + } + } + pub fn from_token(token: &Token) -> Option { + let Token::Symbol(symbol) = token else { + return None; + }; + Some(match symbol { + Symbol::OpenAngle => Self::LessThan, + Symbol::CloseAngle => Self::GreaterThan, + Symbol::Plus => Self::Add, + Symbol::Minus => Self::Sub, + Symbol::Asterisk => Self::Mul, + Symbol::Slash => Self::Div, + Symbol::Dot => Self::Access, + Symbol::Equals => Self::Assign, + _ => { + return None; + } + }) + } + pub fn pad(&self) -> bool { + match self { + Self::Add => true, + Self::Sub => true, + Self::Mul => true, + Self::Div => true, + Self::LessThan => true, + Self::GreaterThan => true, + Self::Access => false, + Self::Assign => true, + } + } +} + +pub enum UnaryOperator { + Not, + Ref, +} + +impl UnaryOperator { + pub fn str(&self) -> &str { + match self { + Self::Not => "!", + Self::Ref => "&", + } + } + pub fn from_token(token: &Token) -> Option { + let Token::Symbol(symbol) = token else { + return None; + }; + Some(match symbol { + Symbol::Ampersand => Self::Ref, + Symbol::Bang => Self::Not, + _ => { + return None; + } + }) + } +} diff --git a/src/parser/v1/statement.rs b/src/parser/v1/nodes/statement.rs similarity index 68% rename from src/parser/v1/statement.rs rename to src/parser/v1/nodes/statement.rs index 0b1fa83..c94adc6 100644 --- a/src/parser/v1/statement.rs +++ b/src/parser/v1/nodes/statement.rs @@ -1,7 +1,6 @@ use std::fmt::{Debug, Write}; use super::{ - Expr, Keyword, MaybeResolved, Node, Parsable, ParserError, ParserErrors, Resolvable, Resolved, - Symbol, Token, TokenCursor, Unresolved, + Expr, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, Symbol, Token, TokenCursor, Unresolved }; pub enum Statement { @@ -10,34 +9,22 @@ pub enum Statement { Expr(Node, R>), } -impl Statement { - pub fn ended_with_error(&self) -> bool { - let expr = match self { - Statement::Let(_, e) => e, - Statement::Return(e) => e, - Statement::Expr(e) => e, - }; - expr.is_err() || expr.as_ref().is_ok_and(|e| e.ended_with_error()) - } -} - impl Parsable for Statement { - fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Result { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult { let next = cursor.expect_peek()?; - Ok(match next.token { + match next.token { Token::Keyword(Keyword::Let) => { cursor.next(); let name = cursor.expect_ident()?; cursor.expect_sym(Symbol::Equals)?; - let expr = Node::parse(cursor, errors); - Self::Let(name, expr) + Node::parse(cursor, errors).map(|expr| Self::Let(name, expr)) } Token::Keyword(Keyword::Return) => { cursor.next(); - Self::Return(Node::parse(cursor, errors)) + Node::parse(cursor, errors).map(Self::Return) } - _ => Self::Expr(Node::parse(cursor, errors)), - }) + _ => Node::parse(cursor, errors).map(Self::Expr), + } } } diff --git a/src/parser/v1/val.rs b/src/parser/v1/nodes/val.rs similarity index 100% rename from src/parser/v1/val.rs rename to src/parser/v1/nodes/val.rs diff --git a/src/parser/v1/op.rs b/src/parser/v1/op.rs deleted file mode 100644 index 5dada7e..0000000 --- a/src/parser/v1/op.rs +++ /dev/null @@ -1,71 +0,0 @@ -use super::{Symbol, Token}; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Operator { - Add, - Sub, - Mul, - Div, - LessThan, - GreaterThan, - Access, - Assign, -} - -impl Operator { - pub fn presedence(&self) -> u32 { - match self { - Operator::Assign => 0, - Operator::LessThan => 1, - Operator::GreaterThan => 1, - Operator::Add => 2, - Operator::Sub => 3, - Operator::Mul => 4, - Operator::Div => 5, - Operator::Access => 6, - } - } - pub fn str(&self) -> &str { - match self { - Self::Add => "+", - Self::Sub => "-", - Self::Mul => "*", - Self::Div => "/", - Self::LessThan => "<", - Self::GreaterThan => ">", - Self::Access => ".", - Self::Assign => "=", - } - } - pub fn from_token(token: &Token) -> Option { - let Token::Symbol(symbol) = token else { - return None; - }; - Some(match symbol { - Symbol::OpenAngle => Operator::LessThan, - Symbol::CloseAngle => Operator::GreaterThan, - Symbol::Plus => Operator::Add, - Symbol::Minus => Operator::Sub, - Symbol::Asterisk => Operator::Mul, - Symbol::Slash => Operator::Div, - Symbol::Dot => Operator::Access, - Symbol::Equals => Operator::Assign, - _ => { - return None; - } - }) - } - pub fn pad(&self) -> bool { - match self { - Self::Add => true, - Self::Sub => true, - Self::Mul => true, - Self::Div => true, - Self::LessThan => true, - Self::GreaterThan => true, - Self::Access => false, - Self::Assign => true, - } - } -} - diff --git a/src/parser/v1/parse.rs b/src/parser/v1/parse.rs new file mode 100644 index 0000000..45abd35 --- /dev/null +++ b/src/parser/v1/parse.rs @@ -0,0 +1,189 @@ +use std::{ + convert::Infallible, + ops::{ControlFlow, FromResidual, Try}, +}; + +use super::{Node, ParserError, ParserErrors, TokenCursor, Unresolved}; + +pub enum ParseResult { + Ok(T), + Recover(T), + Err(ParserError), + SubErr, +} + +impl ParseResult { + pub fn from_recover(data: T, recover: bool) -> Self { + if recover { + Self::Recover(data) + } else { + Self::Ok(data) + } + } +} + +impl Try for ParseResult { + type Output = Result; + type Residual = Option; + fn from_output(output: Self::Output) -> Self { + match output { + Ok(v) => Self::Ok(v), + Err(v) => Self::Recover(v), + } + } + fn branch(self) -> ControlFlow { + match self { + ParseResult::Ok(v) => ControlFlow::Continue(Ok(v)), + ParseResult::Recover(v) => ControlFlow::Continue(Err(v)), + ParseResult::Err(e) => ControlFlow::Break(Some(e)), + ParseResult::SubErr => ControlFlow::Break(None), + } + } +} + +impl FromResidual for ParseResult { + fn from_residual(residual: ::Residual) -> Self { + match residual { + Some(err) => Self::Err(err), + None => Self::SubErr, + } + } +} + +impl FromResidual> for ParseResult { + fn from_residual(residual: Result) -> Self { + match residual { + Err(e) => Self::Err(e), + } + } +} + +impl FromResidual> for ParseResult { + fn from_residual(residual: ParseResult) -> Self { + match residual { + ParseResult::Err(e) => Self::Err(e), + ParseResult::SubErr => Self::SubErr, + _ => unreachable!() + } + } +} + +impl ParseResult { + pub fn map U>(self, op: F) -> ParseResult { + match self { + Self::Ok(v) => ParseResult::Ok(op(v)), + Self::Recover(v) => ParseResult::Recover(op(v)), + Self::Err(e) => ParseResult::Err(e), + Self::SubErr => ParseResult::SubErr, + } + } +} + +pub struct NodeParseResult { + pub node: Node, + pub recover: bool, +} + +impl NodeParseResult { + pub fn map) -> U, U>(self, op: F) -> ParseResult { + let res = op(self.node); + if self.recover { + ParseResult::Recover(res) + } else { + ParseResult::Ok(res) + } + } +} + +impl Try for NodeParseResult { + type Output = Node; + type Residual = ParseResult; + + fn from_output(output: Self::Output) -> Self { + Self { + node: output, + recover: false, + } + } + + fn branch(self) -> ControlFlow { + if self.recover { + ControlFlow::Break(ParseResult::SubErr) + } else { + ControlFlow::Continue(self.node) + } + } +} + +impl FromResidual for NodeParseResult { + fn from_residual(residual: ::Residual) -> Self { + // ??? + unreachable!() + } +} + +pub trait Parsable: Sized { + fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult; +} + +pub trait MaybeParsable: Sized { + fn maybe_parse( + cursor: &mut TokenCursor, + errors: &mut ParserErrors, + ) -> Result, ParserError>; +} + +impl Node { + pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult { + let start = cursor.next_pos(); + let (inner, recover) = match T::parse(cursor, errors) { + ParseResult::Ok(v) => (Ok(v), false), + ParseResult::Recover(v) => (Ok(v), true), + ParseResult::Err(e) => { + errors.add(e); + (Err(()), true) + } + ParseResult::SubErr => (Err(()), true), + }; + let end = cursor.prev_end(); + NodeParseResult { + node: Self { + inner, + span: start.to(end), + }, + recover, + } + } +} + +impl Node { + pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Option { + let start = cursor.next_pos(); + let inner = match T::maybe_parse(cursor, errors) { + Ok(v) => Ok(v?), + Err(e) => { + errors.add(e); + Err(()) + } + }; + let end = cursor.prev_end(); + Some(Self { + inner, + span: start.to(end), + }) + } +} + +pub trait NodeParsable { + fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult + where + Self: Sized; +} +impl NodeParsable for T { + fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult + where + Self: Sized, + { + Node::::parse(cursor, errors) + } +} diff --git a/src/parser/v1/token/cursor.rs b/src/parser/v1/token/cursor.rs index 45eb503..02796f6 100644 --- a/src/parser/v1/token/cursor.rs +++ b/src/parser/v1/token/cursor.rs @@ -46,15 +46,6 @@ impl CharCursor<'_> { self.next_pos.col += 1; } } - pub fn advance_if(&mut self, c: char) -> bool { - if let Some(c2) = self.peek() { - if c2 == c { - self.advance(); - return true; - } - } - false - } pub fn expect_next(&mut self) -> Result { self.next().ok_or(ParserError::unexpected_end()) } diff --git a/src/parser/v1/token/keyword.rs b/src/parser/v1/token/keyword.rs index ef49f21..f22782c 100644 --- a/src/parser/v1/token/keyword.rs +++ b/src/parser/v1/token/keyword.rs @@ -16,12 +16,4 @@ impl Keyword { _ => return None, }) } - pub const fn str(&self) -> &str { - match self { - Keyword::Fn => "fn", - Keyword::Let => "let", - Keyword::If => "if", - Keyword::Return => "return", - } - } } diff --git a/src/parser/v1/token/symbol.rs b/src/parser/v1/token/symbol.rs index 5db8b14..043bedc 100644 --- a/src/parser/v1/token/symbol.rs +++ b/src/parser/v1/token/symbol.rs @@ -28,6 +28,10 @@ pub enum Symbol { SingleQuote, DoubleQuote, Bang, + Ampersand, + DoubleAmpersand, + Pipe, + DoublePipe, } impl Symbol { @@ -59,6 +63,8 @@ impl Symbol { '\'' => Self::SingleQuote, '"' => Self::DoubleQuote, '!' => Self::Bang, + '&' => Self::Ampersand, + '|' => Self::Pipe, _ => return None, }) } @@ -79,10 +85,18 @@ impl Symbol { '=' => Self::DoubleEquals, '>' => Self::DoubleArrow, _ => return, - } + }, Self::Slash => match next { '/' => Self::DoubleSlash, _ => return, + }, + Self::Ampersand => match next { + '&' => Self::DoubleAmpersand, + _ => return, + } + Self::Pipe => match next { + '&' => Self::DoublePipe, + _ => return, } _ => return, }; @@ -114,6 +128,10 @@ impl Symbol { Self::SingleQuote => "'", Self::DoubleQuote => "\"", Self::Bang => "!", + Self::Ampersand => "&", + Self::DoubleAmpersand => "&&", + Self::Pipe => "|", + Self::DoublePipe => "||", } } }