Indexing matrices by ⟦⟧

This commit is contained in:
PaddiM8 2022-01-07 01:19:33 +01:00
parent e2271b7005
commit df26046e1d
3 changed files with 50 additions and 16 deletions

View File

@ -23,7 +23,7 @@ pub enum Expr {
Piecewise(Vec<ConditionalPiece>), Piecewise(Vec<ConditionalPiece>),
Vector(Vec<Expr>), Vector(Vec<Expr>),
Matrix(Vec<Vec<Expr>>), Matrix(Vec<Vec<Expr>>),
Indexer(Box<Expr>, Box<Expr>), Indexer(Box<Expr>, Vec<Expr>),
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]

View File

@ -126,7 +126,7 @@ pub(crate) fn eval_expr(
Expr::Piecewise(pieces) => eval_piecewise(context, pieces, unit), Expr::Piecewise(pieces) => eval_piecewise(context, pieces, unit),
Expr::Vector(values) => eval_vector(context, values), Expr::Vector(values) => eval_vector(context, values),
Expr::Matrix(rows) => eval_matrix(context, rows), Expr::Matrix(rows) => eval_matrix(context, rows),
Expr::Indexer(var, index) => eval_indexer(context, var, index, unit), Expr::Indexer(var, indexes) => eval_indexer(context, var, indexes, unit),
} }
} }
@ -582,19 +582,42 @@ fn eval_matrix(context: &mut Context, rows: &Vec<Vec<Expr>>) -> Result<KalkValue
fn eval_indexer( fn eval_indexer(
context: &mut Context, context: &mut Context,
var: &Expr, var: &Expr,
index: &Expr, indexes: &[Expr],
unit: &str, unit: &str,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
let var_value = eval_expr(context, var, unit)?; let var_value = eval_expr(context, var, unit)?;
if let KalkValue::Vector(values) = var_value { match var_value {
let index_value = eval_expr(context, index, unit)?.to_f64() as usize; KalkValue::Vector(values) => {
if let Some(value) = values.get(index_value) { if indexes.len() != 1 {
Ok(value.clone()) return Err(CalcError::IncorrectAmountOfIndexes(indexes.len(), 1));
} else { }
Err(CalcError::ItemOfIndexDoesNotExist(index_value))
let index_value = eval_expr(context, &indexes[0], unit)?.to_f64() as usize;
if let Some(value) = values.get(index_value) {
Ok(value.clone())
} else {
Err(CalcError::ItemOfIndexDoesNotExist(vec![index_value]))
}
} }
} else { KalkValue::Matrix(rows) => {
Err(CalcError::CanOnlyIndexVectors) if indexes.len() != 2 {
return Err(CalcError::IncorrectAmountOfIndexes(indexes.len(), 2));
}
let row_index = eval_expr(context, &indexes[0], unit)?.to_f64() as usize;
let column_index = eval_expr(context, &indexes[1], unit)?.to_f64() as usize;
if let Some(row) = rows.get(row_index) {
if let Some(value) = row.get(column_index) {
return Ok(value.clone());
}
}
Err(CalcError::ItemOfIndexDoesNotExist(vec![
row_index,
column_index,
]))
}
_ => Err(CalcError::CanOnlyIndexVectors),
} }
} }

View File

@ -104,7 +104,8 @@ pub enum CalcError {
ExpectedDx, ExpectedDx,
ExpectedIf, ExpectedIf,
IncorrectAmountOfArguments(usize, String, usize), IncorrectAmountOfArguments(usize, String, usize),
ItemOfIndexDoesNotExist(usize), IncorrectAmountOfIndexes(usize, usize),
ItemOfIndexDoesNotExist(Vec<usize>),
InconsistentColumnWidths, InconsistentColumnWidths,
InvalidNumberLiteral(String), InvalidNumberLiteral(String),
InvalidOperator, InvalidOperator,
@ -134,7 +135,11 @@ impl ToString for CalcError {
"Expected {} arguments for function {}, but got {}.", "Expected {} arguments for function {}, but got {}.",
expected, func, got expected, func, got
), ),
CalcError::ItemOfIndexDoesNotExist(index) => format!("Item of index {} does not exist.", index), CalcError::IncorrectAmountOfIndexes(expected, got) => format!(
"Expected {} indexes but got {}.",
expected, got
),
CalcError::ItemOfIndexDoesNotExist(indexes) => format!("Item of index ⟦{}⟧ does not exist.", indexes.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(", ")),
CalcError::InconsistentColumnWidths => format!("Inconsistent column widths. Matrix columns must be the same size."), CalcError::InconsistentColumnWidths => format!("Inconsistent column widths. Matrix columns must be the same size."),
CalcError::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x), CalcError::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
CalcError::InvalidOperator => format!("Invalid operator."), CalcError::InvalidOperator => format!("Invalid operator."),
@ -566,9 +571,15 @@ fn parse_indexer(context: &mut Context) -> Result<Expr, CalcError> {
if match_token(context, TokenKind::OpenDoubleBracket) { if match_token(context, TokenKind::OpenDoubleBracket) {
advance(context); advance(context);
let right = Box::new(parse_expr(context)?); let mut indexes = vec![parse_expr(context)?];
while match_token(context, TokenKind::Comma) {
advance(context);
indexes.push(parse_expr(context)?);
}
consume(context, TokenKind::ClosedDoubleBracket)?; consume(context, TokenKind::ClosedDoubleBracket)?;
return Ok(Expr::Indexer(Box::new(left), right));
return Ok(Expr::Indexer(Box::new(left), indexes));
} }
Ok(left) Ok(left)
@ -771,7 +782,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
Ok(Expr::Indexer( Ok(Expr::Indexer(
Box::new(Expr::Var(Identifier::from_full_name(&var_name))), Box::new(Expr::Var(Identifier::from_full_name(&var_name))),
Box::new(lowered_expr), vec![lowered_expr],
)) ))
} else if context.parsing_unit_decl { } else if context.parsing_unit_decl {
context.unit_decl_base_unit = Some(identifier.full_name); context.unit_decl_base_unit = Some(identifier.full_name);