From 794e776e25f6e0f70bc2c7e38fee8f548d7cad2a Mon Sep 17 00:00:00 2001 From: Dummi26 Date: Sat, 1 Apr 2023 16:27:52 +0200 Subject: [PATCH] changed enum type syntax because A: int/string is ambiguous while A(int)/string and A(int/string) aren't. Builtins now use the Err enum variant for errors. --- enums.txt | 13 +--- src/parse/parse.rs | 21 +++-- src/script/block.rs | 35 +++++++-- src/script/builtins.rs | 171 +++++++++++++++++++++++++---------------- src/script/val_data.rs | 2 + 5 files changed, 147 insertions(+), 95 deletions(-) diff --git a/enums.txt b/enums.txt index 1de6dc2..8b13789 100644 --- a/enums.txt +++ b/enums.txt @@ -1,12 +1 @@ -x = if false enum_a: "hello" else "world" -x.debug() -switch! x { - string { - println("no enum") - x.println() - } - enum_a: string { - println("Enum!") - x.noenum().println() - } -} + diff --git a/src/parse/parse.rs b/src/parse/parse.rs index bc76238..5ac0594 100644 --- a/src/parse/parse.rs +++ b/src/parse/parse.rs @@ -522,14 +522,19 @@ fn parse_single_type_adv( } match file.next() { Some(ch) if ch.is_whitespace() => break, - Some(':') => { - break 'parse_single_type VSingleType::EnumVariantS(name, { - let po = parse_type_adv(file, in_fn_args)?; - if po.1 { - closed_bracket_in_fn_args = true; - } - po.0 - }) + Some('(') => { + break 'parse_single_type if name.as_str() == "fn" { + todo!("fn types"); + } else { + VSingleType::EnumVariantS(name, { + let po = parse_type_adv(file, true)?; + if !po.1 { + eprintln!("enum type should be closed by ')', but apparently wasn't?"); + assert_eq!(file.next(), Some(')')); + } + po.0 + }) + }; } Some(')') if in_fn_args => { diff --git a/src/script/block.rs b/src/script/block.rs index bbf8622..753281c 100644 --- a/src/script/block.rs +++ b/src/script/block.rs @@ -100,7 +100,7 @@ pub mod to_runnable { use crate::{script::{ val_data::VDataEnum, - val_type::{VSingleType, VType}, + val_type::{VSingleType, VType}, builtins, }, libs}; use super::{ @@ -168,7 +168,7 @@ pub mod to_runnable { lib_fns.insert(name.to_string(), (libid, fnid)); } } - Self { vars: 0, libs, lib_fns, enum_variants: HashMap::new() } + Self { vars: 0, libs, lib_fns, enum_variants: builtins::EVS.iter().enumerate().map(|(i, v)| (v.to_string(), i)).collect() } } } // Local, used to keep local variables separated @@ -480,11 +480,30 @@ pub mod to_runnable { types_not_covered_req_error = true; types_not_covered = types_not_covered | { let mut v = val_type; - for t in v.types.iter_mut() { - if let VSingleType::EnumVariant(i, v) = t { - *t = VSingleType::EnumVariantS(ginfo.enum_variants.iter().find_map(|(st, us)| if *us == *i { Some(st.clone()) } else { None }).unwrap(), v.clone()); + fn make_readable(v: &mut VType, ginfo: &GInfo) { + for t in v.types.iter_mut() { + match t { + VSingleType::EnumVariant(i, v) => { + let mut v = v.clone(); + make_readable(&mut v, ginfo); + *t = VSingleType::EnumVariantS(ginfo.enum_variants.iter().find_map(|(st, us)| if *us == *i { Some(st.clone()) } else { None }).unwrap(), v); + }, + VSingleType::EnumVariantS(_, v) => make_readable(v, ginfo), + VSingleType::Tuple(v) => for t in v.iter_mut() { + make_readable(t, ginfo) + } + VSingleType::List(t) => make_readable(t, ginfo), + VSingleType::Reference(v) => { + let mut v = v.clone().to(); + make_readable(&mut v, ginfo); + assert_eq!(v.types.len(), 1); + *t = VSingleType::Reference(Box::new(v.types.remove(0))); + } + VSingleType::Bool | VSingleType::Int | VSingleType::Float | VSingleType::String | VSingleType::Function(..) | VSingleType::Thread(..) => (), + } } } + make_readable(&mut v, &ginfo); v }; } @@ -1025,8 +1044,8 @@ impl Display for VSingleType { Self::Function(_) => write!(f, "FUNCTION"), Self::Thread(_) => write!(f, "THREAD"), Self::Reference(r) => write!(f, "&{r}"), - Self::EnumVariant(v, t) => write!(f, "{v}: {t}"), - Self::EnumVariantS(v, t) => write!(f, "{v}: {t}"), + Self::EnumVariant(v, t) => write!(f, "{v}({t})"), + Self::EnumVariantS(v, t) => write!(f, "{v}({t})"), } } } @@ -1147,7 +1166,7 @@ impl Display for VDataEnum { Self::Function(v) => write!(f, "{v}"), Self::Thread(..) => write!(f, "THREAD"), Self::Reference(r) => write!(f, "{}", r.lock().unwrap()), - Self::EnumVariant(v, d) => write!(f, "{v}: {d}"), + Self::EnumVariant(v, d) => write!(f, "{v}({d})"), } } } diff --git a/src/script/builtins.rs b/src/script/builtins.rs index 20ef1bc..f496faf 100644 --- a/src/script/builtins.rs +++ b/src/script/builtins.rs @@ -12,11 +12,16 @@ use super::{ val_type::{VSingleType, VType}, }; +const EV_ERR: usize = 0; +// const EV_??? = 1; +pub const EVS: [&'static str; 1] = ["Err"]; + #[derive(Clone, Debug)] pub enum BuiltinFunction { // core Assume1, // assume []/[t] is [t], return t. Optionally provide a reason as to why (2nd arg) NoEnum, + Matches, // print Print, Println, @@ -26,7 +31,7 @@ pub enum BuiltinFunction { // format ToString, Format, - // match + // parse ParseInt, ParseFloat, // functions @@ -79,6 +84,7 @@ impl BuiltinFunction { Some(match s { "assume1" => Self::Assume1, "noenum" => Self::NoEnum, + "matches" => Self::Matches, "print" => Self::Print, "println" => Self::Println, "debug" => Self::Debug, @@ -141,14 +147,14 @@ impl BuiltinFunction { 1 => len1 = true, _ => return false, }, - _ => return false, + _ => len1 = true, } } if !len0 { - eprintln!("Warn: calling assume1 on a value of type {}, which will always be a length-1 tuple.", input[0]); + eprintln!("Warn: calling assume1 on a value of type {}, which will never be a length-0 tuple and therefore will not cannot fail.", input[0]); } if !len1 { - eprintln!("Warn: calling assume1 on a value of type {}, which will never be a length-1 tuple!", input[0]); + eprintln!("Warn: calling assume1 on a value of type {}, which will always be a length-0 tuple!", input[0]); } if input.len() >= 2 { if input.len() == 2 { @@ -164,6 +170,7 @@ impl BuiltinFunction { } } Self::NoEnum => input.len() == 1, + Self::Matches => input.len() == 1, Self::Print | Self::Println => { if input.len() == 1 { input[0].fits_in(&VSingleType::String.to()).is_empty() @@ -332,12 +339,13 @@ impl BuiltinFunction { out = out | &v[0]; } } - _ => unreachable!(), + v => out = out | v.clone().to(), } } out } Self::NoEnum => input[0].clone().noenum(), + Self::Matches => input[0].matches().1, // [] Self::Print | Self::Println | Self::Debug | Self::Sleep => VType { types: vec![VSingleType::Tuple(vec![])], @@ -410,37 +418,40 @@ impl BuiltinFunction { Self::Exit => VType { types: vec![] }, // doesn't return Self::FsList => VType { types: vec![ - VSingleType::Tuple(vec![]).into(), - VSingleType::List(VSingleType::String.into()).into(), + VSingleType::List(VSingleType::String.into()), + VSingleType::EnumVariant(EV_ERR, VSingleType::String.to()), ], }, Self::FsRead => VType { types: vec![ - VSingleType::Tuple(vec![]).into(), - VSingleType::List(VSingleType::Int.into()).into(), + VSingleType::List(VSingleType::Int.to()), + VSingleType::EnumVariant(EV_ERR, VSingleType::String.to()), ], }, Self::FsWrite => VType { types: vec![ VSingleType::Tuple(vec![]).into(), - VSingleType::List(VSingleType::String.into()).into(), + VSingleType::EnumVariant(EV_ERR, VSingleType::String.to()), ], }, Self::BytesToString => VType { types: vec![ - VSingleType::String.into(), - VSingleType::Tuple(vec![ - VSingleType::String.into(), // lossy string - VSingleType::String.into(), // error message - ]) - .into(), + VSingleType::String, + VSingleType::EnumVariant( + EV_ERR, + VSingleType::Tuple(vec![ + VSingleType::String.into(), // lossy string + VSingleType::String.into(), // error message + ]) + .to(), + ), ], }, Self::StringToBytes => VSingleType::List(VSingleType::Int.into()).into(), Self::RunCommand => VType { types: vec![ // error - VSingleType::String.into(), + VSingleType::EnumVariant(EV_ERR, VSingleType::String.to()), // success: Option, stdout, stderr VSingleType::Tuple(vec![ VType { @@ -454,7 +465,7 @@ impl BuiltinFunction { Self::RunCommandGetBytes => VType { types: vec![ // error - VSingleType::String.into(), + VSingleType::EnumVariant(EV_ERR, VSingleType::String.to()), // success: Option, stdout, stderr VSingleType::Tuple(vec![ VType { @@ -502,18 +513,10 @@ impl BuiltinFunction { Self::Substring => VSingleType::String.into(), Self::Regex => VType { types: vec![ - VSingleType::Tuple(vec![ - // does match - VSingleType::Tuple(vec![VSingleType::List(VSingleType::String.to()).to()]) - .to(), - // no error - ]), - VSingleType::Tuple(vec![ - // does not match - VSingleType::Tuple(vec![]).to(), - // error - VSingleType::String.to(), - ]), + // [string ...] + VSingleType::List(VSingleType::String.to()), + // Err(string) + VSingleType::EnumVariant(EV_ERR, VSingleType::String.to()), ], }, } @@ -525,25 +528,32 @@ impl BuiltinFunction { libs: &Arc>, ) -> VData { match self { - Self::Assume1 => { - if let VDataEnum::Tuple(mut v) = args[0].run(vars, libs).data { - v.pop().unwrap() - } else { - panic!( - "ASSUMPTION FAILED: assume1 :: {}", - if args.len() > 1 { - if let VDataEnum::String(v) = args[1].run(vars, libs).data { - v + Self::Assume1 => match args[0].run(vars, libs).data { + VDataEnum::Tuple(mut v) => { + if let Some(v) = v.pop() { + v + } else { + panic!( + "ASSUMPTION FAILED: assume1 :: {}", + if args.len() > 1 { + if let VDataEnum::String(v) = args[1].run(vars, libs).data { + v + } else { + String::new() + } } else { String::new() } - } else { - String::new() - } - ); + ); + } } - } + v => v.to(), + }, Self::NoEnum => args[0].run(vars, libs).noenum(), + Self::Matches => match args[0].run(vars, libs).data.matches() { + Some(v) => VDataEnum::Tuple(vec![v]).to(), + None => VDataEnum::Tuple(vec![]).to(), + }, BuiltinFunction::Print => { if let VDataEnum::String(arg) = args[0].run(vars, libs).data { print!("{}", arg); @@ -704,8 +714,8 @@ impl BuiltinFunction { if args.len() > 1 { todo!("fs_list advanced filters") } - if let Ok(entries) = std::fs::read_dir(path) { - VDataEnum::List( + match std::fs::read_dir(path) { + Ok(entries) => VDataEnum::List( VSingleType::String.into(), entries .filter_map(|entry| { @@ -722,9 +732,12 @@ impl BuiltinFunction { }) .collect(), ) - .to() - } else { - VDataEnum::Tuple(vec![]).to() + .to(), + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new(VDataEnum::String(e.to_string()).to()), + ) + .to(), } } else { unreachable!("fs_list first arg not a string") @@ -736,16 +749,19 @@ impl BuiltinFunction { Self::FsRead => { if args.len() > 0 { if let VDataEnum::String(path) = args[0].run(vars, libs).data { - if let Ok(data) = std::fs::read(path) { - VDataEnum::List( + match std::fs::read(path) { + Ok(data) => VDataEnum::List( VSingleType::Int.into(), data.into_iter() .map(|v| VDataEnum::Int(v as _).to()) .collect(), ) - .to() - } else { - VDataEnum::Tuple(vec![]).to() + .to(), + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new(VDataEnum::String(e.to_string()).to()), + ) + .to(), } } else { unreachable!("fs_read first arg not a string") @@ -766,7 +782,11 @@ impl BuiltinFunction { } match std::fs::write(file_path, bytes) { Ok(_) => VDataEnum::Tuple(vec![]).to(), - Err(e) => VDataEnum::String(e.to_string()).to(), + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new(VDataEnum::String(e.to_string()).to()), + ) + .to(), } } else { unreachable!( @@ -788,13 +808,20 @@ impl BuiltinFunction { Ok(v) => VDataEnum::String(v).to(), Err(e) => { let err = e.to_string(); - VDataEnum::Tuple(vec![ - VDataEnum::String( - String::from_utf8_lossy(&e.into_bytes()).into_owned(), - ) - .to(), - VDataEnum::String(err).to(), - ]) + VDataEnum::EnumVariant( + EV_ERR, + Box::new( + VDataEnum::Tuple(vec![ + VDataEnum::String( + String::from_utf8_lossy(&e.into_bytes()) + .into_owned(), + ) + .to(), + VDataEnum::String(err).to(), + ]) + .to(), + ), + ) .to() } } @@ -876,7 +903,11 @@ impl BuiltinFunction { .to(), ]) .to(), - Err(e) => VDataEnum::String(e.to_string()).to(), + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new(VDataEnum::String(e.to_string()).to()), + ) + .to(), } } else { unreachable!("run_command not string arg") @@ -1345,10 +1376,16 @@ impl BuiltinFunction { .to()]) .to() } - Err(e) => VDataEnum::Tuple(vec![ - VDataEnum::Tuple(vec![]).to(), // no results - VDataEnum::String(e.to_string()).to(), - ]) + Err(e) => VDataEnum::EnumVariant( + EV_ERR, + Box::new( + VDataEnum::Tuple(vec![ + VDataEnum::Tuple(vec![]).to(), // no results + VDataEnum::String(e.to_string()).to(), + ]) + .to(), + ), + ) .to(), } } else { diff --git a/src/script/val_data.rs b/src/script/val_data.rs index e1e51f8..5d88751 100644 --- a/src/script/val_data.rs +++ b/src/script/val_data.rs @@ -106,6 +106,7 @@ impl VDataEnum { None } } + VDataEnum::EnumVariant(..) => None, other => Some(other.to()), } } @@ -119,6 +120,7 @@ impl VSingleType { None => (true, VType { types: vec![] }), }, Self::Bool => (true, Self::Bool.to()), + Self::EnumVariant(..) | Self::EnumVariantS(..) => (true, VType { types: vec![] }), v => (false, v.clone().to()), } }