a ton of stuff idk more ir work

This commit is contained in:
2024-10-22 02:30:50 -04:00
parent 14a4fb1ff9
commit 87f755b763
46 changed files with 1967 additions and 540 deletions

View File

@@ -1,5 +1,5 @@
mod v1;
mod v2;
// mod v1;
// mod v2;
mod v3;
pub use v3::*;

View File

@@ -1,6 +1,7 @@
use super::error::ParserError;
use crate::ir::FilePos;
use super::error::ParserMsg;
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
use super::FilePos;
pub struct TokenCursor<'a> {
cursor: CharCursor<'a>,
@@ -15,19 +16,19 @@ impl<'a> TokenCursor<'a> {
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<TokenInstance, ParserError> {
self.peek().ok_or(ParserError::unexpected_end())?;
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserMsg> {
self.peek().ok_or(ParserMsg::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<(), ParserMsg> {
let next = self.expect_next()?;
if t == next.token {
Ok(())
} else {
Err(ParserError::unexpected_token(&next, &format!("{t:?}")))
Err(ParserMsg::unexpected_token(&next, &format!("{t:?}")))
}
}
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserError> {
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> {
self.expect_token(Token::Symbol(symbol))
}
pub fn seek_sym(&mut self, symbol: Symbol) {
@@ -52,14 +53,14 @@ impl<'a> TokenCursor<'a> {
self.next();
}
}
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserError> {
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserMsg> {
self.expect_token(Token::Keyword(kw))
}
pub fn peek(&self) -> Option<&TokenInstance> {
self.next.as_ref()
}
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserError> {
self.peek().ok_or(ParserError::unexpected_end())
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserMsg> {
self.peek().ok_or(ParserMsg::unexpected_end())
}
pub fn chars(&mut self) -> &mut CharCursor<'a> {
&mut self.cursor

View File

@@ -1,21 +1,21 @@
use super::{
token::{FileSpan, TokenInstance},
FilePos, Ident, Node,
};
use crate::ir::{FilePos, FileSpan};
use super::{token::TokenInstance, Ident, Node};
#[derive(Debug, Clone)]
pub struct ParserError {
pub struct ParserMsg {
pub msg: String,
pub spans: Vec<FileSpan>,
}
pub struct ParserErrors {
pub errs: Vec<ParserError>,
pub struct ParserOutput {
pub errs: Vec<ParserMsg>,
pub hints: Vec<ParserMsg>,
}
impl ParserError {
impl ParserMsg {
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
ParserError {
ParserMsg {
msg,
spans: instances.iter().map(|i| i.span).collect(),
}
@@ -49,14 +49,14 @@ impl ParserError {
}
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
let t = &inst.token;
ParserError::from_instances(
ParserMsg::from_instances(
&[inst],
format!("unexpected token {t:?}; expected {expected}"),
)
}
pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
let after = if self.spans.is_empty() { "" } else { ":" };
writeln!(writer, "error: {}{}", self.msg, after)?;
writeln!(writer, "{}: {}{}", ty, self.msg, after)?;
for span in &self.spans {
span.write_for(writer, file)?;
}
@@ -64,11 +64,25 @@ impl ParserError {
}
}
impl ParserErrors {
impl ParserOutput {
pub fn new() -> Self {
Self { errs: Vec::new() }
Self {
errs: Vec::new(),
hints: Vec::new(),
}
}
pub fn add(&mut self, err: ParserError) {
pub fn err(&mut self, err: ParserMsg) {
self.errs.push(err);
}
pub fn hint(&mut self, err: ParserMsg) {
self.hints.push(err);
}
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
for err in &self.errs {
err.write_for("error", out, file).unwrap();
}
for hint in &self.hints {
hint.write_for("hint", out, file).unwrap();
}
}
}

View File

@@ -0,0 +1,58 @@
use crate::ir::Instruction;
use super::{Block, ExprResult, FnLowerCtx, Node, Statement};
impl Node<Block> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
self.as_ref()?.lower(ctx)
}
}
impl Block {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
let ctx = &mut ctx.sub();
for statement in &self.statements {
statement.lower(ctx);
}
self.result.as_ref()?.lower(ctx)
}
}
impl Node<Box<Statement>> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
self.as_ref()?.lower(ctx)
}
}
impl Node<Statement> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
self.as_ref()?.lower(ctx)
}
}
impl Statement {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
match self {
super::Statement::Let(def, e) => {
let def = def.lower(ctx.map, ctx.output)?;
let res = e.lower(ctx);
if let Some(res) = res {
match res {
ExprResult::Var(v) => ctx.map.name_var(&def, v),
ExprResult::Fn(_) => todo!(),
}
}
None
}
super::Statement::Return(e) => {
let res = e.lower(ctx)?;
match res {
ExprResult::Var(v) => ctx.push(Instruction::Ret { src: v }),
_ => todo!(),
}
None
}
super::Statement::Expr(e) => e.lower(ctx),
}
}
}

View File

@@ -0,0 +1,59 @@
use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef};
use super::{Node, ParserMsg, ParserOutput, Type as PType, VarDef as PVarDef};
impl Node<PVarDef> {
pub fn lower(
&self,
namespace: &mut NamespaceGuard,
output: &mut ParserOutput,
) -> Option<VarDef> {
let s = self.as_ref()?;
let name = s.name.as_ref()?.val().clone();
let ty = match &s.ty {
Some(ty) => ty.lower(namespace, output),
None => Type::Infer,
};
Some(VarDef {
name,
ty,
origin: Origin::File(self.span),
})
}
}
impl Node<PType> {
pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut ParserOutput) -> Type {
self.as_ref()
.map(|t| t.lower(namespace, output, self.span))
.unwrap_or(Type::Error)
}
}
impl PType {
pub fn lower(
&self,
namespace: &mut NamespaceGuard,
output: &mut ParserOutput,
span: FileSpan,
) -> Type {
match namespace.get(&self.name).map(|ids| ids.ty).flatten() {
Some(id) => {
if self.args.is_empty() {
Type::Concrete(id)
} else {
let args = self
.args
.iter()
.map(|n| n.lower(namespace, output))
.collect();
Type::Generic { base: id, args }
}
}
None => {
output.err(ParserMsg::from_span(span, "Type not found".to_string()));
Type::Error
}
}
}
}

136
src/parser/v3/lower/expr.rs Normal file
View File

@@ -0,0 +1,136 @@
use super::{func::FnLowerCtx, Expr as PExpr, Node, UnaryOp};
use crate::ir::{FnIdent, Instruction, Type, VarIdent, VarOrFnIdent};
impl PExpr {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
Some(match self {
PExpr::Lit(l) => match l.as_ref()? {
super::Literal::String(s) => todo!(),
super::Literal::Char(c) => todo!(),
super::Literal::Number(n) => todo!(),
super::Literal::Unit => {
todo!();
}
},
PExpr::Ident(i) => {
let name = i.as_ref()?.val();
let Some(id) = ctx.get(name) else {
ctx.err(format!("Identifier '{}' not found.", name));
return None;
};
let Some(vf) = id.var_func else {
ctx.err(format!("Variable or function '{}' not found; Found type, but types cannot be used here.", name));
return None;
};
match vf {
VarOrFnIdent::Var(var) => ExprResult::Var(var),
VarOrFnIdent::Fn(f) => ExprResult::Fn(f),
}
}
PExpr::BinaryOp(op, e1, e2) => {
let res1 = e1.lower(ctx)?;
let res2 = e2.lower(ctx)?;
op.traitt();
todo!();
}
PExpr::UnaryOp(op, e) => {
let res = e.lower(ctx)?;
match op {
UnaryOp::Ref => ExprResult::Var(match res {
ExprResult::Var(v) => {
let temp = ctx.temp(ctx.map.get_var(v).ty.clone());
ctx.push(Instruction::Ref { dest: temp, src: v });
temp
}
ExprResult::Fn(f) => {
let temp = ctx.temp(Type::Ref(Box::new(ctx.map.get_fn(f).ty())));
ctx.push(Instruction::Lf { dest: temp, src: f });
temp
}
}),
UnaryOp::Deref => match res {
ExprResult::Var(v) => match &ctx.map.get_var(v).ty {
Type::Ref(inner) => {
todo!()
}
t => {
ctx.err(format!(
"Cannot dereference type {:?}",
ctx.map.type_name(t)
));
return None;
}
},
ExprResult::Fn(f) => {
ctx.err("Cannot dereference functions".to_string());
return None;
}
},
UnaryOp::Not => todo!(),
}
}
PExpr::Block(b) => b.lower(ctx)?,
PExpr::AsmBlock(b) => {
ctx.push(Instruction::AsmBlock {
instructions: b.as_ref()?.instructions.clone(),
});
return None;
}
PExpr::Call(e, args) => {
let fe = e.lower(ctx)?;
let mut nargs = Vec::new();
for arg in args.iter() {
let arg = arg.lower(ctx)?;
nargs.push(match arg {
ExprResult::Var(v) => v,
ExprResult::Fn(_) => todo!(),
});
}
match fe {
ExprResult::Fn(f) => {
let temp = ctx.temp(ctx.map.get_fn(f).ret.clone());
ctx.push(Instruction::Call {
dest: temp,
f,
args: nargs,
});
ExprResult::Var(temp)
}
o => {
ctx.err(format!("Expected function, found {:?}", o));
return None;
}
}
}
PExpr::Group(e) => e.lower(ctx)?,
})
}
}
impl Node<PExpr> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
self.inner.as_ref()?.lower(&mut FnLowerCtx {
map: ctx.map,
instructions: ctx.instructions,
output: ctx.output,
span: self.span,
})
}
}
impl Node<Box<PExpr>> {
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
self.inner.as_ref()?.lower(&mut FnLowerCtx {
map: ctx.map,
instructions: ctx.instructions,
output: ctx.output,
span: self.span,
})
}
}
#[derive(Debug)]
pub enum ExprResult {
Var(VarIdent),
Fn(FnIdent),
}

