mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 22:37:46 +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 {
|
match nchar {
|
||||||
Some('=') => {
|
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(':') => {
|
Some(':') => {
|
||||||
return Ok(SStatement::new(SStatementEnum::EnumVariant(
|
return Ok(SStatement::new(SStatementEnum::EnumVariant(
|
||||||
@ -671,7 +673,7 @@ fn parse_statement_adv(
|
|||||||
file.skip_whitespaces();
|
file.skip_whitespaces();
|
||||||
if !file[file.get_pos().current_char_index..].starts_with("..") {
|
if !file[file.get_pos().current_char_index..].starts_with("..") {
|
||||||
// dot chain syntax only works if there is only one dot
|
// 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)
|
// consume the dot (otherwise, a.b.c syntax will break in certain cases)
|
||||||
file.next();
|
file.next();
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ impl SFunction {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SStatement {
|
pub struct SStatement {
|
||||||
pub output_to: Option<String>,
|
pub output_to: Option<(String, usize)>,
|
||||||
pub statement: Box<SStatementEnum>,
|
pub statement: Box<SStatementEnum>,
|
||||||
}
|
}
|
||||||
impl SStatement {
|
impl SStatement {
|
||||||
@ -51,8 +51,8 @@ impl SStatement {
|
|||||||
statement: Box::new(statement),
|
statement: Box::new(statement),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn output_to(mut self, var: String) -> Self {
|
pub fn output_to(mut self, var: String, derefs: usize) -> Self {
|
||||||
self.output_to = Some(var);
|
self.output_to = Some((var, derefs));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,6 +112,8 @@ pub mod to_runnable {
|
|||||||
MainWrongInput,
|
MainWrongInput,
|
||||||
UseOfUndefinedVariable(String),
|
UseOfUndefinedVariable(String),
|
||||||
UseOfUndefinedFunction(String),
|
UseOfUndefinedFunction(String),
|
||||||
|
CannotDeclareVariableWithDereference(String),
|
||||||
|
CannotDereferenceTypeNTimes(VType, usize, VType),
|
||||||
FunctionWrongArgCount(String, usize, usize),
|
FunctionWrongArgCount(String, usize, usize),
|
||||||
InvalidType {
|
InvalidType {
|
||||||
expected: VType,
|
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::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::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::FunctionWrongArgCount(v, a, b) => write!(f, "Tried to call function \"{v}\", which takes {a} arguments, with {b} arguments instead."),
|
||||||
Self::InvalidType {
|
Self::InvalidType {
|
||||||
expected,
|
expected,
|
||||||
@ -634,25 +640,45 @@ pub mod to_runnable {
|
|||||||
}, statement(s, ginfo, linfo)?),
|
}, statement(s, ginfo, linfo)?),
|
||||||
}
|
}
|
||||||
.to();
|
.to();
|
||||||
if let Some(opt) = &s.output_to {
|
if let Some((opt, derefs)) = &s.output_to {
|
||||||
if let Some(var) = linfo.vars.get(opt) {
|
if let Some((var_id, var_out)) = linfo.vars.get(opt) {
|
||||||
let out = statement.out();
|
let out = statement.out();
|
||||||
let var_id = var.0;
|
let mut var_derefd = var_out.clone();
|
||||||
let var_out = &var.1;
|
for _ in 0..*derefs {
|
||||||
let inv_types = out.fits_in(&var_out);
|
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() {
|
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.");
|
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));
|
linfo.vars.insert(opt.clone(), (ginfo.vars, out));
|
||||||
statement.output_to = Some(ginfo.vars);
|
statement.output_to = Some((ginfo.vars, 0));
|
||||||
ginfo.vars += 1;
|
ginfo.vars += 1;
|
||||||
} else {
|
} else {
|
||||||
statement.output_to = Some(var_id);
|
// mutate existing variable
|
||||||
|
statement.output_to = Some((*var_id, *derefs));
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
linfo
|
||||||
.vars
|
.vars
|
||||||
.insert(opt.clone(), (ginfo.vars, statement.out()));
|
.insert(opt.clone(), (ginfo.vars, out));
|
||||||
statement.output_to = Some(ginfo.vars);
|
statement.output_to = Some((ginfo.vars, *derefs));
|
||||||
ginfo.vars += 1;
|
ginfo.vars += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -735,14 +761,23 @@ impl RFunction {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RStatement {
|
pub struct RStatement {
|
||||||
output_to: Option<usize>,
|
output_to: Option<(usize, usize)>,
|
||||||
statement: Box<RStatementEnum>,
|
statement: Box<RStatementEnum>,
|
||||||
}
|
}
|
||||||
impl RStatement {
|
impl RStatement {
|
||||||
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
pub fn run(&self, vars: &Vec<Am<VData>>, libs: &Arc<Vec<libs::Lib>>) -> VData {
|
||||||
let out = self.statement.run(vars, libs);
|
let out = self.statement.run(vars, libs);
|
||||||
if let Some(v) = self.output_to {
|
if let Some((v, derefs)) = self.output_to {
|
||||||
*vars[v].lock().unwrap() = out;
|
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()
|
VDataEnum::Tuple(vec![]).to()
|
||||||
} else {
|
} else {
|
||||||
out
|
out
|
||||||
@ -1105,7 +1140,7 @@ impl Display for VSingleType {
|
|||||||
impl Display for SStatement {
|
impl Display for SStatement {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if let Some(to) = self.output_to.as_ref() {
|
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)
|
write!(f, "{}", self.statement)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ impl VSingleType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl VType {
|
impl VType {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self { types: vec![] }
|
||||||
|
}
|
||||||
pub fn get(&self, i: usize) -> Option<VType> {
|
pub fn get(&self, i: usize) -> Option<VType> {
|
||||||
let mut out = VType { types: vec![] };
|
let mut out = VType { types: vec![] };
|
||||||
for t in &self.types {
|
for t in &self.types {
|
||||||
@ -59,6 +62,13 @@ impl VType {
|
|||||||
None
|
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 {
|
impl VSingleType {
|
||||||
@ -79,6 +89,13 @@ impl VSingleType {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn deref(&self) -> Option<VSingleType> {
|
||||||
|
if let Self::Reference(v) = self {
|
||||||
|
Some(*v.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl VType {
|
impl VType {
|
||||||
pub fn get_any(&self) -> Option<VType> {
|
pub fn get_any(&self) -> Option<VType> {
|
||||||
|
Loading…
Reference in New Issue
Block a user