nodes + dyn stuff which is dumb and I'ma replace
This commit is contained in:
@@ -2,12 +2,27 @@ use std::io::{stdout, BufRead, BufReader};
|
|||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
use parser::{Module, Statement, TokenCursor};
|
use parser::{Module, Node, NodeContainer, Statement, TokenCursor};
|
||||||
|
|
||||||
pub fn parse_file(file: &str) {
|
pub fn parse_file(file: &str) {
|
||||||
match Module::parse(&mut TokenCursor::from(file)) {
|
let node = Node::<Module>::parse(&mut TokenCursor::from(file));
|
||||||
|
match node.inner {
|
||||||
Err(err) => err.write_for(&mut stdout(), file).unwrap(),
|
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<Node<Box<dyn NodeContainer>>>, 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 str = &line.expect("failed to read line");
|
||||||
let mut cursor = TokenCursor::from(&str[..]);
|
let mut cursor = TokenCursor::from(&str[..]);
|
||||||
let out = &mut stdout();
|
let out = &mut stdout();
|
||||||
match Statement::parse(&mut cursor) {
|
match Node::<Statement>::parse(&mut cursor).inner {
|
||||||
Ok(expr) => println!("{:?}", expr),
|
Ok(expr) => println!("{:?}", expr),
|
||||||
Err(err) => err.write_for(out, str).unwrap(),
|
Err(err) => err.write_for(out, str).unwrap(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +1,81 @@
|
|||||||
use std::fmt::{Debug, Write};
|
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 crate::util::Padder;
|
||||||
|
|
||||||
use super::{Expr, ParserError, TokenCursor};
|
use super::{Expr, ParserError, TokenCursor};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Node<Statement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Let(String, Expr),
|
Let(String, Node<Expr>),
|
||||||
Return(Expr),
|
Return(Node<Expr>),
|
||||||
Expr(Expr),
|
Expr(Node<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Body {
|
impl Parsable for Body {
|
||||||
pub fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
|
let statement_end = &[Symbol::Semicolon, Symbol::CloseCurly];
|
||||||
cursor.expect_sym(Symbol::OpenCurly)?;
|
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||||
|
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||||
|
cursor.next();
|
||||||
|
return Ok(Self { statements });
|
||||||
|
}
|
||||||
loop {
|
loop {
|
||||||
let next = cursor.expect_peek()?;
|
let next = cursor.expect_peek()?;
|
||||||
if next.is_symbol(Symbol::CloseCurly) {
|
if next.is_symbol(Symbol::CloseCurly) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
return Ok(Self { statements });
|
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 {
|
impl Parsable for Statement {
|
||||||
pub fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
||||||
let next = cursor.expect_peek()?;
|
let next = cursor.expect_peek()?;
|
||||||
Ok(match next.token {
|
Ok(match next.token {
|
||||||
Token::Keyword(Keyword::Let) => {
|
Token::Keyword(Keyword::Let) => {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let name = cursor.expect_ident()?;
|
let name = cursor.expect_ident()?;
|
||||||
cursor.expect_sym(Symbol::Equals)?;
|
cursor.expect_sym(Symbol::Equals)?;
|
||||||
let expr = Expr::parse(cursor)?;
|
let expr = Node::parse(cursor);
|
||||||
cursor.expect_sym(Symbol::Semicolon)?;
|
|
||||||
Self::Let(name, expr)
|
Self::Let(name, expr)
|
||||||
}
|
}
|
||||||
Token::Keyword(Keyword::Return) => {
|
Token::Keyword(Keyword::Return) => {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let expr = Expr::parse(cursor)?;
|
Self::Return(Node::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::Expr(Node::parse(cursor)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,3 +120,19 @@ impl Debug for Body {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NodeContainer for Body {
|
||||||
|
fn children(&self) -> Vec<Node<Box<dyn NodeContainer>>> {
|
||||||
|
self.statements.iter().map(|f| f.containerr()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeContainer for Statement {
|
||||||
|
fn children(&self) -> Vec<Node<Box<dyn NodeContainer>>> {
|
||||||
|
match self {
|
||||||
|
Statement::Let(_, e) => vec![e.containerr()],
|
||||||
|
Statement::Return(e) => vec![e.containerr()],
|
||||||
|
Statement::Expr(e) => vec![e.containerr()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use super::error::ParserError;
|
use super::error::ParserError;
|
||||||
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
||||||
|
use super::FilePos;
|
||||||
|
|
||||||
pub struct TokenCursor<'a> {
|
pub struct TokenCursor<'a> {
|
||||||
cursor: CharCursor<'a>,
|
cursor: CharCursor<'a>,
|
||||||
next: Option<TokenInstance>,
|
next: Option<TokenInstance>,
|
||||||
|
next_pos: FilePos,
|
||||||
|
prev_end: FilePos,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TokenCursor<'a> {
|
impl<'a> TokenCursor<'a> {
|
||||||
pub fn next(&mut self) -> Option<TokenInstance> {
|
pub fn next(&mut self) -> Option<TokenInstance> {
|
||||||
|
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))
|
std::mem::replace(&mut self.next, TokenInstance::parse(&mut self.cursor))
|
||||||
}
|
}
|
||||||
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserError> {
|
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserError> {
|
||||||
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> {
|
pub fn expect_token(&mut self, t: Token) -> Result<(), ParserError> {
|
||||||
let next = self.expect_next()?;
|
let next = self.expect_next()?;
|
||||||
@@ -26,6 +30,20 @@ impl<'a> TokenCursor<'a> {
|
|||||||
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> {
|
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> {
|
||||||
self.expect_token(Token::Symbol(symbol))
|
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> {
|
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserError> {
|
||||||
self.expect_token(Token::Keyword(kw))
|
self.expect_token(Token::Keyword(kw))
|
||||||
}
|
}
|
||||||
@@ -45,6 +63,12 @@ impl<'a> TokenCursor<'a> {
|
|||||||
pub fn chars(&mut self) -> &mut CharCursor<'a> {
|
pub fn chars(&mut self) -> &mut CharCursor<'a> {
|
||||||
&mut self.cursor
|
&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> {
|
impl<'a> From<&'a str> for TokenCursor<'a> {
|
||||||
@@ -56,6 +80,11 @@ impl<'a> From<&'a str> for TokenCursor<'a> {
|
|||||||
impl<'a> From<CharCursor<'a>> for TokenCursor<'a> {
|
impl<'a> From<CharCursor<'a>> for TokenCursor<'a> {
|
||||||
fn from(mut cursor: CharCursor<'a>) -> Self {
|
fn from(mut cursor: CharCursor<'a>) -> Self {
|
||||||
let cur = TokenInstance::parse(&mut cursor);
|
let cur = TokenInstance::parse(&mut cursor);
|
||||||
Self { cursor, next: cur }
|
Self {
|
||||||
|
cursor,
|
||||||
|
next: cur,
|
||||||
|
next_pos: FilePos::start(),
|
||||||
|
prev_end: FilePos::start(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 struct ParserError {
|
||||||
pub msg: String,
|
pub msg: String,
|
||||||
pub regions: Vec<FileRegion>,
|
pub spans: Vec<FileSpan>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParserErrors {
|
||||||
|
pub errs: Vec<ParserError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserError {
|
impl ParserError {
|
||||||
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
|
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
|
||||||
ParserError {
|
ParserError {
|
||||||
msg,
|
msg,
|
||||||
regions: instances.iter().map(|i| i.region).collect(),
|
spans: instances.iter().map(|i| i.span).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_msg(msg: String) -> Self {
|
pub fn from_msg(msg: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
msg,
|
msg,
|
||||||
regions: Vec::new(),
|
spans: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn at(pos: FilePos, msg: String) -> Self {
|
pub fn at(pos: FilePos, msg: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
msg,
|
msg,
|
||||||
regions: vec![FileRegion {
|
spans: vec![FileSpan::at(pos)],
|
||||||
start: pos,
|
|
||||||
end: pos,
|
|
||||||
}],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn unexpected_end() -> Self {
|
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<()> {
|
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)?;
|
writeln!(writer, "error: {}{}", self.msg, after)?;
|
||||||
for reg in &self.regions {
|
for span in &self.spans {
|
||||||
reg.write_for(writer, file)?;
|
span.write_for(writer, file)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ParserErrors {
|
||||||
|
pub fn add(&mut self, err: ParserError) {
|
||||||
|
self.errs.push(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
use super::token::{Symbol, Token};
|
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 {
|
pub enum Expr {
|
||||||
Val(Val),
|
Val(Node<Val>),
|
||||||
Ident(String),
|
Ident(String),
|
||||||
BinaryOp(Operator, Box<Expr>, Box<Expr>),
|
BinaryOp(Operator, Node<Box<Expr>>, Node<Box<Expr>>),
|
||||||
Block(Body),
|
Block(Node<Body>),
|
||||||
Call(Box<Expr>, Vec<Expr>),
|
Call(Node<Box<Expr>>, Vec<Node<Expr>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
@@ -22,64 +23,78 @@ pub enum Operator {
|
|||||||
Access,
|
Access,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Parsable for Expr {
|
||||||
pub fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
||||||
|
let start = cursor.next_pos();
|
||||||
let Some(next) = cursor.peek() else {
|
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) {
|
let mut e1 = if next.is_symbol(Symbol::OpenParen) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let expr = Self::parse(cursor)?;
|
let expr = Node::parse(cursor);
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
if expr.is_ok() {
|
||||||
expr
|
cursor.expect_sym(Symbol::CloseParen)?;
|
||||||
|
} else {
|
||||||
|
cursor.seek_sym(Symbol::CloseParen);
|
||||||
|
}
|
||||||
|
expr.take()?
|
||||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||||
let expr = Body::parse(cursor)?;
|
Self::Block(Node::parse(cursor))
|
||||||
Expr::Block(expr)
|
} else if let Some(val) = Node::maybe_parse(cursor) {
|
||||||
|
Self::Val(val)
|
||||||
} else {
|
} 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 {
|
let Some(mut next) = cursor.peek() else {
|
||||||
return Ok(e1);
|
return Ok(e1);
|
||||||
};
|
};
|
||||||
while next.is_symbol(Symbol::OpenParen) {
|
while next.is_symbol(Symbol::OpenParen) {
|
||||||
cursor.next();
|
cursor.next();
|
||||||
let inner = Self::parse(cursor)?;
|
let inner = Node::parse(cursor);
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
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 {
|
let Some(next2) = cursor.peek() else {
|
||||||
return Ok(e1);
|
return Ok(e1);
|
||||||
};
|
};
|
||||||
next = next2
|
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();
|
cursor.next();
|
||||||
let e2 = Self::parse(cursor)?;
|
let mut n1 = Node::new(Box::new(e1), start.to(end));
|
||||||
if let Self::BinaryOp(op_next, e3, e4) = e2 {
|
let mut n2 = Node::<Self>::parse(cursor);
|
||||||
if op.presedence() > op_next.presedence() {
|
if let Ok(Self::BinaryOp(op2, n21, n22)) = &*n2 {
|
||||||
Self::BinaryOp(op_next, Box::new(Self::BinaryOp(op, Box::new(e1), e3)), e4)
|
if op.presedence() > op2.presedence() {
|
||||||
} else {
|
n1 = Node::new(
|
||||||
Self::BinaryOp(op, Box::new(e1), Box::new(Self::BinaryOp(op_next, e3, e4)))
|
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 {
|
} else {
|
||||||
e1
|
e1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn parse_unit(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
|
||||||
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 {
|
impl Operator {
|
||||||
@@ -166,3 +181,18 @@ impl Debug for Expr {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NodeContainer for Expr {
|
||||||
|
fn children(&self) -> Vec<Node<Box<dyn NodeContainer>>> {
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,34 +6,37 @@ mod error;
|
|||||||
mod expr;
|
mod expr;
|
||||||
mod token;
|
mod token;
|
||||||
mod val;
|
mod val;
|
||||||
|
mod node;
|
||||||
|
|
||||||
pub use body::*;
|
pub use body::*;
|
||||||
pub use cursor::*;
|
pub use cursor::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use expr::*;
|
pub use expr::*;
|
||||||
pub use val::*;
|
pub use val::*;
|
||||||
|
pub use node::*;
|
||||||
|
|
||||||
use token::*;
|
use token::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
functions: Vec<Function>,
|
functions: Vec<Node<Function>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub body: Body,
|
pub body: Node<Body>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Parsable for Module {
|
||||||
pub fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
||||||
let mut functions = Vec::new();
|
let mut functions = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let Some(next) = cursor.peek() else {
|
let Some(next) = cursor.peek() else {
|
||||||
return Ok(Self { functions });
|
return Ok(Self { functions });
|
||||||
};
|
};
|
||||||
if next.is_keyword(Keyword::Fn) {
|
if next.is_keyword(Keyword::Fn) {
|
||||||
functions.push(Function::parse(cursor)?);
|
functions.push(Node::parse(cursor));
|
||||||
} else {
|
} else {
|
||||||
return Err(ParserError::unexpected_token(next, "fn"));
|
return Err(ParserError::unexpected_token(next, "fn"));
|
||||||
}
|
}
|
||||||
@@ -41,13 +44,13 @@ impl Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Parsable for Function {
|
||||||
pub fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError> {
|
||||||
cursor.expect_kw(Keyword::Fn)?;
|
cursor.expect_kw(Keyword::Fn)?;
|
||||||
let name = cursor.expect_ident()?;
|
let name = cursor.expect_ident()?;
|
||||||
cursor.expect_sym(Symbol::OpenParen)?;
|
cursor.expect_sym(Symbol::OpenParen)?;
|
||||||
cursor.expect_sym(Symbol::CloseParen)?;
|
cursor.expect_sym(Symbol::CloseParen)?;
|
||||||
let body = Body::parse(cursor)?;
|
let body = Node::parse(cursor);
|
||||||
Ok(Self { name, body })
|
Ok(Self { name, body })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,3 +64,15 @@ impl Debug for Function {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NodeContainer for Module {
|
||||||
|
fn children(&self) -> Vec<Node<Box<dyn NodeContainer>>> {
|
||||||
|
self.functions.iter().map(|f| f.containerr()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeContainer for Function {
|
||||||
|
fn children(&self) -> Vec<Node<Box<dyn NodeContainer>>> {
|
||||||
|
vec![self.body.containerr()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
132
src/v1/parser/node.rs
Normal file
132
src/v1/parser/node.rs
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{FileSpan, ParserError, TokenCursor};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Node<T> {
|
||||||
|
pub inner: Result<T, ParserError>,
|
||||||
|
pub span: FileSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Parsable: Sized {
|
||||||
|
fn parse(cursor: &mut TokenCursor) -> Result<Self, ParserError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MaybeParsable: Sized {
|
||||||
|
fn maybe_parse(cursor: &mut TokenCursor) -> Result<Option<Self>, ParserError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NodeContainer {
|
||||||
|
fn children(&self) -> Vec<Node<Box<dyn NodeContainer>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NodeContainer + ?Sized> NodeContainer for Node<Box<T>> {
|
||||||
|
fn children(&self) -> Vec<Node<Box<dyn NodeContainer>>> {
|
||||||
|
match &self.inner {
|
||||||
|
Ok(v) => v.children(),
|
||||||
|
Err(_) => Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Parsable> Node<T> {
|
||||||
|
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<T: MaybeParsable> Node<T> {
|
||||||
|
pub fn maybe_parse(cursor: &mut TokenCursor) -> Option<Self> {
|
||||||
|
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<T> Node<T> {
|
||||||
|
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<T, ParserError> {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
pub fn bx(self) -> Node<Box<T>> {
|
||||||
|
Node {
|
||||||
|
inner: self.inner.map(|v| Box::new(v)),
|
||||||
|
span: self.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NodeContainer + Clone + 'static> Node<T> {
|
||||||
|
pub fn containerr(&self) -> Node<Box<dyn NodeContainer>> {
|
||||||
|
Node {
|
||||||
|
inner: self.clone().inner.map(|v| Box::new(v) as Box<dyn NodeContainer>),
|
||||||
|
span: self.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Node<Box<T>> {
|
||||||
|
pub fn unbx(self) -> Node<T> {
|
||||||
|
Node {
|
||||||
|
inner: self.inner.map(|v| *v),
|
||||||
|
span: self.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: NodeContainer + Clone + 'static> Node<Box<T>> {
|
||||||
|
pub fn container(&self) -> Node<Box<dyn NodeContainer>> {
|
||||||
|
Node {
|
||||||
|
inner: self.clone().inner.map(|v| v as Box<dyn NodeContainer>),
|
||||||
|
span: self.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for Node<T> {
|
||||||
|
type Target = Result<T, ParserError>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Node<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> Debug for Node<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match &self.inner {
|
||||||
|
Ok(v) => v.fmt(f),
|
||||||
|
Err(_) => f.write_str("{error}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
use std::{iter::Peekable, str::Chars};
|
use std::{iter::Peekable, str::Chars};
|
||||||
|
|
||||||
use crate::v1::parser::ParserError;
|
use super::super::ParserError;
|
||||||
|
|
||||||
use super::FilePos;
|
use super::FilePos;
|
||||||
|
|
||||||
pub struct CharCursor<'a> {
|
pub struct CharCursor<'a> {
|
||||||
chars: Peekable<Chars<'a>>,
|
chars: Peekable<Chars<'a>>,
|
||||||
pos: FilePos,
|
next_pos: FilePos,
|
||||||
prev_pos: FilePos,
|
prev_pos: FilePos,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,12 +38,12 @@ impl CharCursor<'_> {
|
|||||||
let Some(next) = self.chars.next() else {
|
let Some(next) = self.chars.next() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.prev_pos = self.pos;
|
self.prev_pos = self.next_pos;
|
||||||
if next == '\n' {
|
if next == '\n' {
|
||||||
self.pos.col = 0;
|
self.next_pos.col = 0;
|
||||||
self.pos.line += 1;
|
self.next_pos.line += 1;
|
||||||
} else {
|
} else {
|
||||||
self.pos.col += 1;
|
self.next_pos.col += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn advance_if(&mut self, c: char) -> bool {
|
pub fn advance_if(&mut self, c: char) -> bool {
|
||||||
@@ -57,11 +56,10 @@ impl CharCursor<'_> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
pub fn expect_next(&mut self) -> Result<char, ParserError> {
|
pub fn expect_next(&mut self) -> Result<char, ParserError> {
|
||||||
self.next()
|
self.next().ok_or(ParserError::unexpected_end())
|
||||||
.ok_or(ParserError::from_msg("Unexpected end of input".to_string()))
|
|
||||||
}
|
}
|
||||||
pub fn pos(&self) -> FilePos {
|
pub fn next_pos(&self) -> FilePos {
|
||||||
self.pos
|
self.next_pos
|
||||||
}
|
}
|
||||||
pub fn prev_pos(&self) -> FilePos {
|
pub fn prev_pos(&self) -> FilePos {
|
||||||
self.prev_pos
|
self.prev_pos
|
||||||
@@ -72,7 +70,7 @@ impl<'a> From<&'a str> for CharCursor<'a> {
|
|||||||
fn from(value: &'a str) -> Self {
|
fn from(value: &'a str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
chars: value.chars().peekable(),
|
chars: value.chars().peekable(),
|
||||||
pos: FilePos::start(),
|
next_pos: FilePos::start(),
|
||||||
prev_pos: FilePos::start(),
|
prev_pos: FilePos::start(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ pub struct FilePos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct FileRegion {
|
pub struct FileSpan {
|
||||||
pub start: FilePos,
|
pub start: FilePos,
|
||||||
pub end: 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 BEFORE: usize = 1;
|
||||||
const AFTER: 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<()> {
|
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 start = self.start.line.saturating_sub(BEFORE);
|
||||||
let num_before = self.start.line - start;
|
let num_before = self.start.line - start;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ mod file;
|
|||||||
mod keyword;
|
mod keyword;
|
||||||
mod symbol;
|
mod symbol;
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
pub use cursor::*;
|
pub use cursor::*;
|
||||||
pub use file::*;
|
pub use file::*;
|
||||||
pub use keyword::*;
|
pub use keyword::*;
|
||||||
@@ -15,17 +17,17 @@ pub enum Token {
|
|||||||
Keyword(Keyword),
|
Keyword(Keyword),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone)]
|
||||||
pub struct TokenInstance {
|
pub struct TokenInstance {
|
||||||
pub token: Token,
|
pub token: Token,
|
||||||
pub region: FileRegion,
|
pub span: FileSpan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenInstance {
|
impl TokenInstance {
|
||||||
pub fn parse(cursor: &mut CharCursor) -> Option<TokenInstance> {
|
pub fn parse(cursor: &mut CharCursor) -> Option<TokenInstance> {
|
||||||
cursor.skip_whitespace();
|
cursor.skip_whitespace();
|
||||||
cursor.peek()?;
|
cursor.peek()?;
|
||||||
let start = cursor.pos();
|
let start = cursor.next_pos();
|
||||||
if let Some(s) = Symbol::parse(cursor) {
|
if let Some(s) = Symbol::parse(cursor) {
|
||||||
if s == Symbol::DoubleSlash {
|
if s == Symbol::DoubleSlash {
|
||||||
while cursor.next() != Some('\n') {}
|
while cursor.next() != Some('\n') {}
|
||||||
@@ -34,7 +36,7 @@ impl TokenInstance {
|
|||||||
let end = cursor.prev_pos();
|
let end = cursor.prev_pos();
|
||||||
return Some(Self {
|
return Some(Self {
|
||||||
token: Token::Symbol(s),
|
token: Token::Symbol(s),
|
||||||
region: FileRegion { start, end },
|
span: FileSpan { start, end },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let mut word = String::new();
|
let mut word = String::new();
|
||||||
@@ -53,7 +55,7 @@ impl TokenInstance {
|
|||||||
};
|
};
|
||||||
Some(Self {
|
Some(Self {
|
||||||
token,
|
token,
|
||||||
region: FileRegion { start, end },
|
span: FileSpan { start, end },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,6 +67,12 @@ impl Token {
|
|||||||
_ => false,
|
_ => 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 {
|
pub fn is_keyword(&self, kw: Keyword) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Token::Keyword(k) => *k == kw,
|
Token::Keyword(k) => *k == kw,
|
||||||
@@ -73,11 +81,10 @@ impl Token {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenInstance {
|
impl Deref for TokenInstance {
|
||||||
pub fn is_keyword(&self, kw: Keyword) -> bool {
|
type Target = Token;
|
||||||
self.token.is_keyword(kw)
|
|
||||||
}
|
fn deref(&self) -> &Self::Target {
|
||||||
pub fn is_symbol(&self, symbol: Symbol) -> bool {
|
&self.token
|
||||||
self.token.is_symbol(symbol)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::{CharCursor, ParserError, Symbol, Token, TokenCursor};
|
use super::{CharCursor, MaybeParsable, NodeContainer, ParserError, Symbol, Token, TokenCursor};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum Val {
|
pub enum Val {
|
||||||
String(String),
|
String(String),
|
||||||
Char(char),
|
Char(char),
|
||||||
@@ -9,15 +9,15 @@ pub enum Val {
|
|||||||
Unit,
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Number {
|
pub struct Number {
|
||||||
pub whole: String,
|
pub whole: String,
|
||||||
pub decimal: Option<String>,
|
pub decimal: Option<String>,
|
||||||
pub ty: Option<String>,
|
pub ty: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Val {
|
impl MaybeParsable for Val {
|
||||||
pub fn parse(cursor: &mut TokenCursor) -> Result<Option<Self>, ParserError> {
|
fn maybe_parse(cursor: &mut TokenCursor) -> Result<Option<Self>, ParserError> {
|
||||||
let inst = cursor.expect_peek()?;
|
let inst = cursor.expect_peek()?;
|
||||||
let mut res = match &inst.token {
|
let mut res = match &inst.token {
|
||||||
Token::Symbol(Symbol::SingleQuote) => {
|
Token::Symbol(Symbol::SingleQuote) => {
|
||||||
@@ -108,3 +108,4 @@ impl Debug for Number {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ impl Debug for Body {
|
|||||||
let mut padder = Padder::new(f);
|
let mut padder = Padder::new(f);
|
||||||
for s in &self.statements {
|
for s in &self.statements {
|
||||||
// they don't expose wrap_buf :grief:
|
// they don't expose wrap_buf :grief:
|
||||||
write!(padder, "{s:?}\n")?;
|
writeln!(padder, "{s:?}")?;
|
||||||
}
|
}
|
||||||
write!(f, "}}")?;
|
write!(f, "}}")?;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ fn main() {
|
|||||||
let y = 4 + 4 + 5;
|
let y = 4 + 4 + 5;
|
||||||
let z = 1 * 2 - 3 / test * 4;
|
let z = 1 * 2 - 3 / test * 4;
|
||||||
let r = 1-2.5 + 3;
|
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 a = test('3');
|
||||||
let c = '3' ;
|
let c = '3' ;
|
||||||
test(5);
|
test(5);
|
||||||
|
|||||||
Reference in New Issue
Block a user