From 07745488b3bd6240056f9e888c903bdeb511c299 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 28 Jul 2023 15:20:02 +0200 Subject: [PATCH] sorted mers_lib/src/program/configs/ and added cargo features --- mers/Cargo.toml | 2 +- mers/src/cfg_globals.rs | 8 ++ mers/src/main.rs | 12 +- mers/test.mers | 12 ++ mers_lib/Cargo.toml | 6 + mers_lib/src/lib.rs | 18 +++ mers_lib/src/program/configs/mod.rs | 147 ++------------------ mers_lib/src/program/configs/with_get.rs | 41 ++++++ mers_lib/src/program/configs/with_iters.rs | 19 +++ mers_lib/src/program/configs/with_math.rs | 45 ++++++ mers_lib/src/program/configs/with_prints.rs | 73 ++++++++++ mers_lib/src/program/mod.rs | 3 + mers_lib/src/program/parsed/mod.rs | 11 ++ mers_lib/src/program/run/mod.rs | 10 ++ 14 files changed, 267 insertions(+), 140 deletions(-) create mode 100644 mers/src/cfg_globals.rs create mode 100644 mers_lib/src/program/configs/with_get.rs create mode 100644 mers_lib/src/program/configs/with_math.rs create mode 100644 mers_lib/src/program/configs/with_prints.rs diff --git a/mers/Cargo.toml b/mers/Cargo.toml index f0673a3..c0bca25 100755 --- a/mers/Cargo.toml +++ b/mers/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -mers_lib = { path = "../mers_lib" } +mers_lib = { path = "../mers_lib", features = ["parse"] } clap = { version = "4.3.19", features = ["derive"] } diff --git a/mers/src/cfg_globals.rs b/mers/src/cfg_globals.rs new file mode 100644 index 0000000..4764de4 --- /dev/null +++ b/mers/src/cfg_globals.rs @@ -0,0 +1,8 @@ +use mers_lib::{ + data::{self, Data}, + prelude_extend_config::*, +}; + +pub fn add_general(cfg: Config) -> Config { + cfg.add_var("mers_cli".to_string(), Data::new(data::bool::Bool(true))) +} diff --git a/mers/src/main.rs b/mers/src/main.rs index fb073d7..f8ffe6e 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -2,8 +2,11 @@ use clap::{Parser, Subcommand, ValueEnum}; use mers_lib::prelude_compile::*; use std::{fmt::Display, fs, path::PathBuf}; +mod cfg_globals; + #[derive(Parser)] struct Args { + /// controls availability of features when compiling/running #[arg(long, value_enum, default_value_t = Configs::Std)] config: Configs, #[command(subcommand)] @@ -11,18 +14,22 @@ struct Args { } #[derive(Subcommand)] enum Command { + /// runs the file Run { file: PathBuf }, + /// runs cli argument Exec { source: String }, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] enum Configs { None, + 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"), } } @@ -30,10 +37,11 @@ impl Display for Configs { fn main() { let args = Args::parse(); - let config = match args.config { + let config = cfg_globals::add_general(match args.config { Configs::None => Config::new(), + Configs::Base => Config::new().bundle_base(), Configs::Std => Config::new().bundle_std(), - }; + }); let (mut info1, mut info2) = config.infos(); match args.command { Command::Run { file } => { diff --git a/mers/test.mers b/mers/test.mers index 1af4528..2d6e08c 100755 --- a/mers/test.mers +++ b/mers/test.mers @@ -9,7 +9,19 @@ list := ( 8, 9, ); + +total := 0 +(list item -> &total = (total, item).sum).iter +"total: ".print +total.println +"sum: ".print +list.sum.println iter := (list item -> { item.println 12 }).map "---".println list := iter.as_list list.println +list.sum.println +list.enumerate.as_list.println + +"mers cli: ".print +mers_cli.println diff --git a/mers_lib/Cargo.toml b/mers_lib/Cargo.toml index 60d5552..abe6218 100755 --- a/mers_lib/Cargo.toml +++ b/mers_lib/Cargo.toml @@ -2,3 +2,9 @@ name = "mers_lib" version = "0.3.0" edition = "2021" + + +[features] +default = [] +parse = ["run"] +run = [] diff --git a/mers_lib/src/lib.rs b/mers_lib/src/lib.rs index a496ab7..0a09e88 100755 --- a/mers_lib/src/lib.rs +++ b/mers_lib/src/lib.rs @@ -1,8 +1,13 @@ +/// data and types in mers pub mod data; +/// shared code handling scopes to guarantee that compiler and runtime scopes match pub mod info; +/// parser implementation. +#[cfg(feature = "parse")] pub mod parsing; pub mod program; +#[cfg(feature = "parse")] pub mod prelude_compile { pub use crate::parsing::parse; pub use crate::parsing::Source; @@ -10,3 +15,16 @@ pub mod prelude_compile { pub use crate::program::parsed::MersStatement as ParsedMersStatement; pub use crate::program::run::MersStatement as RunMersStatement; } + +/// can be used to extend the mers config. +/// with this, you can add values (usually functions), +/// or add your own types to the language: +/// +/// fn add_thing(cfg: Config) -> Config { +/// /// use the methods on Config to add things (see the Config source code for examples) +/// } +/// +/// then use the Config when compiling and running your code, and your customizations will be available. +pub mod prelude_extend_config { + pub use crate::program::configs::Config; +} diff --git a/mers_lib/src/program/configs/mod.rs b/mers_lib/src/program/configs/mod.rs index 5f1a7ff..dd899a6 100755 --- a/mers_lib/src/program/configs/mod.rs +++ b/mers_lib/src/program/configs/mod.rs @@ -7,8 +7,11 @@ use crate::{ }; mod with_command_running; +mod with_get; mod with_iters; mod with_list; +mod with_math; +mod with_prints; /// Usage: create an empty Config using Config::new(), use the methods to customize it, then get the Infos using Config::infos() /// bundle_* for bundles (combines multiple groups or even bundles) @@ -27,14 +30,6 @@ pub struct Config { } impl Config { - pub fn new() -> Self { - Self { - globals: 0, - info_parsed: Default::default(), - info_run: Default::default(), - } - } - /// standard utilitis used in many programs /// `bundle_base()` /// `with_list()` @@ -51,134 +46,12 @@ impl Config { self.with_iters().with_get().with_math().with_prints() } - /// `println: fn` prints to stdout and adds a newline to the end - /// `print: fn` prints to stdout - /// `eprintln: fn` prints to stderr and adds a newline to the end - /// `eprint: fn` prints to stderr - /// `debug: fn` debug-prints any value - pub fn with_prints(self) -> Self { - self.add_var( - "debug".to_string(), - Data::new(data::function::Function { - info: program::run::Info::neverused(), - out: Arc::new(|_a| todo!()), - run: Arc::new(|a, _i| { - eprintln!("{:#?}", a.get()); - Data::empty_tuple() - }), - }), - ) - .add_var( - "eprint".to_string(), - Data::new(data::function::Function { - info: program::run::Info::neverused(), - out: Arc::new(|_a| todo!()), - run: Arc::new(|a, _i| { - eprint!("{}", a.get()); - Data::empty_tuple() - }), - }), - ) - .add_var( - "eprintln".to_string(), - Data::new(data::function::Function { - info: program::run::Info::neverused(), - out: Arc::new(|_a| todo!()), - run: Arc::new(|a, _i| { - eprintln!("{}", a.get()); - Data::empty_tuple() - }), - }), - ) - .add_var( - "print".to_string(), - Data::new(data::function::Function { - info: program::run::Info::neverused(), - out: Arc::new(|_a| todo!()), - run: Arc::new(|a, _i| { - print!("{}", a.get()); - Data::empty_tuple() - }), - }), - ) - .add_var( - "println".to_string(), - Data::new(data::function::Function { - info: program::run::Info::neverused(), - out: Arc::new(|_a| todo!()), - run: Arc::new(|a, _i| { - println!("{}", a.get()); - Data::empty_tuple() - }), - }), - ) - } - /// `sum: fn` returns the sum of all the numbers in the tuple - pub fn with_math(self) -> Self { - self.add_var( - "sum".to_string(), - Data::new(data::function::Function { - info: program::run::Info::neverused(), - out: Arc::new(|_a| todo!()), - run: Arc::new(|a, _i| { - if let Some(tuple) = a.get().as_any().downcast_ref::() { - let mut sumi = 0; - let mut sumf = 0.0; - let mut usef = false; - for val in &tuple.0 { - if let Some(i) = val.get().as_any().downcast_ref::() { - sumi += i.0; - } else if let Some(i) = - val.get().as_any().downcast_ref::() - { - sumf += i.0; - usef = true; - } - } - if usef { - Data::new(data::float::Float(sumi as f64 + sumf)) - } else { - Data::new(data::int::Int(sumi)) - } - } else { - unreachable!("sum called on non-tuple") - } - }), - }), - ) - } - /// `get: fn` is used to retrieve elements from collections - pub fn with_get(self) -> Self { - self.add_var( - "get".to_string(), - Data::new(data::function::Function { - info: program::run::Info::neverused(), - out: Arc::new(|_a| todo!()), - run: Arc::new(|a, _i| { - if let Some(tuple) = a.get().as_any().downcast_ref::() { - if let (Some(v), Some(i)) = (tuple.get(0), tuple.get(1)) { - if let Some(i) = i.get().as_any().downcast_ref::() { - if let Ok(i) = i.0.try_into() { - if let Some(v) = v.get().get(i) { - Data::one_tuple(v) - } else { - Data::empty_tuple() - } - } else { - Data::empty_tuple() - } - } else { - unreachable!("get called with non-int index") - } - } else { - unreachable!("get called on tuple with len < 2") - } - } else { - unreachable!("get called on non-tuple, arg must be (_, index)") - } - }), - }), - ) + pub fn new() -> Self { + Self { + globals: 0, + info_parsed: Default::default(), + info_run: Default::default(), + } } pub fn add_var(mut self, name: String, val: Data) -> Self { @@ -187,7 +60,7 @@ impl Config { self.globals += 1; self } - pub fn add_type(mut self, name: String, t: Type) -> Self { + pub fn add_type(self, _name: String, _t: Type) -> Self { // TODO! needed for type syntax in the parser, everything else probably(?) works already self } diff --git a/mers_lib/src/program/configs/with_get.rs b/mers_lib/src/program/configs/with_get.rs new file mode 100644 index 0000000..a6268d7 --- /dev/null +++ b/mers_lib/src/program/configs/with_get.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; + +use crate::{ + data::{self, Data}, + program, +}; + +use super::Config; + +impl Config { + /// `get: fn` is used to retrieve elements from collections + pub fn with_get(self) -> Self { + self.add_var( + "get".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| { + let a = a.get(); + if let (Some(v), Some(i)) = (a.get(0), a.get(1)) { + if let Some(i) = i.get().as_any().downcast_ref::() { + if let Ok(i) = i.0.try_into() { + if let Some(v) = v.get().get(i) { + Data::one_tuple(v) + } else { + Data::empty_tuple() + } + } else { + Data::empty_tuple() + } + } else { + unreachable!("get called with non-int index") + } + } else { + unreachable!("get called with less than 2 args") + } + }), + }), + ) + } +} diff --git a/mers_lib/src/program/configs/with_iters.rs b/mers_lib/src/program/configs/with_iters.rs index f04daa4..e5467fa 100755 --- a/mers_lib/src/program/configs/with_iters.rs +++ b/mers_lib/src/program/configs/with_iters.rs @@ -10,6 +10,10 @@ use super::Config; impl Config { /// Adds functions to deal with iterables /// `iter: fn` executes a function once for each element of the iterable + /// `map: fn` maps each value in the iterable to a new one by applying a transformation function + /// `filter: fn` filters the iterable by removing all elements where the filter function doesn't return true + /// `filter_map: fn` combines filter and map via matching + /// `enumerate: fn` transforms an iterator over T into one over (Int, T), where Int is the index of the element pub fn with_iters(self) -> Self { self.add_var( "iter".to_string(), @@ -113,6 +117,14 @@ impl Config { }), }), ) + .add_var( + "enumerate".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| Data::new(Iter(Iters::Enumerate, a.clone()))), + }), + ) } } @@ -121,6 +133,7 @@ pub enum Iters { Map(data::function::Function), Filter(data::function::Function), FilterMap(data::function::Function), + Enumerate, } #[derive(Clone, Debug)] pub struct Iter(Iters, Data); @@ -152,6 +165,12 @@ impl MersData for Iter { .filter_map(move |v| f.run(v).get().matches()), ) } + Iters::Enumerate => Box::new(self.1.get().iterable()?.enumerate().map(|(i, v)| { + Data::new(data::tuple::Tuple(vec![ + Data::new(data::int::Int(i as _)), + v, + ])) + })), _ => todo!(), }) } diff --git a/mers_lib/src/program/configs/with_math.rs b/mers_lib/src/program/configs/with_math.rs new file mode 100644 index 0000000..22ef591 --- /dev/null +++ b/mers_lib/src/program/configs/with_math.rs @@ -0,0 +1,45 @@ +use std::sync::Arc; + +use crate::{ + data::{self, Data}, + program, +}; + +use super::Config; + +impl Config { + /// `sum: fn` returns the sum of all the numbers in the tuple + pub fn with_math(self) -> Self { + self.add_var( + "sum".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| { + if let Some(i) = a.get().iterable() { + let mut sumi = 0; + let mut sumf = 0.0; + let mut usef = false; + for val in i { + if let Some(i) = val.get().as_any().downcast_ref::() { + sumi += i.0; + } else if let Some(i) = + val.get().as_any().downcast_ref::() + { + sumf += i.0; + usef = true; + } + } + if usef { + Data::new(data::float::Float(sumi as f64 + sumf)) + } else { + Data::new(data::int::Int(sumi)) + } + } else { + unreachable!("sum called on non-tuple") + } + }), + }), + ) + } +} diff --git a/mers_lib/src/program/configs/with_prints.rs b/mers_lib/src/program/configs/with_prints.rs new file mode 100644 index 0000000..f227c14 --- /dev/null +++ b/mers_lib/src/program/configs/with_prints.rs @@ -0,0 +1,73 @@ +use std::sync::Arc; + +use crate::{ + data::{self, Data}, + program, +}; + +use super::Config; + +impl Config { + /// `println: fn` prints to stdout and adds a newline to the end + /// `print: fn` prints to stdout + /// `eprintln: fn` prints to stderr and adds a newline to the end + /// `eprint: fn` prints to stderr + /// `debug: fn` debug-prints any value + pub fn with_prints(self) -> Self { + self.add_var( + "debug".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| { + eprintln!("{:#?}", a.get()); + Data::empty_tuple() + }), + }), + ) + .add_var( + "eprint".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| { + eprint!("{}", a.get()); + Data::empty_tuple() + }), + }), + ) + .add_var( + "eprintln".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| { + eprintln!("{}", a.get()); + Data::empty_tuple() + }), + }), + ) + .add_var( + "print".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| { + print!("{}", a.get()); + Data::empty_tuple() + }), + }), + ) + .add_var( + "println".to_string(), + Data::new(data::function::Function { + info: program::run::Info::neverused(), + out: Arc::new(|_a| todo!()), + run: Arc::new(|a, _i| { + println!("{}", a.get()); + Data::empty_tuple() + }), + }), + ) + } +} diff --git a/mers_lib/src/program/mod.rs b/mers_lib/src/program/mod.rs index 63801d1..5ee4040 100755 --- a/mers_lib/src/program/mod.rs +++ b/mers_lib/src/program/mod.rs @@ -1,3 +1,6 @@ +/// generates `Info`s required to compile and then run a program pub mod configs; +/// used to represent a parsed program pub mod parsed; +/// used to represent an executable program pub mod run; diff --git a/mers_lib/src/program/parsed/mod.rs b/mers_lib/src/program/parsed/mod.rs index fe9ded7..44948d0 100755 --- a/mers_lib/src/program/parsed/mod.rs +++ b/mers_lib/src/program/parsed/mod.rs @@ -2,16 +2,27 @@ use std::{collections::HashMap, fmt::Debug}; use crate::info; +#[cfg(feature = "parse")] pub mod assign_to; +#[cfg(feature = "parse")] pub mod block; +#[cfg(feature = "parse")] pub mod chain; +#[cfg(feature = "parse")] pub mod function; +#[cfg(feature = "parse")] pub mod r#if; +#[cfg(feature = "parse")] pub mod init_to; +#[cfg(feature = "parse")] pub mod r#loop; +#[cfg(feature = "parse")] pub mod switch; +#[cfg(feature = "parse")] pub mod tuple; +#[cfg(feature = "parse")] pub mod value; +#[cfg(feature = "parse")] pub mod variable; pub trait MersStatement: Debug { diff --git a/mers_lib/src/program/run/mod.rs b/mers_lib/src/program/run/mod.rs index 52cc226..3f53659 100755 --- a/mers_lib/src/program/run/mod.rs +++ b/mers_lib/src/program/run/mod.rs @@ -5,15 +5,25 @@ use crate::{ info, }; +#[cfg(feature = "run")] pub mod assign_to; +#[cfg(feature = "run")] pub mod block; +#[cfg(feature = "run")] pub mod chain; +#[cfg(feature = "run")] pub mod function; +#[cfg(feature = "run")] pub mod r#if; +#[cfg(feature = "run")] pub mod r#loop; +#[cfg(feature = "run")] pub mod switch; +#[cfg(feature = "run")] pub mod tuple; +#[cfg(feature = "run")] pub mod value; +#[cfg(feature = "run")] pub mod variable; pub trait MersStatement: std::fmt::Debug {