From 216c61228cf92f34146a65c6ce833fc92a202b4b Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 12:09:30 +0200 Subject: [PATCH 01/18] Making a error recovery system --- mist-test/src/main.mist | 2 + parser/src/error.rs | 2 +- parser/src/lib.rs | 65 +++++++++++++++++++++++++++ parser/src/parser/common/statement.rs | 3 +- parser/src/parser/items/mod.rs | 3 +- 5 files changed, 72 insertions(+), 3 deletions(-) diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index 853e686..086ea97 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -12,4 +12,6 @@ void main() { app_instance.boot(); app_instance.run(); + + hi } \ No newline at end of file diff --git a/parser/src/error.rs b/parser/src/error.rs index a3bf8cc..0557cf9 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -108,7 +108,7 @@ where span: ast_err.span, error_code: ast_err.error_code, error_message: ast_err.error_message, - recovered: None, + recovered: Some(items), }), None => Ok(items), } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 5ab2bbf..3e0293f 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -26,3 +26,68 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec {{ + let mut err = None; + + let v = $($item)::+ { + $( + $k: { + let r = $v.get(); + + if let Err(e) = r { + err = Some(e.clone().get()); + + if let Some(recovered) = e.recovered { + Ok(recovered) + } else { + Err(e) + } + } else { + r + } + }.get()? + ),* + }; + + if let Some(mut e) = err { + e.recovered = Some(v); + Err(e) + } else { + Ok(v) + } + }}; + + ($($item:ident)::+ ( $($v:expr),* $(,)? )) => {{ + let mut err = None; + + let v = $($item)::+ ( $({ + let r = $v.get(); + + if let Err(e) = r { + err = Some(e.clone().get()); + + if let Some(recovered) = e.recovered { + Ok(recovered) + } else { + Err(e) + } + } else { + r + } + }.get()?),* ); + + if let Some(mut e) = err { + e.recovered = Some(v); + Err(e) + } else { + Ok(v) + } + }}; + + ($($item:ident)::+) => { + $($item)::+ + }; +} diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 3f5afd5..77e1241 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -1,6 +1,7 @@ use crate::{ Rule, ast::*, + ast_expr, error::{AstError, AstResult, ErrorCode, GetParseError, collect_recovered}, parser::listen_rule, }; @@ -10,7 +11,7 @@ impl<'a> TryFrom> for Block { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { if pair.as_rule() == Rule::block { - Ok(Block(collect_recovered(pair.into_inner()).get()?)) + ast_expr!(Block(collect_recovered(pair.into_inner()))) } else { Err(AstError { span: pair.as_span(), diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 9eba00e..bc5bf65 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -7,6 +7,7 @@ pub mod impl_decl; use crate::{ Rule, ast::*, + ast_expr, error::{AstError, GetParseError, collect_recovered}, parser::consume_rule, }; @@ -43,7 +44,7 @@ impl<'a> TryFrom> for TopLevelKind { Path::try_from(inner.next().unwrap()).get()?, ), - Rule::function_decl => TopLevelKind::FunctionDecl(pair.try_into().get()?), + Rule::function_decl => return ast_expr!(TopLevelKind::FunctionDecl(pair.try_into())), Rule::struct_decl => TopLevelKind::StructDecl { visibility: Visibility::try_from(&mut inner).get()?, From c6b9588f4dc424cbfe9f10e630505062586f7825 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 13:12:52 +0200 Subject: [PATCH 02/18] ast error analyzer --- mist-test/src/app.mist | 95 --------------------------------------- mist-test/src/event.mist | 7 --- mist-test/src/logger.mist | 72 ----------------------------- mist-test/src/main.mist | 11 ----- mist-test/src/plugin.mist | 16 ------- mist-test/src/task.mist | 20 --------- parser/src/error.rs | 34 +++++++++++++- parser/src/lib.rs | 54 +++------------------- 8 files changed, 38 insertions(+), 271 deletions(-) delete mode 100644 mist-test/src/app.mist delete mode 100644 mist-test/src/event.mist delete mode 100644 mist-test/src/logger.mist delete mode 100644 mist-test/src/plugin.mist delete mode 100644 mist-test/src/task.mist diff --git a/mist-test/src/app.mist b/mist-test/src/app.mist deleted file mode 100644 index 01fbd87..0000000 --- a/mist-test/src/app.mist +++ /dev/null @@ -1,95 +0,0 @@ -use ; -use ; -use ; - -pub class Application { - String name; - - Vec tasks; - Vec plugins; - - logger::Logger logger; - - bool running; - i32 ticks; - - pub constructor(str* name) { - self.name = name.to_string(); - - self.tasks = new Vec(); - self.plugins = new Vec(); - - self.logger = new logger::Logger("app"); - - self.running = false; - self.ticks = 0; - } - - pub void boot(self mut*) { - self.logger.info("booting application"); - - self.running = true; - - self.emit(event::Event::Startup); - } - - pub void run(self mut*) { - while(self.running) { - self.tick(); - - if(self.ticks >= 5) { - self.shutdown(); - } - } - } - - void tick(self mut*) { - self.logger.info("tick"); - - self.ticks = self.ticks + 1; - - var task = task::create_task("background-job"); - - self.tasks.push(task); - - println!("tasks: {}", self.tasks.len()); - } - - pub void shutdown(self mut*) { - self.emit(event::Event::Shutdown); - - self.logger.warning("shutdown"); - - self.running = false; - } - - pub void register_plugin(self mut*, String name) { - self.plugins.push(name.clone()); - - self.emit(event::Event::PluginLoaded(name)); - } - - void emit(self*, event::Event event) { - match(event) { - event::Event::Startup => { - self.logger.info("startup event"); - } - - event::Event::Shutdown => { - self.logger.info("shutdown event"); - } - - event::Event::PluginLoaded(name) => { - println!("plugin loaded: {}", name); - } - - event::Event::TaskExecuted(name) => { - println!("task executed: {}", name); - } - - event::Event::Error(message) => { - self.logger.error(&message); - } - } - } -} \ No newline at end of file diff --git a/mist-test/src/event.mist b/mist-test/src/event.mist deleted file mode 100644 index 6340bf4..0000000 --- a/mist-test/src/event.mist +++ /dev/null @@ -1,7 +0,0 @@ -pub enum Event { - Startup, - Shutdown, - TaskExecuted(String), - PluginLoaded(String), - Error(String), -} \ No newline at end of file diff --git a/mist-test/src/logger.mist b/mist-test/src/logger.mist deleted file mode 100644 index a109a0e..0000000 --- a/mist-test/src/logger.mist +++ /dev/null @@ -1,72 +0,0 @@ -use ; -use ; - -pub trait TestLogging: fmt::Display { - String get(); -} - -pub enum LogLevel { - Info, - Warning, - Error, -} - -impl fmt::Display for LogLevel { - fmt::Result fmt(self*, Formatter<'_> mut* f) { - match (self) { - LogLevel::Info => { - return write!(f, "[INFO]"); - } - - LogLevel::Warning => { - return write!(f, "[WARN]"); - } - - LogLevel::Error => { - return write!(f, "[ERROR]"); - } - } - } -} - -pub class Logger { - String prefix; - - pub constructor(str* prefix) { - self.prefix = prefix.to_string(); - } - - pub void info(self*, str* message) { - self.log(LogLevel::Info, message); - } - - pub void warning(self*, str* message) { - self.log(LogLevel::Warning, message); - } - - pub void error(self*, str* message) { - self.log(LogLevel::Error, message); - } - - void log(self*, LogLevel level, str* message) { - match(level) { - LogLevel::Info => { - println!("{level} {} {}", self.prefix, message); - } - - LogLevel::Warning => { - println!("{level} {} {}", self.prefix, message); - } - - LogLevel::Error => { - println!("{level} {} {}", self.prefix, message); - } - } - } - - impl fmt::Display { - fmt::Result fmt(self*, Formatter<'_> mut* f) { - return write!(f, "logger ({})", self.prefix); - } - } -} diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index 086ea97..e0761f2 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -1,15 +1,4 @@ -pub mod app; -pub mod task; -pub mod plugin; -pub mod logger; -pub mod event; - void main() { - var mut app_instance = new app::Application("mist-app"); - - // greeting::register(&mut app_instance); - // statistics::register(&mut app_instance); - app_instance.boot(); app_instance.run(); diff --git a/mist-test/src/plugin.mist b/mist-test/src/plugin.mist deleted file mode 100644 index a3d16ba..0000000 --- a/mist-test/src/plugin.mist +++ /dev/null @@ -1,16 +0,0 @@ -pub struct PluginInfo { - pub String name, - pub String version, -} - -pub class PluginRegistry { - T plugins; - - pub constructor(T plugins) { - self.plugins = plugins; - } - - pub T plugins(self) { - return self.plugins; - } -} \ No newline at end of file diff --git a/mist-test/src/task.mist b/mist-test/src/task.mist deleted file mode 100644 index d902258..0000000 --- a/mist-test/src/task.mist +++ /dev/null @@ -1,20 +0,0 @@ -pub enum TaskState { - Pending, - Running, - Finished, - Failed, -} - -pub struct Task { - pub String name, - pub TaskState state, - pub i32 executions, -} - -pub Task create_task(str* name) { - return Task { - name: name.to_string(), - state: TaskState::Pending, - executions: 0, - }; -} \ No newline at end of file diff --git a/parser/src/error.rs b/parser/src/error.rs index 0557cf9..1e97f27 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + use crate::Rule; pub type AstResult<'a, T, ET = T> = Result>; @@ -75,7 +77,7 @@ impl<'a, F> GetParseError<'a, Option>> for Result>, AstErro } } -pub fn collect_recovered<'a, T, ET>( +pub fn collect_recovered<'a, T: Debug, ET>( pairs: impl Iterator>, ) -> AstResult<'a, Vec, Vec> where @@ -84,7 +86,7 @@ where collect_recovered_map(pairs, T::try_from) } -pub fn collect_recovered_map<'a, T, F, ET>( +pub fn collect_recovered_map<'a, T: Debug, F, ET>( pairs: impl Iterator>, f: F, ) -> AstResult<'a, Vec, Vec> @@ -113,3 +115,31 @@ where None => Ok(items), } } + +pub struct AstErrorAnalyzer<'a, T>(pub Option>); + +impl<'a, T> AstErrorAnalyzer<'a, T> { + pub fn get(&mut self, r: AstResult<'a, V>) -> AstResult<'a, V> { + if let Err(e) = r { + self.0 = Some(e.clone().get()); + + if let Some(recovered) = e.recovered { + Ok(recovered) + } else { + Err(e) + } + } else { + r + } + } + + pub fn build(self, v: T) -> AstResult<'a, T> { + if let Some(mut e) = self.0 { + e.recovered = Some(v); + + Err(e) + } else { + Ok(v) + } + } +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 3e0293f..acc6f36 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -30,61 +30,19 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec {{ - let mut err = None; + let mut analyzer = $crate::error::AstErrorAnalyzer(None); - let v = $($item)::+ { - $( - $k: { - let r = $v.get(); + let v = $($item)::+ { $($k: analyzer.get($v).get()?),* }; - if let Err(e) = r { - err = Some(e.clone().get()); - - if let Some(recovered) = e.recovered { - Ok(recovered) - } else { - Err(e) - } - } else { - r - } - }.get()? - ),* - }; - - if let Some(mut e) = err { - e.recovered = Some(v); - Err(e) - } else { - Ok(v) - } + analyzer.build(v) }}; ($($item:ident)::+ ( $($v:expr),* $(,)? )) => {{ - let mut err = None; + let mut analyzer = $crate::error::AstErrorAnalyzer(None); - let v = $($item)::+ ( $({ - let r = $v.get(); + let v = $($item)::+ ( $(analyzer.get($v).get()?),* ); - if let Err(e) = r { - err = Some(e.clone().get()); - - if let Some(recovered) = e.recovered { - Ok(recovered) - } else { - Err(e) - } - } else { - r - } - }.get()?),* ); - - if let Some(mut e) = err { - e.recovered = Some(v); - Err(e) - } else { - Ok(v) - } + analyzer.build(v) }}; ($($item:ident)::+) => { From efe32d8e5f5381eaeeaf111fb2a694357a2a8199 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 21:57:59 +0200 Subject: [PATCH 03/18] Improved error handling --- parser/src/error.rs | 7 +++++-- parser/src/parser/items/function.rs | 31 ++++++++++++++--------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 1e97f27..4c339b7 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -119,12 +119,15 @@ where pub struct AstErrorAnalyzer<'a, T>(pub Option>); impl<'a, T> AstErrorAnalyzer<'a, T> { - pub fn get(&mut self, r: AstResult<'a, V>) -> AstResult<'a, V> { + pub fn get>( + &mut self, + r: AstResult<'a, V, V2>, + ) -> AstResult<'a, V, V2> { if let Err(e) = r { self.0 = Some(e.clone().get()); if let Some(recovered) = e.recovered { - Ok(recovered) + Ok(recovered.into()) } else { Err(e) } diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs index 0787d52..d42ca5d 100644 --- a/parser/src/parser/items/function.rs +++ b/parser/src/parser/items/function.rs @@ -1,6 +1,7 @@ use crate::{ Rule, ast::*, + ast_expr, error::{AstError, AstResult, GetParseError, collect_recovered}, parser::{consume_rule, listen_rule}, }; @@ -10,14 +11,14 @@ impl<'a> TryFrom> for FunctionDecl { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner).get()?; - let return_type = TypeExpr::try_from(inner.next().unwrap()).get()?; - let name = Identifier::try_from(inner.next().unwrap()).get()?; + let visibility = Visibility::try_from(&mut inner); + let return_type = TypeExpr::try_from(inner.next().unwrap()); + let name = Identifier::try_from(inner.next().unwrap()); + let generics = consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) .transpose() - .get()? - .unwrap_or_default(); + .map(|v| v.unwrap_or_default()); let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { let mut param_inner = param.into_inner(); @@ -56,19 +57,17 @@ impl<'a> TryFrom> for FunctionDecl { Ok(params) } }) - .transpose() - .get()? - .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); + .unwrap_or_else(|| Ok(ParamList(self_param.into_iter().collect()))); - let body = inner.next().map(Block::try_from).transpose().get()?; + let body = inner.next().map(Block::try_from).transpose(); - Ok(Self { - visibility, - name, - generics, - params, - return_type, - body, + ast_expr!(Self { + visibility: visibility, + return_type: return_type, + name: name, + generics: generics, + params: params, + body: body, }) } } From 6346ffc7716ad971eb9181ac3c6a0bfb047d630a Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 22:06:09 +0200 Subject: [PATCH 04/18] Working error recovery --- mist-test/src/main.mist | 2 -- parser/src/lib.rs | 9 +++++++-- parser/src/parser/items/mod.rs | 7 +++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index e0761f2..ad4d9d1 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -1,6 +1,4 @@ void main() { app_instance.boot(); app_instance.run(); - - hi } \ No newline at end of file diff --git a/parser/src/lib.rs b/parser/src/lib.rs index acc6f36..11ff32f 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -18,13 +18,18 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec Ok(v), + Err(e) => Err(ParseError::Ast(e)), + } } #[macro_export] diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index bc5bf65..e8ea0f9 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -18,14 +18,13 @@ impl<'a> TryFrom> for TopLevel { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let attributes = collect_recovered(inner.next().unwrap().into_inner()).get()?; + let attributes = collect_recovered(inner.next().unwrap().into_inner()); - Ok(TopLevel( + ast_expr!(TopLevel( inner .next() .map(TopLevelKind::try_from) - .unwrap_or(Ok(TopLevelKind::ModAttribute)) - .get()?, + .unwrap_or(Ok(TopLevelKind::ModAttribute)), attributes, )) } From b22c0e85270d4f824b7925f00679fccf03da1874 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 15 May 2026 22:20:06 +0200 Subject: [PATCH 05/18] Improved error message --- src/compiler.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/compiler.rs b/src/compiler.rs index 7b8f585..1510f7a 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -5,6 +5,7 @@ use std::{ time::Instant, }; +use mist_parser::error::ParseError; use serde::Deserialize; #[derive(Deserialize)] @@ -100,7 +101,25 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { } }; - let parser_result = mist_parser::parse(&source).map_err(|e| format!("{e:?}")); + let parser_result = mist_parser::parse(&source).map_err(|e| match e { + ParseError::Ast(e) => { + let start_pos = e.span.start_pos().line_col(); + + let span = e.span.as_str(); + + format!( + "\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()), + ) + } + ParseError::PreAst(e) => format!("{e}"), + }); let ast = match parser_result { Ok(ast) => ast, From 0c6723e967836c071201b81a8e365ab4202b3425 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 04:32:19 +0200 Subject: [PATCH 06/18] Improved error casting system --- parser/src/error.rs | 31 +++++---------------------- parser/src/lib.rs | 2 +- parser/src/parser/common/decl.rs | 2 +- parser/src/parser/common/expr.rs | 28 ++++++++++-------------- parser/src/parser/common/mod.rs | 2 +- parser/src/parser/common/statement.rs | 2 +- parser/src/parser/common/types.rs | 2 +- parser/src/parser/items/attribute.rs | 2 +- parser/src/parser/items/class.rs | 2 +- parser/src/parser/items/enums.rs | 4 ++-- parser/src/parser/items/function.rs | 2 +- parser/src/parser/items/impl_decl.rs | 2 +- parser/src/parser/items/mod.rs | 2 +- 13 files changed, 28 insertions(+), 55 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 4c339b7..769b960 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -46,34 +46,13 @@ impl<'a, F> AstError<'a, F> { } } -pub trait GetParseError<'a, F> { - fn get(self) -> AstResult<'a, F, T>; +pub trait IntoErr { + fn get(self) -> T; } -impl<'a, F> GetParseError<'a, F> for AstResult<'a, F> { - fn get(self) -> AstResult<'a, F, T> { - match self { - Ok(v) => Ok(v), - Err(e) => Err(e.get()), - } - } -} - -impl<'a, F> GetParseError<'a, Option> for Result, AstError<'a, F>> { - fn get(self) -> AstResult<'a, Option, T> { - match self { - Ok(v) => Ok(v), - Err(e) => Err(e.get()), - } - } -} - -impl<'a, F> GetParseError<'a, Option>> for Result>, AstError<'a, F>> { - fn get(self) -> AstResult<'a, Option>, T> { - match self { - Ok(v) => Ok(v), - Err(e) => Err(e.get()), - } +impl<'a, T, TE, TE2> IntoErr> for AstResult<'a, T, TE> { + fn get(self) -> AstResult<'a, T, TE2> { + self.map_err(AstError::get) } } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 11ff32f..b9c126b 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -7,7 +7,7 @@ pub mod parser; use ast::*; -use crate::error::{GetParseError, ParseError}; +use crate::error::{IntoErr, ParseError}; #[derive(Parser)] #[grammar = "./src/grammar.pest"] diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index d9a3dc5..64ca940 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, GetParseError}, + error::{AstError, IntoErr}, parser::listen_rule, }; diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index ff0ccd9..b1d8101 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,7 +1,8 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult, GetParseError, collect_recovered, collect_recovered_map}, + ast_expr, + error::{AstError, IntoErr, collect_recovered, collect_recovered_map}, }; impl<'a> TryFrom> for Expression { @@ -15,26 +16,19 @@ impl<'a> TryFrom> for Expression { Rule::expr => { let prefixes = inner .next() - .map(|p| { - p.into_inner() - .into_iter() - .map(Prefix::try_from) - .collect::, _>>() - }) - .transpose() - .get()? - .unwrap_or_default(); + .map(|p| collect_recovered::(p.into_inner())) + .unwrap_or_else(|| Ok(Vec::new())); - let exp = Expression::try_from(inner.next().unwrap())?; + let exp = Expression::try_from(inner.next().unwrap()); - if inner.len() > 0 || prefixes.len() > 0 { - Ok(Expression::Fix { - initial: Box::new(exp), - prefixes, - postfixes: collect_recovered(inner).get()?, + if inner.len() > 0 { + ast_expr!(Expression::Fix { + initial: exp.map(Box::new), + prefixes: prefixes, + postfixes: collect_recovered(inner), }) } else { - Ok(exp) + Ok(exp?) } } Rule::primary => Expression::try_from(inner.next().unwrap()), diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 067dba2..59c47cb 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -6,7 +6,7 @@ pub mod types; use crate::{ Rule, ast::*, - error::{AstError, GetParseError, collect_recovered}, + error::{AstError, IntoErr, collect_recovered}, parser::consume_rule, }; diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 77e1241..32882a5 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -2,7 +2,7 @@ use crate::{ Rule, ast::*, ast_expr, - error::{AstError, AstResult, ErrorCode, GetParseError, collect_recovered}, + error::{AstError, AstResult, ErrorCode, IntoErr, collect_recovered}, parser::listen_rule, }; diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs index 19a91c9..3145689 100644 --- a/parser/src/parser/common/types.rs +++ b/parser/src/parser/common/types.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, GetParseError, collect_recovered}, + error::{AstError, IntoErr, collect_recovered}, parser::{consume_rule, listen_rule}, }; diff --git a/parser/src/parser/items/attribute.rs b/parser/src/parser/items/attribute.rs index 5f64605..f3b22ec 100644 --- a/parser/src/parser/items/attribute.rs +++ b/parser/src/parser/items/attribute.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, GetParseError, collect_recovered}, + error::{AstError, IntoErr, collect_recovered}, }; impl<'a> TryFrom> for Attribute { diff --git a/parser/src/parser/items/class.rs b/parser/src/parser/items/class.rs index 88b2944..6694f7f 100644 --- a/parser/src/parser/items/class.rs +++ b/parser/src/parser/items/class.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, GetParseError}, + error::{AstError, IntoErr}, parser::consume_rule, }; diff --git a/parser/src/parser/items/enums.rs b/parser/src/parser/items/enums.rs index ad8c87e..d04f5c8 100644 --- a/parser/src/parser/items/enums.rs +++ b/parser/src/parser/items/enums.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, GetParseError, collect_recovered}, + error::{AstError, IntoErr, collect_recovered}, }; impl<'a> TryFrom> for EnumItem { @@ -25,7 +25,7 @@ impl<'a> TryFrom> for EnumItem { .next() .map(|pair| collect_recovered::(pair.into_inner())) .transpose() - .get::()? + .get()? .unwrap_or_default(), )), diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs index d42ca5d..c9500e7 100644 --- a/parser/src/parser/items/function.rs +++ b/parser/src/parser/items/function.rs @@ -2,7 +2,7 @@ use crate::{ Rule, ast::*, ast_expr, - error::{AstError, AstResult, GetParseError, collect_recovered}, + error::{AstError, AstResult, IntoErr, collect_recovered}, parser::{consume_rule, listen_rule}, }; diff --git a/parser/src/parser/items/impl_decl.rs b/parser/src/parser/items/impl_decl.rs index 98aa43e..dfcd457 100644 --- a/parser/src/parser/items/impl_decl.rs +++ b/parser/src/parser/items/impl_decl.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, GetParseError, collect_recovered}, + error::{AstError, IntoErr, collect_recovered}, parser::consume_rule, }; diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index e8ea0f9..5ea9b56 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -8,7 +8,7 @@ use crate::{ Rule, ast::*, ast_expr, - error::{AstError, GetParseError, collect_recovered}, + error::{AstError, IntoErr, collect_recovered}, parser::consume_rule, }; From e6bf1e0d2c10532da1c1b9e49a18022fc4b73ab1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 04:42:45 +0200 Subject: [PATCH 07/18] Expr error system --- parser/src/error.rs | 10 +++++++ parser/src/parser/common/expr.rs | 48 ++++++++++++++++---------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 769b960..44984d5 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -56,6 +56,16 @@ impl<'a, T, TE, TE2> IntoErr> for AstResult<'a, T, TE> { } } +pub trait GetLength { + fn len(&self) -> usize; +} + +impl GetLength for Result, E> { + fn len(&self) -> usize { + if let Ok(v) = self { v.len() } else { 0 } + } +} + pub fn collect_recovered<'a, T: Debug, ET>( pairs: impl Iterator>, ) -> AstResult<'a, Vec, Vec> diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index b1d8101..4e4a02a 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -2,7 +2,7 @@ use crate::{ Rule, ast::*, ast_expr, - error::{AstError, IntoErr, collect_recovered, collect_recovered_map}, + error::{AstError, GetLength, IntoErr, collect_recovered, collect_recovered_map}, }; impl<'a> TryFrom> for Expression { @@ -21,19 +21,19 @@ impl<'a> TryFrom> for Expression { let exp = Expression::try_from(inner.next().unwrap()); - if inner.len() > 0 { + if inner.len() > 0 || prefixes.len() > 0 { ast_expr!(Expression::Fix { initial: exp.map(Box::new), prefixes: prefixes, postfixes: collect_recovered(inner), }) } else { - Ok(exp?) + exp } } - Rule::primary => Expression::try_from(inner.next().unwrap()), - Rule::static_path => Ok(Expression::Path(Path::try_from(pair).get()?)), - Rule::literal => Ok(Expression::Literal(Literal::try_from(pair).get()?)), + Rule::primary => inner.next().unwrap().try_into(), + Rule::static_path => ast_expr!(Expression::Path(pair.try_into())), + Rule::literal => ast_expr!(Expression::Literal(pair.try_into())), _ => unimplemented!("{rule:#?}"), } } @@ -62,27 +62,26 @@ impl<'a> TryFrom> for Postfix { let rule = pair.as_rule(); let mut inner = pair.into_inner(); - Ok(match rule { - Rule::postfix => Postfix::try_from(inner.next().unwrap())?, + match rule { + Rule::postfix => Postfix::try_from(inner.next().unwrap()), Rule::field_px => { - Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap()).get()?) + ast_expr!(Postfix::FieldAccess(inner.next().unwrap().try_into())) } - Rule::call_px => Postfix::Call(collect_recovered(inner).get()?), + Rule::call_px => ast_expr!(Postfix::Call(collect_recovered(inner))), - Rule::struct_px => Postfix::StructCall( - collect_recovered_map(inner, |p| { - let mut pi = p.into_inner(); - Ok(( - Identifier::try_from(pi.next().unwrap())?, - Expression::try_from(pi.next().unwrap()).get()?, - )) - }) - .get()?, - ), + Rule::struct_px => ast_expr!(Postfix::StructCall(collect_recovered_map(inner, |p| { + let mut pi = p.into_inner(); + Ok(( + Identifier::try_from(pi.next().unwrap())?, + Expression::try_from(pi.next().unwrap()).get()?, + )) + }))), - Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap()).get()?), + Rule::index_px => { + ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap()))) + } Rule::binary_px => { let op_pair = inner.next().unwrap(); @@ -105,12 +104,13 @@ impl<'a> TryFrom> for Postfix { unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) } }; - Postfix::Binary(op, Expression::try_from(inner.next().unwrap()).get()?) + + Ok(Postfix::Binary(op, inner.next().unwrap().try_into().get()?)) } - Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), + Rule::macro_call_px => Ok(Postfix::MacroCall(inner.as_str().to_string())), _ => unimplemented!("{rule:#?}"), - }) + } } } From cbd060149d3428cdd26230d0b986c85133a14b60 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 04:51:32 +0200 Subject: [PATCH 08/18] error system: decl --- parser/src/parser/common/decl.rs | 48 ++++++++++++++------------------ 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index 64ca940..248fb3f 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,7 +1,8 @@ use crate::{ Rule, ast::*, - error::{AstError, IntoErr}, + ast_expr, + error::{AstError, AstResult, IntoErr}, parser::listen_rule, }; @@ -13,11 +14,10 @@ impl<'a> TryFrom> for VarDeclStmt { Rule::var_decl_statement => { let mut inner = pair.into_inner(); - let decl = VarDecl::try_from(inner.next().unwrap()).get()?; - - let init = inner.next().map(Expression::try_from).transpose().get()?; - - Ok(VarDeclStmt { decl, init }) + ast_expr!(VarDeclStmt { + decl: inner.next().unwrap().try_into(), + init: inner.next().map(Expression::try_from).transpose() + }) } _ => unimplemented!(), @@ -33,11 +33,10 @@ impl<'a> TryFrom> for FieldDeclStmt { Rule::class_field => { let mut inner = pair.into_inner(); - let decl = FieldDecl::try_from(inner.next().unwrap()).get()?; - - let init = inner.next().map(Expression::try_from).transpose().get()?; - - Ok(FieldDeclStmt { decl, init }) + ast_expr!(FieldDeclStmt { + decl: inner.next().unwrap().try_into(), + init: inner.next().map(Expression::try_from).transpose(), + }) } _ => unimplemented!(), @@ -62,17 +61,16 @@ impl<'a> TryFrom> for VarDecl { Some(TypeExpr::try_from(pair)) } }) - .transpose() - .get()?; + .transpose(); - let mutable = listen_rule(&mut inner, Rule::mutable); + let mutable: AstResult<'_, bool> = Ok(listen_rule(&mut inner, Rule::mutable)); - let name = Pattern::try_from(inner.next().unwrap()).get()?; + let name = Pattern::try_from(inner.next().unwrap()); - Ok(VarDecl { - mutable, - name, - type_, + ast_expr!(VarDecl { + type_: type_, + mutable: mutable, + name: name, }) } @@ -89,14 +87,10 @@ impl<'a> TryFrom> for FieldDecl { Rule::field => { let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner).get()?; - let type_ = TypeExpr::try_from(inner.next().unwrap()).get()?; - let name = Identifier::try_from(inner.next().unwrap()).get()?; - - Ok(FieldDecl { - visibility, - type_, - name, + ast_expr!(FieldDecl { + visibility: Visibility::try_from(&mut inner), + type_: TypeExpr::try_from(inner.next().unwrap()), + name: Identifier::try_from(inner.next().unwrap()), }) } From 1a80fe074bfd142c39e6de3e85e52fb079ff797a Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 05:32:10 +0200 Subject: [PATCH 09/18] Improved bug implementations --- parser/src/error.rs | 3 +- parser/src/lib.rs | 16 +++++++++ parser/src/parser/common/mod.rs | 5 ++- parser/src/parser/common/statement.rs | 48 +++++++++++---------------- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 44984d5..e9fc2dd 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -20,7 +20,8 @@ pub struct AstError<'a, T> { #[derive(Debug, Clone)] pub enum ErrorCode { - InvalidStatement = 200, + InvalidStatement, + AstGenBug, } impl From> for ParseError<'_, T> { diff --git a/parser/src/lib.rs b/parser/src/lib.rs index b9c126b..df5cbf5 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -32,6 +32,22 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec $body:block) => { + if $pair.as_rule() == $rule + $body + else { + Err(AstError { + span: $pair.as_span(), + error_code: crate::error::ErrorCode::AstGenBug, + error_message: format!("Possible bug: expected {:?}, got {}", $rule, $pair), + recovered: None, + }) + } + }; +} + #[macro_export] macro_rules! ast_expr { ($($item:ident)::+ { $($k:ident: $v:expr),* $(,)? }) => {{ diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 59c47cb..4fd4853 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -6,6 +6,7 @@ pub mod types; use crate::{ Rule, ast::*, + ast_ensure, error::{AstError, IntoErr, collect_recovered}, parser::consume_rule, }; @@ -14,7 +15,9 @@ impl<'a> TryFrom> for Identifier { type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Ok(Identifier(pair.as_str().to_string())) + ast_ensure!(pair, Rule::identifier => { + Ok(Identifier(pair.as_str().to_string())) + }) } } diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 32882a5..3bd8e9c 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - ast_expr, + ast_ensure, ast_expr, error::{AstError, AstResult, ErrorCode, IntoErr, collect_recovered}, parser::listen_rule, }; @@ -10,19 +10,25 @@ impl<'a> TryFrom> for Block { type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - if pair.as_rule() == Rule::block { + ast_ensure!(pair, Rule::block => { ast_expr!(Block(collect_recovered(pair.into_inner()))) - } else { - Err(AstError { - span: pair.as_span(), - error_code: ErrorCode::InvalidStatement, - error_message: format!( - "BUG: AST requires a block, this isn't a block, it's a {:?}", - pair.as_rule() - ), - recovered: None, - }) - } + }) + } +} + +impl<'a> TryFrom> for StatementBranch { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + + let condition = inner.next().unwrap().try_into().get()?; + let body = inner.next().unwrap().try_into().get()?; + + Ok(StatementBranch { + condition, + body: Box::new(body), + }) } } @@ -114,19 +120,3 @@ impl<'a> TryFrom> for Statement { }) } } - -impl<'a> TryFrom> for StatementBranch { - type Error = AstError<'a, Self>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let mut inner = pair.into_inner(); - - let condition = inner.next().unwrap().try_into().get()?; - let body = inner.next().unwrap().try_into().get()?; - - Ok(StatementBranch { - condition, - body: Box::new(body), - }) - } -} From 32c411ba789b82fdbf0c3c4b889c50b46b058f34 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 05:55:00 +0200 Subject: [PATCH 10/18] error system: common --- parser/src/parser/common/mod.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 4fd4853..5c57d99 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -6,7 +6,7 @@ pub mod types; use crate::{ Rule, ast::*, - ast_ensure, + ast_ensure, ast_expr, error::{AstError, IntoErr, collect_recovered}, parser::consume_rule, }; @@ -59,27 +59,27 @@ impl<'a> TryFrom> for Pattern { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); - Ok(match rule { - Rule::tuple_pattern => Pattern::Tuple(collect_recovered(pair.into_inner()).get()?), + match rule { + Rule::tuple_pattern => ast_expr!(Pattern::Tuple(collect_recovered(pair.into_inner()))), - Rule::named_tuple_pattern => Pattern::NamedTuple( - Path::try_from(inner.next().unwrap()).get()?, - collect_recovered(inner).get()?, - ), + Rule::named_tuple_pattern => ast_expr!(Pattern::NamedTuple( + Path::try_from(inner.next().unwrap()), + collect_recovered(inner), + )), - Rule::struct_pattern => Pattern::Struct( - Path::try_from(inner.next().unwrap()).get()?, - collect_recovered(inner).get()?, - ), + Rule::struct_pattern => ast_expr!(Pattern::Struct( + Path::try_from(inner.next().unwrap()), + collect_recovered(inner), + )), - Rule::literal => Pattern::Literal(Literal::try_from(pair).get()?), + Rule::literal => ast_expr!(Pattern::Literal(pair.try_into())), - Rule::identifier => Pattern::Id(Identifier::try_from(pair).get()?), + Rule::identifier => ast_expr!(Pattern::Id(pair.try_into())), - Rule::static_path => Pattern::Path(Path::try_from(pair).get()?), + Rule::static_path => ast_expr!(Pattern::Path(pair.try_into())), _ => unimplemented!("{rule:?}"), - }) + } } } @@ -90,7 +90,7 @@ impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { Ok(consume_rule(pairs, Rule::visibility) .map(|pair| -> Result> { if let Some(path) = pair.into_inner().next() { - Ok(Visibility::PublicTarget(Path::try_from(path).get()?)) + ast_expr!(Visibility::PublicTarget(Path::try_from(path))) } else { Ok(Visibility::Public) } From a6e52b0191b854586439755b6d5fdd62efc57165 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 06:33:00 +0200 Subject: [PATCH 11/18] error system: statement --- parser/src/error.rs | 14 ++++- parser/src/parser/common/statement.rs | 91 ++++++++++++++------------- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index e9fc2dd..03c60d2 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -47,14 +47,24 @@ impl<'a, F> AstError<'a, F> { } } -pub trait IntoErr { +pub trait IntoErr { fn get(self) -> T; + fn get_map(self, m: impl Fn(FA) -> FR) -> T; } -impl<'a, T, TE, TE2> IntoErr> for AstResult<'a, T, TE> { +impl<'a, T, TE, TE2> IntoErr, TE, TE2> for AstResult<'a, T, TE> { fn get(self) -> AstResult<'a, T, TE2> { self.map_err(AstError::get) } + + fn get_map(self, m: impl Fn(TE) -> TE2) -> AstResult<'a, T, TE2> { + self.map_err(|e| AstError { + span: e.span, + error_code: e.error_code, + error_message: e.error_message, + recovered: e.recovered.map(m), + }) + } } pub trait GetLength { diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 3bd8e9c..5dd84b2 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -22,12 +22,9 @@ impl<'a> TryFrom> for StatementBranch { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let mut inner = pair.into_inner(); - let condition = inner.next().unwrap().try_into().get()?; - let body = inner.next().unwrap().try_into().get()?; - - Ok(StatementBranch { - condition, - body: Box::new(body), + ast_expr!(StatementBranch { + condition: inner.next().unwrap().try_into(), + body: inner.next().unwrap().try_into().map(Box::new), }) } } @@ -39,62 +36,69 @@ impl<'a> TryFrom> for Statement { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); - Ok(match rule { - Rule::statement => Statement::try_from(inner.next().unwrap())?, + match rule { + Rule::statement => Statement::try_from(inner.next().unwrap()), Rule::expr_stmt => { - Statement::Expression(Expression::try_from(inner.next().unwrap()).get()?) + ast_expr!(Statement::Expression(inner.next().unwrap().try_into())) } - Rule::block => Statement::Block(pair.try_into().get()?), + Rule::block => ast_expr!(Statement::Block(pair.try_into())), - Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair).get()?), + Rule::var_decl_statement => { + ast_expr!(Statement::VarDecl(inner.next().unwrap().try_into())) + } Rule::return_stmt => { - Statement::Return(inner.next().map(Expression::try_from).transpose().get()?) + ast_expr!(Statement::Return( + inner.next().map(Expression::try_from).transpose() + )) } - Rule::break_stmt => Statement::Break, + Rule::break_stmt => Ok(Statement::Break), - Rule::continue_stmt => Statement::Continue, + Rule::continue_stmt => Ok(Statement::Continue), Rule::if_stmt => { let mut inner = inner.skip(2); - Statement::If { - initial: StatementBranch::try_from(pair).get()?, - else_if: collect_recovered(inner.next().unwrap().into_inner()).get()?, + ast_expr!(Statement::If { + initial: inner.next().unwrap().try_into(), + else_if: collect_recovered(inner.next().unwrap().into_inner()), else_branch: inner .next() .map(Statement::try_from) - .transpose()? - .map(Box::new), - } + .transpose() + .map(|v| v.map(Box::new)) + .get_map(|v| { Some(Box::new(v)) }), + }) } - Rule::while_stmt => Statement::While(pair.try_into().get()?), + Rule::while_stmt => ast_expr!(Statement::While(pair.try_into())), - Rule::c_for_stmt => Statement::CStyleFor { - init: Box::new(inner.next().unwrap().try_into().get()?), - condition: inner.next().unwrap().try_into().get()?, - update: Box::new(inner.next().unwrap().try_into().get()?), - body: Box::new(inner.next().unwrap().try_into().get()?), - }, - - Rule::for_stmt => Statement::For { - mutable: listen_rule(&mut inner, Rule::mutable), - pattern: inner.next().unwrap().try_into().get()?, - iterator: inner.next().unwrap().try_into().get()?, - body: Box::new(Statement::try_from(inner.next().unwrap())?), - }, - - Rule::assign_statement => Statement::VarAssign(VarAssignStmt { - target: inner.next().unwrap().try_into().get()?, - value: inner.next().unwrap().try_into().get()?, + Rule::c_for_stmt => ast_expr!(Statement::CStyleFor { + init: inner.next().unwrap().try_into().map(Box::new), + condition: inner.next().unwrap().try_into(), + update: inner.next().unwrap().try_into().map(Box::new), + body: inner.next().unwrap().try_into().map(Box::new), }), - Rule::match_stmt => Statement::Match( - inner.next().unwrap().try_into().get()?, + Rule::for_stmt => ast_expr!(Statement::For { + mutable: Ok(listen_rule(&mut inner, Rule::mutable)) as AstResult<'_, bool>, + pattern: inner.next().unwrap().try_into(), + iterator: inner.next().unwrap().try_into(), + body: inner.next().unwrap().try_into().map(Box::new), + }), + + Rule::assign_statement => ast_expr!(VarAssignStmt { + target: inner.next().unwrap().try_into(), + value: inner.next().unwrap().try_into(), + }) + .map(Statement::VarAssign) + .get_map(Statement::VarAssign), + + Rule::match_stmt => ast_expr!(Statement::Match( + inner.next().unwrap().try_into(), inner .map(|match_itms| { let mut match_inner = match_itms.into_inner(); @@ -103,9 +107,8 @@ impl<'a> TryFrom> for Statement { Block::try_from(match_inner.next().unwrap()).get()?, )) }) - .collect::>>() - .get()?, - ), + .collect::>>(), + )), Rule::unexpected_statement => { return Err(AstError { @@ -117,6 +120,6 @@ impl<'a> TryFrom> for Statement { } _ => unimplemented!("{rule:#?}"), - }) + } } } From ced2d47977c003ed09f94ea6ecbe999c907100f1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 06:41:29 +0200 Subject: [PATCH 12/18] error system: types --- parser/src/ast.rs | 6 +++++ parser/src/parser/common/types.rs | 38 +++++++++++++++---------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/parser/src/ast.rs b/parser/src/ast.rs index bcc5408..d2acb95 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -272,3 +272,9 @@ pub enum Literal { Bool(bool), Tuple(Vec), } + +impl TypeExpr { + pub fn no_px(kind: TypeExprKind) -> Self { + Self(kind, Vec::new()) + } +} diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs index 3145689..2ec02a4 100644 --- a/parser/src/parser/common/types.rs +++ b/parser/src/parser/common/types.rs @@ -1,7 +1,8 @@ use crate::{ Rule, ast::*, - error::{AstError, IntoErr, collect_recovered}, + ast_expr, + error::{AstError, GetLength, IntoErr, collect_recovered}, parser::{consume_rule, listen_rule}, }; @@ -47,15 +48,15 @@ impl<'a> TryFrom> for TypeExprKind { let mut inner = pair.into_inner(); match rule { - Rule::tuple_type => Ok(TypeExprKind::Tuple(collect_recovered(inner).get()?)), + Rule::tuple_type => ast_expr!(TypeExprKind::Tuple(collect_recovered(inner))), Rule::path_type => { - let path = Path::try_from(inner.next().unwrap()).get()?; - let params = collect_recovered(inner).get()?; + let path = Path::try_from(inner.next().unwrap()); + let params = collect_recovered(inner); if params.len() == 0 { - Ok(TypeExprKind::Path(path)) + ast_expr!(TypeExprKind::Path(path)) } else { - Ok(TypeExprKind::PathParams(path, params)) + ast_expr!(TypeExprKind::PathParams(path, params)) } } _ => unimplemented!("{rule:#?}"), @@ -71,15 +72,14 @@ impl<'a> TryFrom> for TypeExpr { let mut inner = pair.into_inner(); match rule { - Rule::type_expr => Ok(TypeExpr( - inner.next().unwrap().try_into().get()?, - collect_recovered(inner).get()?, + Rule::type_expr => ast_expr!(TypeExpr( + inner.next().unwrap().try_into(), + collect_recovered(inner), )), Rule::type_expr_param => Self::try_from(inner.next().unwrap()), - Rule::lifetime => Ok(TypeExpr( - TypeExprKind::Lifetime(inner.next().unwrap().try_into().get()?), - Vec::new(), - )), + Rule::lifetime => ast_expr!(TypeExprKind::Lifetime(inner.next().unwrap().try_into())) + .get_map(TypeExpr::no_px) + .map(TypeExpr::no_px), _ => unimplemented!("{rule:#?}"), } } @@ -93,7 +93,7 @@ impl<'a> TryFrom> for Generics { let inner = pair.clone().into_inner(); match rule { - Rule::generics => Ok(Generics(collect_recovered(inner).get()?)), + Rule::generics => ast_expr!(Generics(collect_recovered(inner))), _ => unimplemented!("{rule:#?}"), } } @@ -106,13 +106,13 @@ impl<'a> TryFrom> for Generic { let mut inner = pair.clone().into_inner(); if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { - Ok(Generic::Lifetime( - pair.into_inner().next().unwrap().try_into().get()?, + ast_expr!(Generic::Lifetime( + pair.into_inner().next().unwrap().try_into(), )) } else { - Ok(Generic::Type( - inner.next().unwrap().try_into().get()?, - collect_recovered(inner).get()?, + ast_expr!(Generic::Type( + inner.next().unwrap().try_into(), + collect_recovered(inner), )) } } From 3619f0e7dcd622ae68f2f53a9bc7c6c842de7841 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 06:50:24 +0200 Subject: [PATCH 13/18] Bug implementations --- parser/src/error.rs | 11 +++++++++++ parser/src/parser/common/decl.rs | 8 ++++---- parser/src/parser/common/expr.rs | 15 ++++++++------- parser/src/parser/common/mod.rs | 6 +++--- parser/src/parser/common/statement.rs | 2 +- parser/src/parser/common/types.rs | 16 +++++++++------- parser/src/parser/items/class.rs | 2 +- parser/src/parser/items/enums.rs | 2 +- parser/src/parser/items/impl_decl.rs | 2 +- parser/src/parser/items/mod.rs | 2 +- 10 files changed, 40 insertions(+), 26 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index 03c60d2..e1dd861 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -1,5 +1,7 @@ use std::fmt::Debug; +use pest::iterators::Pair; + use crate::Rule; pub type AstResult<'a, T, ET = T> = Result>; @@ -45,6 +47,15 @@ impl<'a, F> AstError<'a, F> { recovered: None, } } + + pub fn bug_unimplemented(pair: Pair<'a, Rule>) -> AstResult<'a, T, F> { + Err(Self { + span: pair.as_span(), + error_code: ErrorCode::AstGenBug, + error_message: format!("Possible bug, unimplemented: {:#?}", pair), + recovered: None, + }) + } } pub trait IntoErr { diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index 248fb3f..4cf8bfb 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -20,7 +20,7 @@ impl<'a> TryFrom> for VarDeclStmt { }) } - _ => unimplemented!(), + _ => AstError::bug_unimplemented(pair), } } } @@ -39,7 +39,7 @@ impl<'a> TryFrom> for FieldDeclStmt { }) } - _ => unimplemented!(), + _ => AstError::bug_unimplemented(pair), } } } @@ -74,7 +74,7 @@ impl<'a> TryFrom> for VarDecl { }) } - _ => unimplemented!("{:?}", pair.as_rule()), + _ => AstError::bug_unimplemented(pair), } } } @@ -94,7 +94,7 @@ impl<'a> TryFrom> for FieldDecl { }) } - _ => unimplemented!("{:?}", pair.as_rule()), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 4e4a02a..e49680d 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -31,10 +31,12 @@ impl<'a> TryFrom> for Expression { exp } } + Rule::primary => inner.next().unwrap().try_into(), Rule::static_path => ast_expr!(Expression::Path(pair.try_into())), Rule::literal => ast_expr!(Expression::Literal(pair.try_into())), - _ => unimplemented!("{rule:#?}"), + + _ => AstError::bug_unimplemented(pair), } } } @@ -50,7 +52,8 @@ impl<'a> TryFrom> for Prefix { Rule::ref_px => Self::Ref, Rule::new_px => Self::New, Rule::not_px => Self::Not, - _ => unimplemented!("{pair:#?}"), + + _ => return AstError::bug_unimplemented(pair), }) } } @@ -60,7 +63,7 @@ impl<'a> TryFrom> for Postfix { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); - let mut inner = pair.into_inner(); + let mut inner = pair.clone().into_inner(); match rule { Rule::postfix => Postfix::try_from(inner.next().unwrap()), @@ -100,9 +103,7 @@ impl<'a> TryFrom> for Postfix { "&&" => BinaryOp::And, "||" => BinaryOp::Or, - _ => { - unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) - } + _ => return AstError::bug_unimplemented(op_pair), }; Ok(Postfix::Binary(op, inner.next().unwrap().try_into().get()?)) @@ -110,7 +111,7 @@ impl<'a> TryFrom> for Postfix { Rule::macro_call_px => Ok(Postfix::MacroCall(inner.as_str().to_string())), - _ => unimplemented!("{rule:#?}"), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs index 5c57d99..206e3c9 100644 --- a/parser/src/parser/common/mod.rs +++ b/parser/src/parser/common/mod.rs @@ -27,7 +27,7 @@ impl<'a> TryFrom> for Path { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { match pair.as_rule() { Rule::static_path => Ok(Path(collect_recovered(pair.into_inner()).get()?)), - _ => unimplemented!("{pair:#?}"), + _ => AstError::bug_unimplemented(pair), } } } @@ -47,7 +47,7 @@ impl<'a> TryFrom> for Literal { Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), Rule::string_lit => Literal::String(inner.as_str().to_string()), Rule::tuple => Literal::Tuple(collect_recovered(inner).get()?), - _ => unimplemented!("{rule:#?}"), + _ => return AstError::bug_unimplemented(pair), }) } } @@ -78,7 +78,7 @@ impl<'a> TryFrom> for Pattern { Rule::static_path => ast_expr!(Pattern::Path(pair.try_into())), - _ => unimplemented!("{rule:?}"), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 5dd84b2..9de2546 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -119,7 +119,7 @@ impl<'a> TryFrom> for Statement { }); } - _ => unimplemented!("{rule:#?}"), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs index 2ec02a4..7e64d1c 100644 --- a/parser/src/parser/common/types.rs +++ b/parser/src/parser/common/types.rs @@ -11,7 +11,7 @@ impl<'a> TryFrom> for TypePostfix { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); - let mut inner = pair.into_inner(); + let mut inner = pair.clone().into_inner(); match rule { Rule::ref_type => { @@ -35,7 +35,8 @@ impl<'a> TryFrom> for TypePostfix { } }) } - _ => unimplemented!("{rule:#?}"), + + _ => AstError::bug_unimplemented(pair), } } } @@ -45,7 +46,7 @@ impl<'a> TryFrom> for TypeExprKind { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); - let mut inner = pair.into_inner(); + let mut inner = pair.clone().into_inner(); match rule { Rule::tuple_type => ast_expr!(TypeExprKind::Tuple(collect_recovered(inner))), @@ -59,7 +60,7 @@ impl<'a> TryFrom> for TypeExprKind { ast_expr!(TypeExprKind::PathParams(path, params)) } } - _ => unimplemented!("{rule:#?}"), + _ => AstError::bug_unimplemented(pair), } } } @@ -69,7 +70,7 @@ impl<'a> TryFrom> for TypeExpr { fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); - let mut inner = pair.into_inner(); + let mut inner = pair.clone().into_inner(); match rule { Rule::type_expr => ast_expr!(TypeExpr( @@ -80,7 +81,8 @@ impl<'a> TryFrom> for TypeExpr { Rule::lifetime => ast_expr!(TypeExprKind::Lifetime(inner.next().unwrap().try_into())) .get_map(TypeExpr::no_px) .map(TypeExpr::no_px), - _ => unimplemented!("{rule:#?}"), + + _ => AstError::bug_unimplemented(pair), } } } @@ -94,7 +96,7 @@ impl<'a> TryFrom> for Generics { match rule { Rule::generics => ast_expr!(Generics(collect_recovered(inner))), - _ => unimplemented!("{rule:#?}"), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/items/class.rs b/parser/src/parser/items/class.rs index 6694f7f..86eef27 100644 --- a/parser/src/parser/items/class.rs +++ b/parser/src/parser/items/class.rs @@ -44,7 +44,7 @@ impl<'a> TryFrom> for ClassItem { Rule::method => Ok(ClassItem::Method(pair.try_into().get()?)), - _ => unimplemented!("{rule:#?}"), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/items/enums.rs b/parser/src/parser/items/enums.rs index d04f5c8..0f6d8fe 100644 --- a/parser/src/parser/items/enums.rs +++ b/parser/src/parser/items/enums.rs @@ -29,7 +29,7 @@ impl<'a> TryFrom> for EnumItem { .unwrap_or_default(), )), - _ => unimplemented!("{rule:#?}"), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/items/impl_decl.rs b/parser/src/parser/items/impl_decl.rs index dfcd457..6ad4ca4 100644 --- a/parser/src/parser/items/impl_decl.rs +++ b/parser/src/parser/items/impl_decl.rs @@ -35,7 +35,7 @@ impl<'a> TryFrom> for ImplDecl { methods: collect_recovered(inner).get()?, }), - _ => unimplemented!("{rule:#?}"), + _ => AstError::bug_unimplemented(pair), } } } diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index 5ea9b56..f5079c2 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -123,7 +123,7 @@ impl<'a> TryFrom> for TopLevelKind { items: collect_recovered(inner).get()?, }, - _ => unimplemented!("{rule:#?}"), + _ => return AstError::bug_unimplemented(pair), }) } } From b188ef0eb2e620556d39bbd5b7f3d65345d44f81 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 06:52:33 +0200 Subject: [PATCH 14/18] Removed unnecessary whole from unimplemented msg --- parser/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index e1dd861..ebec476 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -52,7 +52,7 @@ impl<'a, F> AstError<'a, F> { Err(Self { span: pair.as_span(), error_code: ErrorCode::AstGenBug, - error_message: format!("Possible bug, unimplemented: {:#?}", pair), + error_message: format!("Possible bug, unimplemented: {:#?}", pair.as_rule()), recovered: None, }) } From 5174cc34ee6ad360eca1772ab727f097c0c6541a Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 07:14:02 +0200 Subject: [PATCH 15/18] error system: top level items --- parser/src/parser/items/mod.rs | 88 ++++++++++++++++------------------ 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs index f5079c2..5cbcaab 100644 --- a/parser/src/parser/items/mod.rs +++ b/parser/src/parser/items/mod.rs @@ -37,93 +37,89 @@ impl<'a> TryFrom> for TopLevelKind { let rule = pair.as_rule(); let mut inner = pair.clone().into_inner(); - Ok(match rule { - Rule::import => TopLevelKind::Import( - Visibility::try_from(&mut inner).get()?, - Path::try_from(inner.next().unwrap()).get()?, - ), + match rule { + Rule::import => ast_expr!(TopLevelKind::Import( + Visibility::try_from(&mut inner), + Path::try_from(inner.next().unwrap()), + )), - Rule::function_decl => return ast_expr!(TopLevelKind::FunctionDecl(pair.try_into())), + Rule::function_decl => ast_expr!(TopLevelKind::FunctionDecl(pair.try_into())), - Rule::struct_decl => TopLevelKind::StructDecl { - visibility: Visibility::try_from(&mut inner).get()?, + Rule::struct_decl => ast_expr!(TopLevelKind::StructDecl { + visibility: Visibility::try_from(&mut inner), - name: inner.next().unwrap().try_into().get()?, + name: inner.next().unwrap().try_into(), generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) .transpose() - .get()? - .unwrap_or_default(), + .map(|v| v.unwrap_or_default()), fields: inner .next() .map(|pair| collect_recovered::(pair.into_inner())) .transpose() - .get()? - .unwrap_or_default(), - }, + .map(|v| v.unwrap_or_default()), + }), - Rule::class_decl => TopLevelKind::ClassDecl { - visibility: Visibility::try_from(&mut inner).get()?, + Rule::class_decl => ast_expr!(TopLevelKind::ClassDecl { + visibility: Visibility::try_from(&mut inner), - name: inner.next().unwrap().try_into().get()?, + name: inner.next().unwrap().try_into(), generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) .transpose() - .get()? - .unwrap_or_default(), + .map(|v| v.unwrap_or_default()), - fields: collect_recovered(inner.next().unwrap().into_inner()).get()?, + fields: collect_recovered(inner.next().unwrap().into_inner()), - constructor: inner.next().unwrap().try_into().get()?, + constructor: inner.next().unwrap().try_into(), - items: collect_recovered(inner).get()?, - }, + items: collect_recovered(inner), + }), - Rule::enum_decl => TopLevelKind::EnumDecl { - visibility: Visibility::try_from(&mut inner).get()?, + Rule::enum_decl => ast_expr!(TopLevelKind::EnumDecl { + visibility: Visibility::try_from(&mut inner), - name: inner.next().unwrap().try_into().get()?, + name: inner.next().unwrap().try_into(), generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) .transpose() - .get()? - .unwrap_or_default(), + .map(|v| v.unwrap_or_default()), - fields: collect_recovered(inner).get()?, - }, + fields: collect_recovered(inner), + }), - Rule::mod_package => TopLevelKind::Mod( - Visibility::try_from(&mut inner).get()?, - inner.next().unwrap().try_into().get()?, - ), + Rule::mod_package => ast_expr!(TopLevelKind::Mod( + Visibility::try_from(&mut inner), + inner.next().unwrap().try_into(), + )), - Rule::impl_for_decl | Rule::impl_decl => TopLevelKind::ImplDecl(pair.try_into().get()?), + Rule::impl_for_decl | Rule::impl_decl => { + ast_expr!(TopLevelKind::ImplDecl(pair.try_into())) + } - Rule::trait_decl => TopLevelKind::TraitDecl { - visibility: Visibility::try_from(&mut inner).get()?, + Rule::trait_decl => ast_expr!(TopLevelKind::TraitDecl { + visibility: Visibility::try_from(&mut inner), - name: inner.next().unwrap().try_into().get()?, + name: inner.next().unwrap().try_into(), generics: consume_rule(&mut inner, Rule::generics) .map(Generics::try_from) .transpose() - .get()? - .unwrap_or_default(), + .map(|v| v.unwrap_or_default()), requirements: consume_rule(&mut inner, Rule::trait_requirements) .map(|pair| collect_recovered::(pair.into_inner())) .transpose() - .get()? - .unwrap_or_default(), + .map(|v| v.unwrap_or_default()), - items: collect_recovered(inner).get()?, - }, + items: collect_recovered(inner), + }), - _ => return AstError::bug_unimplemented(pair), - }) + _ => AstError::bug_unimplemented(pair), + } } } From 47b179b782707cbd5b56acfc7ad6e472af2fd921 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 07:22:43 +0200 Subject: [PATCH 16/18] fix: statement branch --- mist-test/src/main.mist | 11 +++++++++++ parser/src/grammar.pest | 8 +++++--- parser/src/parser/common/statement.rs | 12 +++++++----- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index ad4d9d1..853e686 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -1,4 +1,15 @@ +pub mod app; +pub mod task; +pub mod plugin; +pub mod logger; +pub mod event; + void main() { + var mut app_instance = new app::Application("mist-app"); + + // greeting::register(&mut app_instance); + // statistics::register(&mut app_instance); + app_instance.boot(); app_instance.run(); } \ No newline at end of file diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 13b699f..13b9787 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -357,8 +357,10 @@ assign_statement = { // CONDITIONALS // ------------------------------------------------------ +statement_branch = { "(" ~ expr ~ ")" ~ statement } + else_if = { - "else" ~ "if" ~ "(" ~ expr ~ ")" ~ statement + "else" ~ "if" ~ statement_branch } else_if_list = { @@ -366,7 +368,7 @@ else_if_list = { } if_stmt = { - "if" ~ "(" ~ expr ~ ")" ~ statement ~ else_if_list ~ ("else" ~ statement)? + "if" ~ "(" ~ statement_branch ~ else_if_list ~ ("else" ~ statement)? } // ------------------------------------------------------ @@ -374,7 +376,7 @@ if_stmt = { // ------------------------------------------------------ while_stmt = { - "while" ~ "(" ~ expr ~ ")" ~ statement + "while" ~ statement_branch } c_for_stmt = { diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 9de2546..18edb8e 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -20,11 +20,13 @@ impl<'a> TryFrom> for StatementBranch { type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let mut inner = pair.into_inner(); + let mut inner = pair.clone().into_inner(); - ast_expr!(StatementBranch { - condition: inner.next().unwrap().try_into(), - body: inner.next().unwrap().try_into().map(Box::new), + ast_ensure!(pair, Rule::statement_branch => { + ast_expr!(StatementBranch { + condition: inner.next().unwrap().try_into(), + body: inner.next().unwrap().try_into().map(Box::new), + }) }) } } @@ -74,7 +76,7 @@ impl<'a> TryFrom> for Statement { }) } - Rule::while_stmt => ast_expr!(Statement::While(pair.try_into())), + Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())), Rule::c_for_stmt => ast_expr!(Statement::CStyleFor { init: inner.next().unwrap().try_into().map(Box::new), From 2c426c78c6626216b37506cbd116a1f18aaeb361 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 07:23:03 +0200 Subject: [PATCH 17/18] Added tests back --- mist-test/src/app.mist | 95 +++++++++++++++++++++++++++++++++++++++ mist-test/src/event.mist | 7 +++ mist-test/src/logger.mist | 72 +++++++++++++++++++++++++++++ mist-test/src/plugin.mist | 16 +++++++ mist-test/src/task.mist | 20 +++++++++ 5 files changed, 210 insertions(+) create mode 100644 mist-test/src/app.mist create mode 100644 mist-test/src/event.mist create mode 100644 mist-test/src/logger.mist create mode 100644 mist-test/src/plugin.mist create mode 100644 mist-test/src/task.mist diff --git a/mist-test/src/app.mist b/mist-test/src/app.mist new file mode 100644 index 0000000..01fbd87 --- /dev/null +++ b/mist-test/src/app.mist @@ -0,0 +1,95 @@ +use ; +use ; +use ; + +pub class Application { + String name; + + Vec tasks; + Vec plugins; + + logger::Logger logger; + + bool running; + i32 ticks; + + pub constructor(str* name) { + self.name = name.to_string(); + + self.tasks = new Vec(); + self.plugins = new Vec(); + + self.logger = new logger::Logger("app"); + + self.running = false; + self.ticks = 0; + } + + pub void boot(self mut*) { + self.logger.info("booting application"); + + self.running = true; + + self.emit(event::Event::Startup); + } + + pub void run(self mut*) { + while(self.running) { + self.tick(); + + if(self.ticks >= 5) { + self.shutdown(); + } + } + } + + void tick(self mut*) { + self.logger.info("tick"); + + self.ticks = self.ticks + 1; + + var task = task::create_task("background-job"); + + self.tasks.push(task); + + println!("tasks: {}", self.tasks.len()); + } + + pub void shutdown(self mut*) { + self.emit(event::Event::Shutdown); + + self.logger.warning("shutdown"); + + self.running = false; + } + + pub void register_plugin(self mut*, String name) { + self.plugins.push(name.clone()); + + self.emit(event::Event::PluginLoaded(name)); + } + + void emit(self*, event::Event event) { + match(event) { + event::Event::Startup => { + self.logger.info("startup event"); + } + + event::Event::Shutdown => { + self.logger.info("shutdown event"); + } + + event::Event::PluginLoaded(name) => { + println!("plugin loaded: {}", name); + } + + event::Event::TaskExecuted(name) => { + println!("task executed: {}", name); + } + + event::Event::Error(message) => { + self.logger.error(&message); + } + } + } +} \ No newline at end of file diff --git a/mist-test/src/event.mist b/mist-test/src/event.mist new file mode 100644 index 0000000..6340bf4 --- /dev/null +++ b/mist-test/src/event.mist @@ -0,0 +1,7 @@ +pub enum Event { + Startup, + Shutdown, + TaskExecuted(String), + PluginLoaded(String), + Error(String), +} \ No newline at end of file diff --git a/mist-test/src/logger.mist b/mist-test/src/logger.mist new file mode 100644 index 0000000..7854ab9 --- /dev/null +++ b/mist-test/src/logger.mist @@ -0,0 +1,72 @@ +use ; +use ; + +pub trait TestLogging: fmt::Display { + String get(); +} + +pub enum LogLevel { + Info, + Warning, + Error, +} + +impl fmt::Display for LogLevel { + fmt::Result fmt(self*, Formatter<'_> mut* f) { + match (self) { + LogLevel::Info => { + return write!(f, "[INFO]"); + } + + LogLevel::Warning => { + return write!(f, "[WARN]"); + } + + LogLevel::Error => { + return write!(f, "[ERROR]"); + } + } + } +} + +pub class Logger { + String prefix; + + pub constructor(str* prefix) { + self.prefix = prefix.to_string(); + } + + pub void info(self*, str* message) { + self.log(LogLevel::Info, message); + } + + pub void warning(self*, str* message) { + self.log(LogLevel::Warning, message); + } + + pub void error(self*, str* message) { + self.log(LogLevel::Error, message); + } + + void log(self*, LogLevel level, str* message) { + match(level) { + LogLevel::Info => { + println!("{level} {} {}", self.prefix, message); + } + + LogLevel::Warning => { + println!("{level} {} {}", self.prefix, message); + } + + LogLevel::Error => { + println!("{level} {} {}", self.prefix, message); + } + } + } + + impl fmt::Display { + fmt::Result fmt(self*, Formatter<'_> mut* f) { + return write!(f, "logger ({})", self.prefix); + } + } +} \ No newline at end of file diff --git a/mist-test/src/plugin.mist b/mist-test/src/plugin.mist new file mode 100644 index 0000000..a3d16ba --- /dev/null +++ b/mist-test/src/plugin.mist @@ -0,0 +1,16 @@ +pub struct PluginInfo { + pub String name, + pub String version, +} + +pub class PluginRegistry { + T plugins; + + pub constructor(T plugins) { + self.plugins = plugins; + } + + pub T plugins(self) { + return self.plugins; + } +} \ No newline at end of file diff --git a/mist-test/src/task.mist b/mist-test/src/task.mist new file mode 100644 index 0000000..d902258 --- /dev/null +++ b/mist-test/src/task.mist @@ -0,0 +1,20 @@ +pub enum TaskState { + Pending, + Running, + Finished, + Failed, +} + +pub struct Task { + pub String name, + pub TaskState state, + pub i32 executions, +} + +pub Task create_task(str* name) { + return Task { + name: name.to_string(), + state: TaskState::Pending, + executions: 0, + }; +} \ No newline at end of file From 50b05b6def48d52eb62103fce88e6e270b0b8465 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 16 May 2026 07:28:18 +0200 Subject: [PATCH 18/18] Var decl and if statement --- parser/src/grammar.pest | 2 +- parser/src/parser/common/statement.rs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 13b9787..945c825 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -368,7 +368,7 @@ else_if_list = { } if_stmt = { - "if" ~ "(" ~ statement_branch ~ else_if_list ~ ("else" ~ statement)? + "if" ~ statement_branch ~ else_if_list ~ ("else" ~ statement)? } // ------------------------------------------------------ diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 18edb8e..243e6a3 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -47,9 +47,7 @@ impl<'a> TryFrom> for Statement { Rule::block => ast_expr!(Statement::Block(pair.try_into())), - Rule::var_decl_statement => { - ast_expr!(Statement::VarDecl(inner.next().unwrap().try_into())) - } + Rule::var_decl_statement => ast_expr!(Statement::VarDecl(pair.try_into())), Rule::return_stmt => { ast_expr!(Statement::Return( @@ -62,8 +60,6 @@ impl<'a> TryFrom> for Statement { Rule::continue_stmt => Ok(Statement::Continue), Rule::if_stmt => { - let mut inner = inner.skip(2); - ast_expr!(Statement::If { initial: inner.next().unwrap().try_into(), else_if: collect_recovered(inner.next().unwrap().into_inner()),