From f3f2c13702775d8c4eb93dcaec12fe8413092cff Mon Sep 17 00:00:00 2001 From: Mark <> Date: Thu, 22 Feb 2024 13:34:02 +0100 Subject: [PATCH] add loop syntax, remove loop function, change CLI --- mers/Cargo.toml | 4 +- mers/src/main.rs | 186 +++++++++++++--------- mers_lib/Cargo.toml | 2 +- mers_lib/examples/01_user_scripts.rs | 2 +- mers_lib/src/parsing/statements.rs | 17 ++ mers_lib/src/program/configs/with_base.rs | 49 ------ mers_lib/src/program/parsed/mod.rs | 2 + mers_lib/src/program/run/mod.rs | 2 + 8 files changed, 133 insertions(+), 131 deletions(-) diff --git a/mers/Cargo.toml b/mers/Cargo.toml index 1413b15..c7ba5a7 100755 --- a/mers/Cargo.toml +++ b/mers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers" -version = "0.5.0" +version = "0.6.0" edition = "2021" license = "MIT OR Apache-2.0" description = "dynamically typed but type-checked programming language" @@ -11,6 +11,6 @@ repository = "https://github.com/Dummi26/mers" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -mers_lib = "0.5.0" +mers_lib = "0.6.0" # mers_lib = { path = "../mers_lib" } clap = { version = "4.3.19", features = ["derive"] } diff --git a/mers/src/main.rs b/mers/src/main.rs index 3d68649..7251e59 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -1,6 +1,6 @@ use clap::{Parser, Subcommand, ValueEnum}; use mers_lib::prelude_compile::*; -use std::{fmt::Display, path::PathBuf, process::exit, sync::Arc}; +use std::{path::PathBuf, process::exit, sync::Arc}; mod cfg_globals; @@ -11,38 +11,36 @@ struct Args { /// controls availability of features when compiling/running #[arg(long, value_enum, default_value_t = Configs::Std)] config: Configs, - /// perform checks to avoid runtime crashes - #[arg(long, default_value_t = Check::Yes)] - check: Check, /// in error messages, hide comments and only show actual code #[arg(long)] hide_comments: bool, } #[derive(Subcommand)] enum Command { + /// Check if code is valid. If yes, print output type. + /// + /// Exit status is 20 for parse errors, 24 for compile errors and 28 for check errors (type errors). + Check { + #[command(subcommand)] + source: From, + }, + /// Check and then run code. Exit status is 255 if checks fail. + Run { + #[command(subcommand)] + source: From, + }, + /// Run code, but skip type-checks. Will panic at runtime if code is not valid. + RunUnchecked { + #[command(subcommand)] + source: From, + }, +} +#[derive(Subcommand, Clone)] +enum From { /// runs the file - Run { file: PathBuf }, + File { file: PathBuf }, /// runs cli argument - Exec { source: String }, -} -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -enum Check { - No, - Yes, - Only, -} -impl Display for Check { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self { - Self::No => "no", - Self::Yes => "yes", - Self::Only => "only", - } - ) - } + Arg { source: String }, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] enum Configs { @@ -50,15 +48,6 @@ enum Configs { Base, Std, } -impl Display for Configs { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::None => write!(f, "none"), - Self::Base => write!(f, "base"), - Self::Std => write!(f, "std"), - } - } -} fn main() { let args = Args::parse(); @@ -67,52 +56,93 @@ fn main() { Configs::Base => Config::new().bundle_base(), Configs::Std => Config::new().bundle_std(), }); - let (mut info_parsed, mut info_run, mut info_check) = config.infos(); - let mut source = match args.command { - Command::Run { file } => match Source::new_from_file(PathBuf::from(&file)) { - Ok(s) => s, - Err(e) => { - eprintln!("Can't read file {file:?}: {e}"); - exit(10); - } - }, - Command::Exec { source } => Source::new_from_string(source), - }; - let srca = Arc::new(source.clone()); - let parsed = match parse(&mut source, &srca) { - Ok(v) => v, - Err(e) => { - eprintln!("{}", e.display().show_comments(!args.hide_comments)); - exit(20); - } - }; - #[cfg(debug_assertions)] - dbg!(&parsed); - let run = match parsed.compile(&mut info_parsed, Default::default()) { - Ok(v) => v, - Err(e) => { - eprintln!("{}", e.display().show_comments(!args.hide_comments)); - exit(24); - } - }; - #[cfg(debug_assertions)] - dbg!(&run); - match args.check { - Check::No => { - run.run(&mut info_run); - } - Check::Yes | Check::Only => { - let return_type = match run.check(&mut info_check, None) { - Ok(v) => v, + fn get_source(source: From) -> Source { + match source { + From::File { file } => match Source::new_from_file(PathBuf::from(&file)) { + Ok(s) => s, Err(e) => { - eprint!("{}", e.display().show_comments(!args.hide_comments)); - exit(28); + eprintln!("Can't read file {file:?}: {e}"); + exit(10); + } + }, + From::Arg { source } => Source::new_from_string(source), + } + } + match args.command { + Command::Check { source } => { + let mut src = get_source(source); + let srca = Arc::new(src.clone()); + match parse(&mut src, &srca) { + Err(e) => { + eprintln!("{e}"); + exit(20); + } + Ok(parsed) => { + let (mut i1, _, mut i3) = config.infos(); + match parsed.compile(&mut i1, CompInfo::default()) { + Err(e) => { + eprintln!("{e}"); + exit(24); + } + Ok(compiled) => match compiled.check(&mut i3, None) { + Err(e) => { + eprintln!("{e}"); + exit(28); + } + Ok(output_type) => eprintln!("{output_type}"), + }, + } + } + } + } + Command::Run { source } => { + let mut src = get_source(source); + let srca = Arc::new(src.clone()); + match parse(&mut src, &srca) { + Err(e) => { + eprintln!("{e}"); + exit(255); + } + Ok(parsed) => { + let (mut i1, mut i2, mut i3) = config.infos(); + match parsed.compile(&mut i1, CompInfo::default()) { + Err(e) => { + eprintln!("{e}"); + exit(255); + } + Ok(compiled) => match compiled.check(&mut i3, None) { + Err(e) => { + eprintln!("{e}"); + exit(255); + } + Ok(_) => { + compiled.run(&mut i2); + } + }, + } + } + } + } + Command::RunUnchecked { source } => { + let mut src = get_source(source); + let srca = Arc::new(src.clone()); + match parse(&mut src, &srca) { + Err(e) => { + eprintln!("{e}"); + exit(255); + } + Ok(parsed) => { + let (mut i1, mut i2, _) = config.infos(); + match parsed.compile(&mut i1, CompInfo::default()) { + Err(e) => { + eprintln!("{e}"); + exit(255); + } + Ok(compiled) => { + compiled.run(&mut i2); + } + } } - }; - if args.check == Check::Yes { - run.run(&mut info_run); - } else { - eprintln!("return type is {}", return_type) } } } diff --git a/mers_lib/Cargo.toml b/mers_lib/Cargo.toml index a229cf2..d291727 100755 --- a/mers_lib/Cargo.toml +++ b/mers_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers_lib" -version = "0.5.0" +version = "0.6.0" edition = "2021" license = "MIT OR Apache-2.0" description = "library to use the mers language in other projects" diff --git a/mers_lib/examples/01_user_scripts.rs b/mers_lib/examples/01_user_scripts.rs index b32f040..a920dde 100644 --- a/mers_lib/examples/01_user_scripts.rs +++ b/mers_lib/examples/01_user_scripts.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use mers_lib::{ - data::{self, Data, MersType, Type}, + data::{self, Data, Type}, errors::CheckError, prelude_compile::{parse, CompInfo, Config, Source}, }; diff --git a/mers_lib/src/parsing/statements.rs b/mers_lib/src/parsing/statements.rs index 8ad7cfe..2326a89 100755 --- a/mers_lib/src/parsing/statements.rs +++ b/mers_lib/src/parsing/statements.rs @@ -440,6 +440,23 @@ pub fn parse_no_chain( on_false, }) } + "loop" => { + src.section_begin("loop".to_string()); + src.skip_whitespace(); + let inner = match parse(src, srca) { + Ok(Some(v)) => v, + Ok(None) => { + return Err(CheckError::new() + .src(vec![((pos_in_src, src.get_pos(), srca).into(), None)]) + .msg(format!("EOF after `loop`"))) + } + Err(e) => return Err(e), + }; + Box::new(program::parsed::r#loop::Loop { + pos_in_src: (pos_in_src, src.get_pos(), srca).into(), + inner, + }) + } "true" => Box::new(program::parsed::value::Value { pos_in_src: (pos_in_src, src.get_pos(), srca).into(), data: Data::new(crate::data::bool::Bool(true)), diff --git a/mers_lib/src/program/configs/with_base.rs b/mers_lib/src/program/configs/with_base.rs index 20ad7b3..abab867 100755 --- a/mers_lib/src/program/configs/with_base.rs +++ b/mers_lib/src/program/configs/with_base.rs @@ -137,55 +137,6 @@ impl Config { }), inner_statements: None, }), - ).add_var( - "loop".to_string(), - Data::new(data::function::Function { - info: Arc::new(Info::neverused()), - info_check: Arc::new(Mutex::new(CheckInfo::neverused())), - out: Arc::new(|a, _i| { - let mut o = Type::empty(); - for t in a.types.iter().flat_map(|v| if let Some(t) = v.as_any().downcast_ref::() { - if let Some(t) = t.0.get(1) { - t.types.iter().collect::>() - } else { [v].into_iter().collect() } - } else { [v].into_iter().collect() }) { - if let Some(t) = t.as_any().downcast_ref::() { - for t in t.o(&Type::empty_tuple())?.types { - if let Some(t) = t.as_any().downcast_ref::() { - if t.0.len() > 1 { - return Err(format!("called loop with funcion that might return a tuple of length > 1").into()); - } else if let Some(v) = t.0.first() { - o.add(Arc::new(v.clone())) - } - } else { - return Err(format!("called loop with funcion that might return something other than a tuple").into()); - } - } - } else { - return Err(format!("called loop on a non-function").into()); - } - } - Ok(o) - }), - run: Arc::new(|a, _i| { - let a = a.get(); - let delay_drop; - let function = if let Some(function) = a.as_any().downcast_ref::() { - function - } else if let Some(r) = a.as_any().downcast_ref::() { - delay_drop = r.0[1].get(); - delay_drop.as_any().downcast_ref::().unwrap() - } else { - unreachable!("called loop on non-function") - }; - loop { - if let Some(r) = function.run(Data::empty_tuple()).one_tuple_content() { - break r; - } - } - }), - inner_statements: None, - }), ) .add_var( "eq".to_string(), diff --git a/mers_lib/src/program/parsed/mod.rs b/mers_lib/src/program/parsed/mod.rs index 56630f1..46f4530 100755 --- a/mers_lib/src/program/parsed/mod.rs +++ b/mers_lib/src/program/parsed/mod.rs @@ -28,6 +28,8 @@ pub mod include_mers; #[cfg(feature = "parse")] pub mod init_to; #[cfg(feature = "parse")] +pub mod r#loop; +#[cfg(feature = "parse")] pub mod object; #[cfg(feature = "parse")] pub mod tuple; diff --git a/mers_lib/src/program/run/mod.rs b/mers_lib/src/program/run/mod.rs index bf08c11..1483883 100755 --- a/mers_lib/src/program/run/mod.rs +++ b/mers_lib/src/program/run/mod.rs @@ -25,6 +25,8 @@ pub mod function; #[cfg(feature = "run")] pub mod r#if; #[cfg(feature = "run")] +pub mod r#loop; +#[cfg(feature = "run")] pub mod object; #[cfg(feature = "run")] pub mod tuple;