mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 05:43:53 +01:00
added match statements.
This commit is contained in:
parent
664de5c347
commit
6712097829
34
README.md
34
README.md
@ -68,6 +68,40 @@ run() will return what the function returns while thread() will return a Thread
|
||||
|
||||
using switch! forces you to cover all possible types. Try removing the string or int case and see what happens!
|
||||
|
||||
### Matching on user input
|
||||
|
||||
In this script, we ask the user to enter some text. We match on the entered text.
|
||||
|
||||
- If it can be parsed as an int, we save it as an int.
|
||||
- If it can't be parsed as an int, but it can be parsed as a float, we save it as a float
|
||||
- If it can't ba parsed as an int or a float, we return an error (of type string)
|
||||
|
||||
println("Enter some text, I will try to parse it!")
|
||||
text = read_line()
|
||||
|
||||
num = match text {
|
||||
// if possible, returns an int, otherwise a float, if that's also not possible, returns an error message in form of a string
|
||||
// parse_int and parse_float return either [] (which won't match) or int/float (which will match), so they just work with the match statement.
|
||||
parse_int(text) text
|
||||
parse_float(text) text
|
||||
// eq returns a bool, which will match if it was *true*, but not if it was *false*
|
||||
text.eq("some text") "haha, very funny..."
|
||||
// default value (true will always match)
|
||||
true "number wasn't int/float!"
|
||||
}
|
||||
|
||||
"Input: \"{0}\"".format(text).println()
|
||||
num.debug()
|
||||
|
||||
A match arm consists of two consecutive statements: The condition statement followed by the action statement.
|
||||
|
||||
If the condition statement matches, the action statement will be executed. The matched value from the condition statement can be found in the variable we originally matched on, so it can be used in the action statement.
|
||||
|
||||
**These are the rules for matching:**
|
||||
- The condition statement *does not match* if it returns **false** or **[]**
|
||||
- If the condition statement returns a length 1 tuple [v], it will match and the matched value will be v. The condition statement can't return any tuple except [] and [v] to avoid confusion. To return a tuple, wrap it in a length-1 tuple: [[val_1, val_2, val_3]].
|
||||
- Otherwise, the condition statement will match and the matched value will be whatever it returned.
|
||||
|
||||
### Reading /tmp/ and filtering for files/directories
|
||||
|
||||
for file fs_list("/tmp/") {
|
||||
|
@ -256,7 +256,7 @@ fn parse_statement_adv(
|
||||
file.skip_whitespaces();
|
||||
if let Some('{') = file.next() {
|
||||
} else {
|
||||
eprintln!("switch statement should be followed by {{ (because they must be closed by }}). This might lead to errors when parsing, although it isn't fatal.");
|
||||
eprintln!("switch statements should be followed by {{ (because they must be closed by }}). This might lead to errors when parsing, although it isn't fatal.");
|
||||
}
|
||||
let mut cases = vec![];
|
||||
loop {
|
||||
@ -269,6 +269,31 @@ fn parse_statement_adv(
|
||||
}
|
||||
break SStatementEnum::Switch(switch_on_what, cases, force).into();
|
||||
}
|
||||
"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();
|
||||
if let Some('{') = file.next() {
|
||||
} else {
|
||||
eprintln!("match statements should be followed by {{ (because they must be closed by }}). This might lead to errors when parsing, although it isn't fatal.");
|
||||
}
|
||||
let mut cases = vec![];
|
||||
loop {
|
||||
file.skip_whitespaces();
|
||||
if let Some('}') = file.peek() {
|
||||
file.next();
|
||||
break;
|
||||
}
|
||||
cases.push((parse_statement(file)?, parse_statement(file)?));
|
||||
}
|
||||
break SStatementEnum::Match(match_what, cases).into();
|
||||
}
|
||||
"true" => {
|
||||
break SStatementEnum::Value(VDataEnum::Bool(true).to()).into()
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ pub enum SStatementEnum {
|
||||
While(SStatement),
|
||||
For(String, SStatement, SStatement),
|
||||
Switch(String, Vec<(VType, SStatement)>, bool),
|
||||
// Match(???),
|
||||
Match(String, Vec<(SStatement, SStatement)>),
|
||||
IndexFixed(SStatement, usize),
|
||||
}
|
||||
impl Into<SStatement> for SStatementEnum {
|
||||
@ -117,6 +117,7 @@ pub mod to_runnable {
|
||||
},
|
||||
InvalidTypeForWhileLoop(VType),
|
||||
CaseForceButTypeNotCovered(VType),
|
||||
MatchConditionInvalidReturn(VType),
|
||||
NotIndexableFixed(VType, usize),
|
||||
}
|
||||
impl Debug for ToRunnableError {
|
||||
@ -143,6 +144,7 @@ pub mod to_runnable {
|
||||
}
|
||||
Self::InvalidTypeForWhileLoop(v) => write!(f, "Invalid type: Expected bool or Tuples of length 0 or 1 as return types for the while loop, but found {v:?} instead."),
|
||||
Self::CaseForceButTypeNotCovered(v) => write!(f, "Switch! statement, but not all types covered. Types to cover: {v}"),
|
||||
Self::MatchConditionInvalidReturn(v) => write!(f, "match statement condition returned {v}, which is not necessarily a tuple of size 0 to 1."),
|
||||
Self::NotIndexableFixed(t, i) => write!(f, "Cannot use fixed-index {i} on type {t}."),
|
||||
}
|
||||
}
|
||||
@ -386,10 +388,11 @@ pub mod to_runnable {
|
||||
let o = RStatementEnum::For(for_loop_var, container, block);
|
||||
o
|
||||
}
|
||||
|
||||
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 og_type = linfo.vars.get(switch_on).unwrap().1.clone();
|
||||
let og_type = switch_on_v.1.clone(); // linfo.vars.get(switch_on).unwrap().1.clone();
|
||||
for case in cases {
|
||||
linfo.vars.get_mut(switch_on).unwrap().1 = case.0.clone();
|
||||
ncases.push((case.0.clone(), statement(&case.1, ginfo, linfo)?));
|
||||
@ -426,6 +429,56 @@ pub mod to_runnable {
|
||||
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();
|
||||
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(
|
||||
switch_on_v.0,
|
||||
ncases,
|
||||
)
|
||||
} else {
|
||||
return Err(ToRunnableError::UseOfUndefinedVariable(match_on.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
SStatementEnum::IndexFixed(st, i) => {
|
||||
let st = statement(st, ginfo, linfo)?;
|
||||
let ok = 'ok: {
|
||||
@ -589,6 +642,7 @@ pub enum RStatementEnum {
|
||||
While(RStatement),
|
||||
For(usize, RStatement, RStatement),
|
||||
Switch(RStatement, Vec<(VType, RStatement)>),
|
||||
Match(usize, Vec<(RStatement, RStatement)>),
|
||||
IndexFixed(RStatement, usize),
|
||||
}
|
||||
impl RStatementEnum {
|
||||
@ -694,6 +748,24 @@ impl RStatementEnum {
|
||||
}
|
||||
out
|
||||
}
|
||||
Self::Match(match_on, cases) => 'm: {
|
||||
for (case_condition, case_action) in cases {
|
||||
// [t] => Some(t), t => Some(t), [] => None
|
||||
if let Some(v) = match case_condition.run(vars).data {
|
||||
VDataEnum::Tuple(mut tuple) => tuple.pop(),
|
||||
VDataEnum::Bool(v) => if v { Some(VDataEnum::Bool(v).to()) } else { None },
|
||||
other => Some(other.to()),
|
||||
} {
|
||||
let og = {
|
||||
std::mem::replace(&mut *vars[*match_on].lock().unwrap(), v)
|
||||
};
|
||||
let res = case_action.run(vars);
|
||||
*vars[*match_on].lock().unwrap() = og;
|
||||
break 'm res;
|
||||
}
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
Self::IndexFixed(st, i) => st.run(vars).get(*i).unwrap(),
|
||||
}
|
||||
}
|
||||
@ -782,6 +854,13 @@ impl RStatementEnum {
|
||||
}
|
||||
out
|
||||
}
|
||||
Self::Match(_, cases) => {
|
||||
let mut out = VSingleType::Tuple(vec![]).to();
|
||||
for case in cases {
|
||||
out = out | case.1.out();
|
||||
}
|
||||
out
|
||||
}
|
||||
Self::IndexFixed(st, i) => st.out().get(*i).unwrap(),
|
||||
}
|
||||
}
|
||||
@ -949,6 +1028,13 @@ impl Display for SStatementEnum {
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
SStatementEnum::Match(match_on, cases) => {
|
||||
writeln!(f, "match {match_on} {{")?;
|
||||
for (case_cond, case_action) in cases.iter() {
|
||||
writeln!(f, "{} {}", case_cond, case_action)?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
SStatementEnum::IndexFixed(st, i) => write!(f, "{st}.{i}"),
|
||||
}
|
||||
}
|
||||
|
@ -16,15 +16,14 @@ pub enum BuiltinFunction {
|
||||
Print,
|
||||
Println,
|
||||
Debug,
|
||||
// stdin
|
||||
StdinReadLine,
|
||||
// format
|
||||
ToString,
|
||||
Format,
|
||||
// math and basic operators (not possible, need to be different for each type)
|
||||
// Add,
|
||||
// Sub,
|
||||
// Mul,
|
||||
// Div,
|
||||
// Mod,
|
||||
// match
|
||||
ParseInt,
|
||||
ParseFloat,
|
||||
// functions
|
||||
Run,
|
||||
Thread,
|
||||
@ -47,6 +46,13 @@ pub enum BuiltinFunction {
|
||||
Div,
|
||||
Mod,
|
||||
Pow,
|
||||
Eq,
|
||||
Gt,
|
||||
Lt,
|
||||
Gtoe,
|
||||
Ltoe,
|
||||
Min,
|
||||
Max,
|
||||
// List
|
||||
Push,
|
||||
Insert,
|
||||
@ -62,8 +68,11 @@ impl BuiltinFunction {
|
||||
"print" => Self::Print,
|
||||
"println" => Self::Println,
|
||||
"debug" => Self::Debug,
|
||||
"read_line" => Self::StdinReadLine,
|
||||
"to_string" => Self::ToString,
|
||||
"format" => Self::Format,
|
||||
"parse_int" => Self::ParseInt,
|
||||
"parse_float" => Self::ParseFloat,
|
||||
"run" => Self::Run,
|
||||
"thread" => Self::Thread,
|
||||
"await" => Self::Await,
|
||||
@ -83,6 +92,13 @@ impl BuiltinFunction {
|
||||
"div" => Self::Div,
|
||||
"mod" => Self::Mod,
|
||||
"pow" => Self::Pow,
|
||||
"eq" => Self::Eq,
|
||||
"lt" => Self::Lt,
|
||||
"gt" => Self::Gt,
|
||||
"ltoe" => Self::Ltoe,
|
||||
"gtoe" => Self::Gtoe,
|
||||
"min" => Self::Min,
|
||||
"max" => Self::Max,
|
||||
"push" => Self::Push,
|
||||
"insert" => Self::Insert,
|
||||
"pop" => Self::Pop,
|
||||
@ -110,6 +126,10 @@ impl BuiltinFunction {
|
||||
false
|
||||
}
|
||||
}
|
||||
Self::StdinReadLine => input.is_empty(),
|
||||
Self::ParseInt | Self::ParseFloat => {
|
||||
input.len() == 1 && input[0].fits_in(&VSingleType::String.to()).is_empty()
|
||||
}
|
||||
Self::Run | Self::Thread => {
|
||||
if input.len() >= 1 {
|
||||
input[0].types.iter().all(|v| {
|
||||
@ -184,7 +204,31 @@ impl BuiltinFunction {
|
||||
false
|
||||
}
|
||||
}
|
||||
Self::Add | Self::Sub | Self::Mul | Self::Div | Self::Mod | Self::Pow => {
|
||||
Self::Eq => {
|
||||
if input.len() == 2 {
|
||||
let num = &VType {
|
||||
types: vec![VSingleType::Int, VSingleType::Float],
|
||||
};
|
||||
let string = &VSingleType::String.to();
|
||||
(input[0].fits_in(num).is_empty() && input[1].fits_in(num).is_empty())
|
||||
|| (input[0].fits_in(string).is_empty()
|
||||
&& input[1].fits_in(string).is_empty())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Self::Add
|
||||
| Self::Sub
|
||||
| Self::Mul
|
||||
| Self::Div
|
||||
| Self::Mod
|
||||
| Self::Pow
|
||||
| Self::Gt
|
||||
| Self::Lt
|
||||
| Self::Gtoe
|
||||
| Self::Ltoe
|
||||
| Self::Min
|
||||
| Self::Max => {
|
||||
input.len() == 2 && {
|
||||
let num = VType {
|
||||
types: vec![VSingleType::Int, VSingleType::Float],
|
||||
@ -229,8 +273,15 @@ impl BuiltinFunction {
|
||||
Self::Print | Self::Println | Self::Debug | Self::Sleep => VType {
|
||||
types: vec![VSingleType::Tuple(vec![])],
|
||||
},
|
||||
Self::StdinReadLine => VSingleType::String.to(),
|
||||
// String
|
||||
Self::ToString | Self::Format => VSingleType::String.into(),
|
||||
Self::ParseInt => VType {
|
||||
types: vec![VSingleType::Tuple(vec![]), VSingleType::Int],
|
||||
},
|
||||
Self::ParseFloat => VType {
|
||||
types: vec![VSingleType::Tuple(vec![]), VSingleType::Float],
|
||||
},
|
||||
// !
|
||||
Self::Run | Self::Thread => {
|
||||
if let Some(funcs) = input.first() {
|
||||
@ -338,7 +389,14 @@ impl BuiltinFunction {
|
||||
]),
|
||||
],
|
||||
},
|
||||
Self::Add | Self::Sub | Self::Mul | Self::Div | Self::Mod | Self::Pow => {
|
||||
Self::Add
|
||||
| Self::Sub
|
||||
| Self::Mul
|
||||
| Self::Div
|
||||
| Self::Mod
|
||||
| Self::Pow
|
||||
| Self::Min
|
||||
| Self::Max => {
|
||||
if input.len() == 2 {
|
||||
match (
|
||||
(
|
||||
@ -360,6 +418,7 @@ impl BuiltinFunction {
|
||||
unreachable!("called add/sub/mul/div/mod/pow with args != 2")
|
||||
}
|
||||
}
|
||||
Self::Eq | Self::Lt | Self::Gt | Self::Ltoe | Self::Gtoe => VSingleType::Bool.to(),
|
||||
Self::Push | Self::Insert => VSingleType::Tuple(vec![]).into(),
|
||||
Self::Len => VSingleType::Int.into(),
|
||||
}
|
||||
@ -386,6 +445,11 @@ impl BuiltinFunction {
|
||||
println!("{:#?}", args[0].run(vars).data);
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
Self::StdinReadLine => {
|
||||
let mut line = String::new();
|
||||
_ = std::io::stdin().read_line(&mut line);
|
||||
VDataEnum::String(line.trim_end_matches(['\n', '\r']).to_string()).to()
|
||||
}
|
||||
BuiltinFunction::ToString => {
|
||||
VDataEnum::String(format!("{}", args[0].run(vars).data)).to()
|
||||
}
|
||||
@ -400,6 +464,36 @@ impl BuiltinFunction {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
BuiltinFunction::ParseInt => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::String(s) = args[0].run(vars).data {
|
||||
if let Ok(s) = s.parse() {
|
||||
VDataEnum::Int(s).to()
|
||||
} else {
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
} else {
|
||||
unreachable!("parse arg not string")
|
||||
}
|
||||
} else {
|
||||
unreachable!("parse args != 1")
|
||||
}
|
||||
}
|
||||
BuiltinFunction::ParseFloat => {
|
||||
if args.len() == 1 {
|
||||
if let VDataEnum::String(s) = args[0].run(vars).data {
|
||||
if let Ok(s) = s.parse() {
|
||||
VDataEnum::Float(s).to()
|
||||
} else {
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
}
|
||||
} else {
|
||||
unreachable!("parse arg not string")
|
||||
}
|
||||
} else {
|
||||
unreachable!("parse args != 1")
|
||||
}
|
||||
}
|
||||
BuiltinFunction::Run => {
|
||||
if args.len() >= 1 {
|
||||
if let VDataEnum::Function(f) = args[0].run(vars).data {
|
||||
@ -780,6 +874,132 @@ impl BuiltinFunction {
|
||||
unreachable!("pow: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Eq => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a == b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 == b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Bool(a == b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a == b).to(),
|
||||
(VDataEnum::String(a), VDataEnum::String(b)) => {
|
||||
VDataEnum::Bool(a == b).to()
|
||||
}
|
||||
_ => unreachable!("eq: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("eq: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Gt => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a > b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 > b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Bool(a > b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a > b).to(),
|
||||
_ => unreachable!("gt: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("gt: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Lt => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a < b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool((a as f64) < b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Bool(a < b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a < b).to(),
|
||||
_ => unreachable!("lt: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("lt: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Gtoe => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a >= b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 >= b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Bool(a >= b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a >= b).to(),
|
||||
_ => unreachable!("gtoe: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("gtoe: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Ltoe => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a <= b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 <= b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Bool(a <= b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a <= b).to(),
|
||||
_ => unreachable!("ltoe: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("ltoe: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Min => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a.min(b)).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float((a as f64).min(b)).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a.min(b as f64)).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a.min(b)).to()
|
||||
}
|
||||
_ => unreachable!("min: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("min: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Max => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars).data, args[1].run(vars).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Int(a.max(b)).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float((a as f64).max(b)).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Float(a.max(b as f64)).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Float(a.max(b)).to()
|
||||
}
|
||||
_ => unreachable!("max: not a number"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("max: not 2 args")
|
||||
}
|
||||
}
|
||||
Self::Push => {
|
||||
if args.len() == 2 {
|
||||
if let VDataEnum::Reference(v) = args[0].run(vars).data {
|
||||
|
Loading…
Reference in New Issue
Block a user