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