type checking !?!?

This commit is contained in:
2025-03-22 14:40:32 -04:00
parent 606cb30c6b
commit 7f809d797c
44 changed files with 664 additions and 314 deletions

View File

@@ -1,10 +1,13 @@
use std::ops::{Deref, DerefMut};
use super::{MaybeParsable, Node, NodeParseResult, Parsable, ParserMsg, ParserOutput, TokenCursor};
use super::{
MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith, CompilerMsg, CompilerOutput,
TokenCursor,
};
pub struct ParserCtx<'a> {
pub cursor: TokenCursor<'a>,
pub output: ParserOutput,
pub output: CompilerOutput,
}
impl<'a> Deref for ParserCtx<'a> {
@@ -22,15 +25,18 @@ impl DerefMut for ParserCtx<'_> {
}
impl<'a> ParserCtx<'a> {
pub fn err(&mut self, msg: ParserMsg) {
pub fn err(&mut self, msg: CompilerMsg) {
self.output.err(msg);
}
pub fn hint(&mut self, msg: ParserMsg) {
pub fn hint(&mut self, msg: CompilerMsg) {
self.output.hint(msg);
}
pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> {
Node::parse(self)
}
pub fn parse_with<T: ParsableWith>(&mut self, data: T::Data) -> NodeParseResult<T> {
Node::parse_with(self, data)
}
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
Node::maybe_parse(self)
}
@@ -40,7 +46,7 @@ impl<'a> From<TokenCursor<'a>> for ParserCtx<'a> {
fn from(cursor: TokenCursor<'a>) -> Self {
Self {
cursor,
output: ParserOutput::new(),
output: CompilerOutput::new(),
}
}
}
@@ -49,7 +55,7 @@ impl<'a> From<&'a str> for ParserCtx<'a> {
fn from(string: &'a str) -> Self {
Self {
cursor: TokenCursor::from(string),
output: ParserOutput::new(),
output: CompilerOutput::new(),
}
}
}

View File

