mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-06-25 04:01:51 +02: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],
|
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 => {
|
||||||
|
@ -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,10 +605,20 @@ 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> {
|
||||||
let identifier = Identifier::from_full_name(&advance(context).value);
|
let identifier = Identifier::from_full_name(&advance(context).value);
|
||||||
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user