mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
added dereferences to assignments: x = 1 y = &x *y = 2 x.debug()
will print 2 because we changed x through the reference.
This commit is contained in:
parent
ed8aecde86
commit
14d004d848
@ -459,7 +459,9 @@ fn parse_statement_adv(
|
||||
};
|
||||
match nchar {
|
||||
Some('=') => {
|
||||
break parse_statement(file)?.output_to(start.trim().to_string());
|
||||
let start = start.trim();
|
||||
let derefs = start.chars().take_while(|c| *c == '*').count();
|
||||
break parse_statement(file)?.output_to(start[derefs..].to_owned(), derefs);
|
||||
}
|
||||
Some(':') => {
|
||||
return Ok(SStatement::new(SStatementEnum::EnumVariant(
|
||||
@ -671,7 +673,7 @@ fn parse_statement_adv(
|
||||
file.skip_whitespaces();
|
||||
if !file[file.get_pos().current_char_index..].starts_with("..") {
|
||||
// dot chain syntax only works if there is only one dot
|
||||
if let Some('.') = file.get_char(file.get_pos().current_char_index) {
|
||||
if let Some('.') = file.peek() {
|
||||
// consume the dot (otherwise, a.b.c syntax will break in certain cases)
|
||||
file.next();
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ impl SFunction {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SStatement {
|
||||
pub output_to: Option<String>,
|
||||
pub output_to: Option<(String, usize)>,
|
||||
pub statement: Box<SStatementEnum>,
|
||||
}
|
||||
impl SStatement {
|
||||
@ -51,8 +51,8 @@ impl SStatement {
|
||||
statement: Box::new(statement),
|
||||
}
|
||||
}
|
||||
pub fn output_to(mut self, var: String) -> Self {
|
||||
self.output_to = Some(var);
|
||||
pub fn output_to(mut self, var: String, derefs: usize) -> Self {
|
||||
self.output_to = Some((var, derefs));
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -112,6 +112,8 @@ pub mod to_runnable {
|
||||
MainWrongInput,
|
||||
UseOfUndefinedVariable(String),
|
||||
UseOfUndefinedFunction(String),
|
||||
CannotDeclareVariableWithDereference(String),
|
||||
CannotDereferenceTypeNTimes(VType, usize, VType),
|
||||
FunctionWrongArgCount(String, usize, usize),
|
||||
InvalidType {
|
||||
expected: VType,
|
||||
@ -139,6 +141,10 @@ pub mod to_runnable {
|
||||
),
|
||||
Self::UseOfUndefinedVariable(v) => write!(f, "Cannot use variable \"{v}\" as it isn't defined (yet?)."),
|
||||
Self::UseOfUndefinedFunction(v) => write!(f, "Cannot use function \"{v}\" as it isn't defined (yet?)."),
|
||||
Self::CannotDeclareVariableWithDereference(v) => write!(f, "Cannot declare a variable and dereference it (variable '{v}')."),
|
||||
Self::CannotDereferenceTypeNTimes(og_type, derefs_wanted, last_valid_type) => write!(f,
|
||||
"Cannot dereference type {og_type} {derefs_wanted} times (stopped at {last_valid_type})."
|
||||
),
|
||||
Self::FunctionWrongArgCount(v, a, b) => write!(f, "Tried to call function \"{v}\", which takes {a} arguments, with {b} arguments instead."),
|
||||
Self::InvalidType {
|
||||
expected,
|
||||
@ -634,25 +640,45 @@ pub mod to_runnable {
|
||||
}, statement(s, ginfo, linfo)?),
|
||||
}
|
||||
.to();
|
||||
if let Some(opt) = &s.output_to {
|
||||
if let Some(var) = linfo.vars.get(opt) {
|
||||
if let Some((opt, derefs)) = &s.output_to {
|
||||
if let Some((var_id, var_out)) = linfo.vars.get(opt) {
|
||||
let out = statement.out();
|
||||
let var_id = var.0;
|
||||
let var_out = &var.1;
|
||||
let inv_types = out.fits_in(&var_out);
|
||||
let mut var_derefd = var_out.clone();
|
||||
for _ in 0..*derefs {
|
||||
var_derefd = if let Some(v) = var_derefd.dereference() {
|
||||
v
|
||||
} else {
|
||||
return Err(ToRunnableError::CannotDereferenceTypeNTimes(var_out.clone(), *derefs, var_derefd));
|
||||
}
|
||||
}
|
||||
let inv_types = out.fits_in(&var_derefd);
|
||||
if !inv_types.is_empty() {
|
||||
eprintln!("Warn: shadowing variable {opt} because statement's output type {out} does not fit in the original variable's {var_out}. This might become an error in the future, or it might stop shadowing the variiable entirely - for stable scripts, avoid this by giving the variable a different name.");
|
||||
if *derefs != 0 {
|
||||
return Err(ToRunnableError::CannotDeclareVariableWithDereference(
|
||||
opt.clone(),
|
||||
));
|
||||
}
|
||||
linfo.vars.insert(opt.clone(), (ginfo.vars, out));
|
||||
statement.output_to = Some(ginfo.vars);
|
||||
statement.output_to = Some((ginfo.vars, 0));
|
||||
ginfo.vars += 1;
|
||||
} else {
|
||||
statement.output_to = Some(var_id);
|
||||
// mutate existing variable
|
||||
statement.output_to = Some((*var_id, *derefs));
|
||||
}
|
||||
} else {
|
||||
let mut out = statement.out();
|
||||
for _ in 0..*derefs {
|
||||
out = if let Some(v) = out.dereference() {
|
||||
v
|
||||
} else {
|
||||
return Err(ToRunnableError::CannotDereferenceTypeNTimes(statement.out(), *derefs, out));
|
||||
}
|
||||
}
|
||||
linfo
|
||||
.vars
|
||||
.insert(opt.clone(), (ginfo.vars, statement.out()));
|
||||
statement.output_to = Some(ginfo.vars);
|
||||
.insert(opt.clone(), (ginfo.vars, out));
|
||||
statement.output_to = Some((ginfo.vars, *derefs));
|
||||
ginfo.vars += 1;
|
||||
}
|
||||
}
|
||||
@ -735,14 +761,23 @@ impl RFunction {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RStatement {
|
||||
output_to: Option<usize>,
|
||||
output_to: Option<(usize, usize)>,
|
||||
statement: Box<RStatementEnum>,
|
||||
}
|
||||
impl RStatement {
|
||||
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
||||
let out = self.statement.run(vars, libs);
|
||||
if let Some(v) = self.output_to {
|
||||
*vars[v].lock().unwrap() = out;
|
||||
if let Some((v, derefs)) = self.output_to {
|
||||
let mut val = vars[v].clone();
|
||||
for _ in 0..derefs {
|
||||
let v = if let VDataEnum::Reference(v) = &val.lock().unwrap().data {
|
||||
v.clone()
|
||||
} else {
|
||||
unreachable!("dereferencing something that isn't a reference in assignment")
|
||||
};
|
||||
val = v;
|
||||
}
|
||||
*val.lock().unwrap() = out;
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
out
|
||||
@ -1105,7 +1140,7 @@ impl Display for VSingleType {
|
||||
impl Display for SStatement {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(to) = self.output_to.as_ref() {
|
||||
write!(f, "{} = ", to.as_str())?;
|
||||
write!(f, "{}{} = ", "*".repeat(to.1), to.0.as_str())?;
|
||||
}
|
||||
write!(f, "{}", self.statement)
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ impl VSingleType {
|
||||
}
|
||||
}
|
||||
impl VType {
|
||||
pub fn empty() -> Self {
|
||||
Self { types: vec![] }
|
||||
}
|
||||
pub fn get(&self, i: usize) -> Option<VType> {
|
||||
let mut out = VType { types: vec![] };
|
||||
for t in &self.types {
|
||||
@ -59,6 +62,13 @@ impl VType {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn dereference(&self) -> Option<Self> {
|
||||
let mut out = Self::empty();
|
||||
for t in self.types.iter() {
|
||||
out = out | t.deref()?.to();
|
||||
}
|
||||
Some(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl VSingleType {
|
||||
@ -79,6 +89,13 @@ impl VSingleType {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
pub fn deref(&self) -> Option<VSingleType> {
|
||||
if let Self::Reference(v) = self {
|
||||
Some(*v.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
impl VType {
|
||||
pub fn get_any(&self) -> Option<VType> {
|
||||
|
Loading…
Reference in New Issue
Block a user