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>),
Vector(Vec<Expr>),
Matrix(Vec<Vec<Expr>>),
Indexer(Box<Expr>, Box<Expr>),
Indexer(Box<Expr>, Vec<Expr>),
}
#[derive(Debug, Clone, PartialEq)]

View File

@ -126,7 +126,7 @@ pub(crate) fn eval_expr(
Expr::Piecewise(pieces) => eval_piecewise(context, pieces, unit),
Expr::Vector(values) => eval_vector(context, values),
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(
context: &mut Context,
var: &Expr,
index: &Expr,
indexes: &[Expr],
unit: &str,
) -> Result<KalkValue, CalcError> {
let var_value = eval_expr(context, var, unit)?;
if let KalkValue::Vector(values) = var_value {
let index_value = eval_expr(context, index, unit)?.to_f64() as usize;
if let Some(value) = values.get(index_value) {
Ok(value.clone())
} else {
Err(CalcError::ItemOfIndexDoesNotExist(index_value))
match var_value {
KalkValue::Vector(values) => {
if indexes.len() != 1 {
return Err(CalcError::IncorrectAmountOfIndexes(indexes.len(), 1));
}
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 {
Err(CalcError::CanOnlyIndexVectors)
KalkValue::Matrix(rows) => {
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,
ExpectedIf,
IncorrectAmountOfArguments(usize, String, usize),
ItemOfIndexDoesNotExist(usize),
IncorrectAmountOfIndexes(usize, usize),
ItemOfIndexDoesNotExist(Vec<usize>),
InconsistentColumnWidths,
InvalidNumberLiteral(String),
InvalidOperator,
@ -134,7 +135,11 @@ impl ToString for CalcError {
"Expected {} arguments for function {}, but 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::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
CalcError::InvalidOperator => format!("Invalid operator."),
@ -566,9 +571,15 @@ fn parse_indexer(context: &mut Context) -> Result<Expr, CalcError> {
if match_token(context, TokenKind::OpenDoubleBracket) {
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)?;
return Ok(Expr::Indexer(Box::new(left), right));
return Ok(Expr::Indexer(Box::new(left), indexes));
}
Ok(left)
@ -771,7 +782,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
Ok(Expr::Indexer(
Box::new(Expr::Var(Identifier::from_full_name(&var_name))),
Box::new(lowered_expr),
vec![lowered_expr],
))
} else if context.parsing_unit_decl {
context.unit_decl_base_unit = Some(identifier.full_name);