Make passes actually return errors well
This commit is contained in:
parent
e4845c4084
commit
575abe8172
@ -41,6 +41,9 @@ Currently missing relevant features (TODOs) are:
|
||||
- Debug Information
|
||||
- Borrows+Pointers
|
||||
|
||||
Smaller features:
|
||||
- Easier way to initialize arrays with a single value
|
||||
|
||||
### Why "Reid"
|
||||
|
||||
[ᚱ is an Elder Futhark rune](https://en.wikipedia.org/wiki/Raido) which means
|
||||
|
@ -1,10 +1,21 @@
|
||||
|
||||
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) {
|
||||
puts(message);
|
||||
}
|
||||
|
||||
pub fn intdiv(numerator: i32, denominator: i32) -> DivT {
|
||||
return div(numerator, denominator);
|
||||
}
|
||||
|
||||
fn main() -> u16 {
|
||||
return 0;
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ pub fn perform_all_passes<'map>(
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
|
||||
let state = context.pass(&mut LinkerPass { module_map });
|
||||
let state = context.pass(&mut LinkerPass { module_map })?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
@ -137,7 +137,7 @@ pub fn perform_all_passes<'map>(
|
||||
|
||||
let refs = TypeRefs::default();
|
||||
|
||||
let state = context.pass(&mut TypeInference { refs: &refs });
|
||||
let state = context.pass(&mut TypeInference { refs: &refs })?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
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)]
|
||||
println!("{}", &context);
|
||||
@ -189,13 +189,19 @@ pub fn compile_and_pass<'map>(
|
||||
let path = path.canonicalize().unwrap();
|
||||
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 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)?;
|
||||
|
||||
dbg!(&mir_context);
|
||||
println!("Context: {}", &mir_context);
|
||||
|
||||
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
||||
let codegen_modules = mir_context.codegen(&mut context, &module_map);
|
||||
|
||||
|
@ -7,10 +7,15 @@ use std::{
|
||||
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::{
|
||||
pass::{Pass, PassState},
|
||||
pass::{Pass, PassResult, PassState},
|
||||
r#impl::EqualsIssue,
|
||||
Context, FunctionDefinition, Import, Metadata, Module,
|
||||
};
|
||||
@ -41,14 +46,16 @@ pub enum ErrorKind {
|
||||
FunctionIsPrivate(String, String),
|
||||
}
|
||||
|
||||
pub fn compile_std(module_map: &mut ModuleMap) -> (super::Module, Vec<FullToken>) {
|
||||
let (id, tokens) = parse_module(STD_SOURCE, "standard_library", module_map).unwrap();
|
||||
let module = compile_module(id, &tokens, module_map, None, false).unwrap();
|
||||
pub fn compile_std(
|
||||
module_map: &mut ModuleMap,
|
||||
) -> 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 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
|
||||
@ -62,7 +69,7 @@ type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
||||
impl<'map> Pass for LinkerPass<'map> {
|
||||
type Data = ();
|
||||
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
|
||||
.modules
|
||||
.iter()
|
||||
@ -70,16 +77,16 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
.collect::<Vec<_>>();
|
||||
if mains.len() > 1 {
|
||||
state.note_errors(&vec![ErrorKind::MultipleMainsAtStart], Metadata::default());
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
let Some(main) = mains.first() else {
|
||||
state.note_errors(&vec![ErrorKind::NoMainDefined], Metadata::default());
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let Some(_) = main.functions.iter().find(|f| f.name == "main") else {
|
||||
state.note_errors(&vec![ErrorKind::NoMainFunction], Metadata::default());
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
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(
|
||||
// "std".to_owned(),
|
||||
// Rc::new(RefCell::new(compile_std(&mut self.module_map))),
|
||||
// );
|
||||
modules.insert(
|
||||
"std".to_owned(),
|
||||
Rc::new(RefCell::new(compile_std(&mut self.module_map)?)),
|
||||
);
|
||||
|
||||
let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> =
|
||||
modules.values().cloned().collect();
|
||||
@ -243,5 +250,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
.into_values()
|
||||
.map(|v| Rc::into_inner(v).unwrap().into_inner().0)
|
||||
.collect();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ use std::collections::HashMap;
|
||||
use std::convert::Infallible;
|
||||
use std::error::Error as STDError;
|
||||
|
||||
use crate::error_raporting::ReidError;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[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 {
|
||||
type Data: Clone + Default;
|
||||
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(
|
||||
&mut self,
|
||||
_function: &mut FunctionDefinition,
|
||||
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 {
|
||||
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 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 {
|
||||
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,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
) {
|
||||
) -> PassResult {
|
||||
for typedef in &self.typedefs {
|
||||
let kind = match &typedef.kind {
|
||||
TypeDefinitionKind::Struct(fields) => TypeDefinitionKind::Struct(fields.clone()),
|
||||
@ -262,11 +296,12 @@ impl Module {
|
||||
.ok();
|
||||
}
|
||||
|
||||
pass.module(self, PassState::from(state, scope));
|
||||
pass.module(self, PassState::from(state, scope))?;
|
||||
|
||||
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,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
) {
|
||||
) -> PassResult {
|
||||
for param in &self.parameters {
|
||||
scope
|
||||
.variables
|
||||
@ -290,15 +325,16 @@ impl FunctionDefinition {
|
||||
.ok();
|
||||
}
|
||||
|
||||
pass.function(self, PassState::from(state, scope));
|
||||
pass.function(self, PassState::from(state, scope))?;
|
||||
|
||||
match &mut self.kind {
|
||||
FunctionDefinitionKind::Local(block, _) => {
|
||||
scope.return_type_hint = Some(self.return_type.clone());
|
||||
block.pass(pass, state, scope);
|
||||
block.pass(pass, state, scope)?;
|
||||
}
|
||||
FunctionDefinitionKind::Extern(_) => {}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,14 +344,14 @@ impl Block {
|
||||
pass: &mut T,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
) {
|
||||
) -> PassResult {
|
||||
let mut scope = scope.inner();
|
||||
|
||||
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,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
) {
|
||||
) -> PassResult {
|
||||
match &mut self.0 {
|
||||
StmtKind::Let(_, _, expression) => {
|
||||
expression.pass(pass, state, scope);
|
||||
expression.pass(pass, state, scope)?;
|
||||
}
|
||||
StmtKind::Set(_, expression) => {
|
||||
expression.pass(pass, state, scope);
|
||||
expression.pass(pass, state, scope)?;
|
||||
}
|
||||
StmtKind::Import(_) => {} // Never exists at this stage
|
||||
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 {
|
||||
StmtKind::Let(variable_reference, mutable, _) => {
|
||||
@ -358,6 +394,7 @@ impl Statement {
|
||||
StmtKind::Import(_) => {} // Never exists at this stage
|
||||
StmtKind::Expression(_) => {}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,7 +404,8 @@ impl Expression {
|
||||
pass: &mut T,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
) {
|
||||
pass.expr(self, PassState::from(state, scope));
|
||||
) -> PassResult {
|
||||
pass.expr(self, PassState::from(state, scope))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use crate::{mir::*, util::try_all};
|
||||
use VagueType as Vague;
|
||||
|
||||
use super::{
|
||||
pass::{Pass, PassState, ScopeFunction, ScopeVariable},
|
||||
pass::{Pass, PassResult, PassState, ScopeFunction, ScopeVariable},
|
||||
typerefs::TypeRefs,
|
||||
};
|
||||
|
||||
@ -70,7 +70,7 @@ impl<'t> Pass for TypeCheck<'t> {
|
||||
type Data = ();
|
||||
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();
|
||||
for typedef in &module.typedefs {
|
||||
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());
|
||||
state.ok(res, function.block_meta());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use std::{convert::Infallible, iter};
|
||||
use crate::{mir::TypeKind, util::try_all};
|
||||
|
||||
use super::{
|
||||
pass::{Pass, PassState},
|
||||
pass::{Pass, PassResult, PassState},
|
||||
r#impl::pick_return,
|
||||
typecheck::ErrorKind,
|
||||
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
||||
@ -32,11 +32,12 @@ impl<'t> Pass for TypeInference<'t> {
|
||||
type Data = ();
|
||||
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 {
|
||||
let res = function.infer_types(&self.refs, &mut state.inner());
|
||||
state.ok(res, function.block_meta());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ fn compiles() {
|
||||
#[test]
|
||||
fn passes_all_passes() {
|
||||
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
|
||||
std.is_main = true;
|
||||
|
12
reid_src/std_test.reid
Normal file
12
reid_src/std_test.reid
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
import std::print;
|
||||
import std::intdiv;
|
||||
|
||||
fn main() {
|
||||
let hello = "hello world";
|
||||
|
||||
print(intdiv(10, 5).quot);
|
||||
|
||||
print(hello);
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user