Attempt to significantly improve error-raporting
This commit is contained in:
parent
64e34ecf13
commit
f0e47a5d57
@ -1,6 +1,6 @@
|
|||||||
use std::{env, error::Error, fs, path::PathBuf};
|
use std::{env, fs, path::PathBuf};
|
||||||
|
|
||||||
use reid::compile;
|
use reid::compile_simple;
|
||||||
use reid_lib::compile::CompileOutput;
|
use reid_lib::compile::CompileOutput;
|
||||||
|
|
||||||
fn main() -> Result<(), std::io::Error> {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
@ -15,7 +15,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
let before = std::time::SystemTime::now();
|
let before = std::time::SystemTime::now();
|
||||||
|
|
||||||
let text = fs::read_to_string(&path)?;
|
let text = fs::read_to_string(&path)?;
|
||||||
match compile(&text, PathBuf::from(&path)) {
|
match compile_simple(&text, PathBuf::from(&path)) {
|
||||||
Ok(CompileOutput {
|
Ok(CompileOutput {
|
||||||
triple,
|
triple,
|
||||||
assembly,
|
assembly,
|
||||||
|
@ -0,0 +1,175 @@
|
|||||||
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast, lexer,
|
||||||
|
mir::{self, pass, Metadata, SourceModuleId},
|
||||||
|
token_stream,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<T: std::error::Error + std::fmt::Display> pass::Error<T> {
|
||||||
|
fn fmt_simple(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(&self.kind, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ErrorKind {
|
||||||
|
#[error("Lexing: {0:?}")]
|
||||||
|
LexerError(#[from] mir::pass::Error<lexer::Error>),
|
||||||
|
#[error("Parsing: {0:?}")]
|
||||||
|
ParserError(#[from] mir::pass::Error<token_stream::Error>),
|
||||||
|
#[error("Typechecking: {0:?}")]
|
||||||
|
TypeCheckError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
|
||||||
|
#[error("Type Inference: {0:?}")]
|
||||||
|
TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
|
||||||
|
#[error("Linking: {0:?}")]
|
||||||
|
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorKind {
|
||||||
|
pub fn from_typecheck(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind {
|
||||||
|
ErrorKind::TypeCheckError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_typeinference(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind {
|
||||||
|
ErrorKind::TypeInferenceError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorKind {
|
||||||
|
fn get_meta(&self) -> Metadata {
|
||||||
|
match &self {
|
||||||
|
ErrorKind::LexerError(error) => error.metadata,
|
||||||
|
ErrorKind::ParserError(error) => error.metadata,
|
||||||
|
ErrorKind::TypeCheckError(error) => error.metadata,
|
||||||
|
ErrorKind::TypeInferenceError(error) => error.metadata,
|
||||||
|
ErrorKind::LinkerError(error) => error.metadata,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for ErrorKind {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
self.get_meta()
|
||||||
|
.source_module_id
|
||||||
|
.partial_cmp(&other.get_meta().source_module_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for ErrorKind {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.get_meta().cmp(&other.get_meta())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
|
pub struct ModuleMap {
|
||||||
|
module_map: HashMap<mir::SourceModuleId, String>,
|
||||||
|
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());
|
||||||
|
Some(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ReidError {
|
||||||
|
map: ModuleMap,
|
||||||
|
errors: Vec<ErrorKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ReidError {}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ReidError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut sorted_errors = self.errors.clone();
|
||||||
|
sorted_errors.sort_by(|a, b| a.cmp(&b));
|
||||||
|
|
||||||
|
let mut curr_module = None;
|
||||||
|
for error in sorted_errors {
|
||||||
|
let meta = error.get_meta();
|
||||||
|
if curr_module != Some(meta.source_module_id) {
|
||||||
|
curr_module = Some(meta.source_module_id);
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"Errors in module {}:",
|
||||||
|
self.map.module_map.get(&meta.source_module_id).unwrap()
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
write!(f, " Error: ")?;
|
||||||
|
std::fmt::Display::fmt(&error, f)?;
|
||||||
|
writeln!(f, " At: {}", meta)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReidError {
|
||||||
|
pub fn from_lexer<U>(
|
||||||
|
result: Result<U, lexer::Error>,
|
||||||
|
map: ModuleMap,
|
||||||
|
module: SourceModuleId,
|
||||||
|
) -> Result<U, ReidError> {
|
||||||
|
result.map_err(|error| {
|
||||||
|
let pass_err = pass::Error {
|
||||||
|
metadata: Metadata {
|
||||||
|
source_module_id: module,
|
||||||
|
range: Default::default(),
|
||||||
|
position: Some(*error.get_position()),
|
||||||
|
},
|
||||||
|
kind: error,
|
||||||
|
};
|
||||||
|
ReidError {
|
||||||
|
map,
|
||||||
|
errors: vec![ErrorKind::LexerError(pass_err)],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_parser<U>(
|
||||||
|
result: Result<U, token_stream::Error>,
|
||||||
|
map: ModuleMap,
|
||||||
|
module: SourceModuleId,
|
||||||
|
) -> Result<U, ReidError> {
|
||||||
|
result.map_err(|error| {
|
||||||
|
let pass_err = pass::Error {
|
||||||
|
metadata: Metadata {
|
||||||
|
source_module_id: module,
|
||||||
|
range: Default::default(),
|
||||||
|
position: error.get_position().copied(),
|
||||||
|
},
|
||||||
|
kind: error,
|
||||||
|
};
|
||||||
|
ReidError {
|
||||||
|
map,
|
||||||
|
errors: vec![ErrorKind::ParserError(pass_err)],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_kind<U>(errors: Vec<ErrorKind>, map: ModuleMap) -> ReidError {
|
||||||
|
ReidError { map, errors }
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ use std::{fmt::Debug, str::Chars};
|
|||||||
|
|
||||||
static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
#[derive(Debug, Eq, PartialEq, Clone, PartialOrd, Ord)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
/// Values
|
/// Values
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
@ -273,10 +273,19 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)]
|
#[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)]
|
||||||
InvalidToken(char, Position),
|
InvalidToken(char, Position),
|
||||||
#[error("String literal that starts at Ln {}, Col {} is never finished!", (.0).1, (.0).0)]
|
#[error("String literal that starts at Ln {}, Col {} is never finished!", (.0).1, (.0).0)]
|
||||||
MissingQuotation(Position),
|
MissingQuotation(Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn get_position(&self) -> &Position {
|
||||||
|
match self {
|
||||||
|
Error::InvalidToken(_, pos) => pos,
|
||||||
|
Error::MissingQuotation(pos) => pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -41,8 +41,9 @@
|
|||||||
//! - Debug Symbols
|
//! - Debug Symbols
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::{convert::Infallible, path::PathBuf};
|
||||||
|
|
||||||
|
use error_raporting::{ErrorKind as ErrorRapKind, ModuleMap, ReidError};
|
||||||
use mir::{
|
use mir::{
|
||||||
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
|
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
|
||||||
SourceModuleId,
|
SourceModuleId,
|
||||||
@ -53,34 +54,22 @@ use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
|
|||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
mod error_raporting;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
pub mod mir;
|
pub mod mir;
|
||||||
mod pad_adapter;
|
mod pad_adapter;
|
||||||
mod token_stream;
|
mod token_stream;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
pub fn compile_module<'map>(
|
||||||
pub enum ReidError {
|
|
||||||
#[error(transparent)]
|
|
||||||
LexerError(#[from] lexer::Error),
|
|
||||||
#[error(transparent)]
|
|
||||||
ParserError(#[from] token_stream::Error),
|
|
||||||
#[error("Errors during typecheck: {0:?}")]
|
|
||||||
TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
|
|
||||||
#[error("Errors during type inference: {0:?}")]
|
|
||||||
TypeInferenceErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
|
|
||||||
#[error("Errors during linking: {0:?}")]
|
|
||||||
LinkerErrors(Vec<mir::pass::Error<mir::linker::ErrorKind>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_module(
|
|
||||||
source: &str,
|
source: &str,
|
||||||
name: String,
|
name: String,
|
||||||
module_id: SourceModuleId,
|
map: &'map mut ModuleMap,
|
||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
is_main: bool,
|
is_main: bool,
|
||||||
) -> Result<mir::Module, ReidError> {
|
) -> Result<mir::Module, ReidError> {
|
||||||
let tokens = lexer::tokenize(source)?;
|
let id = map.add_module(name.clone()).unwrap();
|
||||||
|
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
dbg!(&tokens);
|
dbg!(&tokens);
|
||||||
@ -90,7 +79,8 @@ pub fn compile_module(
|
|||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
|
|
||||||
while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) {
|
while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) {
|
||||||
let statement = token_stream.parse::<TopLevelStatement>()?;
|
let statement =
|
||||||
|
ReidError::from_parser(token_stream.parse::<TopLevelStatement>(), map.clone(), id)?;
|
||||||
statements.push(statement);
|
statements.push(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,17 +91,24 @@ pub fn compile_module(
|
|||||||
is_main,
|
is_main,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ast_module.process(module_id))
|
Ok(ast_module.process(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
pub fn perform_all_passes<'map>(
|
||||||
|
context: &mut mir::Context,
|
||||||
|
map: &'map mut ModuleMap,
|
||||||
|
) -> Result<(), ReidError> {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
dbg!(&context);
|
dbg!(&context);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("{}", &context);
|
println!("{}", &context);
|
||||||
|
|
||||||
let state = context.pass(&mut LinkerPass);
|
let mut module_map = (&*context).try_into().unwrap();
|
||||||
|
|
||||||
|
let state = context.pass(&mut LinkerPass {
|
||||||
|
module_map: &mut module_map,
|
||||||
|
});
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("{}", &context);
|
println!("{}", &context);
|
||||||
@ -119,7 +116,10 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
|||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::LinkerErrors(state.errors));
|
return Err(ReidError::from_kind::<()>(
|
||||||
|
state.errors.iter().map(|e| e.clone().into()).collect(),
|
||||||
|
map.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let refs = TypeRefs::default();
|
let refs = TypeRefs::default();
|
||||||
@ -134,7 +134,14 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
|||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::TypeInferenceErrors(state.errors));
|
return Err(ReidError::from_kind::<()>(
|
||||||
|
state
|
||||||
|
.errors
|
||||||
|
.iter()
|
||||||
|
.map(|e| ErrorRapKind::TypeInferenceError(e.clone()))
|
||||||
|
.collect(),
|
||||||
|
map.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = context.pass(&mut TypeCheck { refs: &refs });
|
let state = context.pass(&mut TypeCheck { refs: &refs });
|
||||||
@ -145,7 +152,14 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
|||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::TypeCheckErrors(state.errors));
|
return Err(ReidError::from_kind::<()>(
|
||||||
|
state
|
||||||
|
.errors
|
||||||
|
.iter()
|
||||||
|
.map(|e| ErrorRapKind::TypeCheckError(e.clone()))
|
||||||
|
.collect(),
|
||||||
|
map.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -154,21 +168,24 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
|||||||
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
|
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
|
||||||
/// and `hello.asm` from it, which can be linked using `ld` to produce an
|
/// and `hello.asm` from it, which can be linked using `ld` to produce an
|
||||||
/// executable file.
|
/// executable file.
|
||||||
pub fn compile(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> {
|
pub fn compile_and_pass<'map>(
|
||||||
|
source: &str,
|
||||||
|
path: PathBuf,
|
||||||
|
module_map: &'map mut ModuleMap,
|
||||||
|
) -> Result<CompileOutput, ReidError> {
|
||||||
let path = path.canonicalize().unwrap();
|
let path = path.canonicalize().unwrap();
|
||||||
|
|
||||||
let mut mir_context = mir::Context::from(
|
let module = compile_module(
|
||||||
vec![compile_module(
|
|
||||||
source,
|
source,
|
||||||
path.file_name().unwrap().to_str().unwrap().to_owned(),
|
path.file_name().unwrap().to_str().unwrap().to_owned(),
|
||||||
SourceModuleId::default(),
|
module_map,
|
||||||
Some(path.clone()),
|
Some(path.clone()),
|
||||||
true,
|
true,
|
||||||
)?],
|
)?;
|
||||||
path.parent().unwrap().to_owned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
perform_all_passes(&mut mir_context)?;
|
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
|
||||||
|
|
||||||
|
perform_all_passes(&mut mir_context, module_map)?;
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
let codegen_modules = mir_context.codegen(&mut context);
|
let codegen_modules = mir_context.codegen(&mut context);
|
||||||
@ -179,3 +196,8 @@ pub fn compile(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError>
|
|||||||
let compiled = codegen_modules.compile();
|
let compiled = codegen_modules.compile();
|
||||||
Ok(compiled.output())
|
Ok(compiled.output())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compile_simple(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> {
|
||||||
|
let mut map = ModuleMap::default();
|
||||||
|
compile_and_pass(source, path, &mut map)
|
||||||
|
}
|
||||||
|
@ -279,7 +279,7 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, thiserror::Error)]
|
#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum EqualsIssue {
|
pub enum EqualsIssue {
|
||||||
#[error("Function is already defined locally at {:?}", (.0).range)]
|
#[error("Function is already defined locally at {:?}", (.0).range)]
|
||||||
ExistsLocally(Metadata),
|
ExistsLocally(Metadata),
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{compile_module, ReidError};
|
use crate::{compile_module, error_raporting::ModuleMap};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pass::{Pass, PassState},
|
pass::{Pass, PassState},
|
||||||
@ -17,14 +17,14 @@ use super::{
|
|||||||
|
|
||||||
pub static STD_SOURCE: &str = include_str!("../../lib/std.reid");
|
pub static STD_SOURCE: &str = include_str!("../../lib/std.reid");
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
#[error("Unable to import inner modules, not yet supported: {0}")]
|
#[error("Unable to import inner modules, not yet supported: {0}")]
|
||||||
InnerModulesNotYetSupported(Import),
|
InnerModulesNotYetSupported(Import),
|
||||||
#[error("No such module: {0}")]
|
#[error("No such module: {0}")]
|
||||||
ModuleNotFound(String),
|
ModuleNotFound(String),
|
||||||
#[error("Error while compiling module {0}: {1}")]
|
#[error("Error while compiling module {0}: {1}")]
|
||||||
ModuleCompilationError(String, ReidError),
|
ModuleCompilationError(String, String),
|
||||||
#[error("No such function {0} found in module {1}")]
|
#[error("No such function {0} found in module {1}")]
|
||||||
NoSuchFunctionInModule(String, String),
|
NoSuchFunctionInModule(String, String),
|
||||||
#[error("Importing function {0}::{1} not possible: {2}")]
|
#[error("Importing function {0}::{1} not possible: {2}")]
|
||||||
@ -41,11 +41,11 @@ pub enum ErrorKind {
|
|||||||
FunctionIsPrivate(String, String),
|
FunctionIsPrivate(String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_std(module_id: SourceModuleId) -> super::Module {
|
pub fn compile_std(module_map: &mut ModuleMap) -> super::Module {
|
||||||
let module = compile_module(
|
let module = compile_module(
|
||||||
STD_SOURCE,
|
STD_SOURCE,
|
||||||
"standard_library".to_owned(),
|
"standard_library".to_owned(),
|
||||||
module_id,
|
module_map,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
@ -59,11 +59,13 @@ pub fn compile_std(module_id: SourceModuleId) -> super::Module {
|
|||||||
|
|
||||||
/// 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
|
||||||
/// MIR.
|
/// MIR.
|
||||||
pub struct LinkerPass;
|
pub struct LinkerPass<'map> {
|
||||||
|
pub module_map: &'map mut ModuleMap,
|
||||||
|
}
|
||||||
|
|
||||||
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
||||||
|
|
||||||
impl Pass for LinkerPass {
|
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) {
|
||||||
@ -92,15 +94,9 @@ impl Pass for LinkerPass {
|
|||||||
modules.insert(module.name.clone(), Rc::new(RefCell::new(module)));
|
modules.insert(module.name.clone(), Rc::new(RefCell::new(module)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut module_counter = modules
|
|
||||||
.values()
|
|
||||||
.map(|m| m.borrow().module_id)
|
|
||||||
.max()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
modules.insert(
|
modules.insert(
|
||||||
"std".to_owned(),
|
"std".to_owned(),
|
||||||
Rc::new(RefCell::new(compile_std(module_counter.increment()))),
|
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>>> = modules.values().cloned().collect();
|
||||||
@ -136,7 +132,7 @@ impl Pass for LinkerPass {
|
|||||||
match compile_module(
|
match compile_module(
|
||||||
&source,
|
&source,
|
||||||
module_name.clone(),
|
module_name.clone(),
|
||||||
module_counter.increment(),
|
&mut self.module_map,
|
||||||
Some(file_path),
|
Some(file_path),
|
||||||
false,
|
false,
|
||||||
) {
|
) {
|
||||||
@ -159,7 +155,10 @@ impl Pass for LinkerPass {
|
|||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::ModuleCompilationError(module_name.clone(), err)),
|
Err(ErrorKind::ModuleCompilationError(
|
||||||
|
module_name.clone(),
|
||||||
|
format!("{}", err),
|
||||||
|
)),
|
||||||
import.1,
|
import.1,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
use crate::token_stream::TokenRange;
|
use crate::{lexer::Position, token_stream::TokenRange};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
pub mod r#impl;
|
pub mod r#impl;
|
||||||
@ -24,10 +24,11 @@ impl SourceModuleId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
pub range: TokenRange,
|
|
||||||
pub source_module_id: SourceModuleId,
|
pub source_module_id: SourceModuleId,
|
||||||
|
pub range: TokenRange,
|
||||||
|
pub position: Option<Position>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Add for Metadata {
|
impl std::ops::Add for Metadata {
|
||||||
@ -38,6 +39,7 @@ impl std::ops::Add for Metadata {
|
|||||||
Metadata {
|
Metadata {
|
||||||
range: self.range + rhs.range,
|
range: self.range + rhs.range,
|
||||||
source_module_id: self.source_module_id,
|
source_module_id: self.source_module_id,
|
||||||
|
position: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +49,12 @@ impl TokenRange {
|
|||||||
Metadata {
|
Metadata {
|
||||||
range: self,
|
range: self,
|
||||||
source_module_id: module,
|
source_module_id: module,
|
||||||
|
position: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
|
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)]
|
||||||
pub enum TypeKind {
|
pub enum TypeKind {
|
||||||
#[error("bool")]
|
#[error("bool")]
|
||||||
Bool,
|
Bool,
|
||||||
@ -89,7 +92,7 @@ pub enum TypeKind {
|
|||||||
Vague(#[from] VagueType),
|
Vague(#[from] VagueType),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)]
|
||||||
pub enum VagueType {
|
pub enum VagueType {
|
||||||
#[error("Unknown")]
|
#[error("Unknown")]
|
||||||
Unknown,
|
Unknown,
|
||||||
@ -125,7 +128,7 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
I8(i8),
|
I8(i8),
|
||||||
I16(i16),
|
I16(i16),
|
||||||
@ -142,7 +145,7 @@ pub enum Literal {
|
|||||||
Vague(VagueLiteral),
|
Vague(VagueLiteral),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum VagueLiteral {
|
pub enum VagueLiteral {
|
||||||
Number(u64),
|
Number(u64),
|
||||||
}
|
}
|
||||||
@ -204,7 +207,7 @@ pub enum ReturnKind {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
|
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Import(pub Vec<String>, pub Metadata);
|
pub struct Import(pub Vec<String>, pub Metadata);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -15,10 +15,10 @@ pub enum SimplePassError {
|
|||||||
VariableAlreadyDefined(String),
|
VariableAlreadyDefined(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Error<TErr: STDError> {
|
pub struct Error<TErr: STDError> {
|
||||||
metadata: Metadata,
|
pub metadata: Metadata,
|
||||||
kind: TErr,
|
pub kind: TErr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TErr: STDError> std::fmt::Display for Error<TErr> {
|
impl<TErr: STDError> std::fmt::Display for Error<TErr> {
|
||||||
|
@ -10,7 +10,7 @@ use super::{
|
|||||||
typerefs::TypeRefs,
|
typerefs::TypeRefs,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
#[error("NULL error, should never occur!")]
|
#[error("NULL error, should never occur!")]
|
||||||
Null,
|
Null,
|
||||||
|
@ -174,7 +174,7 @@ impl Drop for TokenStream<'_, '_> {
|
|||||||
|
|
||||||
/// Index-range that can be used with the original array of [`FullToken`]s to
|
/// Index-range that can be used with the original array of [`FullToken`]s to
|
||||||
/// retrieve the precise location of a failure.
|
/// retrieve the precise location of a failure.
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct TokenRange {
|
pub struct TokenRange {
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
@ -207,7 +207,7 @@ impl std::iter::Sum for TokenRange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
||||||
Expected(String, Token, Position),
|
Expected(String, Token, Position),
|
||||||
@ -220,3 +220,14 @@ pub enum Error {
|
|||||||
#[error("Condition failed for parse-if. Should never be returned to end-user.")]
|
#[error("Condition failed for parse-if. Should never be returned to end-user.")]
|
||||||
IfFailed,
|
IfFailed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn get_position(&self) -> Option<&Position> {
|
||||||
|
match self {
|
||||||
|
Error::Expected(_, _, pos) => Some(pos),
|
||||||
|
Error::FileEmpty => None,
|
||||||
|
Error::Undefined => None,
|
||||||
|
Error::IfFailed => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,88 +7,70 @@ use util::assert_err;
|
|||||||
|
|
||||||
mod util;
|
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,
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_err(perform_all_passes(
|
||||||
|
&mut mir::Context {
|
||||||
|
modules: vec![module],
|
||||||
|
base: Default::default(),
|
||||||
|
},
|
||||||
|
&mut map,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
pub static ARRAY: &str = include_str!("../../reid_src/array.reid");
|
pub static ARRAY: &str = include_str!("../../reid_src/array.reid");
|
||||||
pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid");
|
pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid");
|
||||||
pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid");
|
pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid");
|
||||||
pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid");
|
pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid");
|
||||||
pub static STRINGS: &str = include_str!("../../reid_src/strings.reid");
|
pub static STRINGS: &str = include_str!("../../reid_src/strings.reid");
|
||||||
|
pub static ARRAYS: &str = include_str!("../../reid_src/array.reid");
|
||||||
|
pub static STRUCTS: &str = include_str!("../../reid_src/struct.reid");
|
||||||
|
pub static ARRAY_STRUCTS: &str = include_str!("../../reid_src/array_structs.reid");
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn array_compiles_well() {
|
fn array_compiles_well() {
|
||||||
let module = assert_err(compile_module(
|
test(ARRAY, "array");
|
||||||
ARRAY,
|
|
||||||
"array".to_owned(),
|
|
||||||
Default::default(),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_err(perform_all_passes(&mut mir::Context {
|
|
||||||
modules: vec![module],
|
|
||||||
base: Default::default(),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fibonacci_compiles_well() {
|
fn fibonacci_compiles_well() {
|
||||||
let module = assert_err(compile_module(
|
test(FIBONACCI, "fibonacci");
|
||||||
FIBONACCI,
|
|
||||||
"fibonacci".to_owned(),
|
|
||||||
Default::default(),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_err(perform_all_passes(&mut mir::Context {
|
|
||||||
modules: vec![module],
|
|
||||||
base: Default::default(),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hello_world_compiles_well() {
|
fn hello_world_compiles_well() {
|
||||||
let module = assert_err(compile_module(
|
test(HELLO_WORLD, "hello_world");
|
||||||
HELLO_WORLD,
|
|
||||||
"hello_world".to_owned(),
|
|
||||||
Default::default(),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_err(perform_all_passes(&mut mir::Context {
|
|
||||||
modules: vec![module],
|
|
||||||
base: Default::default(),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mutable_compiles_well() {
|
fn mutable_compiles_well() {
|
||||||
let module = assert_err(compile_module(
|
test(MUTABLE, "mutable");
|
||||||
MUTABLE,
|
|
||||||
"mutable".to_owned(),
|
|
||||||
Default::default(),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_err(perform_all_passes(&mut mir::Context {
|
|
||||||
modules: vec![module],
|
|
||||||
base: Default::default(),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn strings_compiles_well() {
|
fn strings_compiles_well() {
|
||||||
let module = assert_err(compile_module(
|
test(STRINGS, "strings");
|
||||||
STRINGS,
|
}
|
||||||
"strings".to_owned(),
|
|
||||||
Default::default(),
|
#[test]
|
||||||
None,
|
fn arrays_compiles_well() {
|
||||||
true,
|
test(ARRAY, "array");
|
||||||
));
|
}
|
||||||
|
|
||||||
assert_err(perform_all_passes(&mut mir::Context {
|
#[test]
|
||||||
modules: vec![module],
|
fn struct_compiles_well() {
|
||||||
base: Default::default(),
|
test(STRUCTS, "struct");
|
||||||
}));
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_structs_compiles_well() {
|
||||||
|
test(ARRAY_STRUCTS, "array_structs");
|
||||||
}
|
}
|
||||||
|
@ -8,18 +8,22 @@ mod util;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compiles() {
|
fn compiles() {
|
||||||
let _ = compile_std(Default::default());
|
let _ = compile_std(&mut Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn passes_all_passes() {
|
fn passes_all_passes() {
|
||||||
let mut std = compile_std(Default::default());
|
let mut map = Default::default();
|
||||||
|
let mut std = compile_std(&mut map);
|
||||||
|
|
||||||
// Needed to pass linker-pass
|
// Needed to pass linker-pass
|
||||||
std.is_main = true;
|
std.is_main = true;
|
||||||
|
|
||||||
assert_err(perform_all_passes(&mut mir::Context {
|
assert_err(perform_all_passes(
|
||||||
|
&mut mir::Context {
|
||||||
modules: vec![std],
|
modules: vec![std],
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
}));
|
},
|
||||||
|
&mut map,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user