actually compiles and does stuff now
This commit is contained in:
55
src/parser/v3/ctx.rs
Normal file
55
src/parser/v3/ctx.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use super::{MaybeParsable, Node, NodeParseResult, Parsable, ParserMsg, ParserOutput, TokenCursor};
|
||||
|
||||
pub struct ParserCtx<'a> {
|
||||
pub cursor: TokenCursor<'a>,
|
||||
pub output: ParserOutput,
|
||||
}
|
||||
|
||||
impl<'a> Deref for ParserCtx<'a> {
|
||||
type Target = TokenCursor<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cursor
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ParserCtx<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.cursor
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ParserCtx<'a> {
|
||||
pub fn err(&mut self, msg: ParserMsg) {
|
||||
self.output.err(msg);
|
||||
}
|
||||
pub fn hint(&mut self, msg: ParserMsg) {
|
||||
self.output.hint(msg);
|
||||
}
|
||||
pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> {
|
||||
Node::parse(self)
|
||||
}
|
||||
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
|
||||
Node::maybe_parse(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<TokenCursor<'a>> for ParserCtx<'a> {
|
||||
fn from(cursor: TokenCursor<'a>) -> Self {
|
||||
Self {
|
||||
cursor,
|
||||
output: ParserOutput::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for ParserCtx<'a> {
|
||||
fn from(string: &'a str) -> Self {
|
||||
Self {
|
||||
cursor: TokenCursor::from(string),
|
||||
output: ParserOutput::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,23 @@ use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
||||
pub struct TokenCursor<'a> {
|
||||
cursor: CharCursor<'a>,
|
||||
next: Option<TokenInstance>,
|
||||
next_pos: FilePos,
|
||||
next_start: FilePos,
|
||||
prev_end: FilePos,
|
||||
}
|
||||
|
||||
impl<'a> TokenCursor<'a> {
|
||||
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))
|
||||
self.prev_end = self
|
||||
.next
|
||||
.as_ref()
|
||||
.map(|i| i.span.end)
|
||||
.unwrap_or(FilePos::start());
|
||||
let next = TokenInstance::parse(&mut self.cursor);
|
||||
self.next_start = next
|
||||
.as_ref()
|
||||
.map(|i| i.span.end)
|
||||
.unwrap_or(FilePos::start());
|
||||
std::mem::replace(&mut self.next, next)
|
||||
}
|
||||
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserMsg> {
|
||||
self.peek().ok_or(ParserMsg::unexpected_end())?;
|
||||
@@ -31,11 +39,11 @@ impl<'a> TokenCursor<'a> {
|
||||
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> {
|
||||
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 next_on_new_line(&mut self) -> bool {
|
||||
self.next_start.line != self.prev_end.line
|
||||
}
|
||||
pub fn seek_sym(&mut self, sym: Symbol) {
|
||||
while self.next().is_some_and(|n| !n.is_symbol(sym)) {}
|
||||
}
|
||||
pub fn seek_syms(&mut self, syms: &[Symbol]) {
|
||||
while self
|
||||
@@ -45,6 +53,9 @@ impl<'a> TokenCursor<'a> {
|
||||
self.next();
|
||||
}
|
||||
}
|
||||
pub fn seek_sym_on_line(&mut self, sym: Symbol) {
|
||||
while !self.next_on_new_line() && self.next().is_some_and(|n| !n.is_symbol(sym)) {}
|
||||
}
|
||||
pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> {
|
||||
loop {
|
||||
if f(self.peek()?) {
|
||||
@@ -68,8 +79,8 @@ impl<'a> TokenCursor<'a> {
|
||||
pub fn prev_end(&self) -> FilePos {
|
||||
self.prev_end
|
||||
}
|
||||
pub fn next_pos(&self) -> FilePos {
|
||||
self.next_pos
|
||||
pub fn next_start(&self) -> FilePos {
|
||||
self.next_start
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +96,7 @@ impl<'a> From<CharCursor<'a>> for TokenCursor<'a> {
|
||||
Self {
|
||||
cursor,
|
||||
next: cur,
|
||||
next_pos: FilePos::start(),
|
||||
next_start: FilePos::start(),
|
||||
prev_end: FilePos::start(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::ir::{FilePos, FileSpan};
|
||||
|
||||
use super::{token::TokenInstance, Ident, Node};
|
||||
use super::{token::TokenInstance, PIdent, Node};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParserMsg {
|
||||
@@ -32,9 +32,9 @@ impl ParserMsg {
|
||||
spans: vec![span],
|
||||
}
|
||||
}
|
||||
pub fn identifier_not_found(id: &Node<Ident>) -> Self {
|
||||
pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
|
||||
Self {
|
||||
msg: format!("Identifier '{}' not found", id.as_ref().unwrap().val()),
|
||||
msg: format!("Identifier '{}' not found", id.as_ref().unwrap()),
|
||||
spans: vec![id.span],
|
||||
}
|
||||
}
|
||||
@@ -71,11 +71,11 @@ impl ParserOutput {
|
||||
hints: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn err(&mut self, err: ParserMsg) {
|
||||
self.errs.push(err);
|
||||
pub fn err(&mut self, msg: ParserMsg) {
|
||||
self.errs.push(msg);
|
||||
}
|
||||
pub fn hint(&mut self, err: ParserMsg) {
|
||||
self.hints.push(err);
|
||||
pub fn hint(&mut self, msg: ParserMsg) {
|
||||
self.hints.push(msg);
|
||||
}
|
||||
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
|
||||
for err in &self.errs {
|
||||
|
||||
2
src/parser/v3/lower/arch/mod.rs
Normal file
2
src/parser/v3/lower/arch/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod riscv64;
|
||||
pub use super::*;
|
||||
109
src/parser/v3/lower/arch/riscv64.rs
Normal file
109
src/parser/v3/lower/arch/riscv64.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
use super::{PAsmArg, FnLowerCtx, PIdent, Node, PInstruction};
|
||||
use crate::{
|
||||
compiler::arch::riscv64::*,
|
||||
ir::{
|
||||
arch::riscv64::{RV64Instruction, RegRef},
|
||||
VarID,
|
||||
},
|
||||
};
|
||||
|
||||
impl RV64Instruction {
|
||||
pub fn parse(inst: &PInstruction, ctx: &mut FnLowerCtx) -> Option<Self> {
|
||||
let args = &inst.args[..];
|
||||
Some(match &**inst.op.inner.as_ref()? {
|
||||
"ecall" => Self::Ecall,
|
||||
"li" => {
|
||||
let [dest, imm] = args else {
|
||||
ctx.err("li requires 2 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let imm = i64_from_arg(imm, ctx)?;
|
||||
Self::Li { dest, imm }
|
||||
}
|
||||
"la" => {
|
||||
let [dest, src] = args else {
|
||||
ctx.err("la requires 2 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let src = arg_to_var(src, ctx)?;
|
||||
Self::La { dest, src }
|
||||
}
|
||||
"ld" => {
|
||||
let [dest, offset, base] = args else {
|
||||
ctx.err("ld requires 3 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let offset = i64_from_arg(offset, ctx)?;
|
||||
let base = RegRef::from_arg(base, ctx)?;
|
||||
Self::Ld { dest, offset, base }
|
||||
}
|
||||
"mv" => {
|
||||
let [dest, src] = args else {
|
||||
ctx.err("la requires 2 arguments".to_string());
|
||||
return None;
|
||||
};
|
||||
let dest = RegRef::from_arg(dest, ctx)?;
|
||||
let src = RegRef::from_arg(src, ctx)?;
|
||||
Self::Mv { dest, src }
|
||||
}
|
||||
w => {
|
||||
ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w));
|
||||
return None;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
||||
let PAsmArg::Ref(node) = node.inner.as_ref()? else {
|
||||
ctx.err_at(
|
||||
node.span,
|
||||
"Expected variable / function reference".to_string(),
|
||||
);
|
||||
return None;
|
||||
};
|
||||
ctx.get_var(node)
|
||||
}
|
||||
|
||||
impl RegRef {
|
||||
pub fn from_arg(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<Self> {
|
||||
Some(match node.inner.as_ref()? {
|
||||
PAsmArg::Value(node) => {
|
||||
let Some(reg) = Reg::from_ident(node, ctx) else {
|
||||
return None;
|
||||
};
|
||||
Self::Reg(reg)
|
||||
}
|
||||
PAsmArg::Ref(node) => Self::Var(ctx.get_var(node)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
pub fn from_ident(node: &Node<PIdent>, ctx: &mut FnLowerCtx) -> Option<Self> {
|
||||
let s = &**node.inner.as_ref()?;
|
||||
let res = Reg::from_str(s);
|
||||
if res.is_none() {
|
||||
ctx.err_at(node.span, format!("Unknown reg name '{}'", s));
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
fn i64_from_arg(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<i64> {
|
||||
let PAsmArg::Value(node) = node.inner.as_ref()? else {
|
||||
ctx.err_at(node.span, format!("Expected an i64, found reference"));
|
||||
return None;
|
||||
};
|
||||
let word = node.inner.as_ref()?;
|
||||
match word.parse::<i64>() {
|
||||
Ok(x) => Some(x),
|
||||
Err(_) => {
|
||||
ctx.err_at(node.span, format!("Expected an i64, found {}", word));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/parser/v3/lower/asm.rs
Normal file
53
src/parser/v3/lower/asm.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use crate::{
|
||||
compiler::arch::riscv64::Reg,
|
||||
ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarID},
|
||||
};
|
||||
|
||||
use super::{PAsmBlock, PAsmBlockArg, FnLowerCtx, FnLowerable, PInstruction};
|
||||
|
||||
impl FnLowerable for PInstruction {
|
||||
type Output = RV64Instruction;
|
||||
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<RV64Instruction> {
|
||||
RV64Instruction::parse(self, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl FnLowerable for PAsmBlock {
|
||||
type Output = ();
|
||||
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
||||
let block = IRUInstruction::AsmBlock {
|
||||
instructions: {
|
||||
let mut v = Vec::new();
|
||||
for i in &self.instructions {
|
||||
if let Some(i) = i.lower(ctx) {
|
||||
v.push(i);
|
||||
}
|
||||
}
|
||||
v
|
||||
},
|
||||
args: {
|
||||
let mut v = Vec::new();
|
||||
for a in &self.args {
|
||||
if let Some(a) = a.lower(ctx) {
|
||||
v.push(a);
|
||||
}
|
||||
}
|
||||
v
|
||||
},
|
||||
};
|
||||
ctx.push(block);
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FnLowerable for PAsmBlockArg {
|
||||
type Output = (Reg, VarID);
|
||||
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
||||
let var = ctx.get_var(&self.var)?;
|
||||
let reg = Reg::from_ident(&self.reg, ctx)?;
|
||||
Some((reg, var))
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
use crate::ir::Instruction;
|
||||
use crate::ir::{IRUInstruction, VarID};
|
||||
|
||||
use super::{Block, ExprResult, FnLowerCtx, Node, Statement};
|
||||
use super::{PBlock, FnLowerCtx, FnLowerable, PStatement};
|
||||
|
||||
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> {
|
||||
impl FnLowerable for PBlock {
|
||||
type Output = VarID;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
||||
let ctx = &mut ctx.sub();
|
||||
for statement in &self.statements {
|
||||
statement.lower(ctx);
|
||||
@@ -18,41 +13,24 @@ impl Block {
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
impl FnLowerable for PStatement {
|
||||
type Output = VarID;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
||||
match self {
|
||||
super::Statement::Let(def, e) => {
|
||||
super::PStatement::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!(),
|
||||
}
|
||||
ctx.map.name_var(&def, res);
|
||||
}
|
||||
None
|
||||
}
|
||||
super::Statement::Return(e) => {
|
||||
let res = e.lower(ctx)?;
|
||||
match res {
|
||||
ExprResult::Var(v) => ctx.push(Instruction::Ret { src: v }),
|
||||
_ => todo!(),
|
||||
}
|
||||
super::PStatement::Return(e) => {
|
||||
let src = e.lower(ctx)?;
|
||||
ctx.push(IRUInstruction::Ret { src });
|
||||
None
|
||||
}
|
||||
super::Statement::Expr(e) => e.lower(ctx),
|
||||
super::PStatement::Expr(e) => e.lower(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef};
|
||||
|
||||
use super::{Node, ParserMsg, ParserOutput, Type as PType, VarDef as PVarDef};
|
||||
use super::{Node, ParserMsg, ParserOutput, PType, PVarDef};
|
||||
|
||||
impl Node<PVarDef> {
|
||||
pub fn lower(
|
||||
@@ -9,7 +9,7 @@ impl Node<PVarDef> {
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<VarDef> {
|
||||
let s = self.as_ref()?;
|
||||
let name = s.name.as_ref()?.val().clone();
|
||||
let name = s.name.as_ref()?.to_string();
|
||||
let ty = match &s.ty {
|
||||
Some(ty) => ty.lower(namespace, output),
|
||||
None => Type::Infer,
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
use super::{func::FnLowerCtx, Expr as PExpr, Node, UnaryOp};
|
||||
use crate::ir::{FnIdent, Instruction, Type, VarIdent, VarOrFnIdent};
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||
use crate::ir::{IRUInstruction, Type, VarID};
|
||||
|
||||
impl PExpr {
|
||||
pub fn lower(&self, ctx: &mut FnLowerCtx) -> Option<ExprResult> {
|
||||
impl FnLowerable for PExpr {
|
||||
type Output = VarID;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
||||
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 => {
|
||||
super::PLiteral::String(s) => {
|
||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf());
|
||||
let src = ctx.map.def_data(s.as_bytes().to_vec());
|
||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Char(c) => {
|
||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf());
|
||||
let src = ctx.map.def_data(c.to_string().as_bytes().to_vec());
|
||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::Number(n) => {
|
||||
// TODO: temp
|
||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).arr().rf());
|
||||
let src = ctx
|
||||
.map
|
||||
.def_data(n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec());
|
||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||
dest
|
||||
}
|
||||
super::PLiteral::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::Ident(i) => ctx.get_var(i)?,
|
||||
PExpr::BinaryOp(op, e1, e2) => {
|
||||
let res1 = e1.lower(ctx)?;
|
||||
let res2 = e2.lower(ctx)?;
|
||||
@@ -36,101 +41,50 @@ impl PExpr {
|
||||
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());
|
||||
UnaryOp::Ref => {
|
||||
let temp = ctx.temp(ctx.map.get_var(res).ty.clone());
|
||||
ctx.push(IRUInstruction::Ref {
|
||||
dest: temp,
|
||||
src: res,
|
||||
});
|
||||
temp
|
||||
}
|
||||
UnaryOp::Deref => {
|
||||
let t = &ctx.map.get_var(res).ty;
|
||||
let Type::Ref(inner) = t else {
|
||||
ctx.err(format!(
|
||||
"Cannot dereference type {:?}",
|
||||
ctx.map.type_name(t)
|
||||
));
|
||||
return None;
|
||||
}
|
||||
},
|
||||
};
|
||||
todo!();
|
||||
}
|
||||
UnaryOp::Not => todo!(),
|
||||
}
|
||||
}
|
||||
PExpr::Block(b) => b.lower(ctx)?,
|
||||
PExpr::AsmBlock(b) => {
|
||||
ctx.push(Instruction::AsmBlock {
|
||||
instructions: b.as_ref()?.instructions.clone(),
|
||||
});
|
||||
b.lower(ctx);
|
||||
return None;
|
||||
}
|
||||
PExpr::Call(e, args) => {
|
||||
let fe = e.lower(ctx)?;
|
||||
let f = 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;
|
||||
}
|
||||
nargs.push(arg);
|
||||
}
|
||||
let temp = ctx.temp(ctx.map.get_fn_var(f).ret.clone());
|
||||
ctx.push(IRUInstruction::Call {
|
||||
dest: temp,
|
||||
f,
|
||||
args: nargs,
|
||||
});
|
||||
// ctx.err(format!("Expected function, found {:?}", f));
|
||||
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),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use super::{Function as PFunction, Node, ParserMsg, ParserOutput};
|
||||
use crate::ir::{
|
||||
BuiltinType, FileSpan, FnDef, FnIdent, Function, Idents, Instruction, Instructions,
|
||||
NamespaceGuard, Origin, Type, VarDef, VarIdent,
|
||||
use super::{FnLowerable, PFunction, Node, ParserMsg, ParserOutput};
|
||||
use crate::{
|
||||
ir::{
|
||||
BuiltinType, FileSpan, FnDef, FnID, IRUFunction, Idents, IRUInstruction, IRInstructions,
|
||||
NamespaceGuard, Origin, Type, VarDef, VarID,
|
||||
},
|
||||
parser,
|
||||
};
|
||||
|
||||
impl Node<PFunction> {
|
||||
@@ -9,15 +12,16 @@ impl Node<PFunction> {
|
||||
&self,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<FnIdent> {
|
||||
) -> Option<FnID> {
|
||||
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
|
||||
}
|
||||
pub fn lower_body(
|
||||
&self,
|
||||
id: FnID,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<IRUFunction> {
|
||||
Some(self.as_ref()?.lower_body(id, map, output))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +30,7 @@ impl PFunction {
|
||||
&self,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> Option<FnIdent> {
|
||||
) -> Option<FnID> {
|
||||
let header = self.header.as_ref()?;
|
||||
let name = header.name.as_ref()?;
|
||||
let args = header
|
||||
@@ -44,50 +48,145 @@ impl PFunction {
|
||||
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(),
|
||||
name: name.to_string(),
|
||||
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();
|
||||
pub fn lower_body(
|
||||
&self,
|
||||
id: FnID,
|
||||
map: &mut NamespaceGuard,
|
||||
output: &mut ParserOutput,
|
||||
) -> IRUFunction {
|
||||
let mut instructions = IRInstructions::new();
|
||||
let def = map.get_fn(id).clone();
|
||||
let args = def.args.iter().map(|a| {
|
||||
map.named_var(a.clone())
|
||||
}).collect();
|
||||
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!(),
|
||||
}
|
||||
if let Some(src) = self.body.lower(&mut ctx) {
|
||||
instructions.push(IRUInstruction::Ret { src });
|
||||
}
|
||||
Function::new(instructions)
|
||||
IRUFunction::new(def.name.clone(), args, instructions)
|
||||
}
|
||||
}
|
||||
|
||||
// impl Node<AsmFunction> {
|
||||
// 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> {
|
||||
// Some(self.as_ref()?.lower_body(map, output))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl AsmFunction {
|
||||
// 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()),
|
||||
// // };
|
||||
// let ret = Type::Concrete(BuiltinType::Unit.id());
|
||||
// Some(map.def_fn(FnDef {
|
||||
// name: name.to_string(),
|
||||
// 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,
|
||||
// };
|
||||
// self.body.lower(&mut ctx);
|
||||
// Function::new(instructions)
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct FnLowerCtx<'a, 'n> {
|
||||
pub map: &'a mut NamespaceGuard<'n>,
|
||||
pub instructions: &'a mut Instructions,
|
||||
pub instructions: &'a mut IRInstructions,
|
||||
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)
|
||||
impl<'n> FnLowerCtx<'_, 'n> {
|
||||
pub fn span<'b>(&'b mut self, span: FileSpan) -> FnLowerCtx<'b, 'n> {
|
||||
FnLowerCtx {
|
||||
map: self.map,
|
||||
instructions: self.instructions,
|
||||
output: self.output,
|
||||
span,
|
||||
}
|
||||
}
|
||||
pub fn get(&mut self, node: &Node<parser::PIdent>) -> Option<Idents> {
|
||||
let name = node.inner.as_ref()?;
|
||||
let res = self.map.get(name);
|
||||
if res.is_none() {
|
||||
self.err_at(node.span, format!("Identifier '{}' not found", name));
|
||||
}
|
||||
res
|
||||
}
|
||||
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarID> {
|
||||
let ids = self.get(node)?;
|
||||
if ids.var.is_none() {
|
||||
self.err_at(
|
||||
node.span,
|
||||
format!(
|
||||
"Variable '{}' not found; Type found but cannot be used here",
|
||||
node.inner.as_ref()?
|
||||
),
|
||||
);
|
||||
}
|
||||
ids.var
|
||||
}
|
||||
pub fn err(&mut self, msg: String) {
|
||||
self.output.err(ParserMsg::from_span(self.span, msg))
|
||||
}
|
||||
pub fn temp(&mut self, ty: Type) -> VarIdent {
|
||||
pub fn err_at(&mut self, span: FileSpan, msg: String) {
|
||||
self.output.err(ParserMsg::from_span(span, msg))
|
||||
}
|
||||
pub fn temp(&mut self, ty: Type) -> VarID {
|
||||
self.map.temp_var(self.span, ty)
|
||||
}
|
||||
pub fn push(&mut self, i: Instruction) {
|
||||
pub fn push(&mut self, i: IRUInstruction) {
|
||||
self.instructions.push(i);
|
||||
}
|
||||
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
|
||||
|
||||
@@ -1,12 +1,30 @@
|
||||
mod asm;
|
||||
mod block;
|
||||
mod def;
|
||||
mod expr;
|
||||
mod func;
|
||||
mod module;
|
||||
mod arch;
|
||||
|
||||
use super::*;
|
||||
use block::*;
|
||||
use def::*;
|
||||
use expr::*;
|
||||
use func::*;
|
||||
use module::*;
|
||||
|
||||
pub use func::FnLowerCtx;
|
||||
|
||||
pub trait FnLowerable {
|
||||
type Output;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output>;
|
||||
}
|
||||
|
||||
impl<T: FnLowerable> FnLowerable for Node<T> {
|
||||
type Output = T::Output;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
|
||||
self.as_ref()?.lower(&mut ctx.span(self.span))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FnLowerable> FnLowerable for Box<T> {
|
||||
type Output = T::Output;
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<T::Output> {
|
||||
self.as_ref().lower(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::ir::NamespaceGuard;
|
||||
|
||||
use super::{Module, ParserOutput};
|
||||
use super::{PModule, ParserOutput};
|
||||
|
||||
impl Module {
|
||||
impl PModule {
|
||||
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) {
|
||||
let mut fns = Vec::new();
|
||||
for f in &self.functions {
|
||||
@@ -13,8 +13,10 @@ impl Module {
|
||||
}
|
||||
}
|
||||
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);
|
||||
if let Some(id) = id {
|
||||
if let Some(res) = f.lower_body(id, map, output) {
|
||||
map.write_fn(id, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ mod node;
|
||||
mod nodes;
|
||||
mod parse;
|
||||
mod token;
|
||||
mod ctx;
|
||||
|
||||
pub use cursor::*;
|
||||
pub use error::*;
|
||||
@@ -13,3 +14,4 @@ pub use node::*;
|
||||
pub use nodes::*;
|
||||
pub use parse::*;
|
||||
pub use token::*;
|
||||
pub use ctx::*;
|
||||
|
||||
@@ -1,23 +1,59 @@
|
||||
use crate::compiler::riscv64::AsmInstruction;
|
||||
use super::{
|
||||
util::parse_list, PIdent, Node, Parsable, ParseResult, PInstruction, ParserCtx, Symbol,
|
||||
};
|
||||
|
||||
use super::{Parsable, ParseResult, Symbol};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsmBlock {
|
||||
pub instructions: Vec<AsmInstruction>,
|
||||
pub struct PAsmBlock {
|
||||
pub instructions: Vec<Node<PInstruction>>,
|
||||
pub args: Vec<Node<PAsmBlockArg>>,
|
||||
}
|
||||
|
||||
impl Parsable for AsmBlock {
|
||||
fn parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
output: &mut super::ParserOutput,
|
||||
) -> ParseResult<Self> {
|
||||
cursor.expect_sym(Symbol::OpenCurly)?;
|
||||
pub struct PAsmBlockArg {
|
||||
pub reg: Node<PIdent>,
|
||||
pub var: Node<PIdent>,
|
||||
}
|
||||
|
||||
impl Parsable for PAsmBlock {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let args = if ctx.expect_peek()?.is_symbol(Symbol::OpenParen) {
|
||||
ctx.next();
|
||||
parse_list(ctx, Symbol::CloseParen)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
let mut instructions = Vec::new();
|
||||
while !cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
instructions.push(AsmInstruction::parse(cursor, output)?);
|
||||
while !ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
let res = ctx.parse();
|
||||
instructions.push(res.node);
|
||||
if res.recover {
|
||||
ctx.seek_sym_on_line(Symbol::CloseCurly);
|
||||
}
|
||||
}
|
||||
cursor.expect_sym(Symbol::CloseCurly)?;
|
||||
ParseResult::Ok(Self { instructions })
|
||||
ctx.expect_sym(Symbol::CloseCurly)?;
|
||||
ParseResult::Ok(Self { instructions, args })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for PAsmBlockArg {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let reg = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::Equals)?;
|
||||
let var = ctx.parse()?;
|
||||
ParseResult::Ok(Self { reg, var })
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PAsmBlock {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("asm {")?;
|
||||
for i in &self.instructions {
|
||||
f.write_str("\n ")?;
|
||||
i.fmt(f)?;
|
||||
}
|
||||
if !self.instructions.is_empty() {
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
f.write_str("}")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,63 @@
|
||||
use crate::compiler::riscv64::{AsmInstruction, Reg};
|
||||
|
||||
use super::{
|
||||
util::parse_list, AsmBlock, Ident, Keyword, Node, Parsable, ParseResult, SelfVar, Symbol,
|
||||
util::parse_list, PAsmBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, PType, PVarDef,
|
||||
};
|
||||
|
||||
#[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 })
|
||||
}
|
||||
}
|
||||
// #[derive(Debug)]
|
||||
// pub struct AsmFunctionHeader {
|
||||
// pub name: Node<Ident>,
|
||||
// pub args: Vec<Node<AsmVarDef>>,
|
||||
// }
|
||||
//
|
||||
// #[derive(Debug)]
|
||||
// pub struct AsmFunction {
|
||||
// pub header: Node<AsmFunctionHeader>,
|
||||
// pub body: Node<AsmBlock>,
|
||||
// }
|
||||
//
|
||||
// impl Parsable for AsmFunctionHeader {
|
||||
// fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
// ctx.expect_kw(Keyword::Asm)?;
|
||||
// ctx.expect_kw(Keyword::Fn)?;
|
||||
// let name = ctx.parse()?;
|
||||
// ctx.expect_sym(Symbol::OpenParen)?;
|
||||
// let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
// ParseResult::Ok(Self { name, args })
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Parsable for AsmFunction {
|
||||
// fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
// let header = ctx.parse()?;
|
||||
// let body = ctx.parse()?;
|
||||
// ParseResult::Ok(Self { header, body })
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub struct AsmVarDef {
|
||||
// pub reg: Node<Ident>,
|
||||
// pub name: Node<Ident>,
|
||||
// pub ty: Option<Node<Type>>,
|
||||
// }
|
||||
//
|
||||
// impl Parsable for AsmVarDef {
|
||||
// fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
// let reg = ctx.parse()?;
|
||||
// let name = ctx.parse()?;
|
||||
// if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
// ctx.next();
|
||||
// ctx.parse().map(|ty| Self { reg, name, ty: Some(ty) })
|
||||
// } else {
|
||||
// ParseResult::Ok(Self { reg, name, ty: None })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl std::fmt::Debug for AsmVarDef {
|
||||
// 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(())
|
||||
// }
|
||||
// }
|
||||
|
||||
82
src/parser/v3/nodes/asm_instr.rs
Normal file
82
src/parser/v3/nodes/asm_instr.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
use super::{PIdent, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol};
|
||||
|
||||
pub struct PInstruction {
|
||||
pub op: Node<PIdent>,
|
||||
pub args: Vec<Node<PAsmArg>>,
|
||||
}
|
||||
|
||||
pub enum PAsmArg {
|
||||
Value(Node<PIdent>),
|
||||
Ref(Node<PIdent>),
|
||||
}
|
||||
|
||||
impl Parsable for PInstruction {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let op = ctx.parse()?;
|
||||
let mut args = Vec::new();
|
||||
if !ctx.next_on_new_line() {
|
||||
let arg = ctx.parse()?;
|
||||
args.push(arg);
|
||||
loop {
|
||||
if ctx.next_on_new_line() {
|
||||
break;
|
||||
}
|
||||
ctx.expect_sym(Symbol::Comma)?;
|
||||
let arg = ctx.parse()?;
|
||||
args.push(arg);
|
||||
}
|
||||
}
|
||||
ParseResult::Ok(Self { op, args })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for PAsmArg {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
if let Some(ident) = ctx.maybe_parse() {
|
||||
return ParseResult::Ok(Self::Value(ident));
|
||||
}
|
||||
|
||||
let next = ctx.expect_peek()?;
|
||||
if !next.is_symbol(Symbol::OpenCurly) {
|
||||
return ParseResult::Err(ParserMsg::unexpected_token(
|
||||
next,
|
||||
"An identifier or {identifier}",
|
||||
));
|
||||
}
|
||||
ctx.next();
|
||||
|
||||
let res = ctx.parse();
|
||||
if res.recover {
|
||||
ctx.seek_sym(Symbol::CloseCurly);
|
||||
return ParseResult::SubErr;
|
||||
}
|
||||
|
||||
ctx.expect_sym(Symbol::CloseCurly)?;
|
||||
ParseResult::Ok(Self::Ref(res.node))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PAsmArg {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Value(v) => v.fmt(f),
|
||||
Self::Ref(r) => write!(f, "{{{:?}}}", r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PInstruction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.op.fmt(f)?;
|
||||
let mut iter = self.args.iter();
|
||||
if let Some(arg) = iter.next() {
|
||||
f.write_str(" ")?;
|
||||
arg.fmt(f)?;
|
||||
}
|
||||
for arg in iter {
|
||||
f.write_str(", ")?;
|
||||
arg.fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,52 @@
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use super::{
|
||||
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserMsg, ParserOutput, Statement,
|
||||
TokenCursor,
|
||||
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement,
|
||||
};
|
||||
use crate::util::Padder;
|
||||
|
||||
pub struct Block {
|
||||
pub statements: Vec<Node<Statement>>,
|
||||
pub result: Option<Node<Box<Statement>>>,
|
||||
pub struct PBlock {
|
||||
pub statements: Vec<Node<PStatement>>,
|
||||
pub result: Option<Node<Box<PStatement>>>,
|
||||
}
|
||||
|
||||
impl Parsable for Block {
|
||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||
impl Parsable for PBlock {
|
||||
fn parse(ctx: &mut ParserCtx) -> 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();
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
if ctx.expect_peek()?.is_symbol(Symbol::CloseCurly) {
|
||||
ctx.next();
|
||||
return ParseResult::Ok(Self { statements, result });
|
||||
}
|
||||
let mut expect_semi = false;
|
||||
let mut recover = false;
|
||||
loop {
|
||||
let Some(next) = cursor.peek() else {
|
||||
let Some(next) = ctx.peek() else {
|
||||
recover = true;
|
||||
errors.err(ParserMsg::unexpected_end());
|
||||
ctx.err(ParserMsg::unexpected_end());
|
||||
break;
|
||||
};
|
||||
if next.is_symbol(Symbol::CloseCurly) {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
break;
|
||||
}
|
||||
if next.is_symbol(Symbol::Semicolon) {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
expect_semi = false;
|
||||
continue;
|
||||
} else if expect_semi {
|
||||
errors.err(ParserMsg {
|
||||
ctx.err(ParserMsg {
|
||||
msg: "expected ';'".to_string(),
|
||||
spans: vec![cursor.next_pos().char_span()],
|
||||
spans: vec![ctx.next_start().char_span()],
|
||||
});
|
||||
}
|
||||
let res = Statement::parse_node(cursor, errors);
|
||||
let res = PStatement::parse_node(ctx);
|
||||
statements.push(res.node);
|
||||
expect_semi = true;
|
||||
if res.recover {
|
||||
cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
|
||||
if cursor.peek().is_none() {
|
||||
ctx.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
|
||||
if ctx.peek().is_none() {
|
||||
recover = true;
|
||||
break;
|
||||
}
|
||||
@@ -62,14 +61,17 @@ impl Parsable for Block {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Block {
|
||||
impl Debug for PBlock {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.statements.first().is_some() {
|
||||
if !self.statements.is_empty() || self.result.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"))?;
|
||||
padder.write_str(&format!("{s:?};\n"))?;
|
||||
}
|
||||
if let Some(res) = &self.result {
|
||||
padder.write_str(&format!("{res:?}\n"))?;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
} else {
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{Ident, MaybeParsable, Node, Parsable, ParseResult, ParserMsg, Symbol, Token, Type};
|
||||
use super::{
|
||||
PIdent, MaybeParsable, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token, PType,
|
||||
};
|
||||
|
||||
pub struct VarDef {
|
||||
pub name: Node<Ident>,
|
||||
pub ty: Option<Node<Type>>,
|
||||
pub struct PVarDef {
|
||||
pub name: Node<PIdent>,
|
||||
pub ty: Option<Node<PType>>,
|
||||
}
|
||||
|
||||
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) })
|
||||
impl Parsable for PVarDef {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let name = ctx.parse()?;
|
||||
if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||
ctx.next();
|
||||
ctx.parse().map(|ty| Self { name, ty: Some(ty) })
|
||||
} else {
|
||||
ParseResult::Ok(Self { name, ty: None })
|
||||
}
|
||||
@@ -33,20 +32,17 @@ pub enum SelfType {
|
||||
}
|
||||
|
||||
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() {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, super::ParserMsg> {
|
||||
if let Some(mut next) = ctx.peek() {
|
||||
let mut ty = SelfType::Take;
|
||||
if next.is_symbol(Symbol::Ampersand) {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
ty = SelfType::Ref;
|
||||
next = cursor.expect_peek()?;
|
||||
next = ctx.expect_peek()?;
|
||||
}
|
||||
if let Token::Word(name) = &next.token {
|
||||
if name == "self" {
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
return Ok(Some(Self { ty }));
|
||||
}
|
||||
}
|
||||
@@ -58,7 +54,7 @@ impl MaybeParsable for SelfVar {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VarDef {
|
||||
impl Debug for PVarDef {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.name.fmt(f)?;
|
||||
if let Some(ty) = &self.ty {
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use super::{
|
||||
op::{BinaryOp, UnaryOp},
|
||||
op::{PInfixOp, UnaryOp},
|
||||
util::parse_list,
|
||||
AsmBlock, Block, Ident, Keyword, Literal, Node, NodeParsable, Parsable, ParseResult, ParserMsg,
|
||||
ParserOutput, Symbol, TokenCursor,
|
||||
PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx,
|
||||
ParserMsg, Symbol,
|
||||
};
|
||||
|
||||
type BoxNode = Node<Box<Expr>>;
|
||||
type BoxNode = Node<Box<PExpr>>;
|
||||
|
||||
pub enum Expr {
|
||||
Lit(Node<Literal>),
|
||||
Ident(Node<Ident>),
|
||||
BinaryOp(BinaryOp, BoxNode, BoxNode),
|
||||
pub enum PExpr {
|
||||
Lit(Node<PLiteral>),
|
||||
Ident(Node<PIdent>),
|
||||
BinaryOp(PInfixOp, BoxNode, BoxNode),
|
||||
UnaryOp(UnaryOp, BoxNode),
|
||||
Block(Node<Block>),
|
||||
Call(BoxNode, Vec<Node<Expr>>),
|
||||
Block(Node<PBlock>),
|
||||
Call(BoxNode, Vec<Node<PExpr>>),
|
||||
Group(BoxNode),
|
||||
AsmBlock(Node<AsmBlock>),
|
||||
AsmBlock(Node<PAsmBlock>),
|
||||
}
|
||||
|
||||
impl Parsable for Expr {
|
||||
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||
let start = cursor.next_pos();
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PExpr {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let start = ctx.next_start();
|
||||
let next = ctx.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(),
|
||||
ctx.next();
|
||||
if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
|
||||
ctx.next();
|
||||
return ParseResult::Ok(PExpr::Lit(Node::new(
|
||||
PLiteral::Unit,
|
||||
ctx.next_start().char_span(),
|
||||
)));
|
||||
}
|
||||
let res = Node::parse(cursor, output);
|
||||
let res = ctx.parse();
|
||||
if res.recover {
|
||||
cursor.seek_sym(Symbol::CloseParen);
|
||||
ctx.seek_sym(Symbol::CloseParen);
|
||||
}
|
||||
cursor.expect_sym(Symbol::CloseParen)?;
|
||||
ctx.expect_sym(Symbol::CloseParen)?;
|
||||
Self::Group(res.node.bx())
|
||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||
Self::Block(Block::parse_node(cursor, output)?)
|
||||
Self::Block(PBlock::parse_node(ctx)?)
|
||||
} else if next.is_keyword(Keyword::Asm) {
|
||||
cursor.next();
|
||||
Self::AsmBlock(Node::parse(cursor, output)?)
|
||||
ctx.next();
|
||||
Self::AsmBlock(ctx.parse()?)
|
||||
} else if let Some(op) = UnaryOp::from_token(next) {
|
||||
cursor.next();
|
||||
return Node::parse(cursor, output).map(|n| {
|
||||
ctx.next();
|
||||
return ctx.parse().map(|n| {
|
||||
let n = n.bx();
|
||||
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
|
||||
let span = start.to(n1.span.end);
|
||||
@@ -55,36 +55,36 @@ impl Parsable for Expr {
|
||||
Self::UnaryOp(op, n)
|
||||
}
|
||||
});
|
||||
} else if let Some(val) = Node::maybe_parse(cursor, output) {
|
||||
} else if let Some(val) = Node::maybe_parse(ctx) {
|
||||
Self::Lit(val)
|
||||
} else {
|
||||
let res = Node::parse(cursor, &mut ParserOutput::new());
|
||||
let res = ctx.parse();
|
||||
if res.node.is_some() {
|
||||
Self::Ident(res.node)
|
||||
} else {
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression"));
|
||||
}
|
||||
};
|
||||
let Some(mut next) = cursor.peek() else {
|
||||
let Some(mut next) = ctx.peek() else {
|
||||
return ParseResult::Ok(e1);
|
||||
};
|
||||
while next.is_symbol(Symbol::OpenParen) {
|
||||
cursor.next();
|
||||
let args = parse_list(cursor, output, Symbol::CloseParen)?;
|
||||
let end = cursor.prev_end();
|
||||
ctx.next();
|
||||
let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
let end = ctx.prev_end();
|
||||
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
|
||||
let Some(next2) = cursor.peek() else {
|
||||
let Some(next2) = ctx.peek() else {
|
||||
return ParseResult::Ok(e1);
|
||||
};
|
||||
next = next2
|
||||
}
|
||||
let end = cursor.prev_end();
|
||||
let end = ctx.prev_end();
|
||||
let mut recover = false;
|
||||
let res = if let Some(mut op) = BinaryOp::from_token(&next.token) {
|
||||
cursor.next();
|
||||
let res = if let Some(mut op) = PInfixOp::from_token(&next.token) {
|
||||
ctx.next();
|
||||
let mut n1 = Node::new(e1, start.to(end)).bx();
|
||||
let res = Node::parse(cursor, output);
|
||||
let res = ctx.parse();
|
||||
let mut n2 = res.node.bx();
|
||||
recover = res.recover;
|
||||
if let Some(box Self::BinaryOp(op2, _, _)) = n2.as_ref() {
|
||||
@@ -106,13 +106,13 @@ impl Parsable for Expr {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Expr {
|
||||
impl Debug for PExpr {
|
||||
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) => {
|
||||
PExpr::Lit(c) => c.fmt(f)?,
|
||||
PExpr::Ident(n) => n.fmt(f)?,
|
||||
PExpr::Block(b) => b.fmt(f)?,
|
||||
PExpr::BinaryOp(op, e1, e2) => {
|
||||
write!(f, "({:?}", *e1)?;
|
||||
if op.pad() {
|
||||
write!(f, " {} ", op.str())?;
|
||||
@@ -121,7 +121,7 @@ impl Debug for Expr {
|
||||
}
|
||||
write!(f, "{:?})", *e2)?;
|
||||
}
|
||||
Expr::Call(n, args) => {
|
||||
PExpr::Call(n, args) => {
|
||||
n.fmt(f)?;
|
||||
f.write_char('(')?;
|
||||
if let Some(a) = args.first() {
|
||||
@@ -133,13 +133,13 @@ impl Debug for Expr {
|
||||
}
|
||||
f.write_char(')')?;
|
||||
}
|
||||
Expr::UnaryOp(op, e) => {
|
||||
PExpr::UnaryOp(op, e) => {
|
||||
write!(f, "(")?;
|
||||
write!(f, "{}", op.str())?;
|
||||
write!(f, "{:?})", *e)?;
|
||||
}
|
||||
Expr::Group(inner) => inner.fmt(f)?,
|
||||
Expr::AsmBlock(inner) => inner.fmt(f)?,
|
||||
PExpr::Group(inner) => inner.fmt(f)?,
|
||||
PExpr::AsmBlock(inner) => inner.fmt(f)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,71 +1,69 @@
|
||||
use super::{
|
||||
util::parse_list, Block, Ident, Keyword, Node, Parsable, ParseResult, ParserOutput, SelfVar,
|
||||
Symbol, TokenCursor, Type, VarDef,
|
||||
util::parse_list, PBlock, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx,
|
||||
Symbol, PType, PVarDef,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub struct FunctionHeader {
|
||||
pub name: Node<Ident>,
|
||||
pub sel: Option<Node<SelfVar>>,
|
||||
pub args: Vec<Node<VarDef>>,
|
||||
pub ret: Option<Node<Type>>,
|
||||
pub struct PFunctionHeader {
|
||||
pub name: Node<PIdent>,
|
||||
pub args: Vec<Node<PVarDef>>,
|
||||
pub ret: Option<Node<PType>>,
|
||||
}
|
||||
|
||||
pub struct Function {
|
||||
pub header: Node<FunctionHeader>,
|
||||
pub body: Node<Block>,
|
||||
pub struct PFunction {
|
||||
pub header: Node<PFunctionHeader>,
|
||||
pub body: Node<PBlock>,
|
||||
}
|
||||
|
||||
impl Parsable for FunctionHeader {
|
||||
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self> {
|
||||
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)?;
|
||||
let ret = if cursor.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) {
|
||||
cursor.next();
|
||||
Some(Node::parse(cursor, output)?)
|
||||
impl Parsable for PFunctionHeader {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Fn)?;
|
||||
let name = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::OpenParen)?;
|
||||
// let sel = ctx.maybe_parse();
|
||||
// if sel.is_some() {
|
||||
// if let Err(err) = ctx.expect_sym(Symbol::Comma) {
|
||||
// ctx.err(err);
|
||||
// ctx.seek_syms(&[Symbol::Comma, Symbol::CloseParen]);
|
||||
// if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Comma)) {
|
||||
// ctx.next();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
let args = parse_list(ctx, Symbol::CloseParen)?;
|
||||
let ret = if ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Arrow)) {
|
||||
ctx.next();
|
||||
Some(ctx.parse()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
ParseResult::Ok(Self {
|
||||
name,
|
||||
args,
|
||||
sel,
|
||||
ret,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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)?;
|
||||
impl Parsable for PFunction {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let header = ctx.parse()?;
|
||||
let body = ctx.parse()?;
|
||||
ParseResult::Ok(Self { header, body })
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FunctionHeader {
|
||||
impl Debug for PFunctionHeader {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("fn ")?;
|
||||
self.name.fmt(f)?;
|
||||
f.write_str("(")?;
|
||||
if let Some(s) = &self.sel {
|
||||
s.fmt(f)?;
|
||||
if self.args.first().is_some() {
|
||||
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)?;
|
||||
}
|
||||
@@ -80,7 +78,7 @@ impl Debug for FunctionHeader {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Debug for Function {
|
||||
impl Debug for PFunction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.header.fmt(f)?;
|
||||
f.write_str(" ")?;
|
||||
|
||||
@@ -1,29 +1,52 @@
|
||||
use std::fmt::Debug;
|
||||
use super::{Parsable, ParseResult, ParserMsg, Token};
|
||||
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token};
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
pub struct Ident(String);
|
||||
#[derive(Clone)]
|
||||
pub struct PIdent(String);
|
||||
|
||||
impl Ident {
|
||||
pub fn val(&self) -> &String {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Ident {
|
||||
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserOutput) -> ParseResult<Self> {
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PIdent {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
let Token::Word(name) = &next.token else {
|
||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier"));
|
||||
};
|
||||
let name = name.to_string();
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
ParseResult::Ok(Self(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Ident {
|
||||
impl MaybeParsable for PIdent {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
|
||||
let Some(next) = ctx.peek() else { return Ok(None) };
|
||||
let Token::Word(name) = &next.token else {
|
||||
return Ok(None);
|
||||
};
|
||||
let name = name.to_string();
|
||||
ctx.next();
|
||||
Ok(Some(Self(name)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PIdent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for PIdent {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PIdent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,35 @@
|
||||
use super::{CharCursor, MaybeParsable, ParserMsg, ParserOutput, Symbol, Token, TokenCursor};
|
||||
use super::{CharCursor, MaybeParsable, ParserCtx, ParserMsg, Symbol, Token};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum Literal {
|
||||
pub enum PLiteral {
|
||||
String(String),
|
||||
Char(char),
|
||||
Number(Number),
|
||||
Number(PNumber),
|
||||
Unit,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Number {
|
||||
pub struct PNumber {
|
||||
pub whole: String,
|
||||
pub decimal: Option<String>,
|
||||
pub ty: Option<String>,
|
||||
}
|
||||
|
||||
impl MaybeParsable for Literal {
|
||||
fn maybe_parse(
|
||||
cursor: &mut TokenCursor,
|
||||
_: &mut ParserOutput,
|
||||
) -> Result<Option<Self>, ParserMsg> {
|
||||
let inst = cursor.expect_peek()?;
|
||||
impl MaybeParsable for PLiteral {
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
|
||||
let inst = ctx.expect_peek()?;
|
||||
Ok(Some(match &inst.token {
|
||||
Token::Symbol(Symbol::SingleQuote) => {
|
||||
let chars = cursor.chars();
|
||||
let chars = ctx.chars();
|
||||
let c = chars.expect_next()?;
|
||||
chars.expect('\'')?;
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
Self::Char(c)
|
||||
}
|
||||
Token::Symbol(Symbol::DoubleQuote) => {
|
||||
let res = Self::String(string_from(cursor.chars())?);
|
||||
cursor.next();
|
||||
let res = Self::String(string_from(ctx.chars())?);
|
||||
ctx.next();
|
||||
res
|
||||
}
|
||||
Token::Word(text) => {
|
||||
@@ -41,21 +38,21 @@ impl MaybeParsable for Literal {
|
||||
return Ok(None);
|
||||
}
|
||||
let (whole, ty) = parse_whole_num(text);
|
||||
let mut num = Number {
|
||||
let mut num = PNumber {
|
||||
whole,
|
||||
decimal: None,
|
||||
ty,
|
||||
};
|
||||
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() {
|
||||
ctx.next();
|
||||
if num.ty.is_none() && ctx.peek().is_some_and(|i| i.is_symbol(Symbol::Dot)) {
|
||||
ctx.next();
|
||||
if let Some(next) = ctx.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();
|
||||
ctx.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +107,7 @@ pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Literal {
|
||||
impl Debug for PLiteral {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::String(str) => str.fmt(f),
|
||||
@@ -121,7 +118,7 @@ impl Debug for Literal {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Number {
|
||||
impl Debug for PNumber {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.whole)?;
|
||||
if let Some(d) = &self.decimal {
|
||||
|
||||
@@ -13,6 +13,7 @@ mod util;
|
||||
mod trai;
|
||||
mod asm_fn;
|
||||
mod asm_block;
|
||||
mod asm_instr;
|
||||
|
||||
pub use block::*;
|
||||
pub use expr::*;
|
||||
@@ -28,6 +29,7 @@ pub use trai::*;
|
||||
pub use op::*;
|
||||
pub use asm_fn::*;
|
||||
pub use asm_block::*;
|
||||
pub use asm_instr::*;
|
||||
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1,79 +1,70 @@
|
||||
use super::{
|
||||
AsmFunction, Function, Impl, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
|
||||
Struct, Symbol, Token, TokenCursor, Trait,
|
||||
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg,
|
||||
PStruct, Symbol, Token, PTrait,
|
||||
};
|
||||
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>>,
|
||||
pub struct PModule {
|
||||
pub traits: Vec<Node<PTrait>>,
|
||||
pub structs: Vec<Node<PStruct>>,
|
||||
pub functions: Vec<Node<PFunction>>,
|
||||
pub impls: Vec<Node<PImpl>>,
|
||||
}
|
||||
|
||||
impl Parsable for Module {
|
||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||
impl Parsable for PModule {
|
||||
fn parse(ctx: &mut ParserCtx) -> 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 {
|
||||
let Some(next) = ctx.peek() else {
|
||||
break;
|
||||
};
|
||||
if let Token::Keyword(kw) = next.token {
|
||||
match kw {
|
||||
Keyword::Fn => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
functions.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword::Struct => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
structs.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword::Trait => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
traits.push(res.node);
|
||||
if res.recover {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword::Impl => {
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
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();
|
||||
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||
ctx.next();
|
||||
}
|
||||
}
|
||||
} else if next.is_symbol(Symbol::Semicolon) {
|
||||
errors.hint(ParserMsg::from_instances(
|
||||
ctx.hint(ParserMsg::from_instances(
|
||||
&[next],
|
||||
"unneeded semicolon".to_string(),
|
||||
));
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
} else {
|
||||
errors.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||
cursor.next();
|
||||
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
|
||||
ctx.next();
|
||||
}
|
||||
}
|
||||
ParseResult::Ok(Self {
|
||||
@@ -81,12 +72,11 @@ impl Parsable for Module {
|
||||
structs,
|
||||
traits,
|
||||
impls,
|
||||
asm_fns,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Module {
|
||||
impl Debug for PModule {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for st in &self.structs {
|
||||
st.fmt(f)?;
|
||||
@@ -104,10 +94,6 @@ impl Debug for Module {
|
||||
func.fmt(f)?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
for func in &self.asm_fns {
|
||||
func.fmt(f)?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{Symbol, Token};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BinaryOp {
|
||||
pub enum PInfixOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
@@ -12,7 +12,7 @@ pub enum BinaryOp {
|
||||
Assign,
|
||||
}
|
||||
|
||||
impl BinaryOp {
|
||||
impl PInfixOp {
|
||||
pub fn presedence(&self) -> u32 {
|
||||
match self {
|
||||
Self::Assign => 0,
|
||||
@@ -69,7 +69,7 @@ pub enum UnaryOp {
|
||||
Deref,
|
||||
}
|
||||
|
||||
impl BinaryOp {
|
||||
impl PInfixOp {
|
||||
pub fn from_token(token: &Token) -> Option<Self> {
|
||||
let Token::Symbol(symbol) = token else {
|
||||
return None;
|
||||
|
||||
@@ -1,51 +1,45 @@
|
||||
use super::{
|
||||
Expr, Keyword, Node, Parsable, ParseResult, ParserOutput, Symbol, Token, TokenCursor, VarDef,
|
||||
};
|
||||
use std::fmt::{Debug, Write};
|
||||
use super::{PExpr, Keyword, Node, Parsable, ParseResult, ParserCtx, Symbol, Token, PVarDef};
|
||||
|
||||
pub enum Statement {
|
||||
Let(Node<VarDef>, Node<Expr>),
|
||||
Return(Node<Expr>),
|
||||
Expr(Node<Expr>),
|
||||
pub enum PStatement {
|
||||
Let(Node<PVarDef>, Node<PExpr>),
|
||||
Return(Node<PExpr>),
|
||||
Expr(Node<PExpr>),
|
||||
}
|
||||
|
||||
impl Parsable for Statement {
|
||||
fn parse(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> ParseResult<Self> {
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PStatement {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
match next.token {
|
||||
Token::Keyword(Keyword::Let) => {
|
||||
cursor.next();
|
||||
let def = Node::parse(cursor, errors)?;
|
||||
cursor.expect_sym(Symbol::Equals)?;
|
||||
Node::parse(cursor, errors).map(|expr| Self::Let(def, expr))
|
||||
ctx.next();
|
||||
let def = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::Equals)?;
|
||||
ctx.parse().map(|expr| Self::Let(def, expr))
|
||||
}
|
||||
Token::Keyword(Keyword::Return) => {
|
||||
cursor.next();
|
||||
Node::parse(cursor, errors).map(Self::Return)
|
||||
ctx.next();
|
||||
ctx.parse().map(Self::Return)
|
||||
}
|
||||
_ => Node::parse(cursor, errors).map(Self::Expr),
|
||||
_ => ctx.parse().map(Self::Expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Statement {
|
||||
impl std::fmt::Debug for PStatement {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Statement::Let(n, e) => {
|
||||
PStatement::Let(n, e) => {
|
||||
f.write_str("let ")?;
|
||||
n.fmt(f)?;
|
||||
f.write_str(" = ")?;
|
||||
e.fmt(f)?;
|
||||
f.write_char(';')?;
|
||||
}
|
||||
Statement::Return(e) => {
|
||||
PStatement::Return(e) => {
|
||||
f.write_str("return ")?;
|
||||
e.fmt(f)?;
|
||||
f.write_char(';')?;
|
||||
}
|
||||
Statement::Expr(e) => {
|
||||
PStatement::Expr(e) => {
|
||||
e.fmt(f)?;
|
||||
f.write_char(';')?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{
|
||||
util::parse_list, Ident, Keyword, Node, Parsable, ParseResult, ParserMsg, ParserOutput,
|
||||
Symbol, TokenCursor, Type, VarDef,
|
||||
util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol,
|
||||
PType, PVarDef,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Struct {
|
||||
pub name: Node<Ident>,
|
||||
pub fields: StructFields,
|
||||
pub struct PStruct {
|
||||
pub name: Node<PIdent>,
|
||||
pub fields: PStructFields,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StructFields {
|
||||
Named(Vec<Node<VarDef>>),
|
||||
Tuple(Vec<Node<Type>>),
|
||||
pub enum PStructFields {
|
||||
Named(Vec<Node<PVarDef>>),
|
||||
Tuple(Vec<Node<PType>>),
|
||||
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()?;
|
||||
impl Parsable for PStruct {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Struct)?;
|
||||
let name = ctx.parse()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||
cursor.next();
|
||||
StructFields::None
|
||||
ctx.next();
|
||||
PStructFields::None
|
||||
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||
cursor.next();
|
||||
StructFields::Named(parse_list(cursor, errors, Symbol::CloseCurly)?)
|
||||
ctx.next();
|
||||
PStructFields::Named(parse_list(ctx, Symbol::CloseCurly)?)
|
||||
} else if next.is_symbol(Symbol::OpenParen) {
|
||||
cursor.next();
|
||||
StructFields::Tuple(parse_list(cursor, errors, Symbol::CloseParen)?)
|
||||
ctx.next();
|
||||
PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
|
||||
} else {
|
||||
errors.err(ParserMsg::unexpected_token(next, "`;`, `(`, or `{`"));
|
||||
return ParseResult::Recover(Struct {
|
||||
let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`");
|
||||
ctx.err(msg);
|
||||
return ParseResult::Recover(PStruct {
|
||||
name,
|
||||
fields: StructFields::None,
|
||||
fields: PStructFields::None,
|
||||
});
|
||||
};
|
||||
ParseResult::Ok(Struct { name, fields })
|
||||
ParseResult::Ok(PStruct { name, fields })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
use super::{util::{parse_list, parse_list_nosep}, Function, FunctionHeader, Ident, Keyword, Node, Parsable, Symbol, Type};
|
||||
use super::{
|
||||
util::{parse_list, parse_list_nosep},
|
||||
PFunction, PFunctionHeader, PIdent, Keyword, Node, Parsable, ParserCtx, Symbol, PType,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Trait {
|
||||
pub name: Node<Ident>,
|
||||
pub fns: Vec<Node<FunctionHeader>>
|
||||
pub struct PTrait {
|
||||
pub name: Node<PIdent>,
|
||||
pub fns: Vec<Node<PFunctionHeader>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Impl {
|
||||
pub trait_: Node<Type>,
|
||||
pub for_: Node<Type>,
|
||||
pub fns: Vec<Node<Function>>
|
||||
pub struct PImpl {
|
||||
pub trait_: Node<PType>,
|
||||
pub for_: Node<PType>,
|
||||
pub fns: Vec<Node<PFunction>>,
|
||||
}
|
||||
|
||||
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 PTrait {
|
||||
fn parse(ctx: &mut ParserCtx) -> super::ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Trait)?;
|
||||
let name = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
let fns = parse_list(ctx, 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})
|
||||
impl Parsable for PImpl {
|
||||
fn parse(ctx: &mut ParserCtx) -> super::ParseResult<Self> {
|
||||
ctx.expect_kw(Keyword::Impl)?;
|
||||
let trait_ = ctx.parse()?;
|
||||
ctx.expect_kw(Keyword::For)?;
|
||||
let for_ = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::OpenCurly)?;
|
||||
let fns = parse_list_nosep(ctx, Symbol::CloseCurly)?;
|
||||
super::ParseResult::Ok(Self { trait_, for_, fns })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::{util::parse_list, Node, Parsable, ParseResult, ParserMsg, Symbol, Token};
|
||||
use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token};
|
||||
|
||||
pub struct Type {
|
||||
pub struct PType {
|
||||
pub name: String,
|
||||
pub args: Vec<Node<Type>>,
|
||||
pub args: Vec<Node<PType>>,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
impl PType {
|
||||
pub fn unit() -> Self {
|
||||
Self {
|
||||
name: "()".to_string(),
|
||||
@@ -16,15 +16,12 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Type {
|
||||
fn parse(
|
||||
cursor: &mut super::TokenCursor,
|
||||
errors: &mut super::ParserOutput,
|
||||
) -> ParseResult<Self> {
|
||||
let next = cursor.expect_peek()?;
|
||||
impl Parsable for PType {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
let next = ctx.expect_peek()?;
|
||||
let res = if next.is_symbol(Symbol::Ampersand) {
|
||||
cursor.next();
|
||||
let arg = Node::parse(cursor, errors)?;
|
||||
ctx.next();
|
||||
let arg = ctx.parse()?;
|
||||
Self {
|
||||
name: "&".to_string(),
|
||||
args: vec![arg],
|
||||
@@ -34,12 +31,12 @@ impl Parsable for Type {
|
||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier"));
|
||||
};
|
||||
let n = name.to_string();
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
let mut args = Vec::new();
|
||||
if let Some(next) = cursor.peek() {
|
||||
if let Some(next) = ctx.peek() {
|
||||
if next.is_symbol(Symbol::OpenAngle) {
|
||||
cursor.next();
|
||||
args = parse_list(cursor, errors, Symbol::CloseAngle)?;
|
||||
ctx.next();
|
||||
args = parse_list(ctx, Symbol::CloseAngle)?;
|
||||
}
|
||||
}
|
||||
Self { name: n, args }
|
||||
@@ -48,7 +45,7 @@ impl Parsable for Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Type {
|
||||
impl Debug for PType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.name)?;
|
||||
if self.name == "&" {
|
||||
|
||||
@@ -1,57 +1,54 @@
|
||||
use super::{Node, Parsable, ParserMsg, ParserOutput, Symbol, TokenCursor};
|
||||
use super::{Node, Parsable, ParserCtx, ParserMsg, Symbol};
|
||||
|
||||
pub fn parse_list_sep<T: Parsable>(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
ctx: &mut ParserCtx,
|
||||
sep: Symbol,
|
||||
end: Symbol,
|
||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||
let mut vals = Vec::new();
|
||||
loop {
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
if next.is_symbol(end) {
|
||||
break;
|
||||
}
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
vals.push(res.node);
|
||||
if res.recover {
|
||||
cursor.seek_syms(&[end, sep]);
|
||||
ctx.seek_syms(&[end, sep]);
|
||||
}
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
if !next.is_symbol(sep) {
|
||||
break;
|
||||
}
|
||||
cursor.next();
|
||||
ctx.next();
|
||||
}
|
||||
cursor.expect_sym(end)?;
|
||||
ctx.expect_sym(end)?;
|
||||
Ok(vals)
|
||||
}
|
||||
|
||||
pub fn parse_list<T: Parsable>(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
ctx: &mut ParserCtx,
|
||||
end: Symbol,
|
||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||
parse_list_sep(cursor, errors, Symbol::Comma, end)
|
||||
parse_list_sep(ctx, Symbol::Comma, end)
|
||||
}
|
||||
|
||||
pub fn parse_list_nosep<T: Parsable>(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
ctx: &mut ParserCtx,
|
||||
end: Symbol,
|
||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
||||
let mut vals = Vec::new();
|
||||
loop {
|
||||
let next = cursor.expect_peek()?;
|
||||
let next = ctx.expect_peek()?;
|
||||
if next.is_symbol(end) {
|
||||
break;
|
||||
}
|
||||
let res = Node::parse(cursor, errors);
|
||||
let res = ctx.parse();
|
||||
vals.push(res.node);
|
||||
if res.recover {
|
||||
cursor.seek_sym(end);
|
||||
ctx.seek_sym(end);
|
||||
}
|
||||
}
|
||||
cursor.expect_sym(end)?;
|
||||
ctx.expect_sym(end)?;
|
||||
Ok(vals)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use crate::ir::FilePos;
|
||||
|
||||
use super::{Node, ParserMsg, ParserOutput, TokenCursor};
|
||||
use super::{Node, ParserCtx, ParserMsg};
|
||||
|
||||
pub enum ParseResult<T> {
|
||||
Ok(T),
|
||||
@@ -33,6 +33,7 @@ impl<T> Try for ParseResult<T> {
|
||||
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
||||
match self {
|
||||
ParseResult::Ok(v) => ControlFlow::Continue(v),
|
||||
// TODO: this is messed up; need to break w a Result<Option<T>> or smth :woozy:
|
||||
ParseResult::Recover(v) => ControlFlow::Break(None),
|
||||
ParseResult::Err(e) => ControlFlow::Break(Some(e)),
|
||||
ParseResult::SubErr => ControlFlow::Break(None),
|
||||
@@ -111,29 +112,26 @@ impl<T> FromResidual for NodeParseResult<T> {
|
||||
}
|
||||
|
||||
pub trait Parsable: Sized {
|
||||
fn parse(cursor: &mut TokenCursor, output: &mut ParserOutput) -> ParseResult<Self>;
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self>;
|
||||
}
|
||||
|
||||
pub trait MaybeParsable: Sized {
|
||||
fn maybe_parse(
|
||||
cursor: &mut TokenCursor,
|
||||
errors: &mut ParserOutput,
|
||||
) -> Result<Option<Self>, ParserMsg>;
|
||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg>;
|
||||
}
|
||||
|
||||
impl<T: Parsable> Node<T> {
|
||||
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) {
|
||||
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
|
||||
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
|
||||
let (inner, recover) = match T::parse(ctx) {
|
||||
ParseResult::Ok(v) => (Some(v), false),
|
||||
ParseResult::Recover(v) => (Some(v), true),
|
||||
ParseResult::Err(e) => {
|
||||
output.err(e);
|
||||
ctx.err(e);
|
||||
(None, true)
|
||||
}
|
||||
ParseResult::SubErr => (None, true),
|
||||
};
|
||||
let end = cursor.prev_end();
|
||||
let end = ctx.prev_end();
|
||||
NodeParseResult {
|
||||
node: Self {
|
||||
inner,
|
||||
@@ -145,16 +143,16 @@ impl<T: Parsable> Node<T> {
|
||||
}
|
||||
|
||||
impl<T: MaybeParsable> Node<T> {
|
||||
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) {
|
||||
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
|
||||
let start = ctx.next_start();
|
||||
let inner = match T::maybe_parse(ctx) {
|
||||
Ok(v) => Some(v?),
|
||||
Err(e) => {
|
||||
errors.err(e);
|
||||
ctx.err(e);
|
||||
None
|
||||
}
|
||||
};
|
||||
let end = cursor.prev_end();
|
||||
let end = ctx.prev_end();
|
||||
Some(Self {
|
||||
inner,
|
||||
span: start.to(end),
|
||||
@@ -163,15 +161,15 @@ impl<T: MaybeParsable> Node<T> {
|
||||
}
|
||||
|
||||
pub trait NodeParsable {
|
||||
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self>
|
||||
fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
impl<T: Parsable> NodeParsable for T {
|
||||
fn parse_node(cursor: &mut TokenCursor, errors: &mut ParserOutput) -> NodeParseResult<Self>
|
||||
fn parse_node(ctx: &mut ParserCtx) -> NodeParseResult<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Node::<Self>::parse(cursor, errors)
|
||||
Node::<Self>::parse(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{iter::Peekable, str::Chars};
|
||||
|
||||
use crate::ir::FilePos;
|
||||
use super::super::ParserMsg;
|
||||
use crate::ir::FilePos;
|
||||
|
||||
pub struct CharCursor<'a> {
|
||||
chars: Peekable<Chars<'a>>,
|
||||
|
||||
@@ -9,6 +9,7 @@ pub enum Keyword {
|
||||
Impl,
|
||||
For,
|
||||
Asm,
|
||||
Funne,
|
||||
}
|
||||
|
||||
impl Keyword {
|
||||
@@ -23,6 +24,7 @@ impl Keyword {
|
||||
"trait" => Self::Trait,
|
||||
"impl" => Self::Impl,
|
||||
"asm" => Self::Asm,
|
||||
"funne" => Self::Funne,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user