Fix array expressions (#473)

* fix array expressions

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix-tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2023-09-13 09:23:24 -07:00
committed by GitHub
parent c9ed6c724c
commit fe3ee3806e
3 changed files with 87 additions and 20 deletions

View File

@ -1555,6 +1555,38 @@ impl MemberExpression {
None
}
pub fn get_result_array(&self, memory: &mut ProgramMemory, index: usize) -> Result<MemoryItem, KclError> {
let array = match &self.object {
MemberObject::MemberExpression(member_expr) => member_expr.get_result(memory)?,
MemberObject::Identifier(identifier) => {
let value = memory.get(&identifier.name, identifier.into())?;
value.clone()
}
}
.get_json_value()?;
if let serde_json::Value::Array(array) = array {
if let Some(value) = array.get(index) {
Ok(MemoryItem::UserVal(UserVal {
value: value.clone(),
meta: vec![Metadata {
source_range: self.into(),
}],
}))
} else {
Err(KclError::UndefinedValue(KclErrorDetails {
message: format!("index {} not found in array", index),
source_ranges: vec![self.clone().into()],
}))
}
} else {
Err(KclError::Semantic(KclErrorDetails {
message: format!("MemberExpression array is not an array: {:?}", array),
source_ranges: vec![self.clone().into()],
}))
}
}
pub fn get_result(&self, memory: &mut ProgramMemory) -> Result<MemoryItem, KclError> {
let property_name = match &self.property {
LiteralIdentifier::Identifier(identifier) => identifier.name.to_string(),
@ -1563,9 +1595,12 @@ impl MemberExpression {
// Parse this as a string.
if let serde_json::Value::String(string) = value {
string
} else if let serde_json::Value::Number(_) = &value {
// It can also be a number if we are getting a member of an array.
return self.get_result_array(memory, parse_json_number_as_usize(&value, self.into())?);
} else {
return Err(KclError::Semantic(KclErrorDetails {
message: format!("Expected string literal for property name, found {:?}", value),
message: format!("Expected string literal or number for property name, found {:?}", value),
source_ranges: vec![literal.into()],
}));
}
@ -1767,6 +1802,22 @@ pub fn parse_json_number_as_f64(j: &serde_json::Value, source_range: SourceRange
}
}
pub fn parse_json_number_as_usize(j: &serde_json::Value, source_range: SourceRange) -> Result<usize, KclError> {
if let serde_json::Value::Number(n) = &j {
Ok(n.as_i64().ok_or_else(|| {
KclError::Syntax(KclErrorDetails {
source_ranges: vec![source_range],
message: format!("Invalid index: {}", j),
})
})? as usize)
} else {
Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![source_range],
message: format!("Invalid index: {}", j),
}))
}
}
pub fn parse_json_value_as_string(j: &serde_json::Value) -> Option<String> {
if let serde_json::Value::String(n) = &j {
Some(n.clone())

View File

@ -1114,11 +1114,10 @@ for var in [[3, 6, 10, [0,0]], [1.5, 3, 5, [-10,-10]]] {
}
#[tokio::test(flavor = "multi_thread")]
#[ignore] // ignore til we get working.
async fn test_get_member_of_array_with_function() {
let ast = r#"const box = (array) => {
let myBox = startSketchAt(array[0])
|> line([0, array[1], %)
|> line([0, array[1]], %)
|> line([array[2], 0], %)
|> line([0, -array[1]], %)
|> close(%)

View File

@ -952,12 +952,18 @@ impl Parser {
let opening_brace_token = self.get_token(index)?;
let first_element_token = self.next_meaningful_token(index, None)?;
// Make sure there is a closing brace.
let _closing_brace = self.find_closing_brace(index, 0, "")?;
let closing_brace_index = self.find_closing_brace(index, 0, "").map_err(|_| {
KclError::Syntax(KclErrorDetails {
source_ranges: vec![opening_brace_token.into()],
message: "missing a closing brace for the array".to_string(),
})
})?;
let closing_brace_token = self.get_token(closing_brace_index)?;
let array_elements = self.make_array_elements(first_element_token.index, Vec::new())?;
Ok(ArrayReturn {
expression: ArrayExpression {
start: opening_brace_token.start,
end: self.get_token(array_elements.last_index)?.end,
end: closing_brace_token.end,
elements: array_elements.elements,
},
last_index: array_elements.last_index,
@ -1038,17 +1044,6 @@ impl Parser {
if let Some(argument_token_token) = argument_token.token {
let next_brace_or_comma = self.next_meaningful_token(argument_token.index, None)?;
if let Some(next_brace_or_comma_token) = next_brace_or_comma.token {
let is_identifier_or_literal = next_brace_or_comma_token.token_type == TokenType::Comma
|| next_brace_or_comma_token.token_type == TokenType::Brace;
if argument_token_token.token_type == TokenType::Brace && argument_token_token.value == "[" {
let array_expression = self.make_array_expression(argument_token.index)?;
let next_comma_or_brace_token_index =
self.next_meaningful_token(array_expression.last_index, None)?.index;
let mut _previous_args = previous_args;
_previous_args.push(Value::ArrayExpression(Box::new(array_expression.expression)));
return self.make_arguments(next_comma_or_brace_token_index, _previous_args);
}
if (argument_token_token.token_type == TokenType::Word)
&& (next_brace_or_comma_token.token_type == TokenType::Period
|| (next_brace_or_comma_token.token_type == TokenType::Brace
@ -1062,6 +1057,17 @@ impl Parser {
return self.make_arguments(next_comma_or_brace_token_index, _previous_args);
}
let is_identifier_or_literal = next_brace_or_comma_token.token_type == TokenType::Comma
|| next_brace_or_comma_token.token_type == TokenType::Brace;
if argument_token_token.token_type == TokenType::Brace && argument_token_token.value == "[" {
let array_expression = self.make_array_expression(argument_token.index)?;
let next_comma_or_brace_token_index =
self.next_meaningful_token(array_expression.last_index, None)?.index;
let mut _previous_args = previous_args;
_previous_args.push(Value::ArrayExpression(Box::new(array_expression.expression)));
return self.make_arguments(next_comma_or_brace_token_index, _previous_args);
}
if argument_token_token.token_type == TokenType::Operator && argument_token_token.value == "-" {
let value = self.make_value(argument_token.index)?;
let next_comma_or_brace_token_index = self.next_meaningful_token(value.last_index, None)?.index;
@ -1185,9 +1191,14 @@ impl Parser {
let brace_token = self.next_meaningful_token(index, None)?;
let callee = self.make_identifier(index)?;
// Make sure there is a closing brace.
let _closing_brace_token = self.find_closing_brace(brace_token.index, 0, "")?;
let closing_brace_index = self.find_closing_brace(brace_token.index, 0, "").map_err(|_| {
KclError::Syntax(KclErrorDetails {
source_ranges: vec![current_token.into()],
message: "missing a closing brace for the function call".to_string(),
})
})?;
let closing_brace_token = self.get_token(closing_brace_index)?;
let args = self.make_arguments(brace_token.index, vec![])?;
let closing_brace_token = self.get_token(args.last_index)?;
let function = if let Some(stdlib_fn) = self.stdlib.get(&callee.name) {
crate::abstract_syntax_tree_types::Function::StdLib { func: stdlib_fn }
} else {
@ -2984,7 +2995,10 @@ z(-[["#,
let parser = Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
assert!(result.err().unwrap().to_string().contains("unexpected end"));
assert_eq!(
result.err().unwrap().to_string(),
r#"syntax: KclErrorDetails { source_ranges: [SourceRange([1, 2])], message: "missing a closing brace for the function call" }"#
);
}
#[test]
@ -2996,7 +3010,10 @@ z(-[["#,
let parser = Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
assert!(result.err().unwrap().to_string().contains("unexpected end"));
assert_eq!(
result.err().unwrap().to_string(),
r#"syntax: KclErrorDetails { source_ranges: [SourceRange([0, 1])], message: "missing a closing brace for the function call" }"#
);
}
#[test]