This commit is contained in:
2024-10-18 16:52:12 -04:00
parent b15a40c4d9
commit 14a4fb1ff9
22 changed files with 1672 additions and 77 deletions

View File

@@ -0,0 +1,73 @@
use std::fmt::{Debug, Write};
use super::{
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserError,
ParserErrors, Statement, TokenCursor,
};
use crate::util::Padder;
pub struct Body {
pub statements: Vec<Node<Statement>>,
}
impl Parsable for Body {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
let mut statements = Vec::new();
cursor.expect_sym(Symbol::OpenCurly)?;
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
cursor.next();
return ParseResult::Ok(Self { statements });
}
let mut expect_semi = false;
let mut recover = false;
loop {
let Some(next) = cursor.peek() else {
recover = true;
errors.add(ParserError::unexpected_end());
break;
};
if next.is_symbol(Symbol::CloseCurly) {
cursor.next();
break;
}
if next.is_symbol(Symbol::Semicolon) {
cursor.next();
expect_semi = false;
continue;
} else if expect_semi {
errors.add(ParserError {
msg: "expected ';'".to_string(),
spans: vec![cursor.next_pos().char_span()],
});
}
let res = Statement::parse_node(cursor, errors);
statements.push(res.node);
expect_semi = true;
if res.recover {
cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
if cursor.peek().is_none() {
recover = true;
break;
}
}
}
ParseResult::from_recover(Self { statements }, recover)
}
}
impl Debug for Body {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.statements.first().is_some() {
f.write_str("{\n ")?;
let mut padder = Padder::new(f);
for s in &self.statements {
// they don't expose wrap_buf :grief:
padder.write_str(&format!("{s:?}\n"))?;
}
f.write_char('}')?;
} else {
f.write_str("{}")?;
}
Ok(())
}
}

156
src/parser/v3/nodes/expr.rs Normal file
View File

@@ -0,0 +1,156 @@
use std::fmt::{Debug, Write};
use super::{
BinaryOperator, Body, Ident, Literal, Node, NodeParsable, Parsable, ParseResult, ParserError,
ParserErrors, Symbol, TokenCursor, UnaryOperator,
};
type BoxNode = Node<Box<Expr>>;
pub enum Expr {
Lit(Node<Literal>),
Ident(Node<Ident>),
BinaryOp(BinaryOperator, BoxNode, BoxNode),
UnaryOp(UnaryOperator, BoxNode),
Block(Node<Body>),
Call(BoxNode, Vec<Node<Expr>>),
Group(BoxNode),
}
impl Parsable for Expr {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
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 ParseResult::Ok(Expr::Lit(Node::new(
Literal::Unit,
cursor.next_pos().char_span(),
)));
}
let res = Node::parse(cursor, errors);
if res.recover {
cursor.seek_sym(Symbol::CloseParen);
}
cursor.expect_sym(Symbol::CloseParen)?;
Self::Group(res.node.bx())
} else if next.is_symbol(Symbol::OpenCurly) {
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 Some(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 {
let res = Node::parse(cursor, &mut ParserErrors::new());
if res.node.is_some() {
Self::Ident(res.node)
} else {
let next = cursor.expect_peek()?;
return ParseResult::Err(ParserError::unexpected_token(next, "an expression"));
}
};
let Some(mut next) = cursor.peek() else {
return ParseResult::Ok(e1);
};
while next.is_symbol(Symbol::OpenParen) {
cursor.next();
let mut args = Vec::new();
loop {
let next = cursor.expect_peek()?;
if next.is_symbol(Symbol::CloseParen) {
break;
}
let res = Node::<Expr>::parse(cursor, errors);
args.push(res.node);
if res.recover {
cursor.seek_syms(&[Symbol::CloseParen, Symbol::Comma]);
}
let next = cursor.expect_peek()?;
if !next.is_symbol(Symbol::Comma) {
break;
}
cursor.next();
}
cursor.expect_sym(Symbol::CloseParen)?;
let end = cursor.prev_end();
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
let Some(next2) = cursor.peek() else {
return ParseResult::Ok(e1);
};
next = next2
}
let end = cursor.prev_end();
let mut recover = false;
let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) {
cursor.next();
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 Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
if op.presedence() > op2.presedence() {
let Some(box Self::BinaryOp(op2, n21, n22)) = n2.inner else {
unreachable!();
};
let end = n21.span.end;
n1 = Node::new(Self::BinaryOp(op, n1, n21), start.to(end)).bx();
op = op2;
n2 = n22;
}
}
Self::BinaryOp(op, n1, n2)
} else {
e1
};
ParseResult::from_recover(res, recover)
}
}
impl Debug for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Lit(c) => c.fmt(f)?,
Expr::Ident(n) => n.fmt(f)?,
Expr::Block(b) => b.fmt(f)?,
Expr::BinaryOp(op, e1, e2) => {
write!(f, "({:?}", *e1)?;
if op.pad() {
write!(f, " {} ", op.str())?;
} else {
write!(f, "{}", op.str())?;
}
write!(f, "{:?})", *e2)?;
}
Expr::Call(n, args) => {
n.fmt(f)?;
f.write_char('(')?;
if let Some(a) = args.first() {
a.fmt(f)?;
}
for arg in args.iter().skip(1) {
f.write_str(", ")?;
arg.fmt(f)?;
}
f.write_char(')')?;
}
Expr::UnaryOp(op, e) => {
write!(f, "(")?;
write!(f, "{}", op.str())?;
write!(f, "{:?})", *e)?;
}
Expr::Group(inner) => inner.fmt(f)?,
}
Ok(())
}
}

