diff --git a/mers/src/lang/builtins.rs b/mers/src/lang/builtins.rs index fe05b1a..8d046d7 100755 --- a/mers/src/lang/builtins.rs +++ b/mers/src/lang/builtins.rs @@ -78,7 +78,6 @@ pub enum BuiltinFunction { Pop, Remove, Get, - GetRef, Len, // String Contains, @@ -142,7 +141,6 @@ impl BuiltinFunction { "pop" => Self::Pop, "remove" => Self::Remove, "get" => Self::Get, - "get_ref" => Self::GetRef, "len" => Self::Len, "contains" => Self::Contains, "starts_with" => Self::StartsWith, @@ -448,7 +446,7 @@ impl BuiltinFunction { } } // TODO! finish this - Self::Get | Self::GetRef | Self::Len => true, + Self::Get | Self::Len => true, Self::Substring => { if input.len() >= 2 && input.len() <= 3 { let (s, start) = (&input[0], &input[1]); @@ -603,26 +601,6 @@ impl BuiltinFunction { unreachable!("get, pop or remove called without args") } } - Self::GetRef => { - if let Some(v) = input.first() { - VType { - types: vec![ - VSingleType::Tuple(vec![]), - VSingleType::Tuple(vec![{ - let mut v = v.get_any(info).expect("cannot use get on this type"); - v.types = v - .types - .into_iter() - .map(|v| VSingleType::Reference(Box::new(v))) - .collect(); - v - }]), - ], - } - } else { - unreachable!("get, pop or remove called without args") - } - } Self::Exit => VType { types: vec![] }, // doesn't return Self::FsList => VType { types: vec![ @@ -1395,9 +1373,9 @@ impl BuiltinFunction { _ => unreachable!("max: not a number"), }) }), - Self::Push => args[0].run(info).operate_on_data_mut(info, |list| { + Self::Push => args[0].run(info).operate_on_data_mut(|list| { if let VDataEnum::Reference(v) = list { - v.operate_on_data_mut(info, |list| { + v.operate_on_data_mut(|list| { if let VDataEnum::List(_, v) = list { v.push(args[1].run(info)); } @@ -1407,11 +1385,11 @@ impl BuiltinFunction { unreachable!("push: not a reference") } }), - Self::Insert => args[0].run(info).operate_on_data_mut(info, |v| { + Self::Insert => args[0].run(info).operate_on_data_mut(|v| { args[1].run(info).operate_on_data_immut(|i| { // TODO: find out why the fuck this helps if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i) { - v.operate_on_data_mut(info, |v| { + v.operate_on_data_mut(|v| { if let VDataEnum::List(_, v) = v { v.insert(*i as _, args[2].run(info)); } @@ -1422,9 +1400,9 @@ impl BuiltinFunction { } }) }), - Self::Pop => args[0].run(info).operate_on_data_mut(info, |v| { + Self::Pop => args[0].run(info).operate_on_data_mut(|v| { if let VDataEnum::Reference(v) = v { - v.operate_on_data_mut(info, |v| { + v.operate_on_data_mut(|v| { if let VDataEnum::List(_, v) = v { if let Some(v) = v.pop() { VDataEnum::Tuple(vec![v]) @@ -1440,12 +1418,12 @@ impl BuiltinFunction { unreachable!("pop: not a reference") } }), - Self::Remove => args[0].run(info).operate_on_data_mut(info, |v| { + Self::Remove => args[0].run(info).operate_on_data_mut(|v| { args[1].run(info).operate_on_data_immut(|i| // this being a reference means we wont need to call make_mut() later, so a .as_ref() borrow is enough. if let (VDataEnum::Reference(v), VDataEnum::Int(i)) = (v, i ) { - v.operate_on_data_mut(info, |v| { + v.operate_on_data_mut(|v| { if let VDataEnum::List(_, v) = v { if *i >= 0 && v.len() > *i as _ { let v = v.remove(*i as _); @@ -1464,23 +1442,10 @@ impl BuiltinFunction { args[1].run(info).operate_on_data_immut(|i| { if let VDataEnum::Int(i) = i { if *i >= 0 { - match match container { - VDataEnum::Reference(v) => v.operate_on_data_immut(|v| match v { - VDataEnum::List(_, v) | VDataEnum::Tuple(v) => { - v.get(*i as usize).map(|v| v.clone()) - } - _ => unreachable!( - "get: reference to something other than list/tuple" - ), - }), - VDataEnum::List(_, v) | VDataEnum::Tuple(v) => { - v.get(*i as usize).map(|v| v.clone()) - } - _ => unreachable!("get: not a reference/list/tuple"), - } { - Some(v) => VDataEnum::Tuple(vec![v]).to(), - None => VDataEnum::Tuple(vec![]).to(), - } + container.get(*i as _).map_or_else( + || VDataEnum::Tuple(vec![]).to(), + |v| VDataEnum::Tuple(vec![v]).to(), + ) } else { VDataEnum::Tuple(vec![]).to() } @@ -1489,32 +1454,6 @@ impl BuiltinFunction { } }) }), - Self::GetRef => args[0].run(info).operate_on_data_mut(info, |container| { - args[1].run(info).operate_on_data_immut(|i| { - if let (VDataEnum::Reference(container), VDataEnum::Int(i)) = (container, i) { - if *i >= 0 { - // we can get mutably because this is the content of a reference - match container.operate_on_data_mut(info, |container| match container { - VDataEnum::List(_, v) | VDataEnum::Tuple(v) => { - if let Some(v) = v.get_mut(*i as usize) { - Some(VDataEnum::Reference(v.clone_mut()).to()) - } else { - None - } - } - _ => unreachable!("get: not a reference/list/tuple"), - }) { - Some(v) => VDataEnum::Tuple(vec![v]).to(), - None => VDataEnum::Tuple(vec![]).to(), - } - } else { - VDataEnum::Tuple(vec![]).to() - } - } else { - unreachable!("get_ref: not a reference and index") - } - }) - }), Self::Len => { if args.len() == 1 { VDataEnum::Int(args[0].run(info).operate_on_data_immut(|v| match v { diff --git a/mers/src/lang/code_runnable.rs b/mers/src/lang/code_runnable.rs index 5559a3c..f3c3966 100755 --- a/mers/src/lang/code_runnable.rs +++ b/mers/src/lang/code_runnable.rs @@ -130,7 +130,7 @@ impl RStatement { None => unreachable!("can't dereference..."), }; } - val.assign(info, out); + val.assign(out); } VDataEnum::Tuple(vec![]).to() } else { @@ -181,7 +181,7 @@ impl RStatementEnum { } Self::FunctionCall(func, args) => { for (i, input) in func.inputs.iter().enumerate() { - input.lock().unwrap().assign(info, args[i].run(info)); + input.lock().unwrap().assign(args[i].run(info)); } func.run(info) } diff --git a/mers/src/lang/val_data.rs b/mers/src/lang/val_data.rs index 3191670..0c6dce3 100755 --- a/mers/src/lang/val_data.rs +++ b/mers/src/lang/val_data.rs @@ -100,7 +100,7 @@ impl VData { /// runs func on the underlying data. /// attempts to get a mutable reference to the data. if this fails, it will (partially) clone the data, then point the VData to the new data, /// so that other VDatas pointing to the same original data aren't changed. - pub fn operate_on_data_mut(&mut self, info: &GlobalScriptInfo, mut func: F) -> O + pub fn operate_on_data_mut(&mut self, mut func: F) -> O where F: FnOnce(&mut VDataEnum) -> O, { @@ -116,25 +116,11 @@ impl VData { // *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was. // for proof: data is untouched, only the new_data is ever modified. let new_vdata = VDataInner::Data(0, new_data).to(); - if info.log.vdata_clone.log() { - drop(lock); - info.log.log(LogMsg::VDataClone( - #[cfg(debug_assertions)] - self.1.clone(), - #[cfg(not(debug_assertions))] - None, - self.inner_cloned(), - Arc::as_ptr(&self.0) as usize, - Arc::as_ptr(&new_vdata.0) as usize, - )); - } (Some(new_vdata), o) } } - VDataInner::Mut(inner) => { - (None, inner.lock().unwrap().operate_on_data_mut(info, func)) - } - VDataInner::ClonedFrom(inner) => (None, inner.operate_on_data_mut(info, func)), + VDataInner::Mut(inner) => (None, inner.lock().unwrap().operate_on_data_mut(func)), + VDataInner::ClonedFrom(inner) => (None, inner.operate_on_data_mut(func)), } }; if let Some(nv) = new_val { @@ -145,13 +131,13 @@ impl VData { /// Since operate_on_data_mut can clone, it may be inefficient for just assigning (where we don't care about the previous value, so it doesn't need to be cloned). /// This is what this function is for. (TODO: actually make it more efficient instead of using operate_on_data_mut) - pub fn assign_data(&mut self, info: &GlobalScriptInfo, new_data: VDataEnum) { - let o = self.operate_on_data_mut(info, |d| *d = new_data); + pub fn assign_data(&mut self, new_data: VDataEnum) { + let o = self.operate_on_data_mut(|d| *d = new_data); o } /// Assigns the new_data to self. Affects all muts pointing to the same data, but no ClonedFroms. - pub fn assign(&mut self, info: &GlobalScriptInfo, new: VData) { - self.assign_data(info, new.inner_cloned()) + pub fn assign(&mut self, new: VData) { + self.assign_data(new.inner_cloned()) // !PROBLEM! If ClonedFrom always has to point to a Data, this may break things! // match &mut *self.0.lock().unwrap() { // VDataInner::Data(count, data) => { @@ -244,6 +230,9 @@ impl VData { pub fn get(&self, i: usize) -> Option { self.operate_on_data_immut(|v| v.get(i)) } + pub fn get_ref(&mut self, i: usize) -> Option { + self.operate_on_data_mut(|v| v.get_ref(i)) + } pub fn matches(&self) -> Option { match self.operate_on_data_immut(|v| v.matches()) { Some(Some(v)) => Some(v), @@ -350,10 +339,28 @@ impl VDataEnum { None => None, }, Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(), - Self::Reference(r) => r.get(i), + Self::Reference(r) => r.clone_mut().get_ref(i), Self::EnumVariant(_, v) => v.get(i), } } + /// this is guaranteed to return Self::Reference(_), if it returns Some(_). + pub fn get_ref(&mut self, i: usize) -> Option { + Some(Self::Reference(self.get_ref_inner(i)?).to()) + } + pub fn get_ref_inner(&mut self, i: usize) -> Option { + match self { + Self::Bool(..) + | Self::Int(..) + | Self::Float(..) + | Self::Function(..) + | Self::Thread(..) => None, + // TODO: String + Self::String(s) => None, + Self::Tuple(v) | Self::List(_, v) => v.get(i).map(|v| v.clone_mut()), + Self::Reference(r) => r.get_ref(i), + Self::EnumVariant(_, v) => v.get_ref(i), + } + } pub fn matches_ref_bool(&self) -> bool { match self { VDataEnum::Tuple(v) => !v.is_empty(), diff --git a/mers/src/lang/val_type.rs b/mers/src/lang/val_type.rs index b6ce24a..ef5326e 100755 --- a/mers/src/lang/val_type.rs +++ b/mers/src/lang/val_type.rs @@ -41,6 +41,20 @@ impl VSingleType { Self::String => Some(VSingleType::String.into()), Self::Tuple(t) => t.get(i).cloned(), Self::List(t) => Some(t.clone()), + Self::Reference(r) => r.get_ref(i, gsinfo), + Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get(i, gsinfo), + Self::CustomType(t) => gsinfo.custom_types[*t].get(i, gsinfo), + &Self::CustomTypeS(_) => { + unreachable!("CustomTypeS instead of CustomType, compiler bug? [get]") + } + } + } + pub fn get_ref(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option { + match self { + Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None, + Self::String => Some(VSingleType::String.into()), + Self::Tuple(t) => t.get(i).map(|v| v.reference()), + Self::List(t) => Some(t.clone()), Self::Reference(r) => r.get(i, gsinfo), Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get(i, gsinfo), Self::CustomType(t) => gsinfo.custom_types[*t].get(i, gsinfo), @@ -113,6 +127,16 @@ impl VType { } Some(out) } + pub fn reference(&self) -> Self { + let mut out = Self::empty(); + Self { + types: self + .types + .iter() + .map(|v| VSingleType::Reference(Box::new(v.clone()))) + .collect(), + } + } } impl VSingleType { @@ -122,13 +146,30 @@ impl VSingleType { Self::String => Some(VSingleType::String.into()), 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(info), + Self::Reference(r) => r.get_any_ref(info), Self::EnumVariant(_, t) => t.get_any(info), Self::EnumVariantS(..) => unreachable!(), Self::CustomType(t) => info.custom_types[*t].get_any(info), Self::CustomTypeS(_) => unreachable!(), } } + pub fn get_any_ref(&self, info: &GlobalScriptInfo) -> Option { + match self { + Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None, + Self::String => Some(VSingleType::String.into()), + Self::Tuple(t) => Some( + t.iter() + .fold(VType { types: vec![] }, |a, b| a | b.reference()), + ), + Self::List(t) => Some(t.reference()), + // TODO: idk if this is right... + Self::Reference(r) => r.get_any_ref(info), + Self::EnumVariant(_, t) => t.get_any_ref(info), + Self::EnumVariantS(..) => unreachable!(), + Self::CustomType(t) => info.custom_types[*t].get_any(info), + Self::CustomTypeS(_) => unreachable!(), + } + } pub fn is_reference(&self) -> bool { match self { Self::Reference(_) => true, @@ -151,6 +192,13 @@ impl VType { } Some(out) } + pub fn get_any_ref(&self, info: &GlobalScriptInfo) -> Option { + let mut out = VType { types: vec![] }; + for t in &self.types { + out = out | t.get_any_ref(info)?; // if we can't use *get* on one type, we can't use it at all. + } + Some(out) + } } impl VType { diff --git a/mers/src/parsing/parse.rs b/mers/src/parsing/parse.rs index 203275f..7938109 100755 --- a/mers/src/parsing/parse.rs +++ b/mers/src/parsing/parse.rs @@ -732,7 +732,7 @@ pub mod implementation { // int, float, var break { if let Ok(v) = start.parse() { - if let Some('.') = nchar { + if !is_part_of_chain_already && nchar == Some('.') { let pos = *file.get_pos(); file.next(); let mut pot_float = String::new();