mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
added destructuring assignments for tuples (and lists on the left)
This commit is contained in:
parent
3f76e4f549
commit
be9403d63d
12
examples/destructuring_assignment.mers
Normal file
12
examples/destructuring_assignment.mers
Normal 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, ...]) {
|
||||||
|
// }
|
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user