mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
revamped switch and match syntax
This commit is contained in:
parent
be9403d63d
commit
45f6f30de3
@ -4,14 +4,14 @@ text := "ℑ𝔠𝔥 𝔨𝔞𝔫𝔫 𝔡𝔞𝔰 𝔳𝔢𝔯𝔡𝔞𝔪𝔪
|
|||||||
fn random(min int max int) {
|
fn random(min int max int) {
|
||||||
res := run_command("fish" ["-c" "random " + min.to_string() + " " + max.to_string() ...])
|
res := run_command("fish" ["-c" "random " + min.to_string() + " " + max.to_string() ...])
|
||||||
switch res {
|
switch res {
|
||||||
[[]/int string string] res.1.trim().parse_int().assume1()
|
[[]/int string string] res res.1.trim().parse_int().assume1()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn rnd() {
|
fn rnd() {
|
||||||
r := random(5 15)
|
r := random(5 15)
|
||||||
switch r {
|
switch r {
|
||||||
int r
|
int r r
|
||||||
[] 10
|
[] [] 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ fn print_linked_list(start elem) {
|
|||||||
println(start.0.to_string())
|
println(start.0.to_string())
|
||||||
elem := start.1
|
elem := start.1
|
||||||
switch! elem {
|
switch! elem {
|
||||||
[] {
|
[] elem {
|
||||||
println("[END]")
|
println("[END]")
|
||||||
true // break
|
true // break
|
||||||
}
|
}
|
||||||
elem &start = elem // continue
|
elem elem &start = elem // continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[]
|
[]
|
||||||
|
@ -7,11 +7,11 @@ fn map_string_to_int(list [string ...] func fn((string int))) {
|
|||||||
elem := &list.remove(0)
|
elem := &list.remove(0)
|
||||||
switch! elem {
|
switch! elem {
|
||||||
// if the element was present, run the map function to convert it from a string to an int and return the result
|
// if the element was present, run the map function to convert it from a string to an int and return the result
|
||||||
[string] {
|
[string] [elem] {
|
||||||
[func.run(elem.0)]
|
[func.run(elem)]
|
||||||
}
|
}
|
||||||
// if there are no more elements, return something that doesn't match.
|
// if there are no more elements, return something that doesn't match.
|
||||||
[] []
|
[] [] []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
examples/switch_match.mers
Normal file
19
examples/switch_match.mers
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
x := if true [10 "my text"] else 10
|
||||||
|
|
||||||
|
switch! x {
|
||||||
|
[int string] [num text] {
|
||||||
|
num.debug()
|
||||||
|
text.debug()
|
||||||
|
}
|
||||||
|
int num {
|
||||||
|
println("number:")
|
||||||
|
num.debug()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text := "12.5"
|
||||||
|
match {
|
||||||
|
parse_int(text) num println("int: " + num.to_string())
|
||||||
|
parse_float(text) num println("float: " + num.to_string())
|
||||||
|
true [] println("not a number: " + text)
|
||||||
|
}
|
@ -18,9 +18,9 @@ pub enum SStatementEnum {
|
|||||||
Block(SBlock),
|
Block(SBlock),
|
||||||
If(SStatement, SStatement, Option<SStatement>),
|
If(SStatement, SStatement, Option<SStatement>),
|
||||||
Loop(SStatement),
|
Loop(SStatement),
|
||||||
For(String, SStatement, SStatement),
|
For(SStatement, SStatement, SStatement),
|
||||||
Switch(String, Vec<(VType, SStatement)>, bool),
|
Switch(SStatement, Vec<(VType, SStatement, SStatement)>, bool),
|
||||||
Match(String, Vec<(SStatement, SStatement)>),
|
Match(Vec<(SStatement, SStatement, SStatement)>),
|
||||||
IndexFixed(SStatement, usize),
|
IndexFixed(SStatement, usize),
|
||||||
EnumVariant(String, SStatement),
|
EnumVariant(String, SStatement),
|
||||||
TypeDefinition(String, VType),
|
TypeDefinition(String, VType),
|
||||||
@ -171,8 +171,10 @@ impl FormatGs for SStatementEnum {
|
|||||||
write!(f, "{} ", form.loop_loop(info, "loop".to_owned()))?;
|
write!(f, "{} ", form.loop_loop(info, "loop".to_owned()))?;
|
||||||
b.fmtgs(f, info, form, file)
|
b.fmtgs(f, info, form, file)
|
||||||
}
|
}
|
||||||
Self::For(var, i, b) => {
|
Self::For(assign_to, i, b) => {
|
||||||
write!(f, "{} {} ", form.loop_for(info, "for".to_owned()), var)?;
|
write!(f, "{} ", form.loop_for(info, "for".to_owned()))?;
|
||||||
|
assign_to.fmtgs(f, info, form, file)?;
|
||||||
|
write!(f, " ")?;
|
||||||
i.fmtgs(f, info, form, file)?;
|
i.fmtgs(f, info, form, file)?;
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
b.fmtgs(f, info, form, file)
|
b.fmtgs(f, info, form, file)
|
||||||
@ -194,10 +196,12 @@ impl FormatGs for SStatementEnum {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
form.go_deeper();
|
form.go_deeper();
|
||||||
for (t, action) in arms {
|
for (t, assign_to, action) in arms {
|
||||||
write!(f, "{}", form.line_prefix())?;
|
write!(f, "{}", form.line_prefix())?;
|
||||||
t.fmtgs(f, info, form, file)?;
|
t.fmtgs(f, info, form, file)?;
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
|
assign_to.fmtgs(f, info, form, file)?;
|
||||||
|
write!(f, " ")?;
|
||||||
action.fmtgs(f, info, form, file)?;
|
action.fmtgs(f, info, form, file)?;
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
@ -205,18 +209,20 @@ impl FormatGs for SStatementEnum {
|
|||||||
write!(f, "{}", form.line_prefix())?;
|
write!(f, "{}", form.line_prefix())?;
|
||||||
write!(f, "{}", form.close_bracket(info, "}".to_owned()))
|
write!(f, "{}", form.close_bracket(info, "}".to_owned()))
|
||||||
}
|
}
|
||||||
Self::Match(var, arms) => {
|
Self::Match(arms) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{} {var} {}",
|
"{} {}",
|
||||||
form.kw_match(info, "match".to_owned()),
|
form.kw_match(info, "match".to_owned()),
|
||||||
form.open_bracket(info, "{".to_owned())
|
form.open_bracket(info, "{".to_owned())
|
||||||
)?;
|
)?;
|
||||||
form.go_deeper();
|
form.go_deeper();
|
||||||
for (condition, action) in arms {
|
for (condition, assign_to, action) in arms {
|
||||||
write!(f, "{}", form.line_prefix())?;
|
write!(f, "{}", form.line_prefix())?;
|
||||||
condition.fmtgs(f, info, form, file)?;
|
condition.fmtgs(f, info, form, file)?;
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
|
assign_to.fmtgs(f, info, form, file)?;
|
||||||
|
write!(f, " ")?;
|
||||||
action.fmtgs(f, info, form, file)?;
|
action.fmtgs(f, info, form, file)?;
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,9 @@ pub enum RStatementEnum {
|
|||||||
Block(RBlock),
|
Block(RBlock),
|
||||||
If(RStatement, RStatement, Option<RStatement>),
|
If(RStatement, RStatement, Option<RStatement>),
|
||||||
Loop(RStatement),
|
Loop(RStatement),
|
||||||
For(Arc<Mutex<VData>>, RStatement, RStatement),
|
For(RStatement, RStatement, RStatement),
|
||||||
Switch(RStatement, Vec<(VType, RStatement)>),
|
Switch(RStatement, Vec<(VType, RStatement, RStatement)>, bool),
|
||||||
Match(Arc<Mutex<VData>>, Vec<(RStatement, RStatement)>),
|
Match(Vec<(RStatement, RStatement, RStatement)>),
|
||||||
IndexFixed(RStatement, usize),
|
IndexFixed(RStatement, usize),
|
||||||
EnumVariant(usize, RStatement),
|
EnumVariant(usize, RStatement),
|
||||||
}
|
}
|
||||||
@ -109,24 +109,6 @@ pub struct RStatement {
|
|||||||
pub force_output_type: Option<VType>,
|
pub force_output_type: Option<VType>,
|
||||||
}
|
}
|
||||||
impl RStatement {
|
impl RStatement {
|
||||||
fn assign_to(assign_from: VData, mut assign_to: VData, info: &GSInfo) {
|
|
||||||
eprintln!("Assigning: '{assign_from}'.");
|
|
||||||
assign_to.operate_on_data_mut(|assign_to| match assign_to {
|
|
||||||
VDataEnum::Tuple(v) | VDataEnum::List(_, v) => {
|
|
||||||
for (i, v) in v.iter().enumerate() {
|
|
||||||
Self::assign_to(
|
|
||||||
assign_from.get(i).expect(
|
|
||||||
"tried to assign to tuple, but value didn't return Some(_) on get()",
|
|
||||||
),
|
|
||||||
v.clone_data(),
|
|
||||||
info,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VDataEnum::Reference(r) => r.assign(assign_from),
|
|
||||||
o => todo!("ERR: Cannot assign to {o}."),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
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 {
|
if let Some((v, derefs, is_init)) = &self.output_to {
|
||||||
@ -139,14 +121,14 @@ impl RStatement {
|
|||||||
// }
|
// }
|
||||||
let mut val = v.run(info);
|
let mut val = v.run(info);
|
||||||
if !*is_init {
|
if !*is_init {
|
||||||
for _ in 0..(*derefs + 1) {
|
for _ in 0..*derefs {
|
||||||
val = match val.deref() {
|
val = match val.deref() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => unreachable!("can't dereference..."),
|
None => unreachable!("can't dereference..."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::assign_to(out, val, info);
|
out.assign_to(val, info);
|
||||||
// val.assign(out);
|
// val.assign(out);
|
||||||
}
|
}
|
||||||
VDataEnum::Tuple(vec![]).to()
|
VDataEnum::Tuple(vec![]).to()
|
||||||
@ -230,9 +212,10 @@ impl RStatementEnum {
|
|||||||
},
|
},
|
||||||
Self::For(v, c, b) => {
|
Self::For(v, c, b) => {
|
||||||
// matching values also break with value from a for loop.
|
// matching values also break with value from a for loop.
|
||||||
|
let vv = v.run(info);
|
||||||
c.run(info).operate_on_data_immut(|c: &VDataEnum| {
|
c.run(info).operate_on_data_immut(|c: &VDataEnum| {
|
||||||
let mut in_loop = |c: VData| {
|
let mut in_loop = |c: VData| {
|
||||||
*v.lock().unwrap() = c;
|
c.assign_to(vv.clone_mut(), info);
|
||||||
b.run(info)
|
b.run(info)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -279,25 +262,27 @@ impl RStatementEnum {
|
|||||||
oval
|
oval
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Self::Switch(switch_on, cases) => {
|
Self::Switch(switch_on, cases, _force) => {
|
||||||
let switch_on = switch_on.run(info);
|
let switch_on = switch_on.run(info);
|
||||||
let switch_on_type = switch_on.out();
|
let switch_on_type = switch_on.out();
|
||||||
let mut out = VDataEnum::Tuple(vec![]).to();
|
let mut out = VDataEnum::Tuple(vec![]).to();
|
||||||
for (case_type, case_action) in cases.iter() {
|
for (case_type, assign_to, case_action) in cases.iter() {
|
||||||
if switch_on_type.fits_in(case_type, info).is_empty() {
|
if switch_on_type.fits_in(case_type, info).is_empty() {
|
||||||
|
switch_on.assign_to(assign_to.run(info), info);
|
||||||
out = case_action.run(info);
|
out = case_action.run(info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
Self::Match(match_on, cases) => 'm: {
|
Self::Match(cases) => 'm: {
|
||||||
for (case_condition, case_action) in cases {
|
for (case_condition, assign_to, case_action) in cases {
|
||||||
// [t] => Some(t), t => Some(t), [] | false => None
|
// [t] => Some(t), t => Some(t), [] | false => None
|
||||||
if let Some(v) = case_condition.run(info).matches() {
|
if let Some(v) = case_condition.run(info).matches() {
|
||||||
let og = { std::mem::replace(&mut *match_on.lock().unwrap(), v) };
|
v.assign_to(assign_to.run(info), info);
|
||||||
|
// let og = { std::mem::replace(&mut *match_on.lock().unwrap(), v) };
|
||||||
let res = case_action.run(info);
|
let res = case_action.run(info);
|
||||||
*match_on.lock().unwrap() = og;
|
// *match_on.lock().unwrap() = og;
|
||||||
break 'm res;
|
break 'm res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,31 +334,33 @@ impl RStatementEnum {
|
|||||||
Self::BuiltinFunction(f, args) => {
|
Self::BuiltinFunction(f, args) => {
|
||||||
f.returns(args.iter().map(|rs| rs.out(info)).collect(), info)
|
f.returns(args.iter().map(|rs| rs.out(info)).collect(), info)
|
||||||
}
|
}
|
||||||
Self::Switch(switch_on, cases) => {
|
Self::Switch(switch_on, cases, force) => {
|
||||||
let switch_on = switch_on.out(info).types;
|
let switch_on = switch_on.out(info).types;
|
||||||
let mut might_return_empty = switch_on.is_empty();
|
let mut might_return_empty = switch_on.is_empty();
|
||||||
let mut out = VType { types: vec![] }; // if nothing is executed
|
let mut out = if *force {
|
||||||
|
VSingleType::Tuple(vec![]).to()
|
||||||
|
} else {
|
||||||
|
VType::empty()
|
||||||
|
};
|
||||||
for switch_on in switch_on {
|
for switch_on in switch_on {
|
||||||
let switch_on = switch_on.to();
|
for (_on_type, _assign_to, case) in cases.iter() {
|
||||||
'search: {
|
|
||||||
for (on_type, case) in cases.iter() {
|
|
||||||
if switch_on.fits_in(&on_type, info).is_empty() {
|
|
||||||
out = out | case.out(info);
|
out = out | case.out(info);
|
||||||
break 'search;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
might_return_empty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if might_return_empty {
|
|
||||||
out = out | VSingleType::Tuple(vec![]).to();
|
|
||||||
}
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
Self::Match(_, cases) => {
|
Self::Match(cases) => {
|
||||||
let mut out = VSingleType::Tuple(vec![]).to();
|
let mut out = VType::empty();
|
||||||
for case in cases {
|
let mut can_fail_to_match = true;
|
||||||
out = out | case.1.out(info);
|
for (condition, _assign_to, action) in cases {
|
||||||
|
out = out | action.out(info);
|
||||||
|
if !condition.out(info).matches().0 {
|
||||||
|
can_fail_to_match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if can_fail_to_match {
|
||||||
|
out = out | VSingleType::Tuple(vec![]).to()
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use core::panic;
|
use core::panic;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
eprintln,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
@ -369,7 +370,9 @@ fn statement_adv(
|
|||||||
for (i, v) in v.iter().enumerate() {
|
for (i, v) in v.iter().enumerate() {
|
||||||
if let Some(t) = to_be_assigned_to {
|
if let Some(t) = to_be_assigned_to {
|
||||||
let out_t = if let Some(p) = &prev { p } else { &t.0 };
|
let out_t = if let Some(p) = &prev { p } else { &t.0 };
|
||||||
let inner_t = if let Some(v) = out_t.get_always(i, ginfo) { v } else {
|
let inner_t = if let Some(v) = out_t.get_always(i, ginfo) {
|
||||||
|
v
|
||||||
|
} else {
|
||||||
panic!("cannot assign: cannot get_always({i}) on type {}.", out_t);
|
panic!("cannot assign: cannot get_always({i}) on type {}.", out_t);
|
||||||
};
|
};
|
||||||
let p = std::mem::replace(&mut t.0, inner_t);
|
let p = std::mem::replace(&mut t.0, inner_t);
|
||||||
@ -390,9 +393,15 @@ fn statement_adv(
|
|||||||
}
|
}
|
||||||
SStatementEnum::Variable(v, is_ref) => {
|
SStatementEnum::Variable(v, is_ref) => {
|
||||||
let existing_var = linfo.vars.get(v);
|
let existing_var = linfo.vars.get(v);
|
||||||
let is_init_force = if let Some(v) = &to_be_assigned_to { *v.1 } else { false };
|
let is_init_force = if let Some(v) = &to_be_assigned_to {
|
||||||
|
*v.1
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
// we can't assign to a variable that doesn't exist yet -> create a new one
|
// we can't assign to a variable that doesn't exist yet -> create a new one
|
||||||
if is_init_force || (existing_var.is_none() && ginfo.to_runnable_automatic_initialization) {
|
if is_init_force
|
||||||
|
|| (existing_var.is_none() && ginfo.to_runnable_automatic_initialization)
|
||||||
|
{
|
||||||
// if to_be_assigned_to is some (-> this is on the left side of an assignment), create a new variable. else, return an error.
|
// if to_be_assigned_to is some (-> this is on the left side of an assignment), create a new variable. else, return an error.
|
||||||
if let Some((t, is_init)) = to_be_assigned_to {
|
if let Some((t, is_init)) = to_be_assigned_to {
|
||||||
**is_init = true;
|
**is_init = true;
|
||||||
@ -401,12 +410,10 @@ fn statement_adv(
|
|||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let var = VData::new_placeholder_with_name(v.to_owned());
|
let var = VData::new_placeholder_with_name(v.to_owned());
|
||||||
let var_arc = Arc::new(Mutex::new(var));
|
let var_arc = Arc::new(Mutex::new(var));
|
||||||
linfo.vars.insert(v.to_owned(), (Arc::clone(&var_arc), t.clone()));
|
linfo
|
||||||
RStatementEnum::Variable(
|
.vars
|
||||||
var_arc,
|
.insert(v.to_owned(), (Arc::clone(&var_arc), t.clone()));
|
||||||
t.clone(),
|
RStatementEnum::Variable(var_arc, t.clone(), true)
|
||||||
true,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
|
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
|
||||||
}
|
}
|
||||||
@ -418,7 +425,7 @@ fn statement_adv(
|
|||||||
stypes(&mut v, ginfo)?;
|
stypes(&mut v, ginfo)?;
|
||||||
v
|
v
|
||||||
},
|
},
|
||||||
*is_ref
|
*is_ref,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
|
return Err(ToRunnableError::UseOfUndefinedVariable(v.clone()));
|
||||||
@ -429,11 +436,20 @@ fn statement_adv(
|
|||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
rargs.push(statement(arg, ginfo, linfo)?);
|
rargs.push(statement(arg, ginfo, linfo)?);
|
||||||
}
|
}
|
||||||
fn check_fn_args(args: &Vec<VType>, inputs: &Vec<(Vec<VType>, VType)>, ginfo: &GlobalScriptInfo) -> Option<VType> {
|
fn check_fn_args(
|
||||||
|
args: &Vec<VType>,
|
||||||
|
inputs: &Vec<(Vec<VType>, VType)>,
|
||||||
|
ginfo: &GlobalScriptInfo,
|
||||||
|
) -> Option<VType> {
|
||||||
let mut fit_any = false;
|
let mut fit_any = false;
|
||||||
let mut out = VType::empty();
|
let mut out = VType::empty();
|
||||||
for (inputs, output) in inputs {
|
for (inputs, output) in inputs {
|
||||||
if args.len() == inputs.len() && args.iter().zip(inputs.iter()).all(|(arg, input)| arg.fits_in(input, ginfo).is_empty()) {
|
if args.len() == inputs.len()
|
||||||
|
&& args
|
||||||
|
.iter()
|
||||||
|
.zip(inputs.iter())
|
||||||
|
.all(|(arg, input)| arg.fits_in(input, ginfo).is_empty())
|
||||||
|
{
|
||||||
fit_any = true;
|
fit_any = true;
|
||||||
out = out | output;
|
out = out | output;
|
||||||
}
|
}
|
||||||
@ -446,13 +462,18 @@ fn statement_adv(
|
|||||||
}
|
}
|
||||||
let arg_types: Vec<_> = rargs.iter().map(|v| v.out(ginfo)).collect();
|
let arg_types: Vec<_> = rargs.iter().map(|v| v.out(ginfo)).collect();
|
||||||
if let Some(func) = linfo.fns.get(v) {
|
if let Some(func) = linfo.fns.get(v) {
|
||||||
if let Some(_out) = check_fn_args(&arg_types, &func.input_output_map.iter().map(|v| (v.0.iter().map(|v| v.clone().to()).collect(), v.1.to_owned())).collect(), ginfo) {
|
if let Some(_out) = check_fn_args(
|
||||||
|
&arg_types,
|
||||||
|
&func
|
||||||
|
.input_output_map
|
||||||
|
.iter()
|
||||||
|
.map(|v| (v.0.iter().map(|v| v.clone().to()).collect(), v.1.to_owned()))
|
||||||
|
.collect(),
|
||||||
|
ginfo,
|
||||||
|
) {
|
||||||
RStatementEnum::FunctionCall(func.clone(), rargs)
|
RStatementEnum::FunctionCall(func.clone(), rargs)
|
||||||
} else {
|
} else {
|
||||||
return Err(ToRunnableError::FunctionWrongArgs(
|
return Err(ToRunnableError::FunctionWrongArgs(arg_types, v.to_owned()));
|
||||||
arg_types,
|
|
||||||
v.to_owned()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(builtin) = BuiltinFunction::get(v) {
|
if let Some(builtin) = BuiltinFunction::get(v) {
|
||||||
@ -460,7 +481,11 @@ fn statement_adv(
|
|||||||
if builtin.can_take(&arg_types, ginfo) {
|
if builtin.can_take(&arg_types, ginfo) {
|
||||||
RStatementEnum::BuiltinFunction(builtin, rargs)
|
RStatementEnum::BuiltinFunction(builtin, rargs)
|
||||||
} else {
|
} else {
|
||||||
return Err(ToRunnableError::WrongInputsForBuiltinFunction(builtin, v.to_string(), arg_types));
|
return Err(ToRunnableError::WrongInputsForBuiltinFunction(
|
||||||
|
builtin,
|
||||||
|
v.to_string(),
|
||||||
|
arg_types,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// LIBRARY FUNCTION?
|
// LIBRARY FUNCTION?
|
||||||
@ -470,7 +495,10 @@ fn statement_adv(
|
|||||||
if let Some(fn_out) = check_fn_args(&arg_types, &libfn.1, ginfo) {
|
if let Some(fn_out) = check_fn_args(&arg_types, &libfn.1, ginfo) {
|
||||||
RStatementEnum::LibFunction(*libid, *fnid, rargs, fn_out.clone())
|
RStatementEnum::LibFunction(*libid, *fnid, rargs, fn_out.clone())
|
||||||
} else {
|
} else {
|
||||||
return Err(ToRunnableError::WrongArgsForLibFunction(v.to_owned(), arg_types));
|
return Err(ToRunnableError::WrongArgsForLibFunction(
|
||||||
|
v.to_owned(),
|
||||||
|
arg_types,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(ToRunnableError::UseOfUndefinedFunction(v.clone()));
|
return Err(ToRunnableError::UseOfUndefinedFunction(v.clone()));
|
||||||
@ -496,9 +524,12 @@ fn statement_adv(
|
|||||||
SStatementEnum::If(c, t, e) => RStatementEnum::If(
|
SStatementEnum::If(c, t, e) => RStatementEnum::If(
|
||||||
{
|
{
|
||||||
let condition = statement(&c, ginfo, linfo)?;
|
let condition = statement(&c, ginfo, linfo)?;
|
||||||
let out = condition.out(ginfo).fits_in(&VType {
|
let out = condition.out(ginfo).fits_in(
|
||||||
|
&VType {
|
||||||
types: vec![VSingleType::Bool],
|
types: vec![VSingleType::Bool],
|
||||||
}, ginfo);
|
},
|
||||||
|
ginfo,
|
||||||
|
);
|
||||||
if out.is_empty() {
|
if out.is_empty() {
|
||||||
condition
|
condition
|
||||||
} else {
|
} else {
|
||||||
@ -515,9 +546,7 @@ fn statement_adv(
|
|||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SStatementEnum::Loop(c) => RStatementEnum::Loop(
|
SStatementEnum::Loop(c) => RStatementEnum::Loop(statement(&c, ginfo, linfo)?),
|
||||||
statement(&c, ginfo, linfo)?
|
|
||||||
),
|
|
||||||
SStatementEnum::For(v, c, b) => {
|
SStatementEnum::For(v, c, b) => {
|
||||||
let mut linfo = linfo.clone();
|
let mut linfo = linfo.clone();
|
||||||
let container = statement(&c, ginfo, &mut linfo)?;
|
let container = statement(&c, ginfo, &mut linfo)?;
|
||||||
@ -525,136 +554,75 @@ fn statement_adv(
|
|||||||
if inner.types.is_empty() {
|
if inner.types.is_empty() {
|
||||||
return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes);
|
return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes);
|
||||||
}
|
}
|
||||||
let for_loop_var = Arc::new(Mutex::new(VData::new_placeholder()));
|
let assign_to = statement_adv(v, ginfo, &mut linfo, &mut Some((inner, &mut true)))?;
|
||||||
linfo
|
|
||||||
.vars
|
|
||||||
.insert(v.clone(), (Arc::clone(&for_loop_var), inner));
|
|
||||||
let block = statement(&b, ginfo, &mut linfo)?;
|
let block = statement(&b, ginfo, &mut linfo)?;
|
||||||
let o = RStatementEnum::For(for_loop_var, container, block);
|
let o = RStatementEnum::For(assign_to, container, block);
|
||||||
o
|
o
|
||||||
}
|
}
|
||||||
|
|
||||||
SStatementEnum::Switch(switch_on, cases, force) => {
|
SStatementEnum::Switch(switch_on, cases, force) => {
|
||||||
if let Some(switch_on_v) = linfo.vars.get(switch_on).cloned() {
|
|
||||||
let mut ncases = Vec::with_capacity(cases.len());
|
let mut ncases = Vec::with_capacity(cases.len());
|
||||||
let og_type = switch_on_v.1.clone(); // linfo.vars.get(switch_on).unwrap().1.clone();
|
let switch_on = statement(switch_on, ginfo, linfo)?;
|
||||||
for case in cases {
|
let og_type = switch_on.out(ginfo);
|
||||||
let case0 = { let mut v = case.0.clone(); stypes(&mut v, ginfo)?; v };
|
let mut covered_types = VType::empty();
|
||||||
linfo.vars.get_mut(switch_on).unwrap().1 = case0.clone();
|
for (case_type, case_assign_to, case_action) in cases.iter() {
|
||||||
ncases.push((case0, statement(&case.1, ginfo, linfo)?));
|
let mut linfo = linfo.clone();
|
||||||
}
|
let case_type = {
|
||||||
linfo.vars.get_mut(switch_on).unwrap().1 = og_type;
|
let mut v = case_type.clone();
|
||||||
|
stypes(&mut v, ginfo)?;
|
||||||
let switch_on_out = switch_on_v.1;
|
|
||||||
if *force {
|
|
||||||
let mut types_not_covered_req_error = false;
|
|
||||||
let mut types_not_covered = VType { types: vec![] };
|
|
||||||
for val_type in switch_on_out.types.iter() {
|
|
||||||
let val_type: VType = val_type.clone().into();
|
|
||||||
let mut linf2 = linfo.clone();
|
|
||||||
linf2.vars.get_mut(switch_on).unwrap().1 = val_type.clone();
|
|
||||||
'force: {
|
|
||||||
for (case_type, _) in cases {
|
|
||||||
let mut ct = case_type.clone();
|
|
||||||
stypes(&mut ct, ginfo)?;
|
|
||||||
if val_type.fits_in(&ct, ginfo).is_empty() {
|
|
||||||
break 'force;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
types_not_covered_req_error = true;
|
|
||||||
types_not_covered = types_not_covered | {
|
|
||||||
let mut v = val_type;
|
|
||||||
/// converts the VType to one that is human-readable (changes enum from usize to String, ...)
|
|
||||||
fn make_readable(v: &mut VType, ginfo: &GlobalScriptInfo) {
|
|
||||||
for t in v.types.iter_mut() {
|
|
||||||
match t {
|
|
||||||
VSingleType::EnumVariant(i, v) => {
|
|
||||||
let mut v = v.clone();
|
|
||||||
make_readable(&mut v, ginfo);
|
|
||||||
*t = VSingleType::EnumVariantS(ginfo.enum_variants.iter().find_map(|(st, us)| if *us == *i { Some(st.clone()) } else { None }).unwrap(), v);
|
|
||||||
},
|
|
||||||
VSingleType::CustomType(i) => {
|
|
||||||
*t = VSingleType::CustomTypeS(ginfo.custom_type_names.iter().find_map(|(st, us)| if *us == *i { Some(st.clone()) } else { None }).unwrap());
|
|
||||||
}
|
|
||||||
VSingleType::Tuple(v) => for t in v.iter_mut() {
|
|
||||||
make_readable(t, ginfo)
|
|
||||||
}
|
|
||||||
VSingleType::List(t) | VSingleType::EnumVariantS(_, t) => make_readable(t, ginfo),
|
|
||||||
VSingleType::Reference(v) => {
|
|
||||||
let mut v = v.clone().to();
|
|
||||||
make_readable(&mut v, ginfo);
|
|
||||||
assert_eq!(v.types.len(), 1);
|
|
||||||
*t = VSingleType::Reference(Box::new(v.types.remove(0)));
|
|
||||||
}
|
|
||||||
VSingleType::Bool | VSingleType::Int | VSingleType::Float | VSingleType::String | VSingleType::Function(..) | VSingleType::Thread(..) | VSingleType::CustomTypeS(_) => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
make_readable(&mut v, &ginfo);
|
|
||||||
v
|
v
|
||||||
};
|
};
|
||||||
|
covered_types = covered_types | &case_type;
|
||||||
|
ncases.push((
|
||||||
|
case_type.clone(),
|
||||||
|
statement_adv(
|
||||||
|
case_assign_to,
|
||||||
|
ginfo,
|
||||||
|
&mut linfo,
|
||||||
|
&mut Some((case_type, &mut true)),
|
||||||
|
)?,
|
||||||
|
statement(case_action, ginfo, &mut linfo)?,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if types_not_covered_req_error {
|
|
||||||
return Err(ToRunnableError::CaseForceButTypeNotCovered(types_not_covered));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RStatementEnum::Switch(
|
|
||||||
RStatementEnum::Variable(switch_on_v.0, switch_on_out, false).to(),
|
|
||||||
ncases,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return Err(ToRunnableError::UseOfUndefinedVariable(switch_on.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SStatementEnum::Match(match_on, cases) => {
|
|
||||||
if let Some(switch_on_v) = linfo.vars.get(match_on).cloned() {
|
|
||||||
let mut ncases = Vec::with_capacity(cases.len());
|
|
||||||
let og_type = switch_on_v.1.clone(); // linfo.vars.get(match_on).unwrap().1.clone();
|
|
||||||
for case in cases {
|
|
||||||
let case_condition = statement(&case.0, ginfo, linfo)?;
|
|
||||||
let case_condition_out = case_condition.out(ginfo);
|
|
||||||
let mut refutable = false;
|
|
||||||
let mut success_output = VType { types: vec![] };
|
|
||||||
for case_type in case_condition_out.types.iter() {
|
|
||||||
match case_type {
|
|
||||||
VSingleType::Tuple(tuple) =>
|
|
||||||
match tuple.len() {
|
|
||||||
0 => refutable = true,
|
|
||||||
1 => success_output = success_output | &tuple[0],
|
|
||||||
_ => return Err(ToRunnableError::MatchConditionInvalidReturn(case_condition_out)),
|
|
||||||
},
|
|
||||||
VSingleType::Bool => {
|
|
||||||
refutable = true;
|
|
||||||
success_output = success_output | VSingleType::Bool.to()
|
|
||||||
}
|
|
||||||
_ => success_output = success_output | case_type.clone().to(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if refutable == false {
|
|
||||||
eprintln!("WARN: Irrefutable match condition with return type {}", case_condition_out);
|
|
||||||
}
|
|
||||||
if !success_output.types.is_empty() {
|
|
||||||
let var = linfo.vars.get_mut(match_on).unwrap();
|
|
||||||
let og = var.1.clone();
|
|
||||||
var.1 = success_output;
|
|
||||||
let case_action = statement(&case.1, ginfo, linfo)?;
|
|
||||||
linfo.vars.get_mut(match_on).unwrap().1 = og;
|
|
||||||
ncases.push((case_condition, case_action));
|
|
||||||
} else {
|
|
||||||
eprintln!("WARN: Match condition with return type {} never returns a match and will be ignored entirely. Note: this also skips type-checking for the action part of this match arm because the success type is not known.", case_condition_out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
linfo.vars.get_mut(match_on).unwrap().1 = og_type;
|
|
||||||
|
|
||||||
RStatementEnum::Match(
|
if *force {
|
||||||
switch_on_v.0,
|
let types_not_covered = og_type.fits_in(&covered_types, ginfo);
|
||||||
ncases,
|
if !types_not_covered.is_empty() {
|
||||||
)
|
return Err(ToRunnableError::CaseForceButTypeNotCovered(VType {
|
||||||
} else {
|
types: types_not_covered,
|
||||||
return Err(ToRunnableError::UseOfUndefinedVariable(match_on.clone()));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RStatementEnum::Switch(switch_on, ncases, *force)
|
||||||
|
}
|
||||||
|
SStatementEnum::Match(cases) => {
|
||||||
|
let mut ncases: Vec<(RStatement, RStatement, RStatement)> =
|
||||||
|
Vec::with_capacity(cases.len());
|
||||||
|
let mut ncases = Vec::with_capacity(cases.len());
|
||||||
|
let mut out_type = VType::empty();
|
||||||
|
let mut may_not_match = true;
|
||||||
|
for (condition, assign_to, action) in cases.iter() {
|
||||||
|
let mut linfo = linfo.clone();
|
||||||
|
let condition = statement(condition, ginfo, &mut linfo)?;
|
||||||
|
let (can_fail, matches) = condition.out(ginfo).matches();
|
||||||
|
let assign_to = statement_adv(
|
||||||
|
assign_to,
|
||||||
|
ginfo,
|
||||||
|
&mut linfo,
|
||||||
|
&mut Some((matches, &mut true)),
|
||||||
|
)?;
|
||||||
|
let action = statement(action, ginfo, &mut linfo)?;
|
||||||
|
ncases.push((condition, assign_to, action));
|
||||||
|
if !can_fail {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if may_not_match {
|
||||||
|
out_type = out_type | VSingleType::Tuple(vec![]).to();
|
||||||
|
}
|
||||||
|
|
||||||
|
RStatementEnum::Match(ncases)
|
||||||
|
}
|
||||||
|
|
||||||
SStatementEnum::IndexFixed(st, i) => {
|
SStatementEnum::IndexFixed(st, i) => {
|
||||||
let st = statement(st, ginfo, linfo)?;
|
let st = statement(st, ginfo, linfo)?;
|
||||||
@ -664,7 +632,8 @@ fn statement_adv(
|
|||||||
return Err(ToRunnableError::NotIndexableFixed(st.out(ginfo), *i));
|
return Err(ToRunnableError::NotIndexableFixed(st.out(ginfo), *i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SStatementEnum::EnumVariant(variant, s) => RStatementEnum::EnumVariant({
|
SStatementEnum::EnumVariant(variant, s) => RStatementEnum::EnumVariant(
|
||||||
|
{
|
||||||
if let Some(v) = ginfo.enum_variants.get(variant) {
|
if let Some(v) = ginfo.enum_variants.get(variant) {
|
||||||
*v
|
*v
|
||||||
} else {
|
} else {
|
||||||
@ -672,10 +641,14 @@ fn statement_adv(
|
|||||||
ginfo.enum_variants.insert(variant.clone(), v);
|
ginfo.enum_variants.insert(variant.clone(), v);
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
}, statement(s, ginfo, linfo)?),
|
},
|
||||||
|
statement(s, ginfo, linfo)?,
|
||||||
|
),
|
||||||
SStatementEnum::TypeDefinition(name, t) => {
|
SStatementEnum::TypeDefinition(name, t) => {
|
||||||
// insert to name map has to happen before stypes()
|
// insert to name map has to happen before stypes()
|
||||||
ginfo.custom_type_names.insert(name.to_lowercase(), ginfo.custom_types.len());
|
ginfo
|
||||||
|
.custom_type_names
|
||||||
|
.insert(name.to_lowercase(), ginfo.custom_types.len());
|
||||||
let mut t = t.to_owned();
|
let mut t = t.to_owned();
|
||||||
stypes(&mut t, ginfo)?;
|
stypes(&mut t, ginfo)?;
|
||||||
ginfo.custom_types.push(t);
|
ginfo.custom_types.push(t);
|
||||||
@ -711,41 +684,7 @@ fn statement_adv(
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
if !is_init {
|
|
||||||
let mut opt_type = optr.out(ginfo);
|
|
||||||
for _ in 0..*derefs {
|
|
||||||
if let Some(deref_type) = optr.out(ginfo).dereference() {
|
|
||||||
opt_type = deref_type;
|
|
||||||
} else {
|
|
||||||
return Err(ToRunnableError::CannotDereferenceTypeNTimes(
|
|
||||||
optr.out(ginfo),
|
|
||||||
*derefs,
|
|
||||||
opt_type,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let opt_type_assign = match opt_type.dereference() {
|
|
||||||
Some(v) => v,
|
|
||||||
None => {
|
|
||||||
return Err(ToRunnableError::CannotDereferenceTypeNTimes(
|
|
||||||
optr.out(ginfo),
|
|
||||||
derefs + 1,
|
|
||||||
opt_type,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if state.out(ginfo).fits_in(&opt_type_assign, ginfo).is_empty() {
|
|
||||||
state.output_to = Some((Box::new(optr), *derefs, is_init));
|
state.output_to = Some((Box::new(optr), *derefs, is_init));
|
||||||
} else {
|
|
||||||
return Err(ToRunnableError::CannotAssignTo(
|
|
||||||
state.out(ginfo),
|
|
||||||
opt_type_assign,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO! ??
|
|
||||||
state.output_to = Some((Box::new(optr), *derefs, 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);
|
||||||
|
@ -149,6 +149,23 @@ impl VData {
|
|||||||
// VDataInner::ClonedFrom(inner) => inner.assign(new_data),
|
// VDataInner::ClonedFrom(inner) => inner.assign(new_data),
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
/// assigns the value from self to assign_to if it's a reference, performs destructuring, and panics on invalid types that cannot be assigned to.
|
||||||
|
pub fn assign_to(self: VData, mut assign_to: VData, info: &GSInfo) {
|
||||||
|
// eprintln!("Assigning {self} to {assign_to}");
|
||||||
|
assign_to.operate_on_data_mut(|assign_to| match assign_to {
|
||||||
|
VDataEnum::Tuple(v) | VDataEnum::List(_, v) => {
|
||||||
|
for (i, v) in v.iter().enumerate() {
|
||||||
|
self.get(i)
|
||||||
|
.expect(
|
||||||
|
"tried to assign to tuple, but value didn't return Some(_) on get()",
|
||||||
|
)
|
||||||
|
.assign_to(v.clone_data(), info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VDataEnum::Reference(r) => r.assign(self),
|
||||||
|
o => todo!("ERR: Cannot assign to {o}."),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Drop for VDataInner {
|
impl Drop for VDataInner {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
@ -644,21 +644,7 @@ pub mod implementation {
|
|||||||
}
|
}
|
||||||
"for" => {
|
"for" => {
|
||||||
break SStatementEnum::For(
|
break SStatementEnum::For(
|
||||||
{
|
parse_statement(file)?,
|
||||||
file.skip_whitespaces();
|
|
||||||
let mut buf = String::new();
|
|
||||||
loop {
|
|
||||||
if let Some(ch) = file.next() {
|
|
||||||
if ch.is_whitespace() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf.push(ch);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf
|
|
||||||
},
|
|
||||||
parse_statement(file)?,
|
parse_statement(file)?,
|
||||||
parse_statement(file)?,
|
parse_statement(file)?,
|
||||||
)
|
)
|
||||||
@ -673,14 +659,7 @@ pub mod implementation {
|
|||||||
}
|
}
|
||||||
"switch" | "switch!" => {
|
"switch" | "switch!" => {
|
||||||
let force = start.ends_with("!");
|
let force = start.ends_with("!");
|
||||||
let mut switch_on_what = String::new();
|
let switch_on_what = parse_statement(file)?;
|
||||||
loop {
|
|
||||||
match file.next() {
|
|
||||||
None => break,
|
|
||||||
Some(ch) if ch.is_whitespace() => break,
|
|
||||||
Some(ch) => switch_on_what.push(ch),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file.skip_whitespaces();
|
file.skip_whitespaces();
|
||||||
if let Some('{') = file.next() {
|
if let Some('{') = file.next() {
|
||||||
} else {
|
} else {
|
||||||
@ -693,19 +672,15 @@ pub mod implementation {
|
|||||||
file.next();
|
file.next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cases.push((parse_type(file)?, parse_statement(file)?));
|
cases.push((
|
||||||
|
parse_type(file)?,
|
||||||
|
parse_statement(file)?,
|
||||||
|
parse_statement(file)?,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
break SStatementEnum::Switch(switch_on_what, cases, force).to();
|
break SStatementEnum::Switch(switch_on_what, cases, force).to();
|
||||||
}
|
}
|
||||||
"match" => {
|
"match" => {
|
||||||
let mut match_what = String::new();
|
|
||||||
loop {
|
|
||||||
match file.next() {
|
|
||||||
None => break,
|
|
||||||
Some(ch) if ch.is_whitespace() => break,
|
|
||||||
Some(ch) => match_what.push(ch),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file.skip_whitespaces();
|
file.skip_whitespaces();
|
||||||
if let Some('{') = file.next() {
|
if let Some('{') = file.next() {
|
||||||
} else {
|
} else {
|
||||||
@ -718,9 +693,13 @@ pub mod implementation {
|
|||||||
file.next();
|
file.next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cases.push((parse_statement(file)?, parse_statement(file)?));
|
cases.push((
|
||||||
|
parse_statement(file)?,
|
||||||
|
parse_statement(file)?,
|
||||||
|
parse_statement(file)?,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
break SStatementEnum::Match(match_what, cases).to();
|
break SStatementEnum::Match(cases).to();
|
||||||
}
|
}
|
||||||
"type" => {
|
"type" => {
|
||||||
file.skip_whitespaces();
|
file.skip_whitespaces();
|
||||||
|
Loading…
Reference in New Issue
Block a user