diff --git a/kalk/src/ast.rs b/kalk/src/ast.rs index 035f848..cf8d34e 100644 --- a/kalk/src/ast.rs +++ b/kalk/src/ast.rs @@ -23,7 +23,7 @@ pub enum Expr { Piecewise(Vec), Vector(Vec), Matrix(Vec>), - Indexer(Box, Box), + Indexer(Box, Vec), } #[derive(Debug, Clone, PartialEq)] diff --git a/kalk/src/interpreter.rs b/kalk/src/interpreter.rs index a0fea36..6343115 100644 --- a/kalk/src/interpreter.rs +++ b/kalk/src/interpreter.rs @@ -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>) -> Result Result { 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), } } diff --git a/kalk/src/parser.rs b/kalk/src/parser.rs index 81c74a6..0b6f931 100644 --- a/kalk/src/parser.rs +++ b/kalk/src/parser.rs @@ -104,7 +104,8 @@ pub enum CalcError { ExpectedDx, ExpectedIf, IncorrectAmountOfArguments(usize, String, usize), - ItemOfIndexDoesNotExist(usize), + IncorrectAmountOfIndexes(usize, usize), + ItemOfIndexDoesNotExist(Vec), 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::>().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 { 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 { 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);