added destructuring assignments for tuples (and lists on the left)

This commit is contained in:
mark 2023-05-26 18:46:47 +02:00
parent 3f76e4f549
commit be9403d63d
4 changed files with 107 additions and 56 deletions

View File

@ -0,0 +1,12 @@
x := "https:\//www.google.com"
x.debug()
[a, [b, c]] := [1, ["str", 12.5]]
println("---")
println(a.to_string() + " " + b + " " + c.to_string())
println("~~~")
// switch! run_command("curl", [x, ...]) {
// }

View File

@ -1,4 +1,7 @@
use std::sync::{Arc, Mutex}; use std::{
eprintln,
sync::{Arc, Mutex},
};
use super::{ use super::{
builtins::BuiltinFunction, builtins::BuiltinFunction,
@ -106,33 +109,45 @@ pub struct RStatement {
pub force_output_type: Option<VType>, pub force_output_type: Option<VType>,
} }
impl RStatement { impl RStatement {
fn assign_to(assign_from: VData, mut assign_to: VData, info: &GSInfo) {
eprintln!("Assigning: '{assign_from}'.");
assign_to.operate_on_data_mut(|assign_to| match assign_to {
VDataEnum::Tuple(v) | VDataEnum::List(_, v) => {
for (i, v) in v.iter().enumerate() {
Self::assign_to(
assign_from.get(i).expect(
"tried to assign to tuple, but value didn't return Some(_) on get()",
),
v.clone_data(),
info,
)
}
}
VDataEnum::Reference(r) => r.assign(assign_from),
o => todo!("ERR: Cannot assign to {o}."),
})
}
pub fn run(&self, info: &GSInfo) -> VData { pub fn run(&self, info: &GSInfo) -> VData {
let out = self.statement.run(info); let out = self.statement.run(info);
if let Some((v, derefs, is_init)) = &self.output_to { if let Some((v, derefs, is_init)) = &self.output_to {
'init: { 'init: {
// assigns a new VData to the variable's Arc<Mutex<_>>, so that threads which have captured the variable at some point // // assigns a new VData to the variable's Arc<Mutex<_>>, so that threads which have captured the variable at some point
// won't be updated with its new value (is_init is set to true for initializations, such as in a loop - this can happen multiple times, but each should be its own variable with the same name) // // won't be updated with its new value (is_init is set to true for initializations, such as in a loop - this can happen multiple times, but each should be its own variable with the same name)
if *is_init && *derefs == 0 { // if *is_init && *derefs == 0 {
if let RStatementEnum::Variable(var, _, _) = v.statement.as_ref() { // Self::assign_to(out, v.run(info), info);
let mut varl = var.lock().unwrap(); // break 'init;
#[cfg(debug_assertions)] // }
let varname = varl.1.clone(); let mut val = v.run(info);
*varl = out; if !*is_init {
#[cfg(debug_assertions)] for _ in 0..(*derefs + 1) {
{ val = match val.deref() {
varl.1 = varname; Some(v) => v,
} None => unreachable!("can't dereference..."),
break 'init; };
} }
} }
let mut val = v.run(info); Self::assign_to(out, val, info);
for _ in 0..(*derefs + 1) { // val.assign(out);
val = match val.deref() {
Some(v) => v,
None => unreachable!("can't dereference..."),
};
}
val.assign(out);
} }
VDataEnum::Tuple(vec![]).to() VDataEnum::Tuple(vec![]).to()
} else { } else {

View File

@ -1,3 +1,4 @@
use core::panic;
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::{Debug, Display}, fmt::{Debug, Display},
@ -347,21 +348,39 @@ fn statement(
ginfo: &mut GlobalScriptInfo, ginfo: &mut GlobalScriptInfo,
linfo: &mut LInfo, linfo: &mut LInfo,
) -> Result<RStatement, ToRunnableError> { ) -> Result<RStatement, ToRunnableError> {
statement_adv(s, ginfo, linfo, None) statement_adv(s, ginfo, linfo, &mut None)
} }
fn statement_adv( fn statement_adv(
s: &SStatement, s: &SStatement,
ginfo: &mut GlobalScriptInfo, ginfo: &mut GlobalScriptInfo,
linfo: &mut LInfo, linfo: &mut LInfo,
// if Some((t, is_init)), the statement creates by this function is the left side of an assignment, meaning it can create variables. t is the type that will be assigned to it. // if Some((t, is_init)), the statement creates by this function is the left side of an assignment, meaning it can create variables. t is the type that will be assigned to it.
to_be_assigned_to: Option<(VType, &mut bool)>, to_be_assigned_to: &mut Option<(VType, &mut bool)>,
) -> Result<RStatement, ToRunnableError> { ) -> Result<RStatement, ToRunnableError> {
// eprintln!("TR : {}", s);
// if let Some(t) = &to_be_assigned_to {
// eprintln!(" --> {}", t.0);
// }
let mut state = match &*s.statement { let mut state = match &*s.statement {
SStatementEnum::Value(v) => RStatementEnum::Value(v.clone()), SStatementEnum::Value(v) => RStatementEnum::Value(v.clone()),
SStatementEnum::Tuple(v) | SStatementEnum::List(v) => { SStatementEnum::Tuple(v) | SStatementEnum::List(v) => {
let mut w = Vec::with_capacity(v.len()); let mut w = Vec::with_capacity(v.len());
for v in v { let mut prev = None;
w.push(statement(v, ginfo, linfo)?); for (i, v) in v.iter().enumerate() {
if let Some(t) = to_be_assigned_to {
let out_t = if let Some(p) = &prev { p } else { &t.0 };
let inner_t = if let Some(v) = out_t.get_always(i, ginfo) { v } else {
panic!("cannot assign: cannot get_always({i}) on type {}.", out_t);
};
let p = std::mem::replace(&mut t.0, inner_t);
if prev.is_none() {
prev = Some(p);
}
};
w.push(statement_adv(v, ginfo, linfo, to_be_assigned_to)?);
}
if let (Some(t), Some(prev)) = (to_be_assigned_to, prev) {
t.0 = prev;
} }
if let SStatementEnum::List(_) = &*s.statement { if let SStatementEnum::List(_) = &*s.statement {
RStatementEnum::List(w) RStatementEnum::List(w)
@ -376,7 +395,7 @@ fn statement_adv(
if is_init_force || (existing_var.is_none() && ginfo.to_runnable_automatic_initialization) { if is_init_force || (existing_var.is_none() && ginfo.to_runnable_automatic_initialization) {
// if to_be_assigned_to is some (-> this is on the left side of an assignment), create a new variable. else, return an error. // if to_be_assigned_to is some (-> this is on the left side of an assignment), create a new variable. else, return an error.
if let Some((t, is_init)) = to_be_assigned_to { if let Some((t, is_init)) = to_be_assigned_to {
*is_init = true; **is_init = true;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
let var = VData::new_placeholder(); let var = VData::new_placeholder();
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -385,7 +404,7 @@ fn statement_adv(
linfo.vars.insert(v.to_owned(), (Arc::clone(&var_arc), t.clone())); linfo.vars.insert(v.to_owned(), (Arc::clone(&var_arc), t.clone()));
RStatementEnum::Variable( RStatementEnum::Variable(
var_arc, var_arc,
t, t.clone(),
true, true,
) )
} else { } else {
@ -686,41 +705,46 @@ fn statement_adv(
opt, opt,
ginfo, ginfo,
linfo, linfo,
if *derefs == 0 { &mut if *derefs == 0 {
Some((state.out(ginfo), &mut is_init)) Some((state.out(ginfo), &mut is_init))
} else { } else {
None None
}, },
)?; )?;
let mut opt_type = optr.out(ginfo); if !is_init {
for _ in 0..*derefs { let mut opt_type = optr.out(ginfo);
if let Some(deref_type) = optr.out(ginfo).dereference() { for _ in 0..*derefs {
opt_type = deref_type; if let Some(deref_type) = optr.out(ginfo).dereference() {
opt_type = deref_type;
} else {
return Err(ToRunnableError::CannotDereferenceTypeNTimes(
optr.out(ginfo),
*derefs,
opt_type,
));
}
}
let opt_type_assign = match opt_type.dereference() {
Some(v) => v,
None => {
return Err(ToRunnableError::CannotDereferenceTypeNTimes(
optr.out(ginfo),
derefs + 1,
opt_type,
))
}
};
if state.out(ginfo).fits_in(&opt_type_assign, ginfo).is_empty() {
state.output_to = Some((Box::new(optr), *derefs, is_init));
} else { } else {
return Err(ToRunnableError::CannotDereferenceTypeNTimes( return Err(ToRunnableError::CannotAssignTo(
optr.out(ginfo), state.out(ginfo),
*derefs, opt_type_assign,
opt_type,
)); ));
} }
}
let opt_type_assign = match opt_type.dereference() {
Some(v) => v,
None => {
return Err(ToRunnableError::CannotDereferenceTypeNTimes(
optr.out(ginfo),
derefs + 1,
opt_type,
))
}
};
if state.out(ginfo).fits_in(&opt_type_assign, ginfo).is_empty() {
state.output_to = Some((Box::new(optr), *derefs, is_init));
} else { } else {
return Err(ToRunnableError::CannotAssignTo( // TODO! ??
state.out(ginfo), state.output_to = Some((Box::new(optr), *derefs, is_init));
opt_type_assign,
));
} }
// //
// if let Some((var_id, var_out)) = linfo.vars.get(opt) { // if let Some((var_id, var_out)) = linfo.vars.get(opt) {

View File

@ -34,7 +34,7 @@ pub enum VSingleType {
} }
impl VSingleType { impl VSingleType {
// None => Cannot get, Some(t) => getting can return t or nothing /// None => Cannot get, Some(t) => getting can return t or nothing
pub fn get(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> { pub fn get(&self, i: usize, gsinfo: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None, Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None,
@ -63,7 +63,7 @@ impl VSingleType {
} }
} }
} }
// None => might not always return t, Some(t) => can only return t /// None => might not always return t, Some(t) => can only return t
pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> { pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
match self { match self {
Self::Bool Self::Bool