mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
add loop syntax, remove loop function, change CLI
This commit is contained in:
parent
66c191ba2c
commit
f3f2c13702
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mers"
|
name = "mers"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "dynamically typed but type-checked programming language"
|
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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mers_lib = "0.5.0"
|
mers_lib = "0.6.0"
|
||||||
# mers_lib = { path = "../mers_lib" }
|
# mers_lib = { path = "../mers_lib" }
|
||||||
clap = { version = "4.3.19", features = ["derive"] }
|
clap = { version = "4.3.19", features = ["derive"] }
|
||||||
|
160
mers/src/main.rs
160
mers/src/main.rs
@ -1,6 +1,6 @@
|
|||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
use mers_lib::prelude_compile::*;
|
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;
|
mod cfg_globals;
|
||||||
|
|
||||||
@ -11,38 +11,36 @@ struct Args {
|
|||||||
/// controls availability of features when compiling/running
|
/// controls availability of features when compiling/running
|
||||||
#[arg(long, value_enum, default_value_t = Configs::Std)]
|
#[arg(long, value_enum, default_value_t = Configs::Std)]
|
||||||
config: Configs,
|
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
|
/// in error messages, hide comments and only show actual code
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
hide_comments: bool,
|
hide_comments: bool,
|
||||||
}
|
}
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Command {
|
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
|
/// runs the file
|
||||||
Run { file: PathBuf },
|
File { file: PathBuf },
|
||||||
/// runs cli argument
|
/// runs cli argument
|
||||||
Exec { source: String },
|
Arg { 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",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||||
enum Configs {
|
enum Configs {
|
||||||
@ -50,15 +48,6 @@ enum Configs {
|
|||||||
Base,
|
Base,
|
||||||
Std,
|
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() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
@ -67,52 +56,93 @@ fn main() {
|
|||||||
Configs::Base => Config::new().bundle_base(),
|
Configs::Base => Config::new().bundle_base(),
|
||||||
Configs::Std => Config::new().bundle_std(),
|
Configs::Std => Config::new().bundle_std(),
|
||||||
});
|
});
|
||||||
let (mut info_parsed, mut info_run, mut info_check) = config.infos();
|
fn get_source(source: From) -> Source {
|
||||||
let mut source = match args.command {
|
match source {
|
||||||
Command::Run { file } => match Source::new_from_file(PathBuf::from(&file)) {
|
From::File { file } => match Source::new_from_file(PathBuf::from(&file)) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Can't read file {file:?}: {e}");
|
eprintln!("Can't read file {file:?}: {e}");
|
||||||
exit(10);
|
exit(10);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Command::Exec { source } => Source::new_from_string(source),
|
From::Arg { source } => Source::new_from_string(source),
|
||||||
};
|
}
|
||||||
let srca = Arc::new(source.clone());
|
}
|
||||||
let parsed = match parse(&mut source, &srca) {
|
match args.command {
|
||||||
Ok(v) => v,
|
Command::Check { source } => {
|
||||||
|
let mut src = get_source(source);
|
||||||
|
let srca = Arc::new(src.clone());
|
||||||
|
match parse(&mut src, &srca) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}", e.display().show_comments(!args.hide_comments));
|
eprintln!("{e}");
|
||||||
exit(20);
|
exit(20);
|
||||||
}
|
}
|
||||||
};
|
Ok(parsed) => {
|
||||||
#[cfg(debug_assertions)]
|
let (mut i1, _, mut i3) = config.infos();
|
||||||
dbg!(&parsed);
|
match parsed.compile(&mut i1, CompInfo::default()) {
|
||||||
let run = match parsed.compile(&mut info_parsed, Default::default()) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}", e.display().show_comments(!args.hide_comments));
|
eprintln!("{e}");
|
||||||
exit(24);
|
exit(24);
|
||||||
}
|
}
|
||||||
};
|
Ok(compiled) => match compiled.check(&mut i3, None) {
|
||||||
#[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,
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprint!("{}", e.display().show_comments(!args.hide_comments));
|
eprintln!("{e}");
|
||||||
exit(28);
|
exit(28);
|
||||||
}
|
}
|
||||||
};
|
Ok(output_type) => eprintln!("{output_type}"),
|
||||||
if args.check == Check::Yes {
|
},
|
||||||
run.run(&mut info_run);
|
}
|
||||||
} else {
|
}
|
||||||
eprintln!("return type is {}", return_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mers_lib"
|
name = "mers_lib"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "library to use the mers language in other projects"
|
description = "library to use the mers language in other projects"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use mers_lib::{
|
use mers_lib::{
|
||||||
data::{self, Data, MersType, Type},
|
data::{self, Data, Type},
|
||||||
errors::CheckError,
|
errors::CheckError,
|
||||||
prelude_compile::{parse, CompInfo, Config, Source},
|
prelude_compile::{parse, CompInfo, Config, Source},
|
||||||
};
|
};
|
||||||
|
@ -440,6 +440,23 @@ pub fn parse_no_chain(
|
|||||||
on_false,
|
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 {
|
"true" => Box::new(program::parsed::value::Value {
|
||||||
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||||
data: Data::new(crate::data::bool::Bool(true)),
|
data: Data::new(crate::data::bool::Bool(true)),
|
||||||
|
@ -137,55 +137,6 @@ impl Config {
|
|||||||
}),
|
}),
|
||||||
inner_statements: None,
|
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::<data::tuple::TupleT>() {
|
|
||||||
if let Some(t) = t.0.get(1) {
|
|
||||||
t.types.iter().collect::<Vec<_>>()
|
|
||||||
} else { [v].into_iter().collect() }
|
|
||||||
} else { [v].into_iter().collect() }) {
|
|
||||||
if let Some(t) = t.as_any().downcast_ref::<data::function::FunctionT>() {
|
|
||||||
for t in t.o(&Type::empty_tuple())?.types {
|
|
||||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
|
||||||
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::<data::function::Function>() {
|
|
||||||
function
|
|
||||||
} else if let Some(r) = a.as_any().downcast_ref::<data::tuple::Tuple>() {
|
|
||||||
delay_drop = r.0[1].get();
|
|
||||||
delay_drop.as_any().downcast_ref::<data::function::Function>().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(
|
.add_var(
|
||||||
"eq".to_string(),
|
"eq".to_string(),
|
||||||
|
@ -28,6 +28,8 @@ pub mod include_mers;
|
|||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod init_to;
|
pub mod init_to;
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
|
pub mod r#loop;
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
pub mod object;
|
pub mod object;
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod tuple;
|
pub mod tuple;
|
||||||
|
@ -25,6 +25,8 @@ pub mod function;
|
|||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
pub mod r#if;
|
pub mod r#if;
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
|
pub mod r#loop;
|
||||||
|
#[cfg(feature = "run")]
|
||||||
pub mod object;
|
pub mod object;
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
pub mod tuple;
|
pub mod tuple;
|
||||||
|
Loading…
Reference in New Issue
Block a user