added dereference syntax to go from &t to t by prefixing any statement with a *. for *x.f(), the * is applied to x, not the whole chain (like & would)

This commit is contained in:
mark 2023-05-27 19:20:28 +02:00
parent f43ab49408
commit d62a3f5aa8
5 changed files with 110 additions and 53 deletions

View File

@ -28,20 +28,17 @@ pub enum SStatementEnum {
} }
impl SStatementEnum { impl SStatementEnum {
pub fn to(self) -> SStatement { pub fn to(self) -> SStatement {
SStatement { SStatement::new(self)
output_to: None,
statement: Box::new(self),
force_output_type: None,
}
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct SStatement { pub struct SStatement {
pub derefs: usize,
/// if the statement is a Variable that doesn't exist yet, it will be initialized. /// 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 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. /// if the third value is true, the variable will always be initialized, shadowing previous mentions of the same name.
pub output_to: Option<(Box<SStatement>, usize, bool)>, pub output_to: Option<(Box<SStatement>, bool)>,
pub statement: Box<SStatementEnum>, pub statement: Box<SStatementEnum>,
pub force_output_type: Option<VType>, pub force_output_type: Option<VType>,
} }
@ -49,18 +46,19 @@ pub struct SStatement {
impl SStatement { impl SStatement {
pub fn new(statement: SStatementEnum) -> Self { pub fn new(statement: SStatementEnum) -> Self {
Self { Self {
derefs: 0,
output_to: None, output_to: None,
statement: Box::new(statement), statement: Box::new(statement),
force_output_type: None, force_output_type: None,
} }
} }
pub fn output_to(mut self, statement: SStatement, derefs: usize) -> Self { pub fn output_to(mut self, statement: SStatement) -> Self {
self.output_to = Some((Box::new(statement), derefs, false)); self.output_to = Some((Box::new(statement), false));
self self
} }
/// like output_to, but always initializes the variable (shadows previous variables of the same name) /// 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 { pub fn initialize_to(mut self, statement: SStatement) -> Self {
self.output_to = Some((Box::new(statement), derefs, true)); self.output_to = Some((Box::new(statement), true));
self self
} }
// forces the statement's output to fit in a certain type. // forces the statement's output to fit in a certain type.
@ -259,33 +257,21 @@ impl FormatGs for SStatement {
form: &mut super::fmtgs::FormatInfo, form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>, file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result { ) -> std::fmt::Result {
if let Some((opt, derefs, is_init)) = &self.output_to { // output output_to
// TODO! if let Some((opt, is_init)) = &self.output_to {
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!( write!(
f, f,
"{}{} {} ", "{} {} ",
"*".repeat(*derefs),
opt.with(info, file), opt.with(info, file),
if *is_init { ":=" } else { "=" } if *is_init { ":=" } else { "=" }
)?; )?;
} }
} // output self
}
if let Some(force_opt) = &self.force_output_type { if let Some(force_opt) = &self.force_output_type {
write!(f, " -> ")?; write!(f, " -> ")?;
force_opt.fmtgs(f, info, form, file)?; force_opt.fmtgs(f, info, form, file)?;
} }
write!(f, "{}", "*".repeat(self.derefs))?;
self.statement.fmtgs(f, info, form, file)?; self.statement.fmtgs(f, info, form, file)?;
write!(f, ",") write!(f, ",")
} }

View File

@ -1,5 +1,6 @@
use std::{ use std::{
eprintln, eprintln,
ops::Deref,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -104,14 +105,15 @@ impl RFunction {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RStatement { pub struct RStatement {
// (_, derefs, is_init) // (_, derefs, is_init)
pub output_to: Option<(Box<RStatement>, usize, bool)>, pub derefs: usize,
pub output_to: Option<(Box<RStatement>, bool)>,
statement: Box<RStatementEnum>, statement: Box<RStatementEnum>,
pub force_output_type: Option<VType>, pub force_output_type: Option<VType>,
} }
impl RStatement { impl RStatement {
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 { let mut o = if let Some((v, 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)
@ -120,21 +122,17 @@ impl RStatement {
// break 'init; // break 'init;
// } // }
let mut val = v.run(info); 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); out.assign_to(val, info);
// val.assign(out); // val.assign(out);
} }
VDataEnum::Tuple(vec![]).to() VDataEnum::Tuple(vec![]).to()
} else { } else {
out out
};
for _ in 0..self.derefs {
o = o.deref().expect("couldn't dereference! (run())");
} }
o
} }
pub fn out(&self, info: &GlobalScriptInfo) -> VType { pub fn out(&self, info: &GlobalScriptInfo) -> VType {
// `a = b` evaluates to [] // `a = b` evaluates to []
@ -146,7 +144,11 @@ impl RStatement {
if let Some(t) = &self.force_output_type { if let Some(t) = &self.force_output_type {
return t.clone(); 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 { pub fn to(self) -> RStatement {
RStatement { RStatement {
derefs: 0,
output_to: None, output_to: None,
statement: Box::new(self), statement: Box::new(self),
force_output_type: None, force_output_type: None,

View File

@ -659,6 +659,7 @@ fn statement_adv(
}, },
} }
.to(); .to();
state.derefs = s.derefs;
// if force_output_type is set, verify that the real output type actually fits in the forced one. // 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 { if let Some(force_opt) = &s.force_output_type {
let mut force_opt = force_opt.to_owned(); 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 })); 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 // if false, may be changed to true by statement_adv
let mut is_init = *is_init; let mut is_init = *is_init;
let optr = statement_adv( let optr = statement_adv(
opt, opt,
ginfo, ginfo,
linfo, linfo,
&mut if *derefs == 0 { &mut Some((state.out(ginfo), &mut is_init)),
Some((state.out(ginfo), &mut is_init))
} else {
None
},
)?; )?;
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) { // if let Some((var_id, var_out)) = linfo.vars.get(opt) {
// let out = state.out(ginfo); // let out = state.out(ginfo);

View File

@ -341,6 +341,31 @@ impl VSingleType {
vec![] vec![]
} }
} }
Self::Reference(r) => r.inner_types_ref(),
_ => vec![],
}
}
pub fn inner_types_ref(&self) -> Vec<VSingleType> {
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![], _ => vec![],
} }
} }

