From b1a90d587225cfe44803dc5003800d348a3212ce Mon Sep 17 00:00:00 2001 From: Dummi26 Date: Sat, 1 Apr 2023 14:38:46 +0200 Subject: [PATCH] implemented enum functionality. todo: default functions should use Ok/Err enum variants? --- enums.txt | 12 +++++++ src/libs/mod.rs | 1 + src/parse/parse.rs | 18 +++++++++- src/script/block.rs | 75 ++++++++++++++++++++++++++++++++++++++---- src/script/builtins.rs | 5 +++ src/script/val_data.rs | 16 +++++++-- src/script/val_type.rs | 27 +++++++++++++-- 7 files changed, 141 insertions(+), 13 deletions(-) create mode 100644 enums.txt diff --git a/enums.txt b/enums.txt new file mode 100644 index 0000000..1de6dc2 --- /dev/null +++ b/enums.txt @@ -0,0 +1,12 @@ +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/libs/mod.rs b/src/libs/mod.rs index e29b260..0b2c172 100644 --- a/src/libs/mod.rs +++ b/src/libs/mod.rs @@ -175,6 +175,7 @@ fn data_to_bytes(data: &VData, stdin: &mut ChildStdin) { VDataEnum::Function(..) | VDataEnum::Reference(..) | VDataEnum::Thread(..) => { panic!("cannot use functions, references or threads in LibFunctions.") } + VDataEnum::EnumVariant(..) => todo!(), } stdin.flush().unwrap(); } diff --git a/src/parse/parse.rs b/src/parse/parse.rs index 80b70d2..bc76238 100644 --- a/src/parse/parse.rs +++ b/src/parse/parse.rs @@ -217,6 +217,12 @@ fn parse_statement_adv( Some('=') => { break parse_statement(file)?.output_to(start.trim().to_string()); } + Some(':') => { + return Ok(SStatement::new(SStatementEnum::EnumVariant( + start, + parse_statement(file)?, + ))); + } Some(ch) if ch.is_whitespace() || matches!(ch, '}' | ']' | ')' | '.') => { file.skip_whitespaces(); if let Some('=') = file.peek() { @@ -506,7 +512,7 @@ fn parse_single_type_adv( VSingleType::Tuple(types) } } - Some(ch) => { + Some(ch) => 'parse_single_type: { let mut name = ch.to_string(); loop { match file.peek() { @@ -516,6 +522,16 @@ 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(')') if in_fn_args => { closed_bracket_in_fn_args = true; break; diff --git a/src/script/block.rs b/src/script/block.rs index bb9049a..bbf8622 100644 --- a/src/script/block.rs +++ b/src/script/block.rs @@ -72,6 +72,7 @@ pub enum SStatementEnum { Switch(String, Vec<(VType, SStatement)>, bool), Match(String, Vec<(SStatement, SStatement)>), IndexFixed(SStatement, usize), + EnumVariant(String, SStatement), } impl Into for SStatementEnum { fn into(self) -> SStatement { @@ -157,6 +158,7 @@ pub mod to_runnable { vars: usize, libs: Arc>, lib_fns: HashMap, + enum_variants: HashMap, } impl GInfo { pub fn new(libs: Arc>) -> Self { @@ -166,7 +168,7 @@ pub mod to_runnable { lib_fns.insert(name.to_string(), (libid, fnid)); } } - Self { vars: 0, libs, lib_fns, } + Self { vars: 0, libs, lib_fns, enum_variants: HashMap::new() } } } // Local, used to keep local variables separated @@ -268,6 +270,35 @@ pub mod to_runnable { Ok(RBlock { statements }) } + fn stypes(t: &mut VType, ginfo: &mut GInfo) { + for t in &mut t.types { + stype(t, ginfo); + } + } + fn stype(t: &mut VSingleType, ginfo: &mut GInfo) { + match t { + VSingleType::Tuple(v) => { + for t in v { + stypes(t, ginfo); + } + }, + VSingleType::EnumVariantS(e, v) => *t = VSingleType::EnumVariant({ + if let Some(v) = ginfo.enum_variants.get(e) { + *v + } else { + let v = ginfo.enum_variants.len(); + ginfo.enum_variants.insert(e.clone(), v); + v + } + }, + { + stypes(v, ginfo); + v.clone() + } + ), + _ => (), + } + } fn statement( s: &SStatement, ginfo: &mut GInfo, @@ -288,7 +319,8 @@ pub mod to_runnable { } SStatementEnum::Variable(v, is_ref) => { if let Some(var) = linfo.vars.get(v) { - RStatementEnum::Variable(var.0, var.1.clone(), *is_ref) + RStatementEnum::Variable(var.0, { + let mut v = var.1.clone(); stypes(&mut v, ginfo); v }, *is_ref) } else { return Err(ToRunnableError::UseOfUndefinedVariable(v.clone())); } @@ -423,8 +455,9 @@ pub mod to_runnable { let mut ncases = Vec::with_capacity(cases.len()); let og_type = switch_on_v.1.clone(); // linfo.vars.get(switch_on).unwrap().1.clone(); for case in cases { - linfo.vars.get_mut(switch_on).unwrap().1 = case.0.clone(); - ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?)); + let case0 = { let mut v = case.0.clone(); stypes(&mut v, ginfo); v }; + linfo.vars.get_mut(switch_on).unwrap().1 = case0.clone(); + ncases.push((case0, statement(&case.1, ginfo, linfo)?)); } linfo.vars.get_mut(switch_on).unwrap().1 = og_type; @@ -438,12 +471,22 @@ pub mod to_runnable { linf2.vars.get_mut(switch_on).unwrap().1 = val_type.clone(); 'force: { for (case_type, _) in cases { - if val_type.fits_in(&case_type).is_empty() { + let mut ct = case_type.clone(); + stypes(&mut ct, ginfo); + if val_type.fits_in(&ct).is_empty() { break 'force; } } types_not_covered_req_error = true; - types_not_covered = types_not_covered | val_type; + 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()); + } + } + v + }; } } if types_not_covered_req_error { @@ -532,6 +575,15 @@ pub mod to_runnable { return Err(ToRunnableError::NotIndexableFixed(st.out(), *i)); } } + SStatementEnum::EnumVariant(variant, s) => RStatementEnum::EnumVariant({ + if let Some(v) = ginfo.enum_variants.get(variant) { + *v + } else { + let v = ginfo.enum_variants.len(); + ginfo.enum_variants.insert(variant.clone(), v); + v + } + }, statement(s, ginfo, linfo)?), } .to(); if let Some(opt) = &s.output_to { @@ -674,6 +726,7 @@ pub enum RStatementEnum { Switch(RStatement, Vec<(VType, RStatement)>), Match(usize, Vec<(RStatement, RStatement)>), IndexFixed(RStatement, usize), + EnumVariant(usize, RStatement) } impl RStatementEnum { pub fn run(&self, vars: &Vec>, libs: &Arc>) -> VData { @@ -799,6 +852,9 @@ impl RStatementEnum { VDataEnum::Tuple(vec![]).to() } Self::IndexFixed(st, i) => st.run(vars, libs).get(*i).unwrap(), + Self::EnumVariant(e, v) => { + VDataEnum::EnumVariant(*e, Box::new(v.run(vars, libs))).to() + } } } pub fn out(&self) -> VType { @@ -848,7 +904,7 @@ impl RStatementEnum { let mut might_return_empty = switch_on.is_empty(); let mut out = VType { types: vec![] }; // if nothing is executed for switch_on in switch_on { - let switch_on: VType = switch_on.into(); + let switch_on = switch_on.to(); 'search: { for (on_type, case) in cases.iter() { if switch_on.fits_in(&on_type).is_empty() { @@ -872,6 +928,7 @@ impl RStatementEnum { out } Self::IndexFixed(st, i) => st.out().get(*i).unwrap(), + Self::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out()).to(), } } pub fn to(self) -> RStatement { @@ -968,6 +1025,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}"), } } } @@ -1047,6 +1106,7 @@ impl Display for SStatementEnum { write!(f, "}}") } SStatementEnum::IndexFixed(st, i) => write!(f, "{st}.{i}"), + SStatementEnum::EnumVariant(e, s) => write!(f, "{e}: {s}"), } } } @@ -1087,6 +1147,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}"), } } } diff --git a/src/script/builtins.rs b/src/script/builtins.rs index 7148e33..20ef1bc 100644 --- a/src/script/builtins.rs +++ b/src/script/builtins.rs @@ -16,6 +16,7 @@ use super::{ pub enum BuiltinFunction { // core Assume1, // assume []/[t] is [t], return t. Optionally provide a reason as to why (2nd arg) + NoEnum, // print Print, Println, @@ -77,6 +78,7 @@ impl BuiltinFunction { pub fn get(s: &str) -> Option { Some(match s { "assume1" => Self::Assume1, + "noenum" => Self::NoEnum, "print" => Self::Print, "println" => Self::Println, "debug" => Self::Debug, @@ -161,6 +163,7 @@ impl BuiltinFunction { false } } + Self::NoEnum => input.len() == 1, Self::Print | Self::Println => { if input.len() == 1 { input[0].fits_in(&VSingleType::String.to()).is_empty() @@ -334,6 +337,7 @@ impl BuiltinFunction { } out } + Self::NoEnum => input[0].clone().noenum(), // [] Self::Print | Self::Println | Self::Debug | Self::Sleep => VType { types: vec![VSingleType::Tuple(vec![])], @@ -539,6 +543,7 @@ impl BuiltinFunction { ); } } + Self::NoEnum => args[0].run(vars, libs).noenum(), BuiltinFunction::Print => { if let VDataEnum::String(arg) = args[0].run(vars, libs).data { print!("{}", arg); diff --git a/src/script/val_data.rs b/src/script/val_data.rs index 6c35254..e1e51f8 100644 --- a/src/script/val_data.rs +++ b/src/script/val_data.rs @@ -27,6 +27,7 @@ pub enum VDataEnum { Function(RFunction), Thread(VDataThread, VType), Reference(Arc>), + EnumVariant(usize, Box), } impl VData { @@ -46,11 +47,15 @@ impl VData { VDataEnum::Function(f) => VSingleType::Function(f.input_output_map.clone()), VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()), VDataEnum::Reference(r) => r.lock().unwrap().out_single(), + VDataEnum::EnumVariant(e, v) => VSingleType::EnumVariant(*e, v.out()), } } pub fn get(&self, i: usize) -> Option { self.data.get(i) } + pub fn noenum(self) -> Self { + self.data.noenum() + } } impl VDataEnum { @@ -61,6 +66,12 @@ impl VDataEnum { // get() impl VDataEnum { + pub fn noenum(self) -> VData { + match self { + Self::EnumVariant(_, v) => *v, + v => v.to(), + } + } pub fn get(&self, i: usize) -> Option { match self { Self::Bool(..) @@ -75,6 +86,7 @@ impl VDataEnum { }, Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(), Self::Reference(r) => r.lock().unwrap().get(i), + Self::EnumVariant(_, v) => v.get(i), } } pub fn matches_ref_bool(&self) -> bool { @@ -154,9 +166,7 @@ impl VDataThread { if v.is_finished() { let m = std::mem::replace( &mut *mg, - VDataThreadEnum::Finished(VData { - data: VDataEnum::Bool(false), - }), + VDataThreadEnum::Finished(VDataEnum::Bool(false).to()), ); match m { VDataThreadEnum::Running(v) => { diff --git a/src/script/val_type.rs b/src/script/val_type.rs index 09d1baf..6385153 100644 --- a/src/script/val_type.rs +++ b/src/script/val_type.rs @@ -16,6 +16,8 @@ pub enum VSingleType { Function(Vec<(Vec, VType)>), Thread(VType), Reference(Box), + EnumVariant(usize, VType), + EnumVariantS(String, VType), } impl VSingleType { @@ -27,6 +29,7 @@ impl VSingleType { Self::Tuple(t) => t.get(i).cloned(), Self::List(t) => Some(t.clone()), Self::Reference(r) => r.get(i), + Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get(i), } } } @@ -48,6 +51,8 @@ impl VSingleType { Self::Tuple(t) => Some(t.iter().fold(VType { types: vec![] }, |a, b| a | b)), Self::List(t) => Some(t.clone()), Self::Reference(r) => r.get_any(), + Self::EnumVariant(_, t) => t.get_any(), + Self::EnumVariantS(..) => unreachable!(), } } } @@ -85,6 +90,13 @@ impl VType { pub fn contains(&self, t: &VSingleType) -> bool { self.types.contains(t) } + pub fn noenum(self) -> Self { + let mut o = Self { types: vec![] }; + for t in self.types { + o = o | t.noenum(); + } + o + } } impl BitOr for VType { type Output = Self; @@ -136,8 +148,21 @@ impl VSingleType { _ => vec![], } } + pub fn noenum(self) -> VType { + match self { + Self::EnumVariant(_, v) | Self::EnumVariantS(_, v) => v, + v => v.to(), + } + } pub fn fits_in(&self, rhs: &Self) -> bool { match (self, rhs) { + (Self::Reference(r), Self::Reference(b)) => r.fits_in(b), + (Self::Reference(_), _) | (_, Self::Reference(_)) => false, + (Self::EnumVariant(v1, t1), Self::EnumVariant(v2, t2)) => { + *v1 == *v2 && t1.fits_in(&t2).is_empty() + } + (Self::EnumVariant(..), _) | (_, Self::EnumVariant(..)) => false, + (Self::EnumVariantS(..), _) | (_, Self::EnumVariantS(..)) => unreachable!(), (Self::Bool, Self::Bool) | (Self::Int, Self::Int) | (Self::Float, Self::Float) @@ -171,8 +196,6 @@ impl VSingleType { (Self::Function(..), _) => false, (Self::Thread(a), Self::Thread(b)) => a.fits_in(b).is_empty(), (Self::Thread(..), _) => false, - (Self::Reference(r), Self::Reference(b)) => r.fits_in(b), - (Self::Reference(_), _) => false, } } }