use super::utils::{comma_separate, gather_operands};
use super::{find_matching_parenthesis, ParseNode};
use crate::ast_node::{ASTContext, Node, TokenSlice};
use crate::operations::Operation;
use crate::syntax_error::SyntaxError;
use crate::tokens::Token;
use crate::types::IJType;
use anyhow::Result;
use std::rc::Rc;
#[derive(Debug, PartialEq)]
pub struct LSqBracket;
impl ParseNode for LSqBracket {
fn next_node(
_op: Token,
slice: TokenSlice,
context: &mut ASTContext,
) -> Result<(Rc<Node>, TokenSlice)> {
let rparen_index =
find_matching_parenthesis(context, slice, &Token::LSqBracket, &Token::RSqBracket)
.map_err(|e| context.add_context_to_syntax_error(e, slice))?;
let rest = slice.move_start(rparen_index + 1)?;
let inner_slice = slice.move_end(rparen_index)?;
let content_slices = comma_separate(inner_slice, context)?;
let content_operands = content_slices
.into_iter()
.map(|s| {
let (operands, remainder) = gather_operands(
vec![vec![IJType::Tensor(None)], vec![IJType::Number(None)]],
s,
context,
)?;
match remainder.is_empty() {
true => Ok(operands[0].clone()),
false => Err(SyntaxError::UnhandledTokens(
context.token_slice_to_string(remainder),
)
.into()),
}
})
.collect::<Result<Vec<_>>>()?;
let (output_type, rest) = match context.get_token_at_index(rest.start) {
Ok(Token::NumberType(n)) => (IJType::Tensor(Some(n.clone())), rest.move_start(1)?),
_ => (IJType::Tensor(None), rest),
};
Ok((
Rc::new(Node::new(
Operation::Array,
content_operands
.iter()
.map(|n| n.output_type.clone())
.collect(),
output_type,
content_operands,
context,
)?),
rest,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::parse_str_no_context;
#[test]
fn test_array_node() -> Result<()> {
let (node, _) = parse_str_no_context("[1, 2, 3]")?;
assert_eq!(node.op, Operation::Array);
assert_eq!(node.output_type, IJType::Tensor(None));
let (node, _) = parse_str_no_context("[[1.0]]")?;
assert_eq!(node.op, Operation::Array);
assert_eq!(node.output_type, IJType::Tensor(None));
Ok(())
}
#[test]
fn test_array_node_with_type() -> Result<()> {
let (node, _) = parse_str_no_context("[1, 2, 3]<i64>")?;
assert_eq!(node.op, Operation::Array);
assert_eq!(node.output_type, IJType::Tensor(Some("i64".to_string())));
let (node, _) = parse_str_no_context("[1, 2, 3]<_>")?;
assert_eq!(node.op, Operation::Array);
assert_eq!(node.output_type, IJType::Tensor(Some("_".to_string())));
let (node, _) = parse_str_no_context("[[1.0]]<f64>")?;
assert_eq!(node.op, Operation::Array);
assert_eq!(node.output_type, IJType::Tensor(Some("f64".to_string())));
Ok(())
}
}