101
src/parser/v3/lower/func.rs Normal file
View File

@@ -0,0 +1,101 @@
use super::{Function as PFunction, Node, ParserMsg, ParserOutput};
use crate::ir::{
BuiltinType, FileSpan, FnDef, FnIdent, Function, Idents, Instruction, Instructions,
NamespaceGuard, Origin, Type, VarDef, VarIdent,
};
impl Node<PFunction> {
pub fn lower_header(
&self,
map: &mut NamespaceGuard,
output: &mut ParserOutput,
) -> Option<FnIdent> {
self.as_ref()?.lower_header(map, output)
}
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Option<Function> {
if let Some(f) = self.as_ref() {
Some(f.lower_body(map, output))
} else {
None
}
}
}
impl PFunction {
pub fn lower_header(
&self,
map: &mut NamespaceGuard,
output: &mut ParserOutput,
) -> Option<FnIdent> {
let header = self.header.as_ref()?;
let name = header.name.as_ref()?;
let args = header
.args
.iter()
.map(|a| {
a.lower(map, output).unwrap_or(VarDef {
name: "{error}".to_string(),
origin: Origin::File(a.span),
ty: Type::Error,
})
})
.collect();
let ret = match &header.ret {
Some(ty) => ty.lower(map, output),
None => Type::Concrete(BuiltinType::Unit.id()),
};
// ignoring self var for now
Some(map.def_fn(FnDef {
name: name.val().clone(),
origin: Origin::File(self.header.span),
args,
ret,
}))
}
pub fn lower_body(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) -> Function {
let mut instructions = Instructions::new();
let mut ctx = FnLowerCtx {
instructions: &mut instructions,
map,
output,
span: self.body.span,
};
if let Some(res) = self.body.lower(&mut ctx) {
match res {
super::ExprResult::Var(v) => instructions.push(Instruction::Ret { src: v }),
super::ExprResult::Fn(_) => todo!(),
}
}
Function::new(instructions)
}
}
pub struct FnLowerCtx<'a, 'n> {
pub map: &'a mut NamespaceGuard<'n>,
pub instructions: &'a mut Instructions,
pub output: &'a mut ParserOutput,
pub span: FileSpan,
}
impl<'a, 'n> FnLowerCtx<'a, 'n> {
pub fn get(&self, name: &str) -> Option<Idents> {
self.map.get(name)
}
pub fn err(&mut self, msg: String) {
self.output.err(ParserMsg::from_span(self.span, msg))
}
pub fn temp(&mut self, ty: Type) -> VarIdent {
self.map.temp_var(self.span, ty)
}
pub fn push(&mut self, i: Instruction) {
self.instructions.push(i);
}
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
FnLowerCtx {
map: self.map,
instructions: self.instructions,
output: self.output,
span: self.span,
}
}
}

