mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
to_runnable treats assignment to a variable as initialization/declaration unless is_ref is true. if the variable doesn't exist yet, it will be created. for custom parser implementations, this means that making all variable assignments ones where is_ref is true will work just fine, but explicit declarations can be done by setting it to false if desired. always leaving it at false will repeatedly shadow the variable, so this isn't recommended although it does work.
This commit is contained in:
parent
1ec7296f50
commit
9d3a149648
@ -38,6 +38,7 @@ impl SStatementEnum {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SStatement {
|
||||
// if the statement is a Variable (is_ref == false) and it isn't dereferenced, it will be initialized. To modify a variable, it has to be is_ref.
|
||||
pub output_to: Option<(Box<SStatement>, usize)>,
|
||||
pub statement: Box<SStatementEnum>,
|
||||
pub force_output_type: Option<VType>,
|
||||
@ -248,25 +249,23 @@ impl FormatGs for SStatement {
|
||||
if let Some((opt, derefs)) = &self.output_to {
|
||||
// TODO!
|
||||
match opt.statement.as_ref() {
|
||||
SStatementEnum::Variable(name, is_ref) => {
|
||||
let derefs = if !is_ref { *derefs + 1 } else { *derefs };
|
||||
write!(
|
||||
f,
|
||||
"{}{} = ",
|
||||
"*".repeat(derefs),
|
||||
SStatementEnum::Variable(name.to_owned(), false).with(info, file)
|
||||
)?;
|
||||
}
|
||||
// SStatementEnum::Variable(name, is_ref) => {
|
||||
// let derefs = if !is_ref { *derefs + 1 } else { *derefs };
|
||||
// write!(
|
||||
// f,
|
||||
// "{}{} = ",
|
||||
// "*".repeat(derefs),
|
||||
// SStatementEnum::Variable(name.to_owned(), false).with(info, file)
|
||||
// )?;
|
||||
// }
|
||||
_ => {
|
||||
if let Some(forced_type) = &self.force_output_type {
|
||||
write!(f, "{}{}::", "*".repeat(*derefs), opt.with(info, file))?;
|
||||
forced_type.fmtgs(f, info, form, file)?;
|
||||
write!(f, " = ")?;
|
||||
} else {
|
||||
write!(f, "{}{} = ", "*".repeat(*derefs), opt.with(info, file))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(force_opt) = &self.force_output_type {
|
||||
write!(f, " -> ")?;
|
||||
force_opt.fmtgs(f, info, form, file)?;
|
||||
}
|
||||
self.statement.fmtgs(f, info, form, file)
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ impl RFunction {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RStatement {
|
||||
// (_, _, is_init)
|
||||
// (_, derefs, is_init)
|
||||
pub output_to: Option<(Box<RStatement>, usize, bool)>,
|
||||
statement: Box<RStatementEnum>,
|
||||
pub force_output_type: Option<VType>,
|
||||
@ -110,6 +110,8 @@ impl RStatement {
|
||||
let out = self.statement.run(info);
|
||||
if let Some((v, derefs, is_init)) = &self.output_to {
|
||||
'init: {
|
||||
// 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)
|
||||
if *is_init && *derefs == 0 {
|
||||
if let RStatementEnum::Variable(var, _, _) = v.statement.as_ref() {
|
||||
let mut varl = var.lock().unwrap();
|
||||
|
@ -370,17 +370,28 @@ fn statement_adv(
|
||||
}
|
||||
}
|
||||
SStatementEnum::Variable(v, is_ref) => {
|
||||
if !linfo.vars.contains_key(v) {
|
||||
let existing_var = linfo.vars.get(v);
|
||||
// we can't assign to something that isn't a reference, so create a new variable shadowing the old one.
|
||||
// we also can't assign to a variable that doesn't exist yet, so create a new one in that case, too.
|
||||
if (!*is_ref && to_be_assigned_to.is_some()) || existing_var.is_none() {
|
||||
// if to_be_assigned_to is some (-> this is on the left side of an assignment), create a new variable. else, return an error (later).
|
||||
if let Some((t, is_init)) = to_be_assigned_to {
|
||||
*is_init = true;
|
||||
#[cfg(not(debug_assertions))]
|
||||
let var = VData::new_placeholder();
|
||||
#[cfg(debug_assertions)]
|
||||
let var = VData::new_placeholder_with_name(v.to_owned());
|
||||
linfo.vars.insert(v.to_owned(), (Arc::new(Mutex::new(var)), t));
|
||||
let var_arc = Arc::new(Mutex::new(var));
|
||||
linfo.vars.insert(v.to_owned(), (Arc::clone(&var_arc), t.clone()));
|
||||
RStatementEnum::Variable(
|
||||
var_arc,
|
||||
t,
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
|
||||
}
|
||||
}
|
||||
if let Some(var) = linfo.vars.get(v) {
|
||||
} else if let Some(var) = existing_var {
|
||||
RStatementEnum::Variable(
|
||||
Arc::clone(&var.0),
|
||||
{
|
||||
@ -391,7 +402,7 @@ fn statement_adv(
|
||||
*is_ref
|
||||
)
|
||||
} else {
|
||||
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
SStatementEnum::FunctionCall(v, args) => {
|
||||
|
@ -1008,16 +1008,17 @@ pub mod implementation {
|
||||
// 000 =
|
||||
(0..=0, Some('=')) => {
|
||||
file.next();
|
||||
match out.statement.as_mut() {
|
||||
SStatementEnum::Variable(name, r) => {
|
||||
if name.starts_with("*") {
|
||||
*name = name[1..].to_owned();
|
||||
} else {
|
||||
*r = true
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// NOTE: Old code to change `x = 10` to `&x = 10`
|
||||
// match out.statement.as_mut() {
|
||||
// SStatementEnum::Variable(name, r) => {
|
||||
// if name.starts_with("*") {
|
||||
// *name = name[1..].to_owned();
|
||||
// } else {
|
||||
// *r = true
|
||||
// }
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
// NOTE: Set this 0 to 1 to prevent a = b = c from being valid
|
||||
parse_statement(file)?.output_to(out, 0)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user