diff --git a/mers/src/lang/code_parsed.rs b/mers/src/lang/code_parsed.rs index ce0799a..00151bc 100755 --- a/mers/src/lang/code_parsed.rs +++ b/mers/src/lang/code_parsed.rs @@ -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, usize)>, pub statement: Box, pub force_output_type: Option, @@ -248,26 +249,24 @@ 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))?; - } + 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) } } diff --git a/mers/src/lang/code_runnable.rs b/mers/src/lang/code_runnable.rs index f3c3966..b848711 100755 --- a/mers/src/lang/code_runnable.rs +++ b/mers/src/lang/code_runnable.rs @@ -100,7 +100,7 @@ impl RFunction { #[derive(Clone, Debug)] pub struct RStatement { - // (_, _, is_init) + // (_, derefs, is_init) pub output_to: Option<(Box, usize, bool)>, statement: Box, pub force_output_type: Option, @@ -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>, 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(); diff --git a/mers/src/lang/to_runnable.rs b/mers/src/lang/to_runnable.rs index 0e906a6..435287a 100755 --- a/mers/src/lang/to_runnable.rs +++ b/mers/src/lang/to_runnable.rs @@ -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) => { diff --git a/mers/src/parsing/parse.rs b/mers/src/parsing/parse.rs index ff0a506..25fe848 100755 --- a/mers/src/parsing/parse.rs +++ b/mers/src/parsing/parse.rs @@ -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) }