View File

@@ -0,0 +1,12 @@
mod block;
mod def;
mod expr;
mod func;
mod module;
use super::*;
use block::*;
use def::*;
use expr::*;
use func::*;
use module::*;

View File

@@ -0,0 +1,21 @@
use crate::ir::NamespaceGuard;
use super::{Module, ParserOutput};
impl Module {
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) {
let mut fns = Vec::new();
for f in &self.functions {
if let Some(id) = f.lower_header(map, output) {
fns.push(Some(id));
} else {
fns.push(None)
}
}
for (f, id) in self.functions.iter().zip(fns) {
if let (Some(res), Some(id)) = (f.lower_body(map, output), id) {
map.write_fn(id, res);
}
}
}
}

View File

@@ -1,7 +1,6 @@
use std::io::{stdout, BufRead, BufReader};
mod cursor;
mod error;
mod lower;
mod node;
mod nodes;
mod parse;
@@ -9,43 +8,8 @@ mod token;
pub use cursor::*;
pub use error::*;
pub use lower::*;
pub use node::*;
pub use nodes::*;
pub use parse::*;
pub use token::*;
use crate::ir::Namespace;
pub fn parse_file(file: &str) {
let mut errors = ParserErrors::new();
let res = Module::parse_node(&mut TokenCursor::from(file), &mut errors);
println!("{:?}", res.node);
let out = &mut stdout();
if let Some(module) = res.node.as_ref() {
let mut namespace = Namespace::new();
module.lower(&mut namespace, &mut errors);
println!("{:?}", namespace);
}
for err in errors.errs {
err.write_for(out, file).unwrap();
}
}
pub fn run_stdin() {
for line in BufReader::new(std::io::stdin()).lines() {
let mut errors = ParserErrors::new();
let str = &line.expect("failed to read line");
let mut cursor = TokenCursor::from(&str[..]);
if let Some(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 {
err.write_for(out, str).unwrap();
}
}
}

View File

@@ -3,7 +3,7 @@ use std::{
ops::{Deref, DerefMut},
};
use super::FileSpan;
use crate::ir::FileSpan;
pub struct Node<T> {
pub inner: Option<T>,

View File

@@ -0,0 +1,23 @@
use crate::compiler::riscv64::AsmInstruction;
use super::{Parsable, ParseResult, Symbol};
#[derive(Debug)]
pub struct AsmBlock {
pub instructions: Vec<AsmInstruction>,
}
impl Parsable for AsmBlock {
fn parse(
cursor: &mut super::TokenCursor,
output: &mut super::ParserOutput,
) -> ParseResult<Self> {
cursor.expect_sym(Symbol::OpenCurly)?;
let mut instructions = Vec::new();
while !cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
instructions.push(AsmInstruction::parse(cursor, output)?);
}
cursor.expect_sym(Symbol::CloseCurly)?;
ParseResult::Ok(Self { instructions })
}
}

View File

@@ -0,0 +1,53 @@
use crate::compiler::riscv64::{AsmInstruction, Reg};
use super::{
util::parse_list, AsmBlock, Ident, Keyword, Node, Parsable, ParseResult, SelfVar, Symbol,
};
#[derive(Debug)]
pub struct AsmFunctionHeader {
pub name: Node<Ident>,
pub sel: Option<Node<SelfVar>>,
pub args: Vec<Node<Reg>>,
}
#[derive(Debug)]
pub struct AsmFunction {
pub header: Node<AsmFunctionHeader>,
pub body: Node<AsmBlock>,
}
impl Parsable for AsmFunctionHeader {
fn parse(
cursor: &mut super::TokenCursor,
output: &mut super::ParserOutput,
) -> ParseResult<Self> {
cursor.expect_kw(Keyword::Asm)?;
cursor.expect_kw(Keyword::Fn)?;
let name = Node::parse(cursor, output)?;
cursor.expect_sym(Symbol::OpenParen)?;
let sel = Node::maybe_parse(cursor, output);
if sel.is_some() {
if let Err(err) = cursor.expect_sym(Symbol::Comma) {
output.err(err);
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
cursor.next();
}
}
}
let args = parse_list(cursor, output, Symbol::CloseParen)?;
ParseResult::Ok(Self { name, sel, args })
}
}
impl Parsable for AsmFunction {
fn parse(
cursor: &mut super::TokenCursor,
output: &mut super::ParserOutput,
) -> ParseResult<Self> {
let header = Node::parse(cursor, output)?;
let body = Node::parse(cursor, output)?;
ParseResult::Ok(Self { header, body })
}
}

View File

