Treat any groups with commas as vectors

This commit is contained in:
PaddiM8 2022-01-05 18:50:07 +01:00
parent 971965ddce
commit 0aabade786
5 changed files with 90 additions and 75 deletions

View File

@ -293,6 +293,27 @@ pub(crate) fn eval_fn_call_expr(
expressions: &[Expr], expressions: &[Expr],
unit: &str, unit: &str,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
// Prelude vector function
if prelude::is_vector_func(&identifier.full_name) {
let mut values = Vec::new();
for expression in expressions {
let value = eval_expr(context, expression, "")?;
if expressions.len() == 1 {
if let KalkValue::Vector(internal_values) = value {
values = internal_values;
break;
}
}
values.push(value);
}
return Ok(
prelude::call_vector_func(&identifier.full_name, KalkValue::Vector(values))
.unwrap_or(KalkValue::nan()),
);
}
// Prelude // Prelude
let prelude_func = match expressions.len() { let prelude_func = match expressions.len() {
1 => { 1 => {

View File

@ -568,9 +568,8 @@ fn parse_factorial(context: &mut Context) -> Result<Expr, CalcError> {
fn parse_primary(context: &mut Context) -> Result<Expr, CalcError> { fn parse_primary(context: &mut Context) -> Result<Expr, CalcError> {
let expr = match peek(context).kind { let expr = match peek(context).kind {
TokenKind::OpenParenthesis => parse_group(context)?, TokenKind::OpenParenthesis | TokenKind::OpenBracket => parse_vector(context)?,
TokenKind::Pipe | TokenKind::OpenCeil | TokenKind::OpenFloor => parse_group_fn(context)?, TokenKind::Pipe | TokenKind::OpenCeil | TokenKind::OpenFloor => parse_group_fn(context)?,
TokenKind::OpenBracket => parse_vector(context)?,
TokenKind::Identifier => parse_identifier(context)?, TokenKind::Identifier => parse_identifier(context)?,
TokenKind::Literal => Expr::Literal(string_to_num(&advance(context).value)?), TokenKind::Literal => Expr::Literal(string_to_num(&advance(context).value)?),
_ => return Err(CalcError::UnableToParseExpression), _ => return Err(CalcError::UnableToParseExpression),
@ -579,33 +578,22 @@ fn parse_primary(context: &mut Context) -> Result<Expr, CalcError> {
Ok(expr) Ok(expr)
} }
fn parse_group(context: &mut Context) -> Result<Expr, CalcError> {
advance(context);
let group_expr = Expr::Group(Box::new(parse_expr(context)?));
consume(context, TokenKind::ClosedParenthesis)?;
Ok(group_expr)
}
fn parse_group_fn(context: &mut Context) -> Result<Expr, CalcError> { fn parse_group_fn(context: &mut Context) -> Result<Expr, CalcError> {
let name = match &advance(context).kind { let name = match &peek(context).kind {
TokenKind::Pipe => "abs", TokenKind::Pipe => "abs",
TokenKind::OpenCeil => "ceil", TokenKind::OpenCeil => "ceil",
TokenKind::OpenFloor => "floor", TokenKind::OpenFloor => "floor",
_ => unreachable!(), _ => unreachable!(),
}; };
let expr = parse_expr(context)?; match parse_vector(context)? {
Expr::Vector(arguments) => Ok(Expr::FnCall(Identifier::from_full_name(name), arguments)),
if peek(context).kind == TokenKind::EOF { Expr::Group(argument) => Ok(Expr::FnCall(
return Err(CalcError::Expected(String::from( Identifier::from_full_name(name),
"Closing group symbol, eg. ⌋", vec![*argument],
))); )),
_ => unreachable!(),
} }
advance(context);
Ok(Expr::FnCall(Identifier::from_full_name(name), vec![expr]))
} }
fn parse_vector(context: &mut Context) -> Result<Expr, CalcError> { fn parse_vector(context: &mut Context) -> Result<Expr, CalcError> {
@ -617,9 +605,19 @@ fn parse_vector(context: &mut Context) -> Result<Expr, CalcError> {
values.push(parse_expr(context)?); values.push(parse_expr(context)?);
} }
if peek(context).kind == TokenKind::EOF {
return Err(CalcError::Expected(String::from(
"Closing group symbol, eg. ⌋",
)));
}
advance(context); advance(context);
if values.len() == 1 {
Ok(Expr::Group(Box::new(values.pop().unwrap())))
} else {
Ok(Expr::Vector(values)) Ok(Expr::Vector(values))
}
} }
fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> { fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
@ -659,17 +657,21 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
return Ok(Expr::FnCall(identifier, vec![parameter])); return Ok(Expr::FnCall(identifier, vec![parameter]));
} }
let parse_as_var_instead = match_token(context, TokenKind::OpenParenthesis) let next_is_group = match peek(context).kind {
&& !context.parsing_identifier_stmt TokenKind::OpenParenthesis
&& !exists_as_fn; | TokenKind::OpenBracket
| TokenKind::Pipe
| TokenKind::OpenCeil
| TokenKind::OpenFloor => true,
_ => false,
};
let parse_as_var_instead = next_is_group && !context.parsing_identifier_stmt && !exists_as_fn;
// Eg. sqrt(64) // Eg. sqrt(64)
// If the function doesn't exist, parse it as a variable and multiplication instead. // If the function doesn't exist, parse it as a variable and multiplication instead.
// Although, if the parse_identifier_stmt function called this function, // Although, if the parse_identifier_stmt function called this function,
// parse it as a function anyway, since it might be creating one. // parse it as a function anyway, since it might be creating one.
if !parse_as_var_instead && match_token(context, TokenKind::OpenParenthesis) { if !parse_as_var_instead && next_is_group {
advance(context);
let is_integral = identifier.full_name == "integrate" let is_integral = identifier.full_name == "integrate"
|| identifier.full_name == "integral" || identifier.full_name == "integral"
|| identifier.full_name == ""; || identifier.full_name == "";
@ -677,26 +679,22 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
context.is_in_integral = true; context.is_in_integral = true;
} }
let mut parameters = Vec::new(); let mut arguments = match parse_vector(context)? {
parameters.push(parse_expr(context)?); Expr::Vector(arguments) => arguments,
Expr::Group(argument) => vec![*argument],
while match_token(context, TokenKind::Comma) { _ => unreachable!(),
advance(context); };
parameters.push(parse_expr(context)?);
}
consume(context, TokenKind::ClosedParenthesis)?;
if is_integral { if is_integral {
context.is_in_integral = false; context.is_in_integral = false;
} }
if let Some(log_base) = log_base { if let Some(log_base) = log_base {
parameters.push(log_base); arguments.push(log_base);
return Ok(Expr::FnCall(Identifier::from_full_name("log"), parameters)); return Ok(Expr::FnCall(Identifier::from_full_name("log"), arguments));
} }
return Ok(Expr::FnCall(identifier, parameters)); return Ok(Expr::FnCall(identifier, arguments));
} }
// Eg. x // Eg. x

View File

@ -75,7 +75,6 @@ lazy_static! {
m.insert("abs", (UnaryFuncInfo(abs, Other), "")); m.insert("abs", (UnaryFuncInfo(abs, Other), ""));
m.insert("arg", (UnaryFuncInfo(arg, Other), "")); m.insert("arg", (UnaryFuncInfo(arg, Other), ""));
m.insert("average", (UnaryFuncInfo(average, Other), ""));
m.insert("cbrt", (UnaryFuncInfo(cbrt, Other), "")); m.insert("cbrt", (UnaryFuncInfo(cbrt, Other), ""));
m.insert("ceil", (UnaryFuncInfo(ceil, Other), "")); m.insert("ceil", (UnaryFuncInfo(ceil, Other), ""));
m.insert("iverson", (UnaryFuncInfo(iverson, Other), "")); m.insert("iverson", (UnaryFuncInfo(iverson, Other), ""));
@ -87,8 +86,6 @@ lazy_static! {
m.insert("Γ", (UnaryFuncInfo(gamma, Other), "")); m.insert("Γ", (UnaryFuncInfo(gamma, Other), ""));
m.insert("log", (UnaryFuncInfo(log, Other), "")); m.insert("log", (UnaryFuncInfo(log, Other), ""));
m.insert("ln", (UnaryFuncInfo(ln, Other), "")); m.insert("ln", (UnaryFuncInfo(ln, Other), ""));
m.insert("max", (UnaryFuncInfo(max_vec, Other), ""));
m.insert("min", (UnaryFuncInfo(min_vec, Other), ""));
m.insert("Re", (UnaryFuncInfo(re, Other), "")); m.insert("Re", (UnaryFuncInfo(re, Other), ""));
m.insert("round", (UnaryFuncInfo(round, Other), "")); m.insert("round", (UnaryFuncInfo(round, Other), ""));
m.insert("sqrt", (UnaryFuncInfo(sqrt, Other), "")); m.insert("sqrt", (UnaryFuncInfo(sqrt, Other), ""));
@ -103,8 +100,6 @@ lazy_static! {
m.insert("bitor", (BinaryFuncInfo(bitor, Other), "")); m.insert("bitor", (BinaryFuncInfo(bitor, Other), ""));
m.insert("bitxor", (BinaryFuncInfo(bitxor, Other), "")); m.insert("bitxor", (BinaryFuncInfo(bitxor, Other), ""));
m.insert("bitshift", (BinaryFuncInfo(bitshift, Other), "")); m.insert("bitshift", (BinaryFuncInfo(bitshift, Other), ""));
m.insert("max", (BinaryFuncInfo(max, Other), ""));
m.insert("min", (BinaryFuncInfo(min, Other), ""));
m.insert("hypot", (BinaryFuncInfo(hypot, Other), "")); m.insert("hypot", (BinaryFuncInfo(hypot, Other), ""));
m.insert("gcd", (BinaryFuncInfo(gcd, Other), "")); m.insert("gcd", (BinaryFuncInfo(gcd, Other), ""));
m.insert("lcm", (BinaryFuncInfo(lcm, Other), "")); m.insert("lcm", (BinaryFuncInfo(lcm, Other), ""));
@ -116,6 +111,13 @@ lazy_static! {
m.insert("perm", (BinaryFuncInfo(npr, Other), "")); m.insert("perm", (BinaryFuncInfo(npr, Other), ""));
m m
}; };
pub static ref VECTOR_FUNCS: HashMap<&'static str, VectorFuncInfo> = {
let mut m = HashMap::new();
m.insert("average", VectorFuncInfo(average, Other));
m.insert("max", VectorFuncInfo(max, Other));
m.insert("min", VectorFuncInfo(min, Other));
m
};
} }
enum FuncType { enum FuncType {
@ -128,6 +130,8 @@ pub struct UnaryFuncInfo(fn(KalkValue) -> KalkValue, FuncType);
pub struct BinaryFuncInfo(fn(KalkValue, KalkValue) -> KalkValue, FuncType); pub struct BinaryFuncInfo(fn(KalkValue, KalkValue) -> KalkValue, FuncType);
pub struct VectorFuncInfo(fn(KalkValue) -> KalkValue, FuncType);
impl UnaryFuncInfo { impl UnaryFuncInfo {
fn call( fn call(
&self, &self,
@ -164,6 +168,13 @@ impl BinaryFuncInfo {
} }
} }
impl VectorFuncInfo {
fn call(&self, x: KalkValue) -> KalkValue {
let func = self.0;
func(x)
}
}
pub fn is_prelude_func(identifier: &str) -> bool { pub fn is_prelude_func(identifier: &str) -> bool {
identifier == "sum" identifier == "sum"
|| identifier == "Σ" || identifier == "Σ"
@ -175,6 +186,11 @@ pub fn is_prelude_func(identifier: &str) -> bool {
|| identifier == "" || identifier == ""
|| UNARY_FUNCS.contains_key(identifier) || UNARY_FUNCS.contains_key(identifier)
|| BINARY_FUNCS.contains_key(identifier) || BINARY_FUNCS.contains_key(identifier)
|| VECTOR_FUNCS.contains_key(identifier)
}
pub fn is_vector_func(identifier: &str) -> bool {
VECTOR_FUNCS.contains_key(identifier)
} }
pub fn is_constant(identifier: &str) -> bool { pub fn is_constant(identifier: &str) -> bool {
@ -214,6 +230,14 @@ pub fn call_binary_func(
} }
} }
pub fn call_vector_func(name: &str, x: KalkValue) -> Option<KalkValue> {
if let Some(func_info) = VECTOR_FUNCS.get(name) {
Some(func_info.call(x))
} else {
None
}
}
fn to_angle_unit(context: &mut interpreter::Context, x: KalkValue, angle_unit: &str) -> KalkValue { fn to_angle_unit(context: &mut interpreter::Context, x: KalkValue, angle_unit: &str) -> KalkValue {
match angle_unit { match angle_unit {
"rad" => x, "rad" => x,
@ -700,7 +724,7 @@ pub mod funcs {
} }
} }
pub fn max_vec(x: KalkValue) -> KalkValue { pub fn max(x: KalkValue) -> KalkValue {
let values = as_vector_or_return!(x); let values = as_vector_or_return!(x);
let mut max = &values[0]; let mut max = &values[0];
for value in &values { for value in &values {
@ -714,7 +738,7 @@ pub mod funcs {
max.clone() max.clone()
} }
pub fn min_vec(x: KalkValue) -> KalkValue { pub fn min(x: KalkValue) -> KalkValue {
let values = as_vector_or_return!(x); let values = as_vector_or_return!(x);
let mut min = &values[0]; let mut min = &values[0];
for value in &values { for value in &values {

View File

@ -114,18 +114,4 @@ pub(crate) mod funcs {
KalkValue::Number(real.hypot(real_rhs), float!(0), unit) KalkValue::Number(real.hypot(real_rhs), float!(0), unit)
} }
} }
pub fn max(x: KalkValue, y: KalkValue) -> KalkValue {
let (real, _, unit) = as_number_or_return!(x);
let (real_rhs, _, _) = as_number_or_return!(y);
KalkValue::Number(real.max(real_rhs), float!(0), unit)
}
pub fn min(x: KalkValue, y: KalkValue) -> KalkValue {
let (real, _, unit) = as_number_or_return!(x);
let (real_rhs, _, _) = as_number_or_return!(y);
KalkValue::Number(real.min(real_rhs), float!(0), unit)
}
} }

View File

@ -90,18 +90,4 @@ pub(crate) mod funcs {
KalkValue::Number(real.hypot(&real_rhs), float!(0), unit) KalkValue::Number(real.hypot(&real_rhs), float!(0), unit)
} }
} }
pub fn max(x: KalkValue, y: KalkValue) -> KalkValue {
let (real, _, unit) = as_number_or_return!(x);
let (real_rhs, _, _) = as_number_or_return!(y);
KalkValue::Number(real.max(&real_rhs), float!(0), unit)
}
pub fn min(x: KalkValue, y: KalkValue) -> KalkValue {
let (real, _, unit) = as_number_or_return!(x);
let (real_rhs, _, _) = as_number_or_return!(y);
KalkValue::Number(real.min(&real_rhs), float!(0), unit)
}
} }