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:
@ -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())
|
||||
|
||||
@ -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(%)
|
||||
|
||||
@ -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]
|
||||
|
||||
Reference in New Issue
Block a user