Add FullToken array to error raporting

This commit is contained in:
Sofia 2025-07-17 17:44:18 +03:00
parent ce7c4bfb52
commit 9d1b18f083
7 changed files with 139 additions and 82 deletions

View File

@ -4,7 +4,8 @@ use std::{
};
use crate::{
ast, lexer,
ast,
lexer::{self, FullToken},
mir::{self, pass, Metadata, SourceModuleId},
token_stream,
};
@ -65,37 +66,65 @@ impl Ord for ErrorKind {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrModule {
pub name: String,
pub tokens: Option<Vec<FullToken>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ModuleMap {
module_map: HashMap<mir::SourceModuleId, String>,
module_map: HashMap<mir::SourceModuleId, ErrModule>,
module_counter: mir::SourceModuleId,
}
impl ModuleMap {
pub fn add_module<T: Into<String>>(&mut self, name: T) -> Option<mir::SourceModuleId> {
let id = self.module_counter.increment();
self.module_map.insert(id, name.into().clone());
self.module_map.insert(
id,
ErrModule {
name: name.into(),
tokens: None,
},
);
Some(id)
}
pub fn set_tokens(&mut self, id: mir::SourceModuleId, tokens: Vec<FullToken>) {
if let Some(module) = self.module_map.get_mut(&id) {
module.tokens = Some(tokens);
}
}
impl TryFrom<&mir::Context> for ModuleMap {
type Error = ();
pub fn get_module(&self, id: &mir::SourceModuleId) -> Option<&ErrModule> {
self.module_map.get(id)
}
}
fn try_from(value: &mir::Context) -> Result<Self, Self::Error> {
let mut map = HashMap::new();
for module in &value.modules {
if let Some(_) = map.insert(module.module_id, module.name.clone()) {
return Err(());
}
}
let module_counter = value.modules.iter().map(|m| m.module_id).max().ok_or(())?;
Ok(ModuleMap {
module_map: map,
module_counter,
})
}
}
// impl TryFrom<&mir::Context> for ModuleMap {
// type Error = ();
// fn try_from(value: &mir::Context) -> Result<Self, Self::Error> {
// let mut map = HashMap::new();
// for module in &value.modules {
// if let Some(_) = map.insert(
// module.module_id,
// ErrModule {
// name: module.name.clone(),
// tokens: Some(module.clone()),
// },
// ) {
// return Err(());
// }
// }
// let module_counter = value.modules.iter().map(|m| m.module_id).max().ok_or(())?;
// Ok(ModuleMap {
// module_map: map,
// module_counter,
// })
// }
// }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReidError {
@ -121,7 +150,11 @@ impl std::fmt::Display for ReidError {
"Errors in module {}:",
color_err(format!(
"{}",
self.map.module_map.get(&meta.source_module_id).unwrap()
self.map
.module_map
.get(&meta.source_module_id)
.unwrap()
.name
))?
)?;
}

View File

@ -100,7 +100,7 @@ impl From<Token> for String {
}
/// A token with a position
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FullToken {
pub token: Token,
pub position: Position,

View File

@ -44,6 +44,7 @@
use std::{convert::Infallible, path::PathBuf};
use error_raporting::{ErrorKind as ErrorRapKind, ModuleMap, ReidError};
use lexer::FullToken;
use mir::{
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
SourceModuleId,
@ -61,42 +62,58 @@ mod pad_adapter;
mod token_stream;
mod util;
pub fn compile_module<'map>(
pub fn parse_module<'map, T: Into<String>>(
source: &str,
name: String,
name: T,
map: &'map mut ModuleMap,
) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> {
let id = map.add_module(name.into()).unwrap();
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
map.set_tokens(id, tokens.clone());
#[cfg(debug_assertions)]
dbg!(&tokens);
Ok((id, tokens))
}
pub fn compile_module<'map>(
module_id: mir::SourceModuleId,
tokens: &Vec<FullToken>,
map: &'map mut ModuleMap,
path: Option<PathBuf>,
is_main: bool,
) -> Result<mir::Module, ReidError> {
let id = map.add_module(name.clone()).unwrap();
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
#[cfg(debug_assertions)]
dbg!(&tokens);
let module = map.get_module(&module_id).cloned().unwrap();
let mut token_stream = TokenStream::from(&tokens);
let mut statements = Vec::new();
while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) {
let statement =
ReidError::from_parser(token_stream.parse::<TopLevelStatement>(), map.clone(), id)?;
let statement = ReidError::from_parser(
token_stream.parse::<TopLevelStatement>(),
map.clone(),
module_id,
)?;
statements.push(statement);
}
let ast_module = ast::Module {
name,
name: module.name,
top_level_statements: statements,
path,
is_main,
};
Ok(ast_module.process(id))
Ok(ast_module.process(module_id))
}
pub fn perform_all_passes<'map>(
context: &mut mir::Context,
map: &'map mut ModuleMap,
module_map: &'map mut ModuleMap,
) -> Result<(), ReidError> {
#[cfg(debug_assertions)]
dbg!(&context);
@ -104,11 +121,7 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)]
println!("{}", &context);
let mut module_map = (&*context).try_into().unwrap();
let state = context.pass(&mut LinkerPass {
module_map: &mut module_map,
});
let state = context.pass(&mut LinkerPass { module_map });
#[cfg(debug_assertions)]
println!("{}", &context);
@ -118,7 +131,7 @@ pub fn perform_all_passes<'map>(
if !state.errors.is_empty() {
return Err(ReidError::from_kind::<()>(
state.errors.iter().map(|e| e.clone().into()).collect(),
map.clone(),
module_map.clone(),
));
}
@ -159,7 +172,7 @@ pub fn perform_all_passes<'map>(
);
if !errors.is_empty() {
return Err(ReidError::from_kind::<()>(errors, map.clone()));
return Err(ReidError::from_kind::<()>(errors, module_map.clone()));
}
Ok(())
@ -174,14 +187,10 @@ pub fn compile_and_pass<'map>(
module_map: &'map mut ModuleMap,
) -> Result<CompileOutput, ReidError> {
let path = path.canonicalize().unwrap();
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
let module = compile_module(
source,
path.file_name().unwrap().to_str().unwrap().to_owned(),
module_map,
Some(path.clone()),
true,
)?;
let (id, tokens) = parse_module(source, name, module_map).unwrap();
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());