@@ -1,29 +1,31 @@
use std::fmt::{Debug, Write};
use super::{
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserError,
ParserErrors, Statement, TokenCursor,
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserMsg, ParserOutput, Statement,
TokenCursor,
};
use crate::util::Padder;
pub struct Body {
pub struct Block {
pub statements: Vec<Node<Statement>>,
pub result: Option<Node<Box<Statement>>>,
}
impl Parsable for Body {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
impl Parsable for Block {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
let mut statements = Vec::new();
let mut result = None;
cursor.expect_sym(Symbol::OpenCurly)?;
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
cursor.next();
return ParseResult::Ok(Self { statements });
return ParseResult::Ok(Self { statements, result });
}
let mut expect_semi = false;
let mut recover = false;
loop {
let Some(next) = cursor.peek() else {
recover = true;
errors.add(ParserError::unexpected_end());
errors.err(ParserMsg::unexpected_end());
break;
};
if next.is_symbol(Symbol::CloseCurly) {
@@ -35,7 +37,7 @@ impl Parsable for Body {
expect_semi = false;
continue;
} else if expect_semi {
errors.add(ParserError {
errors.err(ParserMsg {
msg: "expected ';'".to_string(),
spans: vec![cursor.next_pos().char_span()],
});
@@ -51,11 +53,16 @@ impl Parsable for Body {
}
}
}
ParseResult::from_recover(Self { statements }, recover)
if expect_semi {
if let Some(s) = statements.pop() {
result = Some(s.bx());
}
}
ParseResult::from_recover(Self { statements, result }, recover)
}
}
impl Debug for Body {
impl Debug for Block {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.statements.first().is_some() {
f.write_str("{\n ")?;

View File

@@ -0,0 +1,82 @@
use std::fmt::Debug;
use super::{Ident, MaybeParsable, Node, Parsable, ParseResult, ParserMsg, Symbol, Token, Type};
pub struct VarDef {
pub name: Node<Ident>,
pub ty: Option<Node<Type>>,
}
impl Parsable for VarDef {
fn parse(
cursor: &mut super::TokenCursor,
errors: &mut super::ParserOutput,
) -> ParseResult<Self> {
let name = Node::parse(cursor, errors)?;
if cursor.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
cursor.next();
Node::parse(cursor, errors).map(|ty| Self { name, ty: Some(ty) })
} else {
ParseResult::Ok(Self { name, ty: None })
}
}
}
pub struct SelfVar {
pub ty: SelfType,
}
#[derive(PartialEq)]
pub enum SelfType {
Ref,
Take,
}
impl MaybeParsable for SelfVar {
fn maybe_parse(
cursor: &mut super::TokenCursor,
errors: &mut super::ParserOutput,
) -> Result<Option<Self>, super::ParserMsg> {
if let Some(mut next) = cursor.peek() {
let mut ty = SelfType::Take;
if next.is_symbol(Symbol::Ampersand) {
cursor.next();
ty = SelfType::Ref;
next = cursor.expect_peek()?;
}
if let Token::Word(name) = &next.token {
if name == "self" {
cursor.next();
return Ok(Some(Self { ty }));
}
}
if ty != SelfType::Take {
return Err(ParserMsg::unexpected_token(next, "self"));
}
}
Ok(None)
}
}
impl Debug for VarDef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.name.fmt(f)?;
if let Some(ty) = &self.ty {
write!(f, ": {:?}", ty)?;
}
Ok(())
}
}
impl Debug for SelfVar {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self.ty {
SelfType::Ref => "&self",
SelfType::Take => "self",
}
)
}
}

View File

@@ -1,8 +1,10 @@
use std::fmt::{Debug, Write};
use super::{
BinaryOperator, Body, Ident, Literal, Node, NodeParsable, Parsable, ParseResult, ParserError,
ParserErrors, Symbol, TokenCursor, UnaryOperator,
op::{BinaryOp, UnaryOp},
util::parse_list,
AsmBlock, Block, Ident, Keyword, Literal, Node, NodeParsable, Parsable, ParseResult, ParserMsg,
ParserOutput, Symbol, TokenCursor,
};
type BoxNode = Node<Box<Expr>>;
@@ -10,15 +12,16 @@ type BoxNode = Node<Box<Expr>>;
pub enum Expr {
Lit(Node<Literal>),
Ident(Node<Ident>),
BinaryOp(BinaryOperator, BoxNode, BoxNode),
UnaryOp(UnaryOperator, BoxNode),
Block(Node<Body>),
BinaryOp(BinaryOp, BoxNode, BoxNode),
UnaryOp(UnaryOp, BoxNode),
Block(Node<Block>),
Call(BoxNode, Vec<Node<Expr>>),
Group(BoxNode),
AsmBlock(Node<AsmBlock>),
}
impl Parsable for Expr {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
let start = cursor.next_pos();
let next = cursor.expect_peek()?;
let mut e1 = if next.is_symbol(Symbol::OpenParen) {
@@ -30,17 +33,20 @@ impl Parsable for Expr {
cursor.next_pos().char_span(),
)));
}
let res = Node::parse(cursor, errors);
let res = Node::parse(cursor, output);
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) {
Self::Block(Block::parse_node(cursor, output)?)
} else if next.is_keyword(Keyword::Asm) {
cursor.next();
return Node::parse(cursor, errors).map(|n| {
Self::AsmBlock(Node::parse(cursor, output)?)
} else if let Some(op) = UnaryOp::from_token(next) {
cursor.next();
return Node::parse(cursor, output).map(|n| {
let n = n.bx();
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
let span = start.to(n1.span.end);
@@ -49,15 +55,15 @@ impl Parsable for Expr {
Self::UnaryOp(op, n)
}
});
} else if let Some(val) = Node::maybe_parse(cursor, errors) {
} else if let Some(val) = Node::maybe_parse(cursor, output) {
Self::Lit(val)
} else {
let res = Node::parse(cursor, &mut ParserErrors::new());
let res = Node::parse(cursor, &mut ParserOutput::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"));
return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression"));
}
};
let Some(mut next) = cursor.peek() else {
@@ -65,24 +71,7 @@ impl Parsable for Expr {
};
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 args = parse_list(cursor, output, 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 {
@@ -92,10 +81,10 @@ impl Parsable for Expr {
}
let end = cursor.prev_end();
let mut recover = false;
let res = if let Some(mut op) = BinaryOperator::from_token(&next.token) {
let res = if let Some(mut op) = BinaryOp::from_token(&next.token) {
cursor.next();
let mut n1 = Node::new(e1, start.to(end)).bx();
let res = Node::parse(cursor, errors);
let res = Node::parse(cursor, output);
let mut n2 = res.node.bx();
recover = res.recover;
if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
@@ -150,6 +139,7 @@ impl Debug for Expr {
write!(f, "{:?})", *e)?;
}
Expr::Group(inner) => inner.fmt(f)?,
Expr::AsmBlock(inner) => inner.fmt(f)?,
}
Ok(())
}

View File

@@ -1,28 +1,90 @@
use super::{Body, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, TokenCursor};
use super::{
util::parse_list, Block, Ident, Keyword, Node, Parsable, ParseResult, ParserOutput, SelfVar,
Symbol, TokenCursor, Type, VarDef,
};
use std::fmt::Debug;
pub struct Function {
pub struct FunctionHeader {
pub name: Node<Ident>,
pub body: Node<Body>,
pub sel: Option<Node<SelfVar>>,
pub args: Vec<Node<VarDef>>,
pub ret: Option<Node<Type>>,
}
impl Parsable for Function {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
pub struct Function {
pub header: Node<FunctionHeader>,
pub body: Node<Block>,
}
impl Parsable for FunctionHeader {
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
cursor.expect_kw(Keyword::Fn)?;
let name = Node::parse(cursor, errors)?;
let name = Node::parse(cursor, output)?;
cursor.expect_sym(Symbol::OpenParen)?;
cursor.expect_sym(Symbol::CloseParen)?;
Node::parse(cursor, errors).map(|body| Self { name, body })
let sel = Node::maybe_parse(cursor, output);
if sel.is_some() {
if let Err(err) = cursor.expect_sym(Symbol::Comma) {
output.err(err);
cursor.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
cursor.next();
}
}
}
let args = parse_list(cursor, output, Symbol::CloseParen)?;
let ret = if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) {
cursor.next();
Some(Node::parse(cursor, output)?)
} else {
None
};
ParseResult::Ok(Self {
name,
args,
sel,
ret,
})
}
}
impl Debug for Function {
impl Parsable for Function {
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
let header = Node::parse(cursor, output)?;
let body = Node::parse(cursor, output)?;
ParseResult::Ok(Self { header, body })
}
}
impl Debug for FunctionHeader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("fn ")?;
self.name.fmt(f)?;
f.write_str("() ")?;
f.write_str("(")?;
if let Some(s) = &self.sel {
s.fmt(f)?;
if self.args.first().is_some() {
f.write_str(", ")?;
}
}
if let Some(a) = self.args.first() {
a.fmt(f)?;
}
for arg in self.args.iter().skip(1) {
f.write_str(", ")?;
arg.fmt(f)?;
}
f.write_str(")")?;
if let Some(ret) = &self.ret {
write!(f, " -> {:?}", ret)?;
}
Ok(())
}
}
impl Debug for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.header.fmt(f)?;
f.write_str(" ")?;
self.body.fmt(f)?;
Ok(())
}
}

