implemented enum functionality. todo: default functions should use Ok/Err enum variants?

This commit is contained in:
Dummi26 2023-04-01 14:38:46 +02:00
parent 260e42d4a7
commit b1a90d5872
7 changed files with 141 additions and 13 deletions

12
enums.txt Normal file
View File

@ -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()
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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<SStatement> for SStatementEnum {
fn into(self) -> SStatement {
@ -157,6 +158,7 @@ pub mod to_runnable {
vars: usize,
libs: Arc<Vec<libs::Lib>>,
lib_fns: HashMap<String, (usize, usize)>,
enum_variants: HashMap<String, usize>,
}
impl GInfo {
pub fn new(libs: Arc<Vec<libs::Lib>>) -> 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<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> 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}"),
}
}
}

View File

@ -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<Self> {
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);

View File

@ -27,6 +27,7 @@ pub enum VDataEnum {
Function(RFunction),
Thread(VDataThread, VType),
Reference(Arc<Mutex<VData>>),
EnumVariant(usize, Box<VData>),
}
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> {
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<VData> {
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) => {

View File

@ -16,6 +16,8 @@ pub enum VSingleType {
Function(Vec<(Vec<VSingleType>, VType)>),
Thread(VType),
Reference(Box<Self>),
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,
}
}
}