diff --git a/mers/src/lang/code_parsed.rs b/mers/src/lang/code_parsed.rs index 18057d5..c662f62 100755 --- a/mers/src/lang/code_parsed.rs +++ b/mers/src/lang/code_parsed.rs @@ -28,20 +28,17 @@ pub enum SStatementEnum { } impl SStatementEnum { pub fn to(self) -> SStatement { - SStatement { - output_to: None, - statement: Box::new(self), - force_output_type: None, - } + SStatement::new(self) } } #[derive(Debug)] pub struct SStatement { + pub derefs: usize, /// if the statement is a Variable that doesn't exist yet, it will be initialized. /// if it's a variable that exists, but is_ref is false, an error may show up: cannot dereference /// if the third value is true, the variable will always be initialized, shadowing previous mentions of the same name. - pub output_to: Option<(Box, usize, bool)>, + pub output_to: Option<(Box, bool)>, pub statement: Box, pub force_output_type: Option, } @@ -49,18 +46,19 @@ pub struct SStatement { impl SStatement { pub fn new(statement: SStatementEnum) -> Self { Self { + derefs: 0, output_to: None, statement: Box::new(statement), force_output_type: None, } } - pub fn output_to(mut self, statement: SStatement, derefs: usize) -> Self { - self.output_to = Some((Box::new(statement), derefs, false)); + pub fn output_to(mut self, statement: SStatement) -> Self { + self.output_to = Some((Box::new(statement), false)); self } /// like output_to, but always initializes the variable (shadows previous variables of the same name) - pub fn initialize_to(mut self, statement: SStatement, derefs: usize) -> Self { - self.output_to = Some((Box::new(statement), derefs, true)); + pub fn initialize_to(mut self, statement: SStatement) -> Self { + self.output_to = Some((Box::new(statement), true)); self } // forces the statement's output to fit in a certain type. @@ -259,33 +257,21 @@ impl FormatGs for SStatement { form: &mut super::fmtgs::FormatInfo, file: Option<&crate::parsing::file::File>, ) -> std::fmt::Result { - if let Some((opt, derefs, is_init)) = &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) - // )?; - // } - _ => { - write!( - f, - "{}{} {} ", - "*".repeat(*derefs), - opt.with(info, file), - if *is_init { ":=" } else { "=" } - )?; - } - } + // output output_to + if let Some((opt, is_init)) = &self.output_to { + write!( + f, + "{} {} ", + opt.with(info, file), + if *is_init { ":=" } else { "=" } + )?; } + // output self if let Some(force_opt) = &self.force_output_type { write!(f, " -> ")?; force_opt.fmtgs(f, info, form, file)?; } + write!(f, "{}", "*".repeat(self.derefs))?; self.statement.fmtgs(f, info, form, file)?; write!(f, ",") } diff --git a/mers/src/lang/code_runnable.rs b/mers/src/lang/code_runnable.rs index 7a864e6..6f0a484 100755 --- a/mers/src/lang/code_runnable.rs +++ b/mers/src/lang/code_runnable.rs @@ -1,5 +1,6 @@ use std::{ eprintln, + ops::Deref, sync::{Arc, Mutex}, }; @@ -104,14 +105,15 @@ impl RFunction { #[derive(Clone, Debug)] pub struct RStatement { // (_, derefs, is_init) - pub output_to: Option<(Box, usize, bool)>, + pub derefs: usize, + pub output_to: Option<(Box, bool)>, statement: Box, pub force_output_type: Option, } impl RStatement { pub fn run(&self, info: &GSInfo) -> VData { let out = self.statement.run(info); - if let Some((v, derefs, is_init)) = &self.output_to { + let mut o = if let Some((v, 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) @@ -120,21 +122,17 @@ impl RStatement { // break 'init; // } let mut val = v.run(info); - if !*is_init { - for _ in 0..*derefs { - val = match val.deref() { - Some(v) => v, - None => unreachable!("can't dereference..."), - }; - } - } out.assign_to(val, info); // val.assign(out); } VDataEnum::Tuple(vec![]).to() } else { out + }; + for _ in 0..self.derefs { + o = o.deref().expect("couldn't dereference! (run())"); } + o } pub fn out(&self, info: &GlobalScriptInfo) -> VType { // `a = b` evaluates to [] @@ -146,7 +144,11 @@ impl RStatement { if let Some(t) = &self.force_output_type { return t.clone(); } - self.statement.out(info) + let mut o = self.statement.out(info); + for _ in 0..self.derefs { + o = o.dereference().expect("can't dereference (out())"); + } + o } } @@ -370,6 +372,7 @@ impl RStatementEnum { } pub fn to(self) -> RStatement { RStatement { + derefs: 0, output_to: None, statement: Box::new(self), force_output_type: None, diff --git a/mers/src/lang/to_runnable.rs b/mers/src/lang/to_runnable.rs index 527db94..e8faa5f 100755 --- a/mers/src/lang/to_runnable.rs +++ b/mers/src/lang/to_runnable.rs @@ -659,6 +659,7 @@ fn statement_adv( }, } .to(); + state.derefs = s.derefs; // if force_output_type is set, verify that the real output type actually fits in the forced one. if let Some(force_opt) = &s.force_output_type { let mut force_opt = force_opt.to_owned(); @@ -671,20 +672,16 @@ fn statement_adv( return Err(ToRunnableError::StatementRequiresOutputTypeToBeAButItActuallyOutputsBWhichDoesNotFitInA(force_opt.clone(), real_output_type, VType { types: problematic_types })); } } - if let Some((opt, derefs, is_init)) = &s.output_to { + if let Some((opt, is_init)) = &s.output_to { // if false, may be changed to true by statement_adv let mut is_init = *is_init; let optr = statement_adv( opt, ginfo, linfo, - &mut if *derefs == 0 { - Some((state.out(ginfo), &mut is_init)) - } else { - None - }, + &mut Some((state.out(ginfo), &mut is_init)), )?; - state.output_to = Some((Box::new(optr), *derefs, is_init)); + state.output_to = Some((Box::new(optr), is_init)); // // if let Some((var_id, var_out)) = linfo.vars.get(opt) { // let out = state.out(ginfo); diff --git a/mers/src/lang/val_type.rs b/mers/src/lang/val_type.rs index 5fe8fe9..c1020ab 100755 --- a/mers/src/lang/val_type.rs +++ b/mers/src/lang/val_type.rs @@ -341,6 +341,31 @@ impl VSingleType { vec![] } } + Self::Reference(r) => r.inner_types_ref(), + _ => vec![], + } + } + pub fn inner_types_ref(&self) -> Vec { + match self { + Self::Tuple(v) => { + let mut types = vec![]; + for it in v { + // the tuple values + for it in &it.types { + // the possible types for each value + if !types.contains(it) { + types.push(Self::Reference(Box::new(it.clone()))); + } + } + } + types + } + Self::List(v) => v + .types + .iter() + .map(|v| Self::Reference(Box::new(v.clone()))) + .collect(), + Self::Reference(r) => r.inner_types_ref(), _ => vec![], } } diff --git a/mers/src/parsing/parse.rs b/mers/src/parsing/parse.rs index 8cc4b0d..a38d1d6 100755 --- a/mers/src/parsing/parse.rs +++ b/mers/src/parsing/parse.rs @@ -543,6 +543,20 @@ pub mod implementation { ) -> Result { file.skip_whitespaces(); let err_start_of_statement = *file.get_pos(); + let mut derefs = 0; + loop { + if let Some('*') = file.peek() { + derefs += 1; + file.next(); + } else { + break; + } + } + if let Some(ch) = file.peek() { + if ch.is_whitespace() { + file.set_pos(err_start_of_statement); + } + } let out = match file.peek() { Some('{') => Some(SStatementEnum::Block(parse_block(file)?).to()), Some('[') => { @@ -821,6 +835,7 @@ pub mod implementation { } } }; + out.derefs = derefs; let err_end_of_original_statement = *file.get_pos(); // special characters that can follow a statement (loop because these can be chained) loop { @@ -890,7 +905,9 @@ pub mod implementation { } } // 055 * / % - (0..=55, Some('*')) => { + (0..=55, Some('*')) if matches!(file.get_char(file.get_pos().current_char_index + 1), Some(ch) if ch.is_whitespace()) => + { + // * must be followed by whitespace because it's also used for dereferencing file.next(); SStatementEnum::FunctionCall( "mul".to_owned(), @@ -961,6 +978,35 @@ pub mod implementation { ) .to() } + // 023 && || + (0..=23, Some('&')) + if matches!( + file.get_char(file.get_pos().current_char_index + 1), + Some('&') + ) => + { + file.next(); + file.next(); + SStatementEnum::FunctionCall( + "and".to_owned(), + vec![out, parse_statement_adv(file, false, 24)?], + ) + .to() + } + (0..=23, Some('|')) + if matches!( + file.get_char(file.get_pos().current_char_index + 1), + Some('|') + ) => + { + file.next(); + file.next(); + SStatementEnum::FunctionCall( + "or".to_owned(), + vec![out, parse_statement_adv(file, false, 24)?], + ) + .to() + } // 020 == != (0..=20, Some('=')) if matches!( @@ -993,7 +1039,7 @@ pub mod implementation { // 000 = := (0..=0, Some('=')) => { file.next(); - parse_statement(file)?.output_to(out, 0) + parse_statement(file)?.output_to(out) } (0..=0, Some(':')) if matches!( @@ -1003,7 +1049,7 @@ pub mod implementation { { file.next(); file.next(); - parse_statement(file)?.initialize_to(out, 0) + parse_statement(file)?.initialize_to(out) } _ => break, };