View File

@@ -0,0 +1,28 @@
use super::{Body, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, TokenCursor};
use std::fmt::Debug;
pub struct Function {
pub name: Node<Ident>,
pub body: Node<Body>,
}
impl Parsable for Function {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
cursor.expect_kw(Keyword::Fn)?;
let name = Node::parse(cursor, errors)?;
cursor.expect_sym(Symbol::OpenParen)?;
cursor.expect_sym(Symbol::CloseParen)?;
Node::parse(cursor, errors).map(|body| Self { name, body })
}
}
impl Debug for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("fn ")?;
self.name.fmt(f)?;
f.write_str("() ")?;
self.body.fmt(f)?;
Ok(())
}
}

View File

@@ -0,0 +1,29 @@
use std::fmt::Debug;
use super::{Parsable, ParseResult, ParserError, Token};
pub struct Ident(String);
impl Ident {
pub fn val(&self) -> &String {
&self.0
}
}
impl Parsable for Ident {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
let Token::Ident(name) = &next.token else {
return ParseResult::Err(ParserError::unexpected_token(next, "an identifier"));
};
let name = name.to_string();
cursor.next();
ParseResult::Ok(Self(name))
}
}
impl Debug for Ident {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

114
src/parser/v3/nodes/lit.rs Normal file
View File

@@ -0,0 +1,114 @@
use super::{
CharCursor, MaybeParsable, ParserError, ParserErrors, Symbol, Token, TokenCursor,
};
use std::fmt::Debug;
#[derive(Clone, PartialEq, Eq)]
pub enum Literal {
String(String),
Char(char),
Number(Number),
Unit,
}
#[derive(Clone, PartialEq, Eq)]
pub struct Number {
pub whole: String,
pub decimal: Option<String>,
pub ty: Option<String>,
}
impl MaybeParsable for Literal {
fn maybe_parse(
cursor: &mut TokenCursor,
_: &mut ParserErrors,
) -> Result<Option<Self>, ParserError> {
let inst = cursor.expect_peek()?;
let mut res = match &inst.token {
Token::Symbol(Symbol::SingleQuote) => {
let chars = cursor.chars();
let c = chars.expect_next()?;
chars.expect('\'')?;
Self::Char(c)
}
Token::Symbol(Symbol::DoubleQuote) => Self::String(string_from(cursor.chars())?),
Token::Ident(text) => {
let first = text.chars().next().unwrap();
if first.is_ascii_digit() {
Self::Number(Number {
whole: text.to_string(),
decimal: None,
ty: None,
})
} else {
return Ok(None);
}
}
_ => return Ok(None),
};
cursor.next();
if let (Some(next), Self::Number(num)) = (cursor.peek(), &mut res) {
if next.token.is_symbol(Symbol::Dot) {
cursor.next();
if let Some(next) = cursor.peek() {
if let Token::Ident(i) = &next.token {
if i.chars().next().unwrap().is_ascii_digit() {
num.decimal = Some(i.to_string());
cursor.next();
}
}
}
}
}
Ok(Some(res))
}
}
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserError> {
let mut str = String::new();
loop {
let c = cursor.expect_next()?;
if c == '"' {
return Ok(str);
}
str.push(match c {
'\\' => {
let next = cursor.expect_next()?;
match next {
'"' => '"',
'\'' => '\'',
't' => '\t',
'n' => '\n',
'0' => '\0',
_ => {
todo!();
}
}
}
_ => c,
})
}
}
impl Debug for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::String(str) => str.fmt(f),
Self::Char(c) => c.fmt(f),
Self::Number(n) => n.fmt(f),
Self::Unit => f.write_str("()"),
}
}
}
impl Debug for Number {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.whole)?;
if let Some(d) = &self.decimal {
write!(f, ".{}", d)?;
}
if let Some(ty) = &self.ty {
write!(f, "T{}", ty)?;
}
Ok(())
}
}