View File

@ -543,6 +543,20 @@ pub mod implementation {
) -> Result<SStatement, ParseError> { ) -> Result<SStatement, ParseError> {
file.skip_whitespaces(); file.skip_whitespaces();
let err_start_of_statement = *file.get_pos(); 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() { let out = match file.peek() {
Some('{') => Some(SStatementEnum::Block(parse_block(file)?).to()), Some('{') => Some(SStatementEnum::Block(parse_block(file)?).to()),
Some('[') => { Some('[') => {
@ -821,6 +835,7 @@ pub mod implementation {
} }
} }
}; };
out.derefs = derefs;
let err_end_of_original_statement = *file.get_pos(); let err_end_of_original_statement = *file.get_pos();
// special characters that can follow a statement (loop because these can be chained) // special characters that can follow a statement (loop because these can be chained)
loop { loop {
@ -890,7 +905,9 @@ pub mod implementation {
} }
} }
// 055 * / % // 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(); file.next();
SStatementEnum::FunctionCall( SStatementEnum::FunctionCall(
"mul".to_owned(), "mul".to_owned(),
@ -961,6 +978,35 @@ pub mod implementation {
) )
.to() .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 == != // 020 == !=
(0..=20, Some('=')) (0..=20, Some('='))
if matches!( if matches!(
@ -993,7 +1039,7 @@ pub mod implementation {
// 000 = := // 000 = :=
(0..=0, Some('=')) => { (0..=0, Some('=')) => {
file.next(); file.next();
parse_statement(file)?.output_to(out, 0) parse_statement(file)?.output_to(out)
} }
(0..=0, Some(':')) (0..=0, Some(':'))
if matches!( if matches!(
@ -1003,7 +1049,7 @@ pub mod implementation {
{ {
file.next(); file.next();
file.next(); file.next();
parse_statement(file)?.initialize_to(out, 0) parse_statement(file)?.initialize_to(out)
} }
_ => break, _ => break,
}; };