Compare commits

...
Author SHA1 Message Date
selimaj-dev 60e5995dc6 Updated lib version 2026-05-16 11:18:20 +02:00
selimaj-dev c621a1bb8d Updated version 2026-05-16 11:17:12 +02:00
selimaj-dev 58a79ad2ef Merge pull request #30 from mist-go/improved-cli-readme
Improved cli and readme
2026-05-16 11:13:44 +02:00
selimaj-dev 490509cb14 Documentation website link 2026-05-16 11:11:41 +02:00
selimaj-dev bdca96212c improved usage style 2026-05-16 11:10:01 +02:00
selimaj-dev e3d885e22d improved usage style 2026-05-16 10:59:50 +02:00
selimaj-dev 6917d36ac4 short commands 2026-05-16 10:52:41 +02:00
selimaj-dev 90de040ae8 Cargo commands 2026-05-16 10:51:08 +02:00
selimaj-dev 9d024b7e25 Merge pull request #29 from mist-go/error-recovery-system
Error recovery system
2026-05-16 07:32:15 +02:00
selimaj-dev 50b05b6def Var decl and if statement 2026-05-16 07:28:18 +02:00
selimaj-dev 2c426c78c6 Added tests back 2026-05-16 07:23:03 +02:00
selimaj-dev 47b179b782 fix: statement branch 2026-05-16 07:22:43 +02:00
selimaj-dev 5174cc34ee error system: top level items 2026-05-16 07:14:02 +02:00
selimaj-dev b188ef0eb2 Removed unnecessary whole from unimplemented msg 2026-05-16 06:52:33 +02:00
selimaj-dev 3619f0e7dc Bug implementations 2026-05-16 06:50:24 +02:00
selimaj-dev ced2d47977 error system: types 2026-05-16 06:41:29 +02:00
selimaj-dev a6e52b0191 error system: statement 2026-05-16 06:33:00 +02:00
selimaj-dev 32c411ba78 error system: common 2026-05-16 05:55:00 +02:00
selimaj-dev 1a80fe074b Improved bug implementations 2026-05-16 05:32:10 +02:00
selimaj-dev cbd060149d error system: decl 2026-05-16 04:51:32 +02:00
selimaj-dev e6bf1e0d2c Expr error system 2026-05-16 04:42:45 +02:00
selimaj-dev 0c6723e967 Improved error casting system 2026-05-16 04:32:19 +02:00
selimaj-dev b22c0e8527 Improved error message 2026-05-15 22:20:06 +02:00
selimaj-dev 6346ffc771 Working error recovery 2026-05-15 22:06:09 +02:00
selimaj-dev efe32d8e5f Improved error handling 2026-05-15 21:57:59 +02:00
selimaj-dev c6b9588f4d ast error analyzer 2026-05-15 13:12:52 +02:00
selimaj-dev 216c61228c Making a error recovery system 2026-05-15 12:09:30 +02:00
selimaj-dev 3aba4a359b Merge pull request #28 from mist-go/refactor-error-handling
Refactor error handling
2026-05-15 10:45:35 +02:00
selimaj-dev fa2c0b2658 Fixed pattern bug 2026-05-15 10:37:06 +02:00
selimaj-dev 0bb7146d13 Fixed block bug 2026-05-15 10:29:02 +02:00
selimaj-dev 3c5b030bdd Finished error handling 2026-05-15 09:19:49 +02:00
selimaj-dev 6c7692208d enums, functions, impls error handling 2026-05-15 09:11:17 +02:00
selimaj-dev 8c89f9ff65 Attr and class error handling 2026-05-15 09:00:21 +02:00
selimaj-dev f9c5fb4ec8 types error handling 2026-05-15 08:54:48 +02:00
selimaj-dev 527e450f9e Common error handling 2026-05-15 08:44:01 +02:00
selimaj-dev 459c4b1ee0 Reverted back 2026-05-15 02:23:54 +02:00
selimaj-dev 933f102680 Might consider removing ast_expr 2026-05-15 02:02:43 +02:00
selimaj-dev 6fbc2a086e Decl using the ast macro 2026-05-15 01:33:43 +02:00
selimaj-dev 80e17ffafb Ast expression macro 2026-05-15 01:24:55 +02:00
selimaj-dev 25f4b5470d Getting error handling to work 2026-05-15 00:03:04 +02:00
selimaj-dev cdb34984db Error recovery 2026-05-14 23:46:38 +02:00
selimaj-dev 9b04a17fdd Error recovery 2026-05-14 23:37:48 +02:00
selimaj-dev 626990216c Moved pattern to general common 2026-05-14 21:55:32 +02:00
selimaj-dev 78cac259f2 Decl, Expr, and statement 2026-05-14 21:52:56 +02:00
selimaj-dev 5912032dff Enums and impl decl 2026-05-14 21:44:00 +02:00
selimaj-dev 00e10d1097 Separated classes, attributes, and types 2026-05-14 21:35:41 +02:00
selimaj-dev 50fa660392 Separating ast implementations 2026-05-14 21:27:50 +02:00
selimaj-dev 192769c8ad Separate error 2026-05-14 20:51:43 +02:00
selimaj-dev 5920a9f236 Error returning 2026-05-14 20:36:15 +02:00
selimaj-dev d8d3b327dd Visibility error stuff 2026-05-14 20:23:52 +02:00
selimaj-dev 5c732bb8d1 Finishing mass error rewrite 2026-05-14 20:19:22 +02:00
selimaj-dev 01532baf12 Mass improved error handling 2026-05-14 20:14:28 +02:00
selimaj-dev 03f9794671 Mass rewrite 2026-05-14 19:33:12 +02:00
selimaj-dev fd48d6c9c6 Making better errors 2026-05-14 19:25:29 +02:00
selimaj-dev ef7ccc5aed Error recovery 2026-05-14 19:07:36 +02:00
selimaj-dev 23f726fd41 Merge pull request #27 from mist-go/refactor-visibility
Refactor visibility
2026-05-13 22:25:59 +02:00
selimaj-dev a6ad375c58 fix logger 2026-05-13 07:37:55 +02:00
selimaj-dev e4eeb20a2c fix logger 2026-05-13 07:37:32 +02:00
selimaj-dev 5bdcd40edb Pub mod and pub use 2026-05-13 05:52:57 +02:00
selimaj-dev c1cb9bd7bf Refactor publicity system 2026-05-13 05:48:59 +02:00
29 changed files with 1311 additions and 885 deletions
Generated
+2 -2
View File
@@ -76,7 +76,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]] [[package]]
name = "mist-lang" name = "mist-lang"
version = "0.0.1-alpha2" version = "0.0.2-alpha0"
dependencies = [ dependencies = [
"mist-parser", "mist-parser",
"serde", "serde",
@@ -85,7 +85,7 @@ dependencies = [
[[package]] [[package]]
name = "mist-parser" name = "mist-parser"
version = "0.1.0" version = "0.1.1"
dependencies = [ dependencies = [
"pest", "pest",
"pest_derive", "pest_derive",
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "mist-lang" name = "mist-lang"
version = "0.0.1-alpha2" version = "0.0.2-alpha0"
edition = "2024" edition = "2024"
description = "The Mist programming language compiler" description = "The Mist programming language compiler"
license = "Apache-2.0" license = "Apache-2.0"
@@ -12,7 +12,7 @@ categories = ["compilers"]
[dependencies] [dependencies]
serde = { version = "1.0.228", features = ["serde_derive"] } serde = { version = "1.0.228", features = ["serde_derive"] }
serde_json = "1.0.149" serde_json = "1.0.149"
mist-parser = { path = "./parser", version = "0.1.0"} mist-parser = { path = "./parser", version = "0.1.1"}
[[bin]] [[bin]]
name = "mist" name = "mist"
+3 -7
View File
@@ -4,13 +4,9 @@
Originally this readme was part of the Carbon Language project, licensed with Apache-2.0 Originally this readme was part of the Carbon Language project, licensed with Apache-2.0
--> -->
<!-- <p align="center"> <p align="center">
<a href="#why-build-carbon">Why?</a> | <a href="https://mist.selimaj.dev">Documentation</a>
<a href="#language-goals">Goals</a> | </p>
<a href="#project-status">Status</a> |
<a href="#getting-started">Getting started</a> |
<a href="#join-us">Join us</a>
</p> -->
<img src="code.png" align="right" width="575" alt=""> <img src="code.png" align="right" width="575" alt="">
+6 -6
View File
@@ -2,7 +2,7 @@ use <super::task>;
use <super::logger>; use <super::logger>;
use <super::event>; use <super::event>;
public class Application { pub class Application {
String name; String name;
Vec<task::Task> tasks; Vec<task::Task> tasks;
@@ -13,7 +13,7 @@ public class Application {
bool running; bool running;
i32 ticks; i32 ticks;
public constructor(str* name) { pub constructor(str* name) {
self.name = name.to_string(); self.name = name.to_string();
self.tasks = new Vec(); self.tasks = new Vec();
@@ -25,7 +25,7 @@ public class Application {
self.ticks = 0; self.ticks = 0;
} }
public void boot(self mut*) { pub void boot(self mut*) {
self.logger.info("booting application"); self.logger.info("booting application");
self.running = true; self.running = true;
@@ -33,7 +33,7 @@ public class Application {
self.emit(event::Event::Startup); self.emit(event::Event::Startup);
} }
public void run(self mut*) { pub void run(self mut*) {
while(self.running) { while(self.running) {
self.tick(); self.tick();
@@ -55,7 +55,7 @@ public class Application {
println!("tasks: {}", self.tasks.len()); println!("tasks: {}", self.tasks.len());
} }
public void shutdown(self mut*) { pub void shutdown(self mut*) {
self.emit(event::Event::Shutdown); self.emit(event::Event::Shutdown);
self.logger.warning("shutdown"); self.logger.warning("shutdown");
@@ -63,7 +63,7 @@ public class Application {
self.running = false; self.running = false;
} }
public void register_plugin(self mut*, String name) { pub void register_plugin(self mut*, String name) {
self.plugins.push(name.clone()); self.plugins.push(name.clone());
self.emit(event::Event::PluginLoaded(name)); self.emit(event::Event::PluginLoaded(name));
+1 -1
View File
@@ -1,4 +1,4 @@
public enum Event { pub enum Event {
Startup, Startup,
Shutdown, Shutdown,
TaskExecuted(String), TaskExecuted(String),
+10 -9
View File
@@ -1,17 +1,18 @@
use <std::fmt::Formatter>;
use <std::fmt>; use <std::fmt>;
public trait TestLogging<T: fmt::Display>: fmt::Display { pub trait TestLogging<T: fmt::Display>: fmt::Display {
String get(); String get();
} }
public enum LogLevel { pub enum LogLevel {
Info, Info,
Warning, Warning,
Error, Error,
} }
impl fmt::Display for LogLevel { impl fmt::Display for LogLevel {
std::fmt::Result fmt(self*, std::fmt::Formatter<'_> mut* f) { fmt::Result fmt(self*, Formatter<'_> mut* f) {
match (self) { match (self) {
LogLevel::Info => { LogLevel::Info => {
return write!(f, "[INFO]"); return write!(f, "[INFO]");
@@ -28,22 +29,22 @@ impl fmt::Display for LogLevel {
} }
} }
public class Logger { pub class Logger {
String prefix; String prefix;
public constructor(str* prefix) { pub constructor(str* prefix) {
self.prefix = prefix.to_string(); self.prefix = prefix.to_string();
} }
public void info(self*, str* message) { pub void info(self*, str* message) {
self.log(LogLevel::Info, message); self.log(LogLevel::Info, message);
} }
public void warning(self*, str* message) { pub void warning(self*, str* message) {
self.log(LogLevel::Warning, message); self.log(LogLevel::Warning, message);
} }
public void error(self*, str* message) { pub void error(self*, str* message) {
self.log(LogLevel::Error, message); self.log(LogLevel::Error, message);
} }
@@ -64,7 +65,7 @@ public class Logger {
} }
impl fmt::Display { impl fmt::Display {
std::fmt::Result fmt(self*, std::fmt::Formatter<'_> mut* f) { fmt::Result fmt(self*, Formatter<'_> mut* f) {
return write!(f, "logger ({})", self.prefix); return write!(f, "logger ({})", self.prefix);
} }
} }
+5 -5
View File
@@ -1,8 +1,8 @@
mod app; pub mod app;
mod task; pub mod task;
mod plugin; pub mod plugin;
mod logger; pub mod logger;
mod event; pub mod event;
void main() { void main() {
var mut app_instance = new app::Application("mist-app"); var mut app_instance = new app::Application("mist-app");
+6 -6
View File
@@ -1,16 +1,16 @@
public struct PluginInfo { pub struct PluginInfo {
public String name, pub String name,
public String version, pub String version,
} }
public class PluginRegistry<T> { pub class PluginRegistry<T> {
T plugins; T plugins;
public constructor(T plugins) { pub constructor(T plugins) {
self.plugins = plugins; self.plugins = plugins;
} }
public T plugins(self) { pub T plugins(self) {
return self.plugins; return self.plugins;
} }
} }
+6 -6
View File
@@ -1,17 +1,17 @@
public enum TaskState { pub enum TaskState {
Pending, Pending,
Running, Running,
Finished, Finished,
Failed, Failed,
} }
public struct Task { pub struct Task {
public String name, pub String name,
public TaskState state, pub TaskState state,
public i32 executions, pub i32 executions,
} }
public Task create_task(str* name) { pub Task create_task(str* name) {
return Task { return Task {
name: name.to_string(), name: name.to_string(),
state: TaskState::Pending, state: TaskState::Pending,
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "mist-parser" name = "mist-parser"
version = "0.1.0" version = "0.1.1"
edition = "2024" edition = "2024"
description = "The Mist programming language parser" description = "The Mist programming language parser"
license = "Apache-2.0" license = "Apache-2.0"
+9 -2
View File
@@ -20,6 +20,7 @@ pub enum TypePostfix {
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum Visibility { pub enum Visibility {
Public, Public,
PublicTarget(Path),
Private, Private,
} }
@@ -72,8 +73,8 @@ pub struct TopLevel(pub TopLevelKind, pub Vec<Attribute>);
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum TopLevelKind { pub enum TopLevelKind {
ModAttribute, ModAttribute,
Import(Path), Import(Visibility, Path),
Mod(Identifier), Mod(Visibility, Identifier),
ImplDecl(ImplDecl), ImplDecl(ImplDecl),
TraitDecl { TraitDecl {
visibility: Visibility, visibility: Visibility,
@@ -271,3 +272,9 @@ pub enum Literal {
Bool(bool), Bool(bool),
Tuple(Vec<Expression>), Tuple(Vec<Expression>),
} }
impl TypeExpr {
pub fn no_px(kind: TypeExprKind) -> Self {
Self(kind, Vec::new())
}
}
+159
View File
@@ -0,0 +1,159 @@
use std::fmt::Debug;
use pest::iterators::Pair;
use crate::Rule;
pub type AstResult<'a, T, ET = T> = Result<T, AstError<'a, ET>>;
#[derive(Debug, Clone)]
pub enum ParseError<'a, T> {
PreAst(pest::error::Error<Rule>),
Ast(AstError<'a, T>),
}
#[derive(Debug, Clone)]
pub struct AstError<'a, T> {
pub span: pest::Span<'a>,
pub error_code: ErrorCode,
pub error_message: String,
pub recovered: Option<T>,
}
#[derive(Debug, Clone)]
pub enum ErrorCode {
InvalidStatement,
AstGenBug,
}
impl<T> From<pest::error::Error<Rule>> for ParseError<'_, T> {
fn from(value: pest::error::Error<Rule>) -> Self {
Self::PreAst(value)
}
}
impl<'a, T> From<AstError<'a, T>> for ParseError<'a, T> {
fn from(value: AstError<'a, T>) -> Self {
Self::Ast(value)
}
}
impl<'a, F> AstError<'a, F> {
pub fn get<T>(self) -> AstError<'a, T> {
AstError {
span: self.span,
error_code: self.error_code,
error_message: self.error_message,
recovered: None,
}
}
pub fn bug_unimplemented<T>(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.as_rule()),
recovered: None,
})
}
}
pub trait IntoErr<T, FA, FR> {
fn get(self) -> T;
fn get_map(self, m: impl Fn(FA) -> FR) -> T;
}
impl<'a, T, TE, TE2> IntoErr<AstResult<'a, T, TE2>, 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 {
fn len(&self) -> usize;
}
impl<T, E> GetLength for Result<Vec<T>, 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<Item = pest::iterators::Pair<'a, Rule>>,
) -> AstResult<'a, Vec<T>, Vec<T>>
where
T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a, ET>>,
{
collect_recovered_map(pairs, T::try_from)
}
pub fn collect_recovered_map<'a, T: Debug, F, ET>(
pairs: impl Iterator<Item = pest::iterators::Pair<'a, Rule>>,
f: F,
) -> AstResult<'a, Vec<T>, Vec<T>>
where
F: Fn(pest::iterators::Pair<'a, Rule>) -> AstResult<'a, T, ET>,
{
let mut items = Vec::new();
let mut last_error: Option<AstError<'a, ET>> = None;
for pair in pairs {
match f(pair) {
Ok(item) => items.push(item),
Err(e) => {
last_error = Some(e);
}
}
}
match last_error {
Some(ast_err) => Err(AstError {
span: ast_err.span,
error_code: ast_err.error_code,
error_message: ast_err.error_message,
recovered: Some(items),
}),
None => Ok(items),
}
}
pub struct AstErrorAnalyzer<'a, T>(pub Option<AstError<'a, T>>);
impl<'a, T> AstErrorAnalyzer<'a, T> {
pub fn get<V: Clone, V2: Clone + Into<V>>(
&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.into())
} 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)
}
}
}
+28 -22
View File
@@ -48,9 +48,17 @@ program = {
// MODIFIERS // MODIFIERS
// ====================================================== // ======================================================
export = { "public" } visibility = { "pub" ~ ("(" ~ static_path ~ ")")? }
mutable = { "mut" } mutable = { "mut" }
var = { "var" } var = { "var" }
// ======================================================
// ERROR RECOVERY
// ======================================================
unexpected_statement = {
(!(semicolon | "}" | statement) ~ ANY)+
}
// ====================================================== // ======================================================
// GENERICS // GENERICS
@@ -154,7 +162,7 @@ var_decl = {
} }
field = { field = {
export? ~ type_expr ~ identifier visibility? ~ type_expr ~ identifier
} }
field_list = { field_list = {
@@ -170,11 +178,11 @@ param_list = {
// ====================================================== // ======================================================
import = { import = {
"use" ~ "<" ~ static_path ~ ">" ~ semicolon visibility? ~ "use" ~ "<" ~ static_path ~ ">" ~ semicolon
} }
mod_package = { mod_package = {
"mod" ~ identifier ~ semicolon visibility? ~ "mod" ~ identifier ~ semicolon
} }
// ====================================================== // ======================================================
@@ -182,7 +190,7 @@ mod_package = {
// ====================================================== // ======================================================
struct_decl = { struct_decl = {
export? ~ "struct" ~ identifier ~ generics? ~ "{" ~ field_list? ~ "}" visibility? ~ "struct" ~ identifier ~ generics? ~ "{" ~ field_list? ~ "}"
} }
// ====================================================== // ======================================================
@@ -212,7 +220,7 @@ enum_fields = _{
} }
enum_decl = { enum_decl = {
export? ~ "enum" ~ identifier ~ generics? ~ "{" ~ enum_fields ~ "}" visibility? ~ "enum" ~ identifier ~ generics? ~ "{" ~ enum_fields ~ "}"
} }
// ====================================================== // ======================================================
@@ -220,7 +228,7 @@ enum_decl = {
// ====================================================== // ======================================================
class_constructor = { class_constructor = {
export? ~ "constructor" ~ generics? ~ "(" ~ param_list? ~ ")" ~ block visibility? ~ "constructor" ~ generics? ~ "(" ~ param_list? ~ ")" ~ block
} }
class_fields = { class_fields = {
@@ -236,7 +244,7 @@ self_param = {
} }
method = { method = {
export? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ block visibility? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ block
} }
class_item = _{ class_item = _{
@@ -245,7 +253,7 @@ class_item = _{
} }
class_decl = { class_decl = {
export? ~ "class" ~ identifier ~ generics? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}" visibility? ~ "class" ~ identifier ~ generics? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}"
} }
// ====================================================== // ======================================================
@@ -265,7 +273,7 @@ impl_decl = {
trait_requirements = { ":" ~ type_expr_param ~ ("+" ~ type_expr_param)* } trait_requirements = { ":" ~ type_expr_param ~ ("+" ~ type_expr_param)* }
method_no_body = { method_no_body = {
export? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ semicolon visibility? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ ("," ~ param_list?)? ~ ")" ~ semicolon
} }
trait_item = _{ trait_item = _{
@@ -274,7 +282,7 @@ trait_item = _{
} }
trait_decl = { trait_decl = {
export? ~ "trait" ~ identifier ~ generics? ~ trait_requirements? ~ "{" ~ trait_item* ~ "}" visibility? ~ "trait" ~ identifier ~ generics? ~ trait_requirements? ~ "{" ~ trait_item* ~ "}"
} }
// ====================================================== // ======================================================
@@ -282,7 +290,7 @@ trait_decl = {
// ====================================================== // ======================================================
function_decl = { function_decl = {
export? ~ type_expr ~ identifier ~ "(" ~ param_list? ~ ")" ~ block visibility? ~ type_expr ~ identifier ~ "(" ~ param_list? ~ ")" ~ block
} }
// ====================================================== // ======================================================
@@ -299,11 +307,7 @@ top_level = {
// ====================================================== // ======================================================
block = { block = {
"{" ~ statement_list ~ "}" "{" ~ (statement | unexpected_statement)* ~ "}"
}
statement_list = {
statement*
} }
statement = _{ statement = _{
@@ -353,8 +357,10 @@ assign_statement = {
// CONDITIONALS // CONDITIONALS
// ------------------------------------------------------ // ------------------------------------------------------
statement_branch = { "(" ~ expr ~ ")" ~ statement }
else_if = { else_if = {
"else" ~ "if" ~ "(" ~ expr ~ ")" ~ statement "else" ~ "if" ~ statement_branch
} }
else_if_list = { else_if_list = {
@@ -362,7 +368,7 @@ else_if_list = {
} }
if_stmt = { if_stmt = {
"if" ~ "(" ~ expr ~ ")" ~ statement ~ else_if_list ~ ("else" ~ statement)? "if" ~ statement_branch ~ else_if_list ~ ("else" ~ statement)?
} }
// ------------------------------------------------------ // ------------------------------------------------------
@@ -370,7 +376,7 @@ if_stmt = {
// ------------------------------------------------------ // ------------------------------------------------------
while_stmt = { while_stmt = {
"while" ~ "(" ~ expr ~ ")" ~ statement "while" ~ statement_branch
} }
c_for_stmt = { c_for_stmt = {
+38 -797
View File
@@ -2,830 +2,71 @@ use pest::Parser;
use pest_derive::Parser; use pest_derive::Parser;
pub mod ast; pub mod ast;
pub mod error;
pub mod parser;
use ast::*; use ast::*;
use crate::error::{IntoErr, ParseError};
#[derive(Parser)] #[derive(Parser)]
#[grammar = "./src/grammar.pest"] #[grammar = "./src/grammar.pest"]
pub struct MistParser; pub struct MistParser;
// convenience alias for pest errors pub fn parse<'a>(source: &'a str) -> Result<Vec<TopLevel>, ParseError<'a, Vec<TopLevel>>> {
pub type ParseError = pest::error::Error<Rule>;
pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
let mut pairs = MistParser::parse(Rule::program, source)?; let mut pairs = MistParser::parse(Rule::program, source)?;
let mut statements = vec![]; let mut statements = vec![];
let mut analyzer = error::AstErrorAnalyzer(None);
for pair in pairs.next().unwrap().into_inner() { for pair in pairs.next().unwrap().into_inner() {
if pair.as_rule() != Rule::EOI { if pair.as_rule() != Rule::EOI {
statements.push(TopLevel::from(pair)); statements.push(analyzer.get(TopLevel::try_from(pair)).get()?);
} }
} }
Ok(statements) match analyzer.build(statements) {
} Ok(v) => Ok(v),
Err(e) => Err(ParseError::Ast(e)),
impl From<pest::iterators::Pair<'_, Rule>> for TypeExpr {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.into_inner();
match rule {
Rule::type_expr => TypeExpr(
TypeExprKind::from(inner.next().unwrap()),
inner.map(TypePostfix::from).collect(),
),
Rule::type_expr_param => TypeExpr::from(inner.next().unwrap()),
Rule::lifetime => TypeExpr(
TypeExprKind::Lifetime(Identifier::from(inner.next().unwrap())),
Vec::new(),
),
_ => unimplemented!("{rule:#?}"),
}
} }
} }
impl From<pest::iterators::Pair<'_, Rule>> for TypePostfix { #[macro_export]
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { macro_rules! ast_ensure {
let rule = pair.as_rule(); ($pair:expr, $rule:expr => $body:block) => {
let mut inner = pair.into_inner(); if $pair.as_rule() == $rule
$body
match rule { else {
Rule::ref_type => { Err(AstError {
let mutable = listen_rule(&mut inner, Rule::mutable); span: $pair.as_span(),
let lifetime = consume_rule(&mut inner, Rule::lifetime) error_code: crate::error::ErrorCode::AstGenBug,
.map(|pair| Identifier::from(pair.into_inner().next().unwrap())); error_message: format!("Possible bug: expected {:?}, got {}", $rule, $pair),
recovered: None,
if mutable {
if let Some(lifetime) = lifetime {
TypePostfix::RefMutLifetime(lifetime)
} else {
TypePostfix::RefMut
}
} else {
if let Some(lifetime) = lifetime {
TypePostfix::RefLifetime(lifetime)
} else {
TypePostfix::Ref
}
}
}
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for TypeExprKind {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.into_inner();
match rule {
Rule::tuple_type => TypeExprKind::Tuple(inner.map(TypeExpr::from).collect()),
Rule::path_type => {
let path = Path::from(inner.next().unwrap());
let params = inner.map(TypeExpr::from).collect::<Vec<_>>();
if params.len() == 0 {
TypeExprKind::Path(path)
} else {
TypeExprKind::PathParams(path, params)
}
}
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Path {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
match pair.as_rule() {
Rule::static_path => Path(pair.into_inner().map(Identifier::from).collect()),
_ => unimplemented!("{pair:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for ParamList {
fn from(pair: pest::iterators::Pair<Rule>) -> Self {
ParamList(pair.into_inner().map(VarDecl::from).collect())
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Attribute {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
match pair.as_rule() {
Rule::attribute => {
// unwrap #[ ... ]
Attribute::from(pair.into_inner().next().unwrap())
}
Rule::meta => {
let mut inner = pair.into_inner();
// first item is always the path
let path = Path::from(inner.next().unwrap());
// check what comes next
match inner.next() {
None => {
// #[path]
Attribute::Path(path)
}
Some(next) => match next.as_rule() {
Rule::primary => {
// #[path = literal]
Attribute::NameValue {
path,
value: Literal::from(next),
}
}
Rule::meta_list => {
// #[path(...)]
let items = next.into_inner().map(Attribute::from).collect();
Attribute::List { path, items }
}
_ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()),
},
}
}
Rule::meta_list => {
// This case usually won't be hit directly,
// but it's nice to keep it safe if reused
let items = pair.into_inner().map(Attribute::from).collect::<Vec<_>>();
// NOTE: this shouldn't normally construct an Attribute alone
// but you can panic or wrap depending on your design
panic!("meta_list should be handled inside meta: {:?}", items);
}
_ => unreachable!("unexpected rule: {:?}", pair.as_rule()),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for TopLevel {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let mut inner = pair.into_inner();
let attributes = inner
.next()
.unwrap()
.into_inner()
.map(Attribute::from)
.collect::<Vec<_>>();
TopLevel(
inner
.next()
.map(TopLevelKind::from)
.unwrap_or(TopLevelKind::ModAttribute),
attributes,
)
}
}
impl From<pest::iterators::Pair<'_, Rule>> for StatementBranch {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let mut inner = pair.into_inner();
let condition = Expression::from(inner.next().unwrap());
let body = Statement::from(inner.next().unwrap());
StatementBranch {
condition,
body: Box::new(body),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for ClassConstructor {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let mut inner = pair.into_inner();
let visibility = Visibility::from(&mut inner);
let generics = consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default();
let params = consume_rule(&mut inner, Rule::param_list)
.map(ParamList::from)
.unwrap_or_else(|| ParamList(Vec::new()));
Self {
visibility,
generics,
params,
body: Block::from(inner.next().unwrap()),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Generics {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let inner = pair.clone().into_inner();
match rule {
Rule::generics => Generics(
inner
.map(|pair| {
let mut inner = pair.into_inner();
if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) {
Generic::Lifetime(Identifier::from(pair.into_inner().next().unwrap()))
} else {
Generic::Type(
Identifier::from(inner.next().unwrap()),
inner.map(TypeExpr::from).collect(),
)
}
})
.collect(),
),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for TopLevelKind {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::import => TopLevelKind::Import(Path::from(inner.next().unwrap())),
Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::from(pair)),
Rule::struct_decl => TopLevelKind::StructDecl {
visibility: Visibility::from(&mut inner),
name: Identifier::from(inner.next().unwrap()),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
fields: inner
.next()
.map(|pair| pair.into_inner().map(FieldDecl::from).collect())
.unwrap_or_default(),
},
Rule::class_decl => TopLevelKind::ClassDecl {
visibility: Visibility::from(&mut inner),
name: Identifier::from(inner.next().unwrap()),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
fields: inner
.next()
.unwrap()
.into_inner()
.map(FieldDeclStmt::from)
.collect(),
constructor: ClassConstructor::from(inner.next().unwrap()),
items: inner.into_iter().map(ClassItem::from).collect(),
},
Rule::enum_decl => TopLevelKind::EnumDecl {
visibility: Visibility::from(&mut inner),
name: Identifier::from(inner.next().unwrap()),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
fields: inner.map(EnumItem::from).collect(),
},
Rule::mod_package => TopLevelKind::Mod(Identifier::from(inner.next().unwrap())),
Rule::impl_for_decl | Rule::impl_decl => TopLevelKind::ImplDecl(ImplDecl::from(pair)),
Rule::trait_decl => TopLevelKind::TraitDecl {
visibility: Visibility::from(&mut inner),
name: Identifier::from(inner.next().unwrap()),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
requirements: consume_rule(&mut inner, Rule::trait_requirements)
.map(|pair| pair.into_inner().map(TypeExpr::from).collect())
.unwrap_or_default(),
items: inner.map(FunctionDecl::from).collect(),
},
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for ClassItem {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
match rule {
Rule::impl_decl | Rule::impl_for_decl => ClassItem::ImplDecl(ImplDecl::from(pair)),
Rule::method => ClassItem::Method(FunctionDecl::from(pair)),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for ImplDecl {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::impl_for_decl => ImplDecl {
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
trait_: Some(TypeExpr::from(inner.next().unwrap())),
target: TypeExpr::from(inner.next().unwrap()),
methods: inner.map(FunctionDecl::from).collect(),
},
Rule::impl_decl => ImplDecl {
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
trait_: None,
target: TypeExpr::from(inner.next().unwrap()),
methods: inner.map(FunctionDecl::from).collect(),
},
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for EnumItem {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::enum_named => EnumItem::Named(Identifier::from(inner.next().unwrap())),
Rule::enum_tuple => EnumItem::Tuple(
Identifier::from(inner.next().unwrap()),
inner
.next()
.unwrap()
.into_inner()
.map(TypeExpr::from)
.collect(),
),
Rule::enum_struct => EnumItem::Struct(
Identifier::from(inner.next().unwrap()),
inner
.next()
.map(|pair| pair.into_inner().map(FieldDecl::from).collect())
.unwrap_or_default(),
),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Block {
fn from(pair: pest::iterators::Pair<Rule>) -> Self {
let statements = pair
.into_inner()
.flat_map(|pair| {
if pair.as_rule() == Rule::statement_list {
pair.into_inner().map(Statement::from).collect()
} else {
vec![Statement::from(pair)]
}
}) })
.collect();
Block(statements)
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Statement {
fn from(pair: pest::iterators::Pair<Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::statement => Statement::from(inner.next().unwrap()),
Rule::expr_stmt => Statement::Expression(Expression::from(inner.next().unwrap())),
Rule::block => Statement::Block(Block::from(inner.next().unwrap())),
Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::from(pair)),
Rule::return_stmt => {
let expr = inner.next().map(Expression::from);
Statement::Return(expr)
}
Rule::break_stmt => Statement::Break,
Rule::continue_stmt => Statement::Continue,
Rule::if_stmt => {
let mut inner = inner.skip(2);
Statement::If {
initial: pair.into(),
else_if: inner
.next()
.unwrap()
.into_inner()
.map(StatementBranch::from)
.collect(),
else_branch: inner.next().map(Statement::from).map(Box::new),
}
}
Rule::while_stmt => Statement::While(pair.into()),
Rule::c_for_stmt => Statement::CStyleFor {
init: Box::new(Statement::from(inner.next().unwrap())),
condition: inner.next().unwrap().into(),
update: Box::new(Statement::from(inner.next().unwrap())),
body: Box::new(Statement::from(inner.next().unwrap())),
},
Rule::for_stmt => Statement::For {
mutable: listen_rule(&mut inner, Rule::mutable),
pattern: Pattern::from(inner.next().unwrap()),
iterator: inner.next().unwrap().into(),
body: Box::new(Statement::from(inner.next().unwrap())),
},
Rule::assign_statement => Statement::VarAssign(VarAssignStmt {
target: Expression::from(inner.next().unwrap()),
value: Expression::from(inner.next().unwrap()),
}),
Rule::match_stmt => Statement::Match(
Expression::from(inner.next().unwrap()),
inner
.map(|match_itms| {
let mut match_inner = match_itms.into_inner();
(
Pattern::from(match_inner.next().unwrap()),
Block::from(match_inner.next().unwrap()),
)
})
.collect(),
),
_ => unimplemented!("{rule:#?}"),
} }
} };
} }
impl From<pest::iterators::Pair<'_, Rule>> for Literal { #[macro_export]
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { macro_rules! ast_expr {
let rule = pair.as_rule(); ($($item:ident)::+ { $($k:ident: $v:expr),* $(,)? }) => {{
let mut inner = pair.clone().into_inner(); let mut analyzer = $crate::error::AstErrorAnalyzer(None);
match rule { let v = $($item)::+ { $($k: analyzer.get($v).get()?),* };
Rule::primary => Self::from(inner.next().unwrap()),
Rule::literal => Self::from(inner.next().unwrap()),
Rule::integer => Literal::Int(pair.as_str().parse::<i64>().unwrap()),
Rule::float => Literal::Float(pair.as_str().parse::<f64>().unwrap()),
Rule::boolean => Literal::Bool(pair.as_str().parse::<bool>().unwrap()),
Rule::string_lit => Literal::String(inner.as_str().to_string()),
Rule::tuple => Literal::Tuple(inner.map(Expression::from).collect()),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Expression { analyzer.build(v)
fn from(pair: pest::iterators::Pair<Rule>) -> Self { }};
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule { ($($item:ident)::+ ( $($v:expr),* $(,)? )) => {{
Rule::expr => { let mut analyzer = $crate::error::AstErrorAnalyzer(None);
let prefixes: Vec<Prefix> = inner
.next()
.map(|p| p.into_inner().into_iter().map(Prefix::from).collect())
.unwrap_or_default();
let exp = Expression::from(inner.next().unwrap()); let v = $($item)::+ ( $(analyzer.get($v).get()?),* );
if inner.len() > 0 || prefixes.len() > 0 { analyzer.build(v)
Expression::Fix { }};
initial: Box::new(exp),
prefixes,
postfixes: inner.map(|p| Postfix::from(p)).collect(),
}
} else {
exp
}
}
Rule::primary => Expression::from(inner.next().unwrap()),
Rule::static_path => Expression::Path(Path::from(pair)),
Rule::literal => Expression::Literal(Literal::from(pair)),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Prefix { ($($item:ident)::+) => {
fn from(pair: pest::iterators::Pair<Rule>) -> Self { $($item)::+
match pair.as_rule() { };
Rule::prefix => Self::from(pair.into_inner().next().unwrap()),
Rule::deref_px => Self::Deref,
Rule::mut_ref_px => Self::RefMut,
Rule::ref_px => Self::Ref,
Rule::new_px => Self::New,
Rule::not_px => Self::Not,
_ => unimplemented!("{pair:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Postfix {
fn from(pair: pest::iterators::Pair<Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.into_inner();
match rule {
Rule::postfix => Postfix::from(inner.next().unwrap()),
Rule::field_px => Postfix::FieldAccess(Identifier::from(inner.next().unwrap())),
Rule::call_px => Postfix::Call(inner.map(Expression::from).collect()),
Rule::struct_px => Postfix::StructCall(
inner
.map(|p| {
let mut pi = p.into_inner();
(
Identifier::from(pi.next().unwrap()),
Expression::from(pi.next().unwrap()),
)
})
.collect(),
),
Rule::index_px => Postfix::Index(Expression::from(inner.next().unwrap())),
Rule::binary_px => {
let op_pair = inner.next().unwrap();
let op = match op_pair.as_str() {
"+" => BinaryOp::Plus,
"-" => BinaryOp::Minus,
"*" => BinaryOp::Multiply,
"/" => BinaryOp::Divide,
"%" => BinaryOp::Modulo,
"==" => BinaryOp::Equal,
"!=" => BinaryOp::NotEqual,
"<" => BinaryOp::LessThan,
">" => BinaryOp::GreaterThan,
"<=" => BinaryOp::LessThanOrEqual,
">=" => BinaryOp::GreaterThanOrEqual,
"&&" => BinaryOp::And,
"||" => BinaryOp::Or,
_ => {
unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str())
}
};
Postfix::Binary(op, Expression::from(inner.next().unwrap()))
}
Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for VarDeclStmt {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
match pair.as_rule() {
Rule::var_decl_statement => {
let mut inner = pair.into_inner();
let decl = VarDecl::from(inner.next().unwrap());
let init = inner.next().map(Expression::from);
VarDeclStmt { decl, init }
}
_ => unimplemented!(),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for FieldDeclStmt {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
match pair.as_rule() {
Rule::class_field => {
let mut inner = pair.into_inner();
let decl = FieldDecl::from(inner.next().unwrap());
let init = inner.next().map(Expression::from);
FieldDeclStmt { decl, init }
}
_ => unimplemented!(),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Pattern {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::tuple_pattern => Pattern::Tuple(inner.map(Identifier::from).collect()),
Rule::named_tuple_pattern => Pattern::NamedTuple(
Path::from(inner.next().unwrap()),
inner.map(Identifier::from).collect(),
),
Rule::struct_pattern => Pattern::Struct(
Path::from(inner.next().unwrap()),
inner.map(Identifier::from).collect(),
),
Rule::literal => Pattern::Literal(Literal::from(pair)),
Rule::identifier => Pattern::Id(Identifier::from(pair)),
Rule::static_path => Pattern::Path(Path::from(pair)),
_ => unimplemented!("{rule:?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for VarDecl {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
match pair.as_rule() {
Rule::var_decl => {
let mut inner = pair.into_inner();
let type_ = inner.next().and_then(|pair| {
if pair.as_str().trim() == "var" {
None
} else {
Some(TypeExpr::from(pair))
}
});
let mutable = listen_rule(&mut inner, Rule::mutable);
let name = Pattern::from(inner.next().unwrap());
VarDecl {
mutable,
name,
type_,
}
}
_ => unimplemented!("{:?}", pair.as_rule()),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for FieldDecl {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
match pair.as_rule() {
Rule::field => {
let mut inner = pair.into_inner();
let visibility = Visibility::from(&mut inner);
let type_ = TypeExpr::from(inner.next().unwrap());
let name = Identifier::from(inner.next().unwrap());
FieldDecl {
visibility,
type_,
name,
}
}
_ => unimplemented!("{:?}", pair.as_rule()),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for FunctionDecl {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let mut inner = pair.into_inner();
let visibility = Visibility::from(&mut inner);
let return_type = TypeExpr::from(inner.next().unwrap());
let name = Identifier::from(inner.next().unwrap());
let generics = consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default();
let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| {
let mut param_inner = param.into_inner();
let name = Pattern::Id(Identifier(String::from("self")));
let mutable = listen_rule(&mut param_inner, Rule::mutable);
let is_ref = listen_rule(&mut param_inner, Rule::deref_px);
VarDecl {
mutable: mutable && !is_ref,
name: name.clone(),
type_: Some(TypeExpr(
TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])),
if is_ref {
vec![if mutable {
TypePostfix::RefMut
} else {
TypePostfix::Ref
}]
} else {
Vec::new()
},
)),
}
});
let params = consume_rule(&mut inner, Rule::param_list)
.map({
let self_param = self_param.clone();
|params_pair| {
let mut params = ParamList::from(params_pair);
if let Some(x) = self_param {
params.0.insert(0, x);
}
params
}
})
.unwrap_or_else(|| ParamList(self_param.into_iter().collect()));
let body = inner.next().map(Block::from);
Self {
visibility,
name,
generics,
params,
return_type,
body,
}
}
}
impl From<&mut pest::iterators::Pairs<'_, Rule>> for Visibility {
fn from(pairs: &mut pest::iterators::Pairs<'_, Rule>) -> Self {
if listen_rule(pairs, Rule::export) {
Visibility::Public
} else {
Visibility::Private
}
}
}
pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed {
pairs.next();
}
consumed
}
pub fn consume_rule<'a>(
pairs: &mut pest::iterators::Pairs<'a, Rule>,
rule: Rule,
) -> Option<pest::iterators::Pair<'a, Rule>> {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed { pairs.next() } else { None }
}
impl From<pest::iterators::Pair<'_, Rule>> for Identifier {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
Identifier(pair.as_str().to_string())
}
} }
+100
View File
@@ -0,0 +1,100 @@
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, AstResult, IntoErr},
parser::listen_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDeclStmt {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() {
Rule::var_decl_statement => {
let mut inner = pair.into_inner();
ast_expr!(VarDeclStmt {
decl: inner.next().unwrap().try_into(),
init: inner.next().map(Expression::try_from).transpose()
})
}
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDeclStmt {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() {
Rule::class_field => {
let mut inner = pair.into_inner();
ast_expr!(FieldDeclStmt {
decl: inner.next().unwrap().try_into(),
init: inner.next().map(Expression::try_from).transpose(),
})
}
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for VarDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() {
Rule::var_decl => {
let mut inner = pair.into_inner();
let type_ = inner
.next()
.and_then(|pair| {
if pair.as_str().trim() == "var" {
None
} else {
Some(TypeExpr::try_from(pair))
}
})
.transpose();
let mutable: AstResult<'_, bool> = Ok(listen_rule(&mut inner, Rule::mutable));
let name = Pattern::try_from(inner.next().unwrap());
ast_expr!(VarDecl {
type_: type_,
mutable: mutable,
name: name,
})
}
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FieldDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() {
Rule::field => {
let mut inner = pair.into_inner();
ast_expr!(FieldDecl {
visibility: Visibility::try_from(&mut inner),
type_: TypeExpr::try_from(inner.next().unwrap()),
name: Identifier::try_from(inner.next().unwrap()),
})
}
_ => AstError::bug_unimplemented(pair),
}
}
}
+117
View File
@@ -0,0 +1,117 @@
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, GetLength, IntoErr, collect_recovered, collect_recovered_map},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::expr => {
let prefixes = inner
.next()
.map(|p| collect_recovered::<Prefix, Prefix>(p.into_inner()))
.unwrap_or_else(|| Ok(Vec::new()));
let exp = Expression::try_from(inner.next().unwrap());
if inner.len() > 0 || prefixes.len() > 0 {
ast_expr!(Expression::Fix {
initial: exp.map(Box::new),
prefixes: prefixes,
postfixes: collect_recovered(inner),
})
} else {
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())),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(match pair.as_rule() {
Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?,
Rule::deref_px => Self::Deref,
Rule::mut_ref_px => Self::RefMut,
Rule::ref_px => Self::Ref,
Rule::new_px => Self::New,
Rule::not_px => Self::Not,
_ => return AstError::bug_unimplemented(pair),
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::postfix => Postfix::try_from(inner.next().unwrap()),
Rule::field_px => {
ast_expr!(Postfix::FieldAccess(inner.next().unwrap().try_into()))
}
Rule::call_px => ast_expr!(Postfix::Call(collect_recovered(inner))),
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 => {
ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap())))
}
Rule::binary_px => {
let op_pair = inner.next().unwrap();
let op = match op_pair.as_str() {
"+" => BinaryOp::Plus,
"-" => BinaryOp::Minus,
"*" => BinaryOp::Multiply,
"/" => BinaryOp::Divide,
"%" => BinaryOp::Modulo,
"==" => BinaryOp::Equal,
"!=" => BinaryOp::NotEqual,
"<" => BinaryOp::LessThan,
">" => BinaryOp::GreaterThan,
"<=" => BinaryOp::LessThanOrEqual,
">=" => BinaryOp::GreaterThanOrEqual,
"&&" => BinaryOp::And,
"||" => BinaryOp::Or,
_ => return AstError::bug_unimplemented(op_pair),
};
Ok(Postfix::Binary(op, inner.next().unwrap().try_into().get()?))
}
Rule::macro_call_px => Ok(Postfix::MacroCall(inner.as_str().to_string())),
_ => AstError::bug_unimplemented(pair),
}
}
}
+101
View File
@@ -0,0 +1,101 @@
pub mod decl;
pub mod expr;
pub mod statement;
pub mod types;
use crate::{
Rule,
ast::*,
ast_ensure, ast_expr,
error::{AstError, IntoErr, collect_recovered},
parser::consume_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Identifier {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
ast_ensure!(pair, Rule::identifier => {
Ok(Identifier(pair.as_str().to_string()))
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Path {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() {
Rule::static_path => Ok(Path(collect_recovered(pair.into_inner()).get()?)),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Literal {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
Ok(match rule {
Rule::primary => Self::try_from(inner.next().unwrap())?,
Rule::literal => Self::try_from(inner.next().unwrap())?,
Rule::integer => Literal::Int(pair.as_str().parse::<i64>().unwrap()),
Rule::float => Literal::Float(pair.as_str().parse::<f64>().unwrap()),
Rule::boolean => Literal::Bool(pair.as_str().parse::<bool>().unwrap()),
Rule::string_lit => Literal::String(inner.as_str().to_string()),
Rule::tuple => Literal::Tuple(collect_recovered(inner).get()?),
_ => return AstError::bug_unimplemented(pair),
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Pattern {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::tuple_pattern => ast_expr!(Pattern::Tuple(collect_recovered(pair.into_inner()))),
Rule::named_tuple_pattern => ast_expr!(Pattern::NamedTuple(
Path::try_from(inner.next().unwrap()),
collect_recovered(inner),
)),
Rule::struct_pattern => ast_expr!(Pattern::Struct(
Path::try_from(inner.next().unwrap()),
collect_recovered(inner),
)),
Rule::literal => ast_expr!(Pattern::Literal(pair.try_into())),
Rule::identifier => ast_expr!(Pattern::Id(pair.try_into())),
Rule::static_path => ast_expr!(Pattern::Path(pair.try_into())),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility {
type Error = AstError<'a, Self>;
fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result<Self, Self::Error> {
Ok(consume_rule(pairs, Rule::visibility)
.map(|pair| -> Result<Visibility, AstError<'a, Self>> {
if let Some(path) = pair.into_inner().next() {
ast_expr!(Visibility::PublicTarget(Path::try_from(path)))
} else {
Ok(Visibility::Public)
}
})
.transpose()?
.unwrap_or_else(|| Visibility::Private))
}
}
+123
View File
@@ -0,0 +1,123 @@
use crate::{
Rule,
ast::*,
ast_ensure, ast_expr,
error::{AstError, AstResult, ErrorCode, IntoErr, collect_recovered},
parser::listen_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
ast_ensure!(pair, Rule::block => {
ast_expr!(Block(collect_recovered(pair.into_inner())))
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::statement_branch => {
ast_expr!(StatementBranch {
condition: inner.next().unwrap().try_into(),
body: inner.next().unwrap().try_into().map(Box::new),
})
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::statement => Statement::try_from(inner.next().unwrap()),
Rule::expr_stmt => {
ast_expr!(Statement::Expression(inner.next().unwrap().try_into()))
}
Rule::block => ast_expr!(Statement::Block(pair.try_into())),
Rule::var_decl_statement => ast_expr!(Statement::VarDecl(pair.try_into())),
Rule::return_stmt => {
ast_expr!(Statement::Return(
inner.next().map(Expression::try_from).transpose()
))
}
Rule::break_stmt => Ok(Statement::Break),
Rule::continue_stmt => Ok(Statement::Continue),
Rule::if_stmt => {
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(|v| v.map(Box::new))
.get_map(|v| { Some(Box::new(v)) }),
})
}
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),
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::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();
Ok((
Pattern::try_from(match_inner.next().unwrap()).get()?,
Block::try_from(match_inner.next().unwrap()).get()?,
))
})
.collect::<AstResult<'a, Vec<_>>>(),
)),
Rule::unexpected_statement => {
return Err(AstError {
span: pair.as_span(),
error_code: ErrorCode::InvalidStatement,
error_message: "Invalid Statement".to_string(),
recovered: None,
});
}
_ => AstError::bug_unimplemented(pair),
}
}
}
+121
View File
@@ -0,0 +1,121 @@
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, GetLength, IntoErr, collect_recovered},
parser::{consume_rule, listen_rule},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypePostfix {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::ref_type => {
let mutable = listen_rule(&mut inner, Rule::mutable);
let lifetime = consume_rule(&mut inner, Rule::lifetime)
.map(|pair| Identifier::try_from(pair.into_inner().next().unwrap()))
.transpose()
.get()?;
Ok(if mutable {
if let Some(lifetime) = lifetime {
TypePostfix::RefMutLifetime(lifetime)
} else {
TypePostfix::RefMut
}
} else {
if let Some(lifetime) = lifetime {
TypePostfix::RefLifetime(lifetime)
} else {
TypePostfix::Ref
}
})
}
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExprKind {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::tuple_type => ast_expr!(TypeExprKind::Tuple(collect_recovered(inner))),
Rule::path_type => {
let path = Path::try_from(inner.next().unwrap());
let params = collect_recovered(inner);
if params.len() == 0 {
ast_expr!(TypeExprKind::Path(path))
} else {
ast_expr!(TypeExprKind::PathParams(path, params))
}
}
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TypeExpr {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
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 => ast_expr!(TypeExprKind::Lifetime(inner.next().unwrap().try_into()))
.get_map(TypeExpr::no_px)
.map(TypeExpr::no_px),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generics {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let inner = pair.clone().into_inner();
match rule {
Rule::generics => ast_expr!(Generics(collect_recovered(inner))),
_ => AstError::bug_unimplemented(pair),
}
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Generic {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner();
if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) {
ast_expr!(Generic::Lifetime(
pair.into_inner().next().unwrap().try_into(),
))
} else {
ast_expr!(Generic::Type(
inner.next().unwrap().try_into(),
collect_recovered(inner),
))
}
}
}
+68
View File
@@ -0,0 +1,68 @@
use crate::{
Rule,
ast::*,
error::{AstError, IntoErr, collect_recovered},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Attribute {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
match pair.as_rule() {
Rule::attribute => {
// unwrap #[ ... ]
Attribute::try_from(pair.into_inner().next().unwrap())
}
Rule::meta => {
let mut inner = pair.into_inner();
// first item is always the path
let path = inner.next().unwrap().try_into().get()?;
// check what comes next
match inner.next() {
None => {
// #[path]
Ok(Attribute::Path(path))
}
Some(next) => match next.as_rule() {
Rule::primary => {
// #[path = literal]
Ok(Attribute::NameValue {
path,
value: inner.next().unwrap().try_into().get()?,
})
}
Rule::meta_list => {
// #[path(...)]
Ok(Attribute::List {
path,
items: collect_recovered(next.into_inner()).get()?,
})
}
_ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()),
},
}
}
Rule::meta_list => {
// This case usually won't be hit directly,
// but it's nice to keep it safe if reused
let items = pair
.into_inner()
.map(Attribute::try_from)
.collect::<Vec<_>>();
// NOTE: this shouldn't normally construct an Attribute alone
// but you can panic or wrap depending on your design
panic!("meta_list should be handled inside meta: {:?}", items);
}
_ => unreachable!("unexpected rule: {:?}", pair.as_rule()),
}
}
}
+50
View File
@@ -0,0 +1,50 @@
use crate::{
Rule,
ast::*,
error::{AstError, IntoErr},
parser::consume_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassConstructor {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner();
Ok(Self {
visibility: Visibility::try_from(&mut inner).get()?,
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.get()?
.unwrap_or_default(),
params: consume_rule(&mut inner, Rule::param_list)
.map(ParamList::try_from)
.transpose()
.get()?
.unwrap_or_default(),
body: inner.next().unwrap().try_into().get()?,
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ClassItem {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
match rule {
Rule::impl_decl | Rule::impl_for_decl => {
Ok(ClassItem::ImplDecl(pair.try_into().get()?))
}
Rule::method => Ok(ClassItem::Method(pair.try_into().get()?)),
_ => AstError::bug_unimplemented(pair),
}
}
}
+35
View File
@@ -0,0 +1,35 @@
use crate::{
Rule,
ast::*,
error::{AstError, IntoErr, collect_recovered},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for EnumItem {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::enum_named => Ok(EnumItem::Named(inner.next().unwrap().try_into().get()?)),
Rule::enum_tuple => Ok(EnumItem::Tuple(
inner.next().unwrap().try_into().get()?,
collect_recovered(inner.next().unwrap().into_inner()).get()?,
)),
Rule::enum_struct => Ok(EnumItem::Struct(
inner.next().unwrap().try_into().get()?,
inner
.next()
.map(|pair| collect_recovered::<FieldDecl, FieldDecl>(pair.into_inner()))
.transpose()
.get()?
.unwrap_or_default(),
)),
_ => AstError::bug_unimplemented(pair),
}
}
}
+81
View File
@@ -0,0 +1,81 @@
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, AstResult, IntoErr, collect_recovered},
parser::{consume_rule, listen_rule},
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner();
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()
.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();
let name = Pattern::Id(Identifier(String::from("self")));
let mutable = listen_rule(&mut param_inner, Rule::mutable);
let is_ref = listen_rule(&mut param_inner, Rule::deref_px);
VarDecl {
mutable: mutable && !is_ref,
name: name.clone(),
type_: Some(TypeExpr(
TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])),
if is_ref {
vec![if mutable {
TypePostfix::RefMut
} else {
TypePostfix::Ref
}]
} else {
Vec::new()
},
)),
}
});
let params = consume_rule(&mut inner, Rule::param_list)
.map({
let self_param = self_param.clone();
|params_pair| -> AstResult<'a, ParamList> {
let mut params = ParamList::try_from(params_pair)?;
if let Some(x) = self_param {
params.0.insert(0, x);
}
Ok(params)
}
})
.unwrap_or_else(|| Ok(ParamList(self_param.into_iter().collect())));
let body = inner.next().map(Block::try_from).transpose();
ast_expr!(Self {
visibility: visibility,
return_type: return_type,
name: name,
generics: generics,
params: params,
body: body,
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ParamList {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
Ok(ParamList(collect_recovered(pair.into_inner()).get()?))
}
}
+41
View File
@@ -0,0 +1,41 @@
use crate::{
Rule,
ast::*,
error::{AstError, IntoErr, collect_recovered},
parser::consume_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ImplDecl {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::impl_for_decl => Ok(ImplDecl {
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.get()?
.unwrap_or_default(),
trait_: Some(inner.next().unwrap().try_into().get()?),
target: inner.next().unwrap().try_into().get()?,
methods: collect_recovered(inner).get()?,
}),
Rule::impl_decl => Ok(ImplDecl {
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.get()?
.unwrap_or_default(),
trait_: None,
target: inner.next().unwrap().try_into().get()?,
methods: collect_recovered(inner).get()?,
}),
_ => AstError::bug_unimplemented(pair),
}
}
}
+125
View File
@@ -0,0 +1,125 @@
pub mod attribute;
pub mod class;
pub mod enums;
pub mod function;
pub mod impl_decl;
use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, IntoErr, collect_recovered},
parser::consume_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevel {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.into_inner();
let attributes = collect_recovered(inner.next().unwrap().into_inner());
ast_expr!(TopLevel(
inner
.next()
.map(TopLevelKind::try_from)
.unwrap_or(Ok(TopLevelKind::ModAttribute)),
attributes,
))
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::import => ast_expr!(TopLevelKind::Import(
Visibility::try_from(&mut inner),
Path::try_from(inner.next().unwrap()),
)),
Rule::function_decl => ast_expr!(TopLevelKind::FunctionDecl(pair.try_into())),
Rule::struct_decl => ast_expr!(TopLevelKind::StructDecl {
visibility: Visibility::try_from(&mut inner),
name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.map(|v| v.unwrap_or_default()),
fields: inner
.next()
.map(|pair| collect_recovered::<FieldDecl, FieldDecl>(pair.into_inner()))
.transpose()
.map(|v| v.unwrap_or_default()),
}),
Rule::class_decl => ast_expr!(TopLevelKind::ClassDecl {
visibility: Visibility::try_from(&mut inner),
name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.map(|v| v.unwrap_or_default()),
fields: collect_recovered(inner.next().unwrap().into_inner()),
constructor: inner.next().unwrap().try_into(),
items: collect_recovered(inner),
}),
Rule::enum_decl => ast_expr!(TopLevelKind::EnumDecl {
visibility: Visibility::try_from(&mut inner),
name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.map(|v| v.unwrap_or_default()),
fields: collect_recovered(inner),
}),
Rule::mod_package => ast_expr!(TopLevelKind::Mod(
Visibility::try_from(&mut inner),
inner.next().unwrap().try_into(),
)),
Rule::impl_for_decl | Rule::impl_decl => {
ast_expr!(TopLevelKind::ImplDecl(pair.try_into()))
}
Rule::trait_decl => ast_expr!(TopLevelKind::TraitDecl {
visibility: Visibility::try_from(&mut inner),
name: inner.next().unwrap().try_into(),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::try_from)
.transpose()
.map(|v| v.unwrap_or_default()),
requirements: consume_rule(&mut inner, Rule::trait_requirements)
.map(|pair| collect_recovered::<TypeExpr, TypeExpr>(pair.into_inner()))
.transpose()
.map(|v| v.unwrap_or_default()),
items: collect_recovered(inner),
}),
_ => AstError::bug_unimplemented(pair),
}
}
}
+29
View File
@@ -0,0 +1,29 @@
pub mod common;
pub mod items;
use crate::Rule;
pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed {
pairs.next();
}
consumed
}
pub fn consume_rule<'a>(
pairs: &mut pest::iterators::Pairs<'a, Rule>,
rule: Rule,
) -> Option<pest::iterators::Pair<'a, Rule>> {
let consumed = pairs
.peek()
.map(|p| p.as_rule() == rule)
.unwrap_or_default();
if consumed { pairs.next() } else { None }
}
+7 -5
View File
@@ -312,8 +312,10 @@ impl ToRust for TopLevelKind {
fn to_rust(&self, cg: &mut RustCodegen) { fn to_rust(&self, cg: &mut RustCodegen) {
match self { match self {
Self::ModAttribute => {} Self::ModAttribute => {}
Self::Import(path) => cg.addln(&format!("use {};", path.get_rust())), Self::Import(vis, path) => {
Self::Mod(id) => cg.addln(&format!("mod {};", id.get_rust())), cg.addln(&format!("{} use {};", vis.get_rust(), path.get_rust()))
}
Self::Mod(vis, id) => cg.addln(&format!("{} mod {};", vis.get_rust(), id.get_rust())),
Self::FunctionDecl(decl) => decl.to_rust(cg), Self::FunctionDecl(decl) => decl.to_rust(cg),
Self::ImplDecl(impl_) => impl_.to_rust(cg), Self::ImplDecl(impl_) => impl_.to_rust(cg),
Self::StructDecl { Self::StructDecl {
@@ -739,10 +741,10 @@ impl GetRust for TypePostfix {
impl GetRust for Visibility { impl GetRust for Visibility {
fn get_rust(&self) -> String { fn get_rust(&self) -> String {
match self { match self {
Visibility::Public => "pub ", Visibility::Public => "pub ".to_string(),
Visibility::Private => "", Visibility::PublicTarget(path) => format!("pub({}) ", path.get_rust()),
Visibility::Private => "".to_string(),
} }
.to_string()
} }
} }
+20 -1
View File
@@ -5,6 +5,7 @@ use std::{
time::Instant, time::Instant,
}; };
use mist_parser::error::ParseError;
use serde::Deserialize; use serde::Deserialize;
#[derive(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| e.to_string()); 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 { let ast = match parser_result {
Ok(ast) => ast, Ok(ast) => ast,
+16 -12
View File
@@ -1,4 +1,4 @@
use std::process; use std::process::{self, Command};
pub mod codegen; pub mod codegen;
pub mod compiler; pub mod compiler;
@@ -12,13 +12,11 @@ fn main() {
} }
match args[1].as_str() { match args[1].as_str() {
"build" => { "run" | "build" | "r" | "b" => {
if args.len() < 2 {
eprintln!("error: expected a file path\n usage: mist build");
process::exit(1);
}
compiler::build(); compiler::build();
Command::new("cargo").args(&args[1..]).status().unwrap();
} }
"transpile" | "t" => compiler::build(),
"version" | "--version" | "-v" => { "version" | "--version" | "-v" => {
println!("mist {}", env!("CARGO_PKG_VERSION")); println!("mist {}", env!("CARGO_PKG_VERSION"));
} }
@@ -34,11 +32,17 @@ fn main() {
} }
fn print_usage() { fn print_usage() {
println!("mist - the mist compiler"); println!("Mist - the mist compiler\n");
println!(); println!("󰖟 View our documentation! \x1b[35mhttps://mist.selimaj.dev\x1b[0m");
println!(" Follow us on github! \x1b[35mhttps://github.com/mist-go\x1b[0m\n");
println!("usage:"); println!("usage:");
println!(" mist build compile the project in the current directory"); println!(" \x1b[36m mist run\x1b[0m run the project in the current directory\n");
println!(" mist check <file.ms> parse and validate without compiling"); println!(
println!(" mist version print the compiler version"); " \x1b[36m mist build\x1b[0m build the project in the current directory\n"
println!(" mist help print this message"); );
println!(
" \x1b[36m mist transpile\x1b[0m transpile the project in the current directory\n"
);
println!(" \x1b[36m mist version \x1b[0m print the compiler version\n");
println!(" \x1b[36m mist help\x1b[0m print this message\n");
} }