Make passes actually return errors well

This commit is contained in:
Sofia 2025-07-20 15:25:21 +03:00
parent e4845c4084
commit 575abe8172
9 changed files with 132 additions and 49 deletions

View File

@ -41,6 +41,9 @@ Currently missing relevant features (TODOs) are:
- Debug Information - Debug Information
- Borrows+Pointers - Borrows+Pointers
Smaller features:
- Easier way to initialize arrays with a single value
### Why "Reid" ### Why "Reid"
[ᚱ is an Elder Futhark rune](https://en.wikipedia.org/wiki/Raido) which means [ᚱ is an Elder Futhark rune](https://en.wikipedia.org/wiki/Raido) which means

View File

@ -1,10 +1,21 @@
extern fn puts(message: string) -> i32; extern fn puts(message: string) -> i32;
struct DivT {
quot: i32,
rem: i32,
}
extern fn div(numerator: i32, denominator: i32) -> DivT;
pub fn print(message: string) { pub fn print(message: string) {
puts(message); puts(message);
} }
pub fn intdiv(numerator: i32, denominator: i32) -> DivT {
return div(numerator, denominator);
}
fn main() -> u16 { fn main() -> u16 {
return 0; return 0;
} }

View File

@ -121,7 +121,7 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{}", &context); println!("{}", &context);
let state = context.pass(&mut LinkerPass { module_map }); let state = context.pass(&mut LinkerPass { module_map })?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{}", &context); println!("{}", &context);
@ -137,7 +137,7 @@ pub fn perform_all_passes<'map>(
let refs = TypeRefs::default(); let refs = TypeRefs::default();
let state = context.pass(&mut TypeInference { refs: &refs }); let state = context.pass(&mut TypeInference { refs: &refs })?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&refs); dbg!(&refs);
@ -157,7 +157,7 @@ pub fn perform_all_passes<'map>(
)); ));
} }
let state = context.pass(&mut TypeCheck { refs: &refs }); let state = context.pass(&mut TypeCheck { refs: &refs })?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{}", &context); println!("{}", &context);
@ -189,13 +189,19 @@ pub fn compile_and_pass<'map>(
let path = path.canonicalize().unwrap(); let path = path.canonicalize().unwrap();
let name = path.file_name().unwrap().to_str().unwrap().to_owned(); let name = path.file_name().unwrap().to_str().unwrap().to_owned();
let (id, tokens) = parse_module(source, name, module_map).unwrap(); let (id, tokens) = parse_module(source, name, module_map)?;
let module = compile_module(id, &tokens, module_map, Some(path.clone()), true)?; let module = compile_module(id, &tokens, module_map, Some(path.clone()), true)?;
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned()); let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
dbg!(&mir_context);
println!("Context: {}", &mir_context);
perform_all_passes(&mut mir_context, module_map)?; perform_all_passes(&mut mir_context, module_map)?;
dbg!(&mir_context);
println!("Context: {}", &mir_context);
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION"))); let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
let codegen_modules = mir_context.codegen(&mut context, &module_map); let codegen_modules = mir_context.codegen(&mut context, &module_map);

View File