@@ -1,7 +1,7 @@
use crate::ir::FilePos;
use super::error::ParserMsg;
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
use super::{
token::{CharCursor, Keyword, Symbol, Token, TokenInstance},
CompilerMsg, FilePos,
};
pub struct TokenCursor<'a> {
cursor: CharCursor<'a>,
@@ -12,11 +12,7 @@ pub struct TokenCursor<'a> {
impl<'a> TokenCursor<'a> {
pub fn next(&mut self) -> Option<TokenInstance> {
self.prev_end = self
.next
.as_ref()
.map(|i| i.span.end)
.unwrap_or(FilePos::start());
self.prev_end = self.cursor.prev_pos();
let next = TokenInstance::parse(&mut self.cursor);
self.next_start = next
.as_ref()
@@ -24,19 +20,19 @@ impl<'a> TokenCursor<'a> {
.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())?;
pub fn expect_next(&mut self) -> Result<TokenInstance, CompilerMsg> {
self.peek().ok_or(CompilerMsg::unexpected_end())?;
Ok(self.next().unwrap())
}
pub fn expect_token(&mut self, t: Token) -> Result<(), ParserMsg> {
pub fn expect_token(&mut self, t: Token) -> Result<(), CompilerMsg> {
let next = self.expect_next()?;
if t == next.token {
Ok(())
} else {
Err(ParserMsg::unexpected_token(&next, &format!("{t:?}")))
Err(CompilerMsg::unexpected_token(&next, &format!("{t:?}")))
}
}
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> {
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), CompilerMsg> {
self.expect_token(Token::Symbol(symbol))
}
pub fn next_on_new_line(&mut self) -> bool {
@@ -64,14 +60,14 @@ impl<'a> TokenCursor<'a> {
self.next();
}
}
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserMsg> {
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), CompilerMsg> {
self.expect_token(Token::Keyword(kw))
}
pub fn peek(&self) -> Option<&TokenInstance> {
self.next.as_ref()
}
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserMsg> {
self.peek().ok_or(ParserMsg::unexpected_end())
pub fn expect_peek(&mut self) -> Result<&TokenInstance, CompilerMsg> {
self.peek().ok_or(CompilerMsg::unexpected_end())
}
pub fn chars(&mut self) -> &mut CharCursor<'a> {
&mut self.cursor

View File

@@ -1,36 +1,17 @@
use crate::ir::{FilePos, FileSpan};
use super::Node;
use super::PIdent;
use super::CompilerMsg;
use super::TokenInstance;
use super::{token::TokenInstance, PIdent, Node};
#[derive(Debug, Clone)]
pub struct ParserMsg {
pub msg: String,
pub spans: Vec<FileSpan>,
}
pub struct ParserOutput {
pub errs: Vec<ParserMsg>,
pub hints: Vec<ParserMsg>,
}
impl ParserMsg {
impl CompilerMsg {
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
ParserMsg {
CompilerMsg {
msg,
spans: instances.iter().map(|i| i.span).collect(),
}
}
pub fn from_msg(msg: String) -> Self {
Self {
msg,
spans: Vec::new(),
}
}
pub fn from_span(span: FileSpan, msg: String) -> Self {
Self {
msg,
spans: vec![span],
}
pub fn unexpected_end() -> Self {
Self::from_msg("unexpected end of input".to_string())
}
pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
Self {
@@ -38,51 +19,11 @@ impl ParserMsg {
spans: vec![id.span],
}
}
pub fn at(pos: FilePos, msg: String) -> Self {
Self {
msg,
spans: vec![FileSpan::at(pos)],
}
}
pub fn unexpected_end() -> Self {
Self::from_msg("unexpected end of input".to_string())
}
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
let t = &inst.token;
ParserMsg::from_instances(
CompilerMsg::from_instances(
&[inst],
format!("unexpected token {t:?}; expected {expected}"),
)
}
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, "{}: {}{}", ty, self.msg, after)?;
for span in &self.spans {
span.write_for(writer, file)?;
}
Ok(())
}
}
impl ParserOutput {
pub fn new() -> Self {
Self {
errs: Vec::new(),
hints: Vec::new(),
}
}
pub fn err(&mut self, msg: ParserMsg) {
self.errs.push(msg);
}
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 {
err.write_for("error", out, file).unwrap();
}
for hint in &self.hints {
hint.write_for("hint", out, file).unwrap();
}
}
}

View File

@@ -3,7 +3,7 @@ use crate::{
compiler::arch::riscv64::*,
ir::{
arch::riscv64::{RV64Instruction, RegRef},
VarID,
VarInst,
},
};
@@ -57,7 +57,7 @@ impl RV64Instruction {
}
}
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarID> {
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let PAsmArg::Ref(node) = node.inner.as_ref()? else {
ctx.err_at(
node.span,

View File

@@ -1,9 +1,9 @@
use crate::{
compiler::arch::riscv64::Reg,
ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarID},
ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarInst},
};
use super::{PAsmBlock, PAsmBlockArg, FnLowerCtx, FnLowerable, PInstruction};
use super::{FnLowerCtx, FnLowerable, PAsmBlock, PAsmBlockArg, PInstruction};
impl FnLowerable for PInstruction {
type Output = RV64Instruction;
@@ -43,7 +43,7 @@ impl FnLowerable for PAsmBlock {
}
impl FnLowerable for PAsmBlockArg {
type Output = (Reg, VarID);
type Output = (Reg, VarInst);
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
let var = ctx.get_var(&self.var)?;

View File

@@ -1,10 +1,10 @@
use crate::ir::{IRUInstruction, VarID};
use crate::ir::{IRUInstruction, VarInst};
use super::{PBlock, FnLowerCtx, FnLowerable, PStatement};
use super::{FnLowerCtx, FnLowerable, PBlock, PStatement};
impl FnLowerable for PBlock {
type Output = VarID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let ctx = &mut ctx.sub();
for statement in &self.statements {
statement.lower(ctx);
@@ -14,20 +14,20 @@ impl FnLowerable for PBlock {
}
impl FnLowerable for PStatement {
type Output = VarID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
match self {
super::PStatement::Let(def, e) => {
let def = def.lower(ctx.map, ctx.output)?;
let res = e.lower(ctx);
if let Some(res) = res {
ctx.map.name_var(&def, res);
ctx.map.name_var(&def, res.id);
}
None
}
super::PStatement::Return(e) => {
let src = e.lower(ctx)?;
ctx.push(IRUInstruction::Ret { src });
ctx.push_at(IRUInstruction::Ret { src }, src.span);
None
}
super::PStatement::Expr(e) => e.lower(ctx),

View File

@@ -1,12 +1,12 @@
use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef};
use crate::ir::{NamespaceGuard, Origin, Type, VarDef};
use super::{Node, PType, PVarDef, ParserMsg, ParserOutput};
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef};
impl Node<PVarDef> {
pub fn lower(
&self,
namespace: &mut NamespaceGuard,
output: &mut ParserOutput,
output: &mut CompilerOutput,
) -> Option<VarDef> {
let s = self.as_ref()?;
let name = s.name.as_ref()?.to_string();
@@ -23,7 +23,7 @@ impl Node<PVarDef> {
}
impl Node<PType> {
pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut ParserOutput) -> Type {
pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut CompilerOutput) -> Type {
self.as_ref()
.map(|t| t.lower(namespace, output, self.span))
.unwrap_or(Type::Error)
@@ -34,7 +34,7 @@ impl PType {
pub fn lower(
&self,
namespace: &mut NamespaceGuard,
output: &mut ParserOutput,
output: &mut CompilerOutput,
span: FileSpan,
) -> Type {
match namespace.get(&self.name).and_then(|ids| ids.ty) {
@@ -60,7 +60,7 @@ impl PType {
Type::Slice(Box::new(inner))
}
_ => {
output.err(ParserMsg::from_span(span, "Type not found".to_string()));
output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
Type::Error
}
}

View File

@@ -1,31 +1,48 @@
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
use crate::ir::{IRUInstruction, Size, Type, VarID};
use crate::ir::{DataDef, IRUInstruction, Origin, Type, VarInst};
impl FnLowerable for PExpr {
type Output = VarID;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
Some(match self {
PExpr::Lit(l) => match l.as_ref()? {
super::PLiteral::String(s) => {
let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice());
let data = s.as_bytes().to_vec();
let len = data.len() as Size;
let src = ctx.map.def_data(data);
ctx.push(IRUInstruction::LoadSlice { dest, src, len });
let src = ctx.map.def_data(
DataDef {
ty: Type::Bits(8).arr(data.len() as u32),
origin: Origin::File(l.span),
},
data,
);
ctx.push(IRUInstruction::LoadSlice { dest, src });
dest
}
super::PLiteral::Char(c) => {
let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice());
let src = ctx.map.def_data(c.to_string().as_bytes().to_vec());
let ty = Type::Bits(8);
let dest = ctx.map.temp_var(l.span, ty.clone());
let src = ctx.map.def_data(
DataDef {
ty,
origin: Origin::File(l.span),
},
c.to_string().as_bytes().to_vec(),
);
ctx.push(IRUInstruction::LoadData { dest, src });
dest
}
super::PLiteral::Number(n) => {
// TODO: temp
let ty = Type::Bits(64);
let dest = ctx.map.temp_var(l.span, Type::Bits(64));
let src = ctx
.map
.def_data(n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec());
let src = ctx.map.def_data(
DataDef {
ty,
origin: Origin::File(l.span),
},
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
);
ctx.push(IRUInstruction::LoadData { dest, src });
dest
}
@@ -44,7 +61,7 @@ impl FnLowerable for PExpr {
let res = e.lower(ctx)?;
match op {
UnaryOp::Ref => {
let temp = ctx.temp(ctx.map.get_var(res).ty.clone());
let temp = ctx.temp(ctx.map.get_var(res.id).ty.clone());
ctx.push(IRUInstruction::Ref {
dest: temp,
src: res,
@@ -52,7 +69,7 @@ impl FnLowerable for PExpr {
temp
}
UnaryOp::Deref => {
let t = &ctx.map.get_var(res).ty;
let t = &ctx.map.get_var(res.id).ty;
let Type::Ref(inner) = t else {
ctx.err(format!(
"Cannot dereference type {:?}",
@@ -77,7 +94,7 @@ impl FnLowerable for PExpr {
let arg = arg.lower(ctx)?;
nargs.push(arg);
}
let def = ctx.map.get_fn_var(fe);
let def = ctx.map.get_fn_var(fe.id);
let ty = match def {
Some(def) => def.ret.clone(),
None => {
@@ -85,7 +102,7 @@ impl FnLowerable for PExpr {
e.span,
format!(
"Expected function, found {}",
ctx.map.type_name(&ctx.map.get_var(fe).ty)
ctx.map.type_name(&ctx.map.get_var(fe.id).ty)
),
);
Type::Error
@@ -100,6 +117,7 @@ impl FnLowerable for PExpr {
temp
}
PExpr::Group(e) => e.lower(ctx)?,
PExpr::Construct(c) => todo!(),
})
}
}

View File

@@ -1,8 +1,8 @@
use super::{FnLowerable, Node, PFunction, ParserMsg, ParserOutput};
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
use crate::{
ir::{
FileSpan, FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard,
Origin, Type, VarDef, VarID,
FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, Origin,
Type, VarDef, VarID, VarInst,
},
parser,
};
@@ -11,7 +11,7 @@ impl Node<PFunction> {
pub fn lower_header(
&self,
map: &mut NamespaceGuard,
output: &mut ParserOutput,
output: &mut CompilerOutput,
) -> Option<FnID> {
self.as_ref()?.lower_header(map, output)
}
@@ -19,7 +19,7 @@ impl Node<PFunction> {
&self,
id: FnID,
map: &mut NamespaceGuard,
output: &mut ParserOutput,
output: &mut CompilerOutput,
) -> Option<IRUFunction> {
Some(self.as_ref()?.lower_body(id, map, output))
}
@@ -29,7 +29,7 @@ impl PFunction {
pub fn lower_header(
&self,
map: &mut NamespaceGuard,
output: &mut ParserOutput,
output: &mut CompilerOutput,
) -> Option<FnID> {
let header = self.header.as_ref()?;
let name = header.name.as_ref()?;
@@ -59,7 +59,7 @@ impl PFunction {
&self,
id: FnID,
map: &mut NamespaceGuard,
output: &mut ParserOutput,
output: &mut CompilerOutput,
) -> IRUFunction {
let mut instructions = IRInstructions::new();
let def = map.get_fn(id).clone();
@@ -71,7 +71,7 @@ impl PFunction {
span: self.body.span,
};
if let Some(src) = self.body.lower(&mut ctx) {
instructions.push(IRUInstruction::Ret { src });
instructions.push(IRUInstruction::Ret { src }, src.span);
}
IRUFunction::new(def.name.clone(), args, instructions)
}
@@ -80,7 +80,7 @@ impl PFunction {
pub struct FnLowerCtx<'a, 'n> {
pub map: &'a mut NamespaceGuard<'n>,
pub instructions: &'a mut IRInstructions,
pub output: &'a mut ParserOutput,
pub output: &'a mut CompilerOutput,
pub span: FileSpan,
}
@@ -101,7 +101,7 @@ impl<'n> FnLowerCtx<'_, 'n> {
}
res
}
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarID> {
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarInst> {
let ids = self.get(node)?;
if ids.var.is_none() {
self.err_at(
@@ -112,19 +112,25 @@ impl<'n> FnLowerCtx<'_, 'n> {
),
);
}
ids.var
ids.var.map(|id| VarInst {
id,
span: node.span,
})
}
pub fn err(&mut self, msg: String) {
self.output.err(ParserMsg::from_span(self.span, msg))
self.output.err(CompilerMsg::from_span(self.span, msg))
}
pub fn err_at(&mut self, span: FileSpan, msg: String) {
self.output.err(ParserMsg::from_span(span, msg))
self.output.err(CompilerMsg::from_span(span, msg))
}
pub fn temp(&mut self, ty: Type) -> VarID {
pub fn temp(&mut self, ty: Type) -> VarInst {
self.map.temp_var(self.span, ty)
}
pub fn push(&mut self, i: IRUInstruction) {
self.instructions.push(i);
self.instructions.push(i, self.span);
}
pub fn push_at(&mut self, i: IRUInstruction, span: FileSpan) {
self.instructions.push(i, span);
}
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
FnLowerCtx {

View File

@@ -1,9 +1,9 @@
use crate::ir::NamespaceGuard;
use super::{PModule, ParserOutput};
use super::{PModule, CompilerOutput};
impl PModule {
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) {
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut CompilerOutput) {
let mut fns = Vec::new();
for f in &self.functions {
if let Some(id) = f.lower_header(map, output) {

View File

@@ -1,3 +1,4 @@
mod ctx;
mod cursor;
mod error;
mod lower;
@@ -5,13 +6,11 @@ mod node;
mod nodes;
mod parse;
mod token;
mod ctx;
use crate::common::{CompilerMsg, CompilerOutput, FileSpan, FilePos};
pub use ctx::*;
pub use cursor::*;
pub use error::*;
pub use lower::*;
pub use node::*;
pub use nodes::*;
pub use parse::*;
pub use token::*;
pub use ctx::*;

View File

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

View File

@@ -1,4 +1,4 @@
use super::{PIdent, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol};
use super::{Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg};
pub struct PInstruction {
pub op: Node<PIdent>,
@@ -38,7 +38,7 @@ impl Parsable for PAsmArg {
let next = ctx.expect_peek()?;
if !next.is_symbol(Symbol::OpenCurly) {
return ParseResult::Err(ParserMsg::unexpected_token(
return ParseResult::Err(CompilerMsg::unexpected_token(
next,
"An identifier or {identifier}",
));

View File

@@ -1,7 +1,7 @@
use std::fmt::{Debug, Write};
use super::{
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement,
token::Symbol, Node, NodeParsable, PStatement, Parsable, ParseResult, ParserCtx, CompilerMsg,
};
use crate::util::Padder;
@@ -24,7 +24,7 @@ impl Parsable for PBlock {
loop {
let Some(next) = ctx.peek() else {
recover = true;
ctx.err(ParserMsg::unexpected_end());
ctx.err(CompilerMsg::unexpected_end());
break;
};
if next.is_symbol(Symbol::CloseCurly) {
@@ -36,7 +36,7 @@ impl Parsable for PBlock {
expect_semi = false;
continue;
} else if expect_semi {
ctx.err(ParserMsg {
ctx.err(CompilerMsg {
msg: "expected ';'".to_string(),
spans: vec![ctx.next_start().char_span()],
});

View File

@@ -1,7 +1,8 @@
use std::fmt::Debug;
use super::{
PIdent, MaybeParsable, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token, PType,
MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx, Symbol,
Token, CompilerMsg
};
pub struct PVarDef {
@@ -9,6 +10,11 @@ pub struct PVarDef {
pub ty: Option<Node<PType>>,
}
pub struct PFieldDef {
pub name: Node<PIdent>,
pub val: Option<Node<PExpr>>,
}
impl Parsable for PVarDef {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let name = ctx.parse()?;
@@ -21,6 +27,21 @@ impl Parsable for PVarDef {
}
}
impl Parsable for PFieldDef {
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,
val: Some(ty),
})
} else {
ParseResult::Ok(Self { name, val: None })
}
}
}
pub struct SelfVar {
pub ty: SelfType,
}
@@ -32,7 +53,7 @@ pub enum SelfType {
}
impl MaybeParsable for SelfVar {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, super::ParserMsg> {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
if let Some(mut next) = ctx.peek() {
let mut ty = SelfType::Take;
if next.is_symbol(Symbol::Ampersand) {
@@ -47,7 +68,7 @@ impl MaybeParsable for SelfVar {
}
}
if ty != SelfType::Take {
return Err(ParserMsg::unexpected_token(next, "self"));
return Err(CompilerMsg::unexpected_token(next, "self"));
}
}
Ok(None)
@@ -64,6 +85,16 @@ impl Debug for PVarDef {
}
}
impl Debug for PFieldDef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.name.fmt(f)?;
if let Some(val) = &self.val {
write!(f, ": {:?}", val)?;
}
Ok(())
}
}
impl Debug for SelfVar {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(

View File

@@ -1,10 +1,7 @@
use std::fmt::{Debug, Write};
use super::{
op::{PInfixOp, UnaryOp},
util::parse_list,
PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx,
ParserMsg, Symbol,
op::{PInfixOp, UnaryOp}, util::parse_list, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg
};
type BoxNode = Node<Box<PExpr>>;
@@ -18,6 +15,7 @@ pub enum PExpr {
Call(BoxNode, Vec<Node<PExpr>>),
Group(BoxNode),
AsmBlock(Node<PAsmBlock>),
Construct(Node<PConstruct>),
}
impl Parsable for PExpr {
@@ -63,7 +61,7 @@ impl Parsable for PExpr {
Self::Ident(res.node)
} else {
let next = ctx.expect_peek()?;
return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression"));
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression"));
}
};
let Some(mut next) = ctx.peek() else {
@@ -140,6 +138,7 @@ impl Debug for PExpr {
}
PExpr::Group(inner) => inner.fmt(f)?,
PExpr::AsmBlock(inner) => inner.fmt(f)?,
PExpr::Construct(inner) => inner.fmt(f)?,
}
Ok(())
}

View File

@@ -1,4 +1,4 @@
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token};
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, Token, CompilerMsg};
use std::{
fmt::{Debug, Display},
ops::Deref,
@@ -11,7 +11,7 @@ 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"));
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an identifier"));
};
let name = name.to_string();
ctx.next();
@@ -20,7 +20,7 @@ impl Parsable for PIdent {
}
impl MaybeParsable for PIdent {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
let Some(next) = ctx.peek() else { return Ok(None) };
let Token::Word(name) = &next.token else {
return Ok(None);

View File

@@ -1,4 +1,4 @@
use super::{CharCursor, MaybeParsable, ParserCtx, ParserMsg, Symbol, Token};
use super::{CharCursor, MaybeParsable, ParserCtx, CompilerMsg, Symbol, Token};
use std::fmt::Debug;
#[derive(Clone, PartialEq, Eq)]
@@ -17,7 +17,7 @@ pub struct PNumber {
}
impl MaybeParsable for PLiteral {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
let inst = ctx.expect_peek()?;
Ok(Some(match &inst.token {
Token::Symbol(Symbol::SingleQuote) => {
@@ -37,7 +37,7 @@ impl MaybeParsable for PLiteral {
if !first.is_ascii_digit() {
return Ok(None);
}
let (whole, ty) = parse_whole_num(text);
let (whole, ty) = parse_whole_num(&text);
let mut num = PNumber {
whole,
decimal: None,
@@ -81,7 +81,7 @@ pub fn parse_whole_num(text: &str) -> (String, Option<String>) {
(whole, if ty.is_empty() { None } else { Some(ty) })
}
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> {
pub fn string_from(cursor: &mut CharCursor) -> Result<String, CompilerMsg> {
let mut str = String::new();
loop {
let c = cursor.expect_next()?;

View File

@@ -1,5 +1,5 @@
use super::{
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg,
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, CompilerMsg,
PStruct, Symbol, Token, PTrait,
};
use std::fmt::Debug;
@@ -52,18 +52,18 @@ impl Parsable for PModule {
}
}
_ => {
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
ctx.err(CompilerMsg::unexpected_token(next, "a definition"));
ctx.next();
}
}
} else if next.is_symbol(Symbol::Semicolon) {
ctx.hint(ParserMsg::from_instances(
ctx.hint(CompilerMsg::from_instances(
&[next],
"unneeded semicolon".to_string(),
));
ctx.next();
} else {
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
ctx.err(CompilerMsg::unexpected_token(next, "a definition"));
ctx.next();
}
}

View File

@@ -1,8 +1,8 @@
use std::fmt::Debug;
use super::{
util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol,
PType, PVarDef,
util::parse_list, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef, Parsable,
ParseResult, ParserCtx, CompilerMsg, Symbol,
};
#[derive(Debug)]
@@ -11,6 +11,12 @@ pub struct PStruct {
pub fields: PStructFields,
}
#[derive(Debug)]
pub struct PConstruct {
pub name: Node<PIdent>,
pub fields: PConstructFields,
}
#[derive(Debug)]
pub enum PStructFields {
Named(Vec<Node<PVarDef>>),
@@ -18,6 +24,13 @@ pub enum PStructFields {
None,
}
#[derive(Debug)]
pub enum PConstructFields {
Named(Vec<Node<PFieldDef>>),
Tuple(Vec<Node<PExpr>>),
None,
}
impl Parsable for PStruct {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
ctx.expect_kw(Keyword::Struct)?;
@@ -33,7 +46,7 @@ impl Parsable for PStruct {
ctx.next();
PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
} else {
let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`");
let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`");
ctx.err(msg);
return ParseResult::Recover(PStruct {
name,
@@ -43,3 +56,29 @@ impl Parsable for PStruct {
ParseResult::Ok(PStruct { name, fields })
}
}
impl Parsable for PConstruct {
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) {
ctx.next();
PConstructFields::None
} else if next.is_symbol(Symbol::OpenCurly) {
ctx.next();
PConstructFields::Named(parse_list(ctx, Symbol::CloseCurly)?)
} else if next.is_symbol(Symbol::OpenParen) {
ctx.next();
PConstructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
} else {
let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`");
ctx.err(msg);
return ParseResult::Recover(PConstruct {
name,
fields: PConstructFields::None,
});
};
ParseResult::Ok(PConstruct { name, fields })
}
}

View File

@@ -1,6 +1,6 @@
use std::fmt::Debug;
use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token};
use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, CompilerMsg, Symbol, Token};
pub struct PType {
pub name: String,
@@ -19,7 +19,7 @@ impl Parsable for PType {
}
} else {
let Token::Word(name) = &next.token else {
return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier"));
return ParseResult::Err(CompilerMsg::unexpected_token(next, "a type identifier"));
};
let n = name.to_string();
ctx.next();

View File

@@ -1,10 +1,10 @@
use super::{Node, Parsable, ParserCtx, ParserMsg, Symbol};
use super::{Node, Parsable, ParserCtx, CompilerMsg, Symbol};
pub fn parse_list_sep<T: Parsable>(
ctx: &mut ParserCtx,
sep: Symbol,
end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> {
) -> Result<Vec<Node<T>>, CompilerMsg> {
let mut vals = Vec::new();
loop {
let next = ctx.expect_peek()?;
@@ -29,14 +29,14 @@ pub fn parse_list_sep<T: Parsable>(
pub fn parse_list<T: Parsable>(
ctx: &mut ParserCtx,
end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> {
) -> Result<Vec<Node<T>>, CompilerMsg> {
parse_list_sep(ctx, Symbol::Comma, end)
}
pub fn parse_list_nosep<T: Parsable>(
ctx: &mut ParserCtx,
end: Symbol,
) -> Result<Vec<Node<T>>, ParserMsg> {
) -> Result<Vec<Node<T>>, CompilerMsg> {
let mut vals = Vec::new();
loop {
let next = ctx.expect_peek()?;

View File

@@ -3,14 +3,12 @@ use std::{
ops::{ControlFlow, FromResidual, Try},
};
use crate::ir::FilePos;
use super::{Node, ParserCtx, ParserMsg};
use super::{CompilerMsg, FilePos, Node, ParserCtx};
pub enum ParseResult<T> {
Ok(T),
Recover(T),
Err(ParserMsg),
Err(CompilerMsg),
SubErr,
}
@@ -26,7 +24,7 @@ impl<T> ParseResult<T> {
impl<T> Try for ParseResult<T> {
type Output = T;
type Residual = Option<ParserMsg>;
type Residual = Option<CompilerMsg>;
fn from_output(output: Self::Output) -> Self {
Self::Ok(output)
}
@@ -50,8 +48,8 @@ impl<T> FromResidual for ParseResult<T> {
}
}
impl<T> FromResidual<Result<Infallible, ParserMsg>> for ParseResult<T> {
fn from_residual(residual: Result<Infallible, ParserMsg>) -> Self {
impl<T> FromResidual<Result<Infallible, CompilerMsg>> for ParseResult<T> {
fn from_residual(residual: Result<Infallible, CompilerMsg>) -> Self {
match residual {
Err(e) => Self::Err(e),
}
@@ -115,14 +113,28 @@ pub trait Parsable: Sized {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self>;
}
pub trait MaybeParsable: Sized {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg>;
pub trait ParsableWith: Sized {
type Data;
fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult<Self>;
}
impl<T: Parsable> Node<T> {
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
pub trait MaybeParsable: Sized {
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg>;
}
impl<T: Parsable> ParsableWith for T {
type Data = ();
fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult<Self> {
T::parse(ctx)
}
}
impl<T: ParsableWith> Node<T> {
pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult<T> {
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
let (inner, recover) = match T::parse(ctx) {
let (inner, recover) = match T::parse(ctx, data) {
ParseResult::Ok(v) => (Some(v), false),
ParseResult::Recover(v) => (Some(v), true),
ParseResult::Err(e) => {
@@ -142,6 +154,12 @@ impl<T: Parsable> Node<T> {
}
}
impl<T: Parsable> Node<T> {
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
Node::parse_with(ctx, ())
}
}
impl<T: MaybeParsable> Node<T> {
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
let start = ctx.next_start();

View File

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

View File

@@ -7,8 +7,7 @@ use std::ops::Deref;
pub use cursor::*;
pub use keyword::*;
pub use symbol::*;
use crate::ir::FileSpan;
use super::FileSpan;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Token {