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

View File

@ -75,7 +75,6 @@ lazy_static! {
m.insert("abs", (UnaryFuncInfo(abs, Other), ""));
m.insert("arg", (UnaryFuncInfo(arg, Other), ""));
m.insert("average", (UnaryFuncInfo(average, Other), ""));
m.insert("cbrt", (UnaryFuncInfo(cbrt, Other), ""));
m.insert("ceil", (UnaryFuncInfo(ceil, Other), ""));
m.insert("iverson", (UnaryFuncInfo(iverson, Other), ""));
@ -87,8 +86,6 @@ lazy_static! {
m.insert("Γ", (UnaryFuncInfo(gamma, Other), ""));
m.insert("log", (UnaryFuncInfo(log, 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("round", (UnaryFuncInfo(round, Other), ""));
m.insert("sqrt", (UnaryFuncInfo(sqrt, Other), ""));
@ -103,8 +100,6 @@ lazy_static! {
m.insert("bitor", (BinaryFuncInfo(bitor, Other), ""));
m.insert("bitxor", (BinaryFuncInfo(bitxor, 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("gcd", (BinaryFuncInfo(gcd, Other), ""));
m.insert("lcm", (BinaryFuncInfo(lcm, Other), ""));
@ -116,6 +111,13 @@ lazy_static! {
m.insert("perm", (BinaryFuncInfo(npr, Other), ""));
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 {
@ -128,6 +130,8 @@ pub struct UnaryFuncInfo(fn(KalkValue) -> KalkValue, FuncType);
pub struct BinaryFuncInfo(fn(KalkValue, KalkValue) -> KalkValue, FuncType);
pub struct VectorFuncInfo(fn(KalkValue) -> KalkValue, FuncType);
impl UnaryFuncInfo {
fn call(
&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 {
identifier == "sum"
|| identifier == "Σ"
@ -175,6 +186,11 @@ pub fn is_prelude_func(identifier: &str) -> bool {
|| identifier == ""
|| UNARY_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 {
@ -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 {
match angle_unit {
"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 mut max = &values[0];
for value in &values {
@ -714,7 +738,7 @@ pub mod funcs {
max.clone()
}
pub fn min_vec(x: KalkValue) -> KalkValue {
pub fn min(x: KalkValue) -> KalkValue {
let values = as_vector_or_return!(x);
let mut min = &values[0];
for value in &values {

View File

@ -114,18 +114,4 @@ pub(crate) mod funcs {
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)
}
}
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)
}
}