View File

@@ -1,5 +1,5 @@
use std::fmt::Debug;
use super::{Parsable, ParseResult, ParserError, Token};
use super::{Parsable, ParseResult, ParserMsg, Token};
pub struct Ident(String);
@@ -10,10 +10,10 @@ impl Ident {
}
impl Parsable for Ident {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult<Self> {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
let Token::Ident(name) = &next.token else {
return ParseResult::Err(ParserError::unexpected_token(next, "an identifier"));
let Token::Word(name) = &next.token else {
return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier"));
};
let name = name.to_string();
cursor.next();

View File

@@ -1,6 +1,4 @@
use super::{
CharCursor, MaybeParsable, ParserError, ParserErrors, Symbol, Token, TokenCursor,
};
use super::{CharCursor, MaybeParsable, ParserMsg, ParserOutput, Symbol, Token, TokenCursor};
use std::fmt::Debug;
#[derive(Clone, PartialEq, Eq)]
@@ -21,49 +19,72 @@ pub struct Number {
impl MaybeParsable for Literal {
fn maybe_parse(
cursor: &mut TokenCursor,
_: &mut ParserErrors,
) -> Result<Option<Self>, ParserError> {
_: &mut ParserOutput,
) -> Result<Option<Self>, ParserMsg> {
let inst = cursor.expect_peek()?;
let mut res = match &inst.token {
Ok(Some(match &inst.token {
Token::Symbol(Symbol::SingleQuote) => {
let chars = cursor.chars();
let c = chars.expect_next()?;
chars.expect('\'')?;
cursor.next();
Self::Char(c)
}
Token::Symbol(Symbol::DoubleQuote) => Self::String(string_from(cursor.chars())?),
Token::Ident(text) => {
Token::Symbol(Symbol::DoubleQuote) => {
let res = Self::String(string_from(cursor.chars())?);
cursor.next();
res
}
Token::Word(text) => {
let first = text.chars().next().unwrap();
if first.is_ascii_digit() {
Self::Number(Number {
whole: text.to_string(),
decimal: None,
ty: None,
})
} else {
if !first.is_ascii_digit() {
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) {
let (whole, ty) = parse_whole_num(text);
let mut num = Number {
whole,
decimal: None,
ty,
};
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();
if num.ty.is_none() && cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) {
cursor.next();
if let Some(next) = cursor.peek() {
if let Token::Word(i) = &next.token {
if i.chars().next().unwrap().is_ascii_digit() {
let (decimal, ty) = parse_whole_num(i);
num.decimal = Some(decimal);
num.ty = ty;
cursor.next();
}
}
}
}
Self::Number(num)
}
}
Ok(Some(res))
_ => return Ok(None),
}))
}
}
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserError> {
pub fn parse_whole_num(text: &str) -> (String, Option<String>) {
let mut whole = String::new();
let mut ty = String::new();
for c in text.chars() {
if ty.is_empty() {
if c.is_ascii_digit() {
whole.push(c);
} else if c != '_' {
ty.push(c);
}
} else {
ty.push(c);
}
}
(whole, if ty.is_empty() { None } else { Some(ty) })
}
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> {
let mut str = String::new();
loop {
let c = cursor.expect_next()?;
@@ -107,7 +128,7 @@ impl Debug for Number {
write!(f, ".{}", d)?;
}
if let Some(ty) = &self.ty {
write!(f, "T{}", ty)?;
write!(f, "_{}", ty)?;
}
Ok(())
}

View File

@@ -1,4 +1,4 @@
mod body;
mod block;
mod expr;
mod func;
mod module;
@@ -6,14 +6,28 @@ mod op;
mod statement;
mod lit;
mod ident;
mod ty;
mod def;
mod struc;
mod util;
mod trai;
mod asm_fn;
mod asm_block;
pub use body::*;
pub use block::*;
pub use expr::*;
pub use func::*;
pub use module::*;
pub use op::*;
pub use statement::*;
pub use lit::*;
pub use ident::*;
pub use ty::*;
pub use def::*;
pub use struc::*;
pub use trai::*;
pub use op::*;
pub use asm_fn::*;
pub use asm_block::*;
use super::*;

View File

@@ -1,35 +1,113 @@
use super::{
Function, Keyword, Node, Parsable, ParseResult, ParserError, ParserErrors, TokenCursor,
AsmFunction, Function, Impl, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
Struct, Symbol, Token, TokenCursor, Trait,
};
use std::fmt::Debug;
pub struct Module {
pub traits: Vec<Node<Trait>>,
pub structs: Vec<Node<Struct>>,
pub functions: Vec<Node<Function>>,
pub asm_fns: Vec<Node<AsmFunction>>,
pub impls: Vec<Node<Impl>>,
}
impl Parsable for Module {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
let mut functions = Vec::new();
let mut structs = Vec::new();
let mut traits = Vec::new();
let mut impls = Vec::new();
let mut asm_fns = Vec::new();
loop {
let Some(next) = cursor.peek() else {
return ParseResult::Ok(Self { functions });
break;
};
if next.is_keyword(Keyword::Fn) {
let res = Node::parse(cursor, errors);
functions.push(res.node);
if res.recover {
return ParseResult::Recover(Self { functions });
if let Token::Keyword(kw) = next.token {
match kw {
Keyword::Fn => {
let res = Node::parse(cursor, errors);
functions.push(res.node);
if res.recover {
break;
}
}
Keyword::Struct => {
let res = Node::parse(cursor, errors);
structs.push(res.node);
if res.recover {
break;
}
}
Keyword::Trait => {
let res = Node::parse(cursor, errors);
traits.push(res.node);
if res.recover {
break;
}
}
Keyword::Impl => {
let res = Node::parse(cursor, errors);
impls.push(res.node);
if res.recover {
break;
}
}
Keyword::Asm => {
let res = Node::parse(cursor, errors);
asm_fns.push(res.node);
if res.recover {
break;
}
}
_ => {
errors.err(ParserMsg::unexpected_token(next, "a definition"));
cursor.next();
}
}
} else if next.is_symbol(Symbol::Semicolon) {
errors.hint(ParserMsg::from_instances(
&[next],
"unneeded semicolon".to_string(),
));
cursor.next();
} else {
errors.add(ParserError::unexpected_token(next, "fn"));
errors.err(ParserMsg::unexpected_token(next, "a definition"));
cursor.next();
}
}
ParseResult::Ok(Self {
functions,
structs,
traits,
impls,
asm_fns,
})
}
}
impl Debug for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.functions.fmt(f)
for st in &self.structs {
st.fmt(f)?;
writeln!(f)?;
}
for t in &self.traits {
t.fmt(f)?;
writeln!(f)?;
}
for t in &self.impls {
t.fmt(f)?;
writeln!(f)?;
}
for func in &self.functions {
func.fmt(f)?;
writeln!(f)?;
}
for func in &self.asm_fns {
func.fmt(f)?;
writeln!(f)?;
}
Ok(())
}
}

View File

@@ -1,7 +1,7 @@
use super::{Symbol, Token};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BinaryOperator {
pub enum BinaryOp {
Add,
Sub,
Mul,
@@ -12,7 +12,7 @@ pub enum BinaryOperator {
Assign,
}
impl BinaryOperator {
impl BinaryOp {
pub fn presedence(&self) -> u32 {
match self {
Self::Assign => 0,
@@ -37,6 +37,39 @@ impl BinaryOperator {
Self::Assign => "=",
}
}
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 fn traitt(&self) -> &str {
match self {
Self::Add => "Add",
Self::Sub => "Sub",
Self::Mul => "Mul",
Self::Div => "Div",
Self::LessThan => "LessThan",
Self::GreaterThan => "GreaterThan",
Self::Access => "Access",
Self::Assign => "Assign",
}
}
}
pub enum UnaryOp {
Not,
Ref,
Deref,
}
impl BinaryOp {
pub fn from_token(token: &Token) -> Option<Self> {
let Token::Symbol(symbol) = token else {
return None;
@@ -55,30 +88,14 @@ impl BinaryOperator {
}
})
}
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 {
impl UnaryOp {
pub fn str(&self) -> &str {
match self {
Self::Not => "!",
Self::Ref => "&",
Self::Deref => "*",
}
}
pub fn from_token(token: &Token) -> Option<Self> {
@@ -88,6 +105,7 @@ impl UnaryOperator {
Some(match symbol {
Symbol::Ampersand => Self::Ref,
Symbol::Bang => Self::Not,
Symbol::Asterisk => Self::Deref,
_ => {
return None;
}

View File

@@ -1,23 +1,23 @@
use super::{
Expr, Ident, Keyword, Node, Parsable, ParseResult, ParserErrors, Symbol, Token, TokenCursor,
Expr, Keyword, Node, Parsable, ParseResult, ParserOutput, Symbol, Token, TokenCursor, VarDef,
};
use std::fmt::{Debug, Write};
pub enum Statement {
Let(Node<Ident>, Node<Expr>),
Let(Node<VarDef>, Node<Expr>),
Return(Node<Expr>),
Expr(Node<Expr>),
}
impl Parsable for Statement {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
match next.token {
Token::Keyword(Keyword::Let) => {
cursor.next();
let name = Node::parse(cursor, errors)?;
let def = Node::parse(cursor, errors)?;
cursor.expect_sym(Symbol::Equals)?;
Node::parse(cursor, errors).map(|expr| Self::Let(name, expr))
Node::parse(cursor, errors).map(|expr| Self::Let(def, expr))
}
Token::Keyword(Keyword::Return) => {
cursor.next();

View File

@@ -0,0 +1,45 @@
use std::fmt::Debug;
use super::{
util::parse_list, Ident, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
Symbol, TokenCursor, Type, VarDef,
};
#[derive(Debug)]
pub struct Struct {
pub name: Node<Ident>,
pub fields: StructFields,
}
#[derive(Debug)]
pub enum StructFields {
Named(Vec<Node<VarDef>>),
Tuple(Vec<Node<Type>>),
None,
}
impl Parsable for Struct {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
cursor.expect_kw(Keyword::Struct)?;
let name = Node::parse(cursor, errors)?;
let next = cursor.expect_peek()?;
let fields = if next.is_symbol(Symbol::Semicolon) {
cursor.next();
StructFields::None
} else if next.is_symbol(Symbol::OpenCurly) {
cursor.next();
StructFields::Named(parse_list(cursor, errors, Symbol::CloseCurly)?)
} else if next.is_symbol(Symbol::OpenParen) {
cursor.next();
StructFields::Tuple(parse_list(cursor, errors, Symbol::CloseParen)?)
} else {
errors.err(ParserMsg::unexpected_token(next, "`;`, `(`, or `{`"));
return ParseResult::Recover(Struct {
name,
fields: StructFields::None,
});
};
ParseResult::Ok(Struct { name, fields })
}
}

View File

@@ -0,0 +1,36 @@
use super::{util::{parse_list, parse_list_nosep}, Function, FunctionHeader, Ident, Keyword, Node, Parsable, Symbol, Type};
#[derive(Debug)]
pub struct Trait {
pub name: Node<Ident>,
pub fns: Vec<Node<FunctionHeader>>
}
#[derive(Debug)]
pub struct Impl {
pub trait_: Node<Type>,
pub for_: Node<Type>,
pub fns: Vec<Node<Function>>
}
impl Parsable for Trait {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> {
cursor.expect_kw(Keyword::Trait)?;
let name = Node::parse(cursor, errors)?;
cursor.expect_sym(Symbol::OpenCurly)?;
let fns = parse_list(cursor, errors, Symbol::CloseCurly)?;
super::ParseResult::Ok(Self {name, fns})
}
}
impl Parsable for Impl {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> super::ParseResult<Self> {
cursor.expect_kw(Keyword::Impl)?;
let trait_ = Node::parse(cursor, errors)?;
cursor.expect_kw(Keyword::For)?;
let for_ = Node::parse(cursor, errors)?;
cursor.expect_sym(Symbol::OpenCurly)?;
let fns = parse_list_nosep(cursor, errors, Symbol::CloseCurly)?;
super::ParseResult::Ok(Self {trait_, for_, fns})
}
}

61
src/parser/v3/nodes/ty.rs Normal file
View File

@@ -0,0 +1,61 @@
use std::fmt::Debug;
use super::{util::parse_list, Node, Parsable, ParseResult, ParserMsg, Symbol, Token};
pub struct Type {
pub name: String,
pub args: Vec<Node<Type>>,
}
impl Type {
pub fn unit() -> Self {
Self {
name: "()".to_string(),
args: Vec::new(),
}
}
}
impl Parsable for Type {
fn parse(
cursor: &mut super::TokenCursor,
errors: &mut super::ParserOutput,
) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
let res = if next.is_symbol(Symbol::Ampersand) {
cursor.next();
let arg = Node::parse(cursor, errors)?;
Self {
name: "&".to_string(),
args: vec![arg],
}
} else {
let Token::Word(name) = &next.token else {
return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier"));
};
let n = name.to_string();
cursor.next();
let mut args = Vec::new();
if let Some(next) = cursor.peek() {
if next.is_symbol(Symbol::OpenAngle) {
cursor.next();
args = parse_list(cursor, errors, Symbol::CloseAngle)?;
}
}
Self { name: n, args }
};
ParseResult::Ok(res)
}
}
impl Debug for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)?;
if self.name == "&" {
write!(f, "{:?}", self.args[0])?;
} else if !self.args.is_empty() {
write!(f, "<{:?}>", self.args)?;
}
Ok(())
}
}

View File

@@ -0,0 +1,57 @@
use super::{Node, Parsable, ParserMsg, ParserOutput, Symbol, TokenCursor};
pub fn parse_list_sep<T: Parsable>(
cursor: &mut TokenCursor,
errors: &mut ParserOutput,
sep: Symbol,
end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> {
let mut vals = Vec::new();
loop {
let next = cursor.expect_peek()?;
if next.is_symbol(end) {
break;
}
let res = Node::parse(cursor, errors);
vals.push(res.node);
if res.recover {
cursor.seek_syms(&[end, sep]);
}
let next = cursor.expect_peek()?;
if !next.is_symbol(sep) {
break;
}
cursor.next();
}
cursor.expect_sym(end)?;
Ok(vals)
}
pub fn parse_list<T: Parsable>(
cursor: &mut TokenCursor,
errors: &mut ParserOutput,
end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> {
parse_list_sep(cursor, errors, Symbol::Comma, end)
}
pub fn parse_list_nosep<T: Parsable>(
cursor: &mut TokenCursor,
errors: &mut ParserOutput,
end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> {
let mut vals = Vec::new();
loop {
let next = cursor.expect_peek()?;
if next.is_symbol(end) {
break;
}
let res = Node::parse(cursor, errors);
vals.push(res.node);
if res.recover {
cursor.seek_sym(end);
}
}
cursor.expect_sym(end)?;
Ok(vals)
}

View File

@@ -3,12 +3,14 @@ use std::{
ops::{ControlFlow, FromResidual, Try},
};
use super::{Node, ParserError, ParserErrors, TokenCursor};
use crate::ir::FilePos;
use super::{Node, ParserMsg, ParserOutput, TokenCursor};
pub enum ParseResult<T> {
Ok(T),
Recover(T),
Err(ParserError),
Err(ParserMsg),
SubErr,
}
@@ -23,18 +25,15 @@ impl<T> ParseResult<T> {
}
impl<T> Try for ParseResult<T> {
type Output = Result<T, T>;
type Residual = Option<ParserError>;
type Output = T;
type Residual = Option<ParserMsg>;
fn from_output(output: Self::Output) -> Self {
match output {
Ok(v) => Self::Ok(v),
Err(v) => Self::Recover(v),
}
Self::Ok(output)
}
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self {
ParseResult::Ok(v) => ControlFlow::Continue(Ok(v)),
ParseResult::Recover(v) => ControlFlow::Continue(Err(v)),
ParseResult::Ok(v) => ControlFlow::Continue(v),
ParseResult::Recover(v) => ControlFlow::Break(None),
ParseResult::Err(e) => ControlFlow::Break(Some(e)),
ParseResult::SubErr => ControlFlow::Break(None),
}
@@ -50,8 +49,8 @@ impl<T> FromResidual for ParseResult<T> {
}
}
impl<T> FromResidual<Result<Infallible, ParserError>> for ParseResult<T> {
fn from_residual(residual: Result<Infallible, ParserError>) -> Self {
impl<T> FromResidual<Result<Infallible, ParserMsg>> for ParseResult<T> {
fn from_residual(residual: Result<Infallible, ParserMsg>) -> Self {
match residual {
Err(e) => Self::Err(e),
}
@@ -112,24 +111,24 @@ impl<T> FromResidual for NodeParseResult<T> {
}
pub trait Parsable: Sized {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self>;
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self>;
}
pub trait MaybeParsable: Sized {
fn maybe_parse(
cursor: &mut TokenCursor,
errors: &mut ParserErrors,
) -> Result<Option<Self>, ParserError>;
errors: &mut ParserOutput,
) -> Result<Option<Self>, ParserMsg>;
}
impl<T: Parsable> Node<T> {
pub fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<T> {
let start = cursor.next_pos();
let (inner, recover) = match T::parse(cursor, errors) {
pub fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> NodeParseResult<T> {
let start = cursor.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
let (inner, recover) = match T::parse(cursor, output) {
ParseResult::Ok(v) => (Some(v), false),
ParseResult::Recover(v) => (Some(v), true),
ParseResult::Err(e) => {
errors.add(e);
output.err(e);
(None, true)
}
ParseResult::SubErr => (None, true),
@@ -146,12 +145,12 @@ impl<T: Parsable> Node<T> {
}
impl<T: MaybeParsable> Node<T> {
pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> Option<Self> {
pub fn maybe_parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> Option<Self> {
let start = cursor.next_pos();
let inner = match T::maybe_parse(cursor, errors) {
Ok(v) => Some(v?),
Err(e) => {
errors.add(e);
errors.err(e);
None
}
};
@@ -164,12 +163,12 @@ impl<T: MaybeParsable> Node<T> {
}
pub trait NodeParsable {
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<Self>
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self>
where
Self: Sized;
}
impl<T: Parsable> NodeParsable for T {
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> NodeParseResult<Self>
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self>
where
Self: Sized,
{

View File

@@ -1,7 +1,7 @@
use std::{iter::Peekable, str::Chars};
use super::super::ParserError;
use super::FilePos;
use crate::ir::FilePos;
use super::super::ParserMsg;
pub struct CharCursor<'a> {
chars: Peekable<Chars<'a>>,
@@ -15,12 +15,12 @@ impl CharCursor<'_> {
self.advance();
Some(res)
}
pub fn expect(&mut self, c: char) -> Result<(), ParserError> {
pub fn expect(&mut self, c: char) -> Result<(), ParserMsg> {
let next = self.expect_next()?;
if next == c {
Ok(())
} else {
Err(ParserError::at(
Err(ParserMsg::at(
self.prev_pos,
format!("unexpected char '{next}'; expected '{c}'"),
))
@@ -46,8 +46,8 @@ impl CharCursor<'_> {
self.next_pos.col += 1;
}
}
pub fn expect_next(&mut self) -> Result<char, ParserError> {
self.next().ok_or(ParserError::unexpected_end())
pub fn expect_next(&mut self) -> Result<char, ParserMsg> {
self.next().ok_or(ParserMsg::unexpected_end())
}
pub fn next_pos(&self) -> FilePos {
self.next_pos

View File

@@ -1,80 +0,0 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FilePos {
pub line: usize,
pub col: usize,
}
#[derive(Debug, Clone, Copy)]
pub struct FileSpan {
pub start: FilePos,
pub end: FilePos,
}
impl FilePos {
pub fn start() -> Self {
Self { line: 0, col: 0 }
}
}
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 = 0;
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;
let mut lines = file.lines().skip(start);
let width = format!("{}", self.end.line + AFTER).len();
let same_line = self.start.line == self.end.line;
for i in 0..num_before {
writeln!(writer, "{:>width$} | {}", start + i, lines.next().unwrap())?;
}
let line = lines.next().unwrap();
writeln!(writer, "{:>width$} | {}", self.start.line, line)?;
let len = if same_line {
self.end.col - self.start.col + 1
} else {
line.len() - self.start.col
};
writeln!(
writer,
"{} | {}",
" ".repeat(width),
" ".repeat(self.start.col) + &"^".repeat(len)
)?;
if !same_line {
for _ in 0..self.end.line - self.start.line - 1 {
lines.next();
}
let line = lines.next().unwrap();
writeln!(writer, "{:>width$} | {}", self.end.line, line)?;
writeln!(
writer,
"{} | {}",
" ".repeat(width),
"^".repeat(self.end.col + 1)
)?;
}
// for i in 0..AFTER {
// if let Some(next) = lines.next() {
// writeln!(writer, "{:>width$} | {}", self.end.line + i + 1, next)?;
// }
// }
Ok(())
}
}

View File

@@ -4,15 +4,25 @@ pub enum Keyword {
Let,
If,
Return,
Struct,
Trait,
Impl,
For,
Asm,
}
impl Keyword {
pub fn from_string(str: &str) -> Option<Self> {
Some(match str {
"fn" => Self::Fn,
"struct" => Self::Struct,
"let" => Self::Let,
"if" => Self::If,
"for" => Self::For,
"return" => Self::Return,
"trait" => Self::Trait,
"impl" => Self::Impl,
"asm" => Self::Asm,
_ => return None,
})
}

View File

@@ -1,19 +1,19 @@
mod cursor;
mod file;
mod keyword;
mod symbol;
use std::ops::Deref;
pub use cursor::*;
pub use file::*;
pub use keyword::*;
pub use symbol::*;
use crate::ir::FileSpan;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Token {
Symbol(Symbol),
Ident(String),
Word(String),
Keyword(Keyword),
}
@@ -51,7 +51,7 @@ impl TokenInstance {
let token = if let Some(keyword) = Keyword::from_string(&word) {
Token::Keyword(keyword)
} else {
Token::Ident(word)
Token::Word(word)
};
Some(Self {
token,

View File

@@ -17,6 +17,7 @@ pub enum Symbol {
Slash,
DoubleSlash,
Dot,
DoubleDot,
OpenParen,
CloseParen,
OpenCurly,
@@ -100,6 +101,10 @@ impl Symbol {
'&' => Self::DoublePipe,
_ => return,
},
Self::Dot => match next {
'.' => Self::DoubleDot,
_ => return,
}
_ => return,
};
cursor.advance();
@@ -119,6 +124,7 @@ impl Symbol {
Self::Slash => "/",
Self::DoubleSlash => "//",
Self::Dot => ".",
Self::DoubleDot => "..",
Self::OpenParen => "(",
Self::CloseParen => ")",
Self::OpenCurly => "{",