View File

@ -7,7 +7,7 @@ use std::{
rc::Rc,
};
use crate::{compile_module, error_raporting::ModuleMap};
use crate::{compile_module, error_raporting::ModuleMap, lexer::FullToken, parse_module};
use super::{
pass::{Pass, PassState},
@ -41,20 +41,14 @@ pub enum ErrorKind {
FunctionIsPrivate(String, String),
}
pub fn compile_std(module_map: &mut ModuleMap) -> super::Module {
let module = compile_module(
STD_SOURCE,
"standard_library".to_owned(),
module_map,
None,
false,
)
.unwrap();
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();
let mut mir_context = super::Context::from(vec![module], Default::default());
let std_compiled = mir_context.modules.remove(0);
std_compiled
(std_compiled, tokens)
}
/// Struct used to implement a type-checking pass that can be performed on the
@ -88,10 +82,17 @@ impl<'map> Pass for LinkerPass<'map> {
return;
};
let mut modules = HashMap::<String, Rc<RefCell<Module>>>::new();
let mut modules = HashMap::<String, Rc<RefCell<_>>>::new();
for module in context.modules.drain(..) {
modules.insert(module.name.clone(), Rc::new(RefCell::new(module)));
let tokens = self
.module_map
.get_module(&module.module_id)
.unwrap()
.tokens
.clone()
.unwrap();
modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens))));
}
modules.insert(
@ -99,12 +100,13 @@ impl<'map> Pass for LinkerPass<'map> {
Rc::new(RefCell::new(compile_std(&mut self.module_map))),
);
let mut modules_to_process: Vec<Rc<RefCell<Module>>> = modules.values().cloned().collect();
let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> =
modules.values().cloned().collect();
while let Some(module) = modules_to_process.pop() {
let mut importer_module = module.borrow_mut();
for import in importer_module.imports.clone() {
for import in importer_module.0.imports.clone() {
let Import(path, _) = &import;
if path.len() != 2 {
state.ok::<_, Infallible>(
@ -129,13 +131,23 @@ impl<'map> Pass for LinkerPass<'map> {
continue;
};
match compile_module(
&source,
let (id, tokens) =
match parse_module(&source, module_name.clone(), &mut self.module_map) {
Ok(val) => val,
Err(err) => {
state.ok::<_, Infallible>(
Err(ErrorKind::ModuleCompilationError(
module_name.clone(),
&mut self.module_map,
Some(file_path),
false,
) {
format!("{}", err),
)),
import.1,
);
continue;
}
};
match compile_module(id, &tokens, &mut self.module_map, Some(file_path), false)
{
Ok(imported_module) => {
if imported_module.is_main {
state.ok::<_, Infallible>(
@ -147,7 +159,7 @@ impl<'map> Pass for LinkerPass<'map> {
let module_name = imported_module.name.clone();
modules.insert(
module_name.clone(),
Rc::new(RefCell::new(imported_module)),
Rc::new(RefCell::new((imported_module, tokens))),
);
let imported = modules.get_mut(&module_name).unwrap();
modules_to_process.push(imported.clone());
@ -169,7 +181,11 @@ impl<'map> Pass for LinkerPass<'map> {
let func_name = unsafe { path.get_unchecked(1) };
let Some(func) = imported.functions.iter_mut().find(|f| f.name == *func_name)
let Some(func) = imported
.0
.functions
.iter_mut()
.find(|f| f.name == *func_name)
else {
state.ok::<_, Infallible>(
Err(ErrorKind::NoSuchFunctionInModule(
@ -195,6 +211,7 @@ impl<'map> Pass for LinkerPass<'map> {
func.is_imported = true;
if let Some(existing) = importer_module
.0
.functions
.iter()
.find(|f| f.name == *func_name)
@ -211,7 +228,7 @@ impl<'map> Pass for LinkerPass<'map> {
}
}
importer_module.functions.push(FunctionDefinition {
importer_module.0.functions.push(FunctionDefinition {
name: func.name.clone(),
is_pub: false,
is_imported: false,
@ -224,7 +241,7 @@ impl<'map> Pass for LinkerPass<'map> {
context.modules = modules
.into_values()
.map(|v| Rc::into_inner(v).unwrap().into_inner())
.map(|v| Rc::into_inner(v).unwrap().into_inner().0)
.collect();
}
}

View File

@ -4,7 +4,10 @@
use std::{collections::HashMap, path::PathBuf};
use crate::{lexer::Position, token_stream::TokenRange};
use crate::{
lexer::{FullToken, Position},
token_stream::TokenRange,
};
mod display;
pub mod r#impl;

View File

@ -1,7 +1,7 @@
use reid::{
compile_module,
mir::{self},
perform_all_passes,
parse_module, perform_all_passes,
};
use util::assert_err;
@ -9,13 +9,8 @@ mod util;
fn test(source: &str, name: &str) {
let mut map = Default::default();
let module = assert_err(compile_module(
source,
name.to_owned(),
&mut map,
None,
true,
));
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
let module = assert_err(compile_module(id, &tokens, &mut map, None, true));
assert_err(perform_all_passes(
&mut mir::Context {

View File

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