diff --git a/crates/mist-api/src/transpiler.mist b/crates/mist-api/src/transpiler.mist index 6ce29aa..992b3f1 100644 --- a/crates/mist-api/src/transpiler.mist +++ b/crates/mist-api/src/transpiler.mist @@ -184,8 +184,13 @@ fn is_source_newer(source *Path, output *Path) std::io::Result { Ok(source_time > output_time) } +pub enum TranspileError<'a> { + Parse[error::ParseError<'a, Vec>], + Semantic[mist_parser::semantics::SemanticError] +} + pub fn transpile_code<'a>(path *PathBuf, source *'a str, mut output_file PathBuf, mod_decl *str, curr_mod_decl *Option<[mist_parser::ast::Visibility, mist_parser::ast::Identifier]>) - Result<[PathBuf, mist_codegen::RustCodegen, String], error::ParseError<'a, Vec>> { + Result<[PathBuf, mist_codegen::RustCodegen, String], TranspileError<'a>> { if let Some[[_, name]] = &curr_mod_decl { if output_file.file_name().map(fn(v) -> v.to_str()).unwrap_or_default() != Some("mod.rs") { @@ -204,10 +209,10 @@ pub fn transpile_code<'a>(path *PathBuf, source *'a str, mut output_file PathBuf let mut gc = mist_codegen::RustCodegen::new(path.clone()); - let parsed = mist_parser::parse(source)?; + let parsed = mist_parser::parse(source).map_err(TranspileError::Parse)?; for i in &parsed { - let _ = mist_parser::semantics::check_class_semantics(i); + let _ = mist_parser::semantics::check_class_semantics(i).map_err(TranspileError::Semantic)?; } let output = gc.generate(parsed); @@ -221,32 +226,8 @@ pub fn transpile_file(path *PathBuf, source *str, output_file PathBuf, mod_decl let [output_file, gc, output] = match transpile_code(path, source, output_file, mod_decl, curr_mod_decl) { Ok[output] => output; Err[e] => { - match e { - error::ParseError::Ast[e] => { - let start_pos = e.span.start_pos().line_col(); - - let span = e.span.as_str(); - - eprintln!( - "\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}", - path.as_os_str().display(), - start_pos.0, - start_pos.1, - e.error_message, - span, - if span.ends_with("\n") { "" } else { "\n" }, - "^".repeat(span.trim().len()), - ); - - process::exit(1); - } - - error::ParseError::PreAst[e] => { - eprintln!("error: parse failed in {}\n{}", path.display(), e); - - process::exit(1); - } - } + decode_err(&e, path); + process::exit(1); } }; @@ -276,3 +257,44 @@ pub fn transpile_file(path *PathBuf, source *str, output_file PathBuf, mod_decl process::exit(1); } } + +pub fn decode_err<'a>(err *TranspileError<'a>, path *PathBuf) { + let curr_dir = std::env::current_dir().unwrap(); + + match err { + TranspileError::Semantic[e] => { + eprintln!( + "\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}", + path.strip_prefix(curr_dir).unwrap_or_else(|_| path).as_os_str().display(), + e.line, + e.column, + e.error_message, + ); + } + + TranspileError::Parse[e] => { + match e { + error::ParseError::Ast[e] => { + let start_pos = e.span.start_pos().line_col(); + + let span = e.span.as_str(); + + eprintln!( + "\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}{}\t{}", + path.strip_prefix(curr_dir).unwrap_or_else(|_| path).as_os_str().display(), + start_pos.0, + start_pos.1, + e.error_message, + span, + if span.ends_with("\n") { "" } else { "\n" }, + "^".repeat(span.trim().len()), + ); + } + + error::ParseError::PreAst[e] => { + eprintln!("error: parse failed in {}\n{}", path.strip_prefix(curr_dir).unwrap_or_else(|_| path).display(), e); + } + } + } + } +} diff --git a/crates/parser/src/semantics.rs b/crates/parser/src/semantics.rs index 6a2c664..fa369ae 100644 --- a/crates/parser/src/semantics.rs +++ b/crates/parser/src/semantics.rs @@ -1,15 +1,19 @@ -use crate::{ - ast::{ - Block, ClassItem, Expression, FunctionDecl, Identifier, Postfix, Spanned, TopLevel, - TopLevelKind, - }, - error::AstError, +use crate::ast::{ + Block, ClassItem, Expression, FunctionDecl, Identifier, Postfix, Spanned, TopLevel, + TopLevelKind, }; pub trait GetMutability { fn get_mutability(&self) -> Vec; } +#[derive(Debug, Clone)] +pub struct SemanticError { + pub line: usize, + pub column: usize, + pub error_message: String, +} + /// Class semantics - Ensuring fields are initialized pub fn find_function_call<'a>( @@ -29,7 +33,7 @@ pub fn find_function_call<'a>( }) } -pub fn check_class_semantics<'a>(top_level: &TopLevel) -> Result<(), AstError<'a, ()>> { +pub fn check_class_semantics<'a>(top_level: &TopLevel) -> Result<(), SemanticError> { if let TopLevelKind::ClassDecl { fields, constructor, @@ -61,7 +65,11 @@ pub fn check_class_semantics<'a>(top_level: &TopLevel) -> Result<(), AstError<'a for field in &fields { if mutability_iter.find(|v| v == &field.item).is_none() { - panic!("Unable to find set for field {}", field.item.0); + return Err(SemanticError { + line: field.line, + column: field.column, + error_message: format!("Field `{}` is uninitialized", field.item.0), + }); } } } @@ -152,6 +160,6 @@ impl GetMutability for Expression { pub fn mutates_lhs(op: &str) -> bool { matches!( op, - "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" + "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "->" ) }