diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 7d228a9..8424f27 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -1,6 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 774f412..5344698 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -8,41 +8,13 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -171,6 +143,9 @@
+
+
+
diff --git a/main.why b/main.why
index 7518705..43ec5e5 100644
--- a/main.why
+++ b/main.why
@@ -1,3 +1,4 @@
+
fn main() -> int {
return 12;
}
diff --git a/src/root.rs b/src/root.rs
index a018520..2d02dcb 100644
--- a/src/root.rs
+++ b/src/root.rs
@@ -1,4 +1,3 @@
-use name_resolver::resolve_names::resolve_names;
use crate::root::parser::parse::parse;
// use crate::root::assembler::assemble::generate_assembly;
// use crate::root::name_resolver::processor::process;
@@ -11,6 +10,7 @@ use std::path::PathBuf;
use crate::root::compiler::compile::compile;
use crate::root::name_resolver::resolve::resolve;
use shared::common::ByteSize;
+use crate::root::errors::WError;
use crate::root::runner::{assemble, link_gcc, run};
// #[cfg(target_os = "windows")]
@@ -32,6 +32,7 @@ pub mod builtin;
pub mod shared;
pub mod compiler;
pub mod assembler;
+pub mod errors;
pub const POINTER_SIZE: ByteSize = ByteSize(8);
@@ -52,10 +53,12 @@ pub struct Args {
pub fn main() {
let args = Args::parse();
- let _ = main_args(args);
+ if let Err(e) = main_args(args) {
+ println!("\n{e}");
+ }
}
-pub fn main_args(args: Args) {
+pub fn main_args(args: Args) -> Result<(), WError> {
if let Some(path) = PathBuf::from(&args.output).parent() {
if let Err(e) = fs::create_dir_all(path) {
if !matches!(e.kind(), ErrorKind::AlreadyExists) {
@@ -72,7 +75,7 @@ pub fn main_args(args: Args) {
print!("Resolving Names... ");
time!(
- let (global_table, unprocessed_functions) = resolve(parsed);
+ let (global_table, unprocessed_functions) = resolve(parsed)?;
);
print!("Compiling... ");
@@ -107,4 +110,5 @@ pub fn main_args(args: Args) {
}
cprintln!("Done!>");
+ Ok(())
}
diff --git a/src/root/errors/mod.rs b/src/root/errors/mod.rs
new file mode 100644
index 0000000..595dbce
--- /dev/null
+++ b/src/root/errors/mod.rs
@@ -0,0 +1,39 @@
+use std::fmt::{Display, Formatter};
+use color_print::cformat;
+use crate::root::parser::parse::Location;
+
+pub mod parser_errors;
+pub mod name_resolver_errors;
+
+pub struct WError {
+ error: String,
+ location: Option // ! Important, don't do file reads unless necessary (i.e. Display)
+}
+
+impl WError {
+ pub fn n(error: impl Display, location: Location) -> WError {
+ WError {
+ error: format!("{error}"),
+ location: Some(location)
+ }
+ }
+
+ pub fn locationless(error: impl Display) -> WError {
+ WError {
+ error: format!("{error}"),
+ location: None
+ }
+ }
+}
+
+impl Display for WError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ let text = if let Some(location) = &self.location {
+ cformat!("Error:>\n {}\nAt:>\n{}", self.error, location)
+ }
+ else {
+ cformat!("Error:>\n {}", self.error)
+ };
+ f.write_str(&text)
+ }
+}
\ No newline at end of file
diff --git a/src/root/errors/name_resolver_errors.rs b/src/root/errors/name_resolver_errors.rs
new file mode 100644
index 0000000..8bc77d5
--- /dev/null
+++ b/src/root/errors/name_resolver_errors.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum NRErrors {
+ #[error("No top-level main function found")]
+ NoMain,
+ #[error("Cannot create 'impl' for an indirect type")]
+ IndirectImpl
+}
diff --git a/src/root/errors/parser_errors.rs b/src/root/errors/parser_errors.rs
new file mode 100644
index 0000000..0276cbc
--- /dev/null
+++ b/src/root/errors/parser_errors.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum ParseError {
+ // #[error("Names cannot contain character '{0}' (UTF-8 Code: {1:?})")]
+ // BadName(char, Vec),
+}
diff --git a/src/root/name_resolver/resolve.rs b/src/root/name_resolver/resolve.rs
index a720431..74a7d27 100644
--- a/src/root/name_resolver/resolve.rs
+++ b/src/root/name_resolver/resolve.rs
@@ -1,20 +1,21 @@
use std::collections::HashMap;
use crate::root::builtin::register_builtin;
+use crate::root::errors::name_resolver_errors::NRErrors;
+use crate::root::errors::WError;
use crate::root::name_resolver::name_resolvers::GlobalDefinitionTable;
use crate::root::name_resolver::resolve_names::resolve_names;
use crate::root::parser::parse_function::FunctionToken;
use crate::root::parser::parse_toplevel::TopLevelTokens;
use crate::root::shared::common::FunctionID;
-pub fn resolve(ast: Vec) -> (GlobalDefinitionTable, HashMap) {
+pub fn resolve(ast: Vec) -> Result<(GlobalDefinitionTable, HashMap), WError> {
let mut global_table = GlobalDefinitionTable::new();
register_builtin(&mut global_table);
- let unprocessed_functions = resolve_names(ast, &mut global_table);
+ let unprocessed_functions = resolve_names(ast, &mut global_table)?;
if !global_table.function_signatures().contains_key(&FunctionID(0)) {
- // NO MAIN!
- todo!()
+ return Err(WError::locationless(NRErrors::NoMain))
}
- (global_table, unprocessed_functions)
+ Ok((global_table, unprocessed_functions))
}
\ No newline at end of file
diff --git a/src/root/name_resolver/resolve_names.rs b/src/root/name_resolver/resolve_names.rs
index df18f26..9baa875 100644
--- a/src/root/name_resolver/resolve_names.rs
+++ b/src/root/name_resolver/resolve_names.rs
@@ -2,6 +2,8 @@ use std::collections::HashMap;
use derive_getters::Getters;
use itertools::Itertools;
+use crate::root::errors::name_resolver_errors::NRErrors;
+use crate::root::errors::WError;
use crate::root::name_resolver::name_resolvers::{GlobalDefinitionTable, NameResultId};
use crate::root::name_resolver::resolve_function_signatures::resolve_function_signature;
@@ -84,7 +86,7 @@ impl Type for UserType {
}
// ! Unoptimised
-pub fn resolve_names(ast: Vec, global_table: &mut GlobalDefinitionTable) -> HashMap {
+pub fn resolve_names(ast: Vec, global_table: &mut GlobalDefinitionTable) -> Result, WError> {
let mut ast = ast;
// ? User types > 1; Builtin Types < -1
@@ -118,8 +120,8 @@ pub fn resolve_names(ast: Vec, global_table: &mut GlobalDefiniti
.map(|(name, type_name)| {
// TODO
let type_ref = match global_table.resolve_global_name_to_id(&type_name).unwrap().unwrap() {
- NameResultId::Function(_) => todo!(),
NameResultId::Type(type_ref) => type_ref,
+ NameResultId::Function(_) => todo!(),
NameResultId::NotFound => todo!(),
};
@@ -136,9 +138,8 @@ pub fn resolve_names(ast: Vec, global_table: &mut GlobalDefiniti
NameResultId::NotFound => todo!(),
};
- // TODO
if type_ref.indirection().has_indirection() {
- panic!()
+ return WError::n(NRErrors::IndirectImpl, it.location().clone());
}
for ft in it.dissolve().2 {
diff --git a/src/root/parser/parse.rs b/src/root/parser/parse.rs
index dfafc26..5a38797 100644
--- a/src/root/parser/parse.rs
+++ b/src/root/parser/parse.rs
@@ -1,3 +1,5 @@
+use std::cmp::min;
+use std::fmt::{Display, Formatter};
use crate::root::parser::parse_toplevel;
use nom::IResult;
use nom_locate::LocatedSpan;
@@ -21,7 +23,9 @@ pub type ErrorTree<'a> = GenericErrorTree<
#[derive(Debug, Clone, Getters, Hash)]
pub struct Location {
path: Rc,
+ /// Offset in the line, counted from 0
offset: usize,
+ /// Line number, counted from 1
line: u32,
}
@@ -35,6 +39,64 @@ impl Location {
}
}
+const CHAR_LIMIT: usize = 61;
+
+impl Display for Location {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ fn fail(f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Failed to fetch file reference (has the file changed?")
+ }
+
+ let Ok(file) = fs::read_to_string(self.path.as_path()) else { return fail(f); };
+
+ let mut line_iter = file.lines();
+
+ if self.line > 1 {
+ if self.line > 2 {
+ writeln!(f, "{} | ...", self.line - 2)?;
+ }
+
+ let Some(line) = line_iter.nth(self.line as usize - 2) else { return fail(f); };
+ let line = if line.chars().count() > CHAR_LIMIT { format!("{} ...", line.chars().take(CHAR_LIMIT - 4).collect::()) } else { line.to_string() };
+ writeln!(f, "{} | {}", self.line - 1, line)?;
+ }
+
+ let Some(line) = line_iter.next() else { return fail(f); };
+ let (mut start, mut end) = (0usize, line.chars().count() - 1);
+
+ if end > CHAR_LIMIT {
+ let start_dist = self.offset - start;
+ let end_dist = end - self.offset;
+
+ if start_dist > end_dist {
+ let take_from_start = min(start_dist, CHAR_LIMIT / 2);
+ start += take_from_start;
+ end -= CHAR_LIMIT - 1 - take_from_start;
+ }
+ else {
+ let take_from_end = min(end_dist, CHAR_LIMIT / 2);
+ end -= take_from_end;
+ start = CHAR_LIMIT - 1 - take_from_end;
+ }
+ }
+
+ end += 1;
+
+ writeln!(f, "{} | {}", self.line, line.chars().skip(start).take(end - start).collect::())?;
+ writeln!(f, "E | {}^Here", (0..(self.offset - start)).map(|_| ' ').collect::())?;
+
+ if let Some(line) = line_iter.next() {
+ let line = if line.chars().count() > CHAR_LIMIT { format!("{} ...", line.chars().take(CHAR_LIMIT - 4).collect::()) } else { line.to_string() };
+ writeln!(f, "{} | {}", self.line + 1, line)?;
+ if line_iter.next().is_some() {
+ writeln!(f, "{} | ...", self.line + 2)?;
+ }
+ }
+
+ Ok(())
+ }
+}
+
pub fn parse(path: PathBuf) -> Result, ()> {
let text = fs::read_to_string(&path).unwrap();
let path = Rc::new(path);
diff --git a/src/root/parser/parse_function.rs b/src/root/parser/parse_function.rs
index 242240e..a2dcaac 100644
--- a/src/root/parser/parse_function.rs
+++ b/src/root/parser/parse_function.rs
@@ -1,15 +1,14 @@
use derive_getters::{Dissolve, Getters};
use nom::sequence::Tuple;
-use nom::Parser;
+use nom::{Offset, Parser};
use nom_supreme::tag::complete::tag;
use substring::Substring;
-
use crate::root::parser::parse::{ErrorTree, Location, ParseResult, Span};
use crate::root::parser::parse_blocks::default_section;
-use crate::root::parser::parse_function::parse_line::{parse_lines, LineTokens};
+use crate::root::parser::parse_function::parse_line::{LineTokens, parse_lines};
use crate::root::parser::parse_name::{parse_full_name, parse_simple_name, UnresolvedNameToken};
-use crate::root::parser::parse_parameters::{parse_parameters, Parameters};
-use crate::root::parser::parse_toplevel::{TopLevelTokens, ToplevelTestFn};
+use crate::root::parser::parse_parameters::{Parameters, parse_parameters};
+use crate::root::parser::parse_toplevel::{ToplevelTestFn, TopLevelTokens};
use crate::root::parser::parse_util::{discard_ignored, require_ignored};
pub mod parse_assigner;
diff --git a/src/root/utils.rs b/src/root/utils.rs
index a1d0385..d8f3ea8 100644
--- a/src/root/utils.rs
+++ b/src/root/utils.rs
@@ -27,6 +27,19 @@ macro_rules! time {
};
}
+// #[macro_export]
+// macro_rules! try {
+// ($($tts:tt)*) => {
+// match $($tts)* {
+// Err(e) => {
+// println!("\n{}");
+// return;
+// }
+// Ok(v) => v
+// }
+// };
+// }
+
#[macro_export]
macro_rules! ret_time {
($out: expr, $($tts:tt)*) => {