@ -7,10 +7,15 @@ use std::{
rc::Rc, rc::Rc,
}; };
use crate::{compile_module, error_raporting::ModuleMap, lexer::FullToken, parse_module}; use crate::{
compile_module,
error_raporting::{ModuleMap, ReidError},
lexer::FullToken,
parse_module,
};
use super::{ use super::{
pass::{Pass, PassState}, pass::{Pass, PassResult, PassState},
r#impl::EqualsIssue, r#impl::EqualsIssue,
Context, FunctionDefinition, Import, Metadata, Module, Context, FunctionDefinition, Import, Metadata, Module,
}; };
@ -41,14 +46,16 @@ pub enum ErrorKind {
FunctionIsPrivate(String, String), FunctionIsPrivate(String, String),
} }
pub fn compile_std(module_map: &mut ModuleMap) -> (super::Module, Vec<FullToken>) { pub fn compile_std(
let (id, tokens) = parse_module(STD_SOURCE, "standard_library", module_map).unwrap(); module_map: &mut ModuleMap,
let module = compile_module(id, &tokens, module_map, None, false).unwrap(); ) -> Result<(super::Module, Vec<FullToken>), ReidError> {
let (id, tokens) = parse_module(STD_SOURCE, "standard_library", module_map)?;
let module = compile_module(id, &tokens, module_map, None, false)?;
let mut mir_context = super::Context::from(vec![module], Default::default()); let mut mir_context = super::Context::from(vec![module], Default::default());
let std_compiled = mir_context.modules.remove(0); let std_compiled = mir_context.modules.remove(0);
(std_compiled, tokens) Ok((std_compiled, tokens))
} }
/// Struct used to implement a type-checking pass that can be performed on the /// Struct used to implement a type-checking pass that can be performed on the
@ -62,7 +69,7 @@ type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
impl<'map> Pass for LinkerPass<'map> { impl<'map> Pass for LinkerPass<'map> {
type Data = (); type Data = ();
type TError = ErrorKind; type TError = ErrorKind;
fn context(&mut self, context: &mut Context, mut state: LinkerPassState) { fn context(&mut self, context: &mut Context, mut state: LinkerPassState) -> PassResult {
let mains = context let mains = context
.modules .modules
.iter() .iter()
@ -70,16 +77,16 @@ impl<'map> Pass for LinkerPass<'map> {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if mains.len() > 1 { if mains.len() > 1 {
state.note_errors(&vec![ErrorKind::MultipleMainsAtStart], Metadata::default()); state.note_errors(&vec![ErrorKind::MultipleMainsAtStart], Metadata::default());
return; return Ok(());
} }
let Some(main) = mains.first() else { let Some(main) = mains.first() else {
state.note_errors(&vec![ErrorKind::NoMainDefined], Metadata::default()); state.note_errors(&vec![ErrorKind::NoMainDefined], Metadata::default());
return; return Ok(());
}; };
let Some(_) = main.functions.iter().find(|f| f.name == "main") else { let Some(_) = main.functions.iter().find(|f| f.name == "main") else {
state.note_errors(&vec![ErrorKind::NoMainFunction], Metadata::default()); state.note_errors(&vec![ErrorKind::NoMainFunction], Metadata::default());
return; return Ok(());
}; };
let mut modules = HashMap::<String, Rc<RefCell<_>>>::new(); let mut modules = HashMap::<String, Rc<RefCell<_>>>::new();
@ -95,10 +102,10 @@ impl<'map> Pass for LinkerPass<'map> {
modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens)))); modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens))));
} }
// modules.insert( modules.insert(
// "std".to_owned(), "std".to_owned(),
// Rc::new(RefCell::new(compile_std(&mut self.module_map))), Rc::new(RefCell::new(compile_std(&mut self.module_map)?)),
// ); );
let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> = let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> =
modules.values().cloned().collect(); modules.values().cloned().collect();
@ -243,5 +250,7 @@ impl<'map> Pass for LinkerPass<'map> {
.into_values() .into_values()
.map(|v| Rc::into_inner(v).unwrap().into_inner().0) .map(|v| Rc::into_inner(v).unwrap().into_inner().0)
.collect(); .collect();
Ok(())
} }
} }

View File