View File

@@ -0,0 +1,19 @@
mod body;
mod expr;
mod func;
mod module;
mod op;
mod statement;
mod lit;
mod ident;
pub use body::*;
pub use expr::*;
pub use func::*;
pub use module::*;
pub use op::*;
pub use statement::*;
pub use lit::*;
pub use ident::*;
use super::*;

View File

@@ -0,0 +1,35 @@
use super::{
Function, Keyword, Node, Parsable, ParseResult, ParserError, ParserErrors, TokenCursor,
};
use std::fmt::Debug;
pub struct Module {
pub functions: Vec<Node<Function>>,
}
impl Parsable for Module {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
let mut functions = Vec::new();
loop {
let Some(next) = cursor.peek() else {
return ParseResult::Ok(Self { functions });
};
if next.is_keyword(Keyword::Fn) {
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();
}
}
}
}
impl Debug for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.functions.fmt(f)
}
}

96
src/parser/v3/nodes/op.rs Normal file
View File

@@ -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<Self> {
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<Self> {
let Token::Symbol(symbol) = token else {
return None;
};
Some(match symbol {
Symbol::Ampersand => Self::Ref,
Symbol::Bang => Self::Not,
_ => {
return None;
}
})
}
}

View File

@@ -0,0 +1,53 @@
use super::{
Expr, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, Token, TokenCursor,
};
use std::fmt::{Debug, Write};
pub enum Statement {
Let(Node<Ident>, Node<Expr>),
Return(Node<Expr>),
Expr(Node<Expr>),
}
impl Parsable for Statement {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
match next.token {
Token::Keyword(Keyword::Let) => {
cursor.next();
let name = Node::parse(cursor, errors)?;
cursor.expect_sym(Symbol::Equals)?;
Node::parse(cursor, errors).map(|expr| Self::Let(name, expr))
}
Token::Keyword(Keyword::Return) => {
cursor.next();
Node::parse(cursor, errors).map(Self::Return)
}
_ => Node::parse(cursor, errors).map(Self::Expr),
}
}
}
impl Debug for Statement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Statement::Let(n, e) => {
f.write_str("let ")?;
n.fmt(f);
f.write_str(" = ")?;
e.fmt(f)?;
f.write_char(';')?;
}
Statement::Return(e) => {
f.write_str("return ")?;
e.fmt(f)?;
f.write_char(';')?;
}
Statement::Expr(e) => {
e.fmt(f)?;
f.write_char(';')?;
}
}
Ok(())
}
}