mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
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:
parent
f43ab49408
commit
d62a3f5aa8
@ -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, ",")
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user