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