@ -5,6 +5,8 @@ use std::collections::HashMap;
use std::convert::Infallible; use std::convert::Infallible;
use std::error::Error as STDError; use std::error::Error as STDError;
use crate::error_raporting::ReidError;
use super::*; use super::*;
#[derive(thiserror::Error, Debug, Clone)] #[derive(thiserror::Error, Debug, Clone)]
@ -205,33 +207,65 @@ impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, '
} }
} }
pub type PassResult = Result<(), ReidError>;
pub trait Pass { pub trait Pass {
type Data: Clone + Default; type Data: Clone + Default;
type TError: STDError + Clone; type TError: STDError + Clone;
fn context(&mut self, _context: &mut Context, mut _state: PassState<Self::Data, Self::TError>) { fn context(
&mut self,
_context: &mut Context,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(())
}
fn module(
&mut self,
_module: &mut Module,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(())
} }
fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::Data, Self::TError>) {}
fn function( fn function(
&mut self, &mut self,
_function: &mut FunctionDefinition, _function: &mut FunctionDefinition,
mut _state: PassState<Self::Data, Self::TError>, mut _state: PassState<Self::Data, Self::TError>,
) { ) -> PassResult {
Ok(())
}
fn block(
&mut self,
_block: &mut Block,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(())
}
fn stmt(
&mut self,
_stmt: &mut Statement,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(())
}
fn expr(
&mut self,
_expr: &mut Expression,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(())
} }
fn block(&mut self, _block: &mut Block, mut _state: PassState<Self::Data, Self::TError>) {}
fn stmt(&mut self, _stmt: &mut Statement, mut _state: PassState<Self::Data, Self::TError>) {}
fn expr(&mut self, _expr: &mut Expression, mut _state: PassState<Self::Data, Self::TError>) {}
} }
impl Context { impl Context {
pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> { pub fn pass<T: Pass>(&mut self, pass: &mut T) -> Result<State<T::TError>, ReidError> {
let mut state = State::new(); let mut state = State::new();
let mut scope = Scope::default(); let mut scope = Scope::default();
pass.context(self, PassState::from(&mut state, &mut scope)); pass.context(self, PassState::from(&mut state, &mut scope))?;
for module in &mut self.modules { for module in &mut self.modules {
module.pass(pass, &mut state, &mut scope.inner()); module.pass(pass, &mut state, &mut scope.inner())?;
} }
state Ok(state)
} }
} }
@ -241,7 +275,7 @@ impl Module {
pass: &mut T, pass: &mut T,
state: &mut State<T::TError>, state: &mut State<T::TError>,
scope: &mut Scope<T::Data>, scope: &mut Scope<T::Data>,
) { ) -> PassResult {
for typedef in &self.typedefs { for typedef in &self.typedefs {
let kind = match &typedef.kind { let kind = match &typedef.kind {
TypeDefinitionKind::Struct(fields) => TypeDefinitionKind::Struct(fields.clone()), TypeDefinitionKind::Struct(fields) => TypeDefinitionKind::Struct(fields.clone()),
@ -262,11 +296,12 @@ impl Module {
.ok(); .ok();
} }
pass.module(self, PassState::from(state, scope)); pass.module(self, PassState::from(state, scope))?;
for function in &mut self.functions { for function in &mut self.functions {
function.pass(pass, state, &mut scope.inner()); function.pass(pass, state, &mut scope.inner())?;
} }
Ok(())
} }
} }
@ -276,7 +311,7 @@ impl FunctionDefinition {
pass: &mut T, pass: &mut T,
state: &mut State<T::TError>, state: &mut State<T::TError>,
scope: &mut Scope<T::Data>, scope: &mut Scope<T::Data>,
) { ) -> PassResult {
for param in &self.parameters { for param in &self.parameters {
scope scope
.variables .variables
@ -290,15 +325,16 @@ impl FunctionDefinition {
.ok(); .ok();
} }
pass.function(self, PassState::from(state, scope)); pass.function(self, PassState::from(state, scope))?;
match &mut self.kind { match &mut self.kind {
FunctionDefinitionKind::Local(block, _) => { FunctionDefinitionKind::Local(block, _) => {
scope.return_type_hint = Some(self.return_type.clone()); scope.return_type_hint = Some(self.return_type.clone());
block.pass(pass, state, scope); block.pass(pass, state, scope)?;
} }
FunctionDefinitionKind::Extern(_) => {} FunctionDefinitionKind::Extern(_) => {}
}; };
Ok(())
} }
} }
@ -308,14 +344,14 @@ impl Block {
pass: &mut T, pass: &mut T,
state: &mut State<T::TError>, state: &mut State<T::TError>,
scope: &mut Scope<T::Data>, scope: &mut Scope<T::Data>,
) { ) -> PassResult {
let mut scope = scope.inner(); let mut scope = scope.inner();
for statement in &mut self.statements { for statement in &mut self.statements {
statement.pass(pass, state, &mut scope); statement.pass(pass, state, &mut scope)?;
} }
pass.block(self, PassState::from(state, &mut scope)); pass.block(self, PassState::from(state, &mut scope))
} }
} }
@ -325,21 +361,21 @@ impl Statement {
pass: &mut T, pass: &mut T,
state: &mut State<T::TError>, state: &mut State<T::TError>,
scope: &mut Scope<T::Data>, scope: &mut Scope<T::Data>,
) { ) -> PassResult {
match &mut self.0 { match &mut self.0 {
StmtKind::Let(_, _, expression) => { StmtKind::Let(_, _, expression) => {
expression.pass(pass, state, scope); expression.pass(pass, state, scope)?;
} }
StmtKind::Set(_, expression) => { StmtKind::Set(_, expression) => {
expression.pass(pass, state, scope); expression.pass(pass, state, scope)?;
} }
StmtKind::Import(_) => {} // Never exists at this stage StmtKind::Import(_) => {} // Never exists at this stage
StmtKind::Expression(expression) => { StmtKind::Expression(expression) => {
expression.pass(pass, state, scope); expression.pass(pass, state, scope)?;
} }
} }
pass.stmt(self, PassState::from(state, scope)); pass.stmt(self, PassState::from(state, scope))?;
match &mut self.0 { match &mut self.0 {
StmtKind::Let(variable_reference, mutable, _) => { StmtKind::Let(variable_reference, mutable, _) => {
@ -358,6 +394,7 @@ impl Statement {
StmtKind::Import(_) => {} // Never exists at this stage StmtKind::Import(_) => {} // Never exists at this stage
StmtKind::Expression(_) => {} StmtKind::Expression(_) => {}
}; };
Ok(())
} }
} }
@ -367,7 +404,8 @@ impl Expression {
pass: &mut T, pass: &mut T,
state: &mut State<T::TError>, state: &mut State<T::TError>,
scope: &mut Scope<T::Data>, scope: &mut Scope<T::Data>,
) { ) -> PassResult {
pass.expr(self, PassState::from(state, scope)); pass.expr(self, PassState::from(state, scope))?;
Ok(())
} }
} }

View File

@ -6,7 +6,7 @@ use crate::{mir::*, util::try_all};
use VagueType as Vague; use VagueType as Vague;
use super::{ use super::{
pass::{Pass, PassState, ScopeFunction, ScopeVariable}, pass::{Pass, PassResult, PassState, ScopeFunction, ScopeVariable},
typerefs::TypeRefs, typerefs::TypeRefs,
}; };
@ -70,7 +70,7 @@ impl<'t> Pass for TypeCheck<'t> {
type Data = (); type Data = ();
type TError = ErrorKind; type TError = ErrorKind;
fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) { fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult {
let mut defmap = HashMap::new(); let mut defmap = HashMap::new();
for typedef in &module.typedefs { for typedef in &module.typedefs {
let TypeDefinition { name, kind, meta } = &typedef; let TypeDefinition { name, kind, meta } = &typedef;
@ -107,6 +107,7 @@ impl<'t> Pass for TypeCheck<'t> {
let res = function.typecheck(&self.refs, &mut state.inner()); let res = function.typecheck(&self.refs, &mut state.inner());
state.ok(res, function.block_meta()); state.ok(res, function.block_meta());
} }
Ok(())
} }
} }

View File

@ -9,7 +9,7 @@ use std::{convert::Infallible, iter};
use crate::{mir::TypeKind, util::try_all}; use crate::{mir::TypeKind, util::try_all};
use super::{ use super::{
pass::{Pass, PassState}, pass::{Pass, PassResult, PassState},
r#impl::pick_return, r#impl::pick_return,
typecheck::ErrorKind, typecheck::ErrorKind,
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
@ -32,11 +32,12 @@ impl<'t> Pass for TypeInference<'t> {
type Data = (); type Data = ();
type TError = ErrorKind; type TError = ErrorKind;
fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) { fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) -> PassResult {
for function in &mut module.functions { for function in &mut module.functions {
let res = function.infer_types(&self.refs, &mut state.inner()); let res = function.infer_types(&self.refs, &mut state.inner());
state.ok(res, function.block_meta()); state.ok(res, function.block_meta());
} }
Ok(())
} }
} }

View File

@ -14,7 +14,9 @@ fn compiles() {
#[test] #[test]
fn passes_all_passes() { fn passes_all_passes() {
let mut map = Default::default(); let mut map = Default::default();
let (mut std, _) = compile_std(&mut map); let Ok((mut std, _)) = compile_std(&mut map) else {
panic!()
};
// Needed to pass linker-pass // Needed to pass linker-pass
std.is_main = true; std.is_main = true;

12
reid_src/std_test.reid Normal file
View File

@ -0,0 +1,12 @@
import std::print;
import std::intdiv;
fn main() {
let hello = "hello world";
print(intdiv(10, 5).quot);
print(hello);
}