fixed [[2]].0.0 parsing 0.0 as a float, removed get_ref() and made get() return a reference to the inner value if called on a reference to a collection (&[int ...].get(0) returns []/[&int]).

This commit is contained in:
mark 2023-05-23 12:01:27 +02:00
parent 56b457e1b3
commit 7af9902b6a
5 changed files with 94 additions and 100 deletions

View File

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

View File

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

View File

@ -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<F, O>(&mut self, info: &GlobalScriptInfo, mut func: F) -> O
pub fn operate_on_data_mut<F, O>(&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<VData> {
self.operate_on_data_immut(|v| v.get(i))
}
pub fn get_ref(&mut self, i: usize) -> Option<VData> {
self.operate_on_data_mut(|v| v.get_ref(i))
}
pub fn matches(&self) -> Option<Self> {
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<VData> {
Some(Self::Reference(self.get_ref_inner(i)?).to())
}
pub fn get_ref_inner(&mut self, i: usize) -> Option<VData> {
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(),

View File

@ -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<VType> {
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<VType> {
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<VType> {
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 {

View File

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