mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-12-12 09:30:40 +01:00
Treat any groups with commas as vectors
This commit is contained in:
parent
971965ddce
commit
0aabade786
@ -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 => {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user