fix negative word binary expression (#549)

* fix negative word binary expression

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

* updates

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-15 13:19:53 -07:00
committed by GitHub
parent caddac5059
commit ce51f26701
5 changed files with 110 additions and 18 deletions

View File

@ -510,6 +510,8 @@ impl BinaryPart {
let mut new_pipe_info = pipe_info.clone();
new_pipe_info.is_in_pipe = false;
println!("BinaryPart::get_result: {:?}", self);
match self {
BinaryPart::Literal(literal) => Ok(literal.into()),
BinaryPart::Identifier(identifier) => {
@ -521,11 +523,7 @@ impl BinaryPart {
}
BinaryPart::CallExpression(call_expression) => call_expression.execute(memory, &mut new_pipe_info, engine),
BinaryPart::UnaryExpression(unary_expression) => {
// Return an error this should not happen.
Err(KclError::Semantic(KclErrorDetails {
message: format!("UnaryExpression should not be a BinaryPart: {:?}", unary_expression),
source_ranges: vec![unary_expression.into()],
}))
unary_expression.get_result(memory, &mut new_pipe_info, engine)
}
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(memory),
}

View File

@ -1182,4 +1182,28 @@ show(thisBox)
memory.root.get("thing").unwrap().get_json_value().unwrap()
);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_math_negative_variable_in_binary_expression() {
let ast = r#"const sigmaAllow = 35000 // psi
const width = 1 // inch
const p = 150 // lbs
const distance = 6 // inches
const FOS = 2
const leg1 = 5 // inches
const leg2 = 8 // inches
const thickness_squared = distance * p * FOS * 6 / sigmaAllow
const thickness = 0.56 // inches. App does not support square root function yet
const bracket = startSketchAt([0,0])
|> line([0, leg1], %)
|> line([leg2, 0], %)
|> line([0, -thickness], %)
|> line([-leg2 + thickness, 0], %)
"#;
parse_execute(ast).await.unwrap();
}
}

View File

@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
use crate::{
abstract_syntax_tree_types::{
BinaryExpression, BinaryOperator, BinaryPart, CallExpression, Identifier, Literal, MemberExpression, ValueMeta,
BinaryExpression, BinaryOperator, BinaryPart, CallExpression, Identifier, Literal, MemberExpression,
UnaryExpression, ValueMeta,
},
errors::{KclError, KclErrorDetails},
executor::SourceRange,
@ -82,6 +83,7 @@ pub enum MathExpression {
ExtendedBinaryExpression(Box<ExtendedBinaryExpression>),
ParenthesisToken(Box<ParenthesisToken>),
MemberExpression(Box<MemberExpression>),
UnaryExpression(Box<UnaryExpression>),
}
impl MathExpression {
@ -94,6 +96,7 @@ impl MathExpression {
MathExpression::ExtendedBinaryExpression(extended_binary_expression) => extended_binary_expression.start(),
MathExpression::ParenthesisToken(parenthesis_token) => parenthesis_token.start(),
MathExpression::MemberExpression(member_expression) => member_expression.start(),
MathExpression::UnaryExpression(unary_expression) => unary_expression.start(),
}
}
@ -106,6 +109,7 @@ impl MathExpression {
MathExpression::ExtendedBinaryExpression(extended_binary_expression) => extended_binary_expression.end(),
MathExpression::ParenthesisToken(parenthesis_token) => parenthesis_token.end(),
MathExpression::MemberExpression(member_expression) => member_expression.end(),
MathExpression::UnaryExpression(unary_expression) => unary_expression.end(),
}
}
}
@ -208,7 +212,8 @@ impl ReversePolishNotation {
if prevtoken.token_type == TokenType::Operator {
// Get the next token and see if it is a number.
if let Ok(nexttoken) = self.parser.get_token(1) {
if nexttoken.token_type == TokenType::Number {
if nexttoken.token_type == TokenType::Number || nexttoken.token_type == TokenType::Word
{
// We have a negative number/ word or string.
// Change the value of the token to be the negative number/ word or string.
let mut new_token = nexttoken.clone();
@ -250,7 +255,7 @@ impl ReversePolishNotation {
&& current_token.value == "-"
{
if let Ok(nexttoken) = self.parser.get_token(1) {
if nexttoken.token_type == TokenType::Number {
if nexttoken.token_type == TokenType::Number || nexttoken.token_type == TokenType::Word {
// We have a negative number/ word or string.
// Change the value of the token to be the negative number/ word or string.
let mut new_token = nexttoken.clone();
@ -435,11 +440,25 @@ impl ReversePolishNotation {
);
}
let mut new_stack = stack;
new_stack.push(MathExpression::Identifier(Box::new(Identifier {
name: current_token.value.clone(),
start: current_token.start,
end: current_token.end,
})));
if current_token.value.starts_with('-') {
let expression = UnaryExpression {
start: current_token.start,
end: current_token.end,
operator: crate::abstract_syntax_tree_types::UnaryOperator::Neg,
argument: BinaryPart::Identifier(Box::new(Identifier {
name: current_token.value.trim_start_matches('-').to_string(),
start: current_token.start + 1,
end: current_token.end,
})),
};
new_stack.push(MathExpression::UnaryExpression(Box::new(expression)));
} else {
new_stack.push(MathExpression::Identifier(Box::new(Identifier {
name: current_token.value.clone(),
start: current_token.start,
end: current_token.end,
})));
}
return self.build_tree(&reverse_polish_notation_tokens[1..], new_stack);
}
} else if current_token.token_type == TokenType::Brace && current_token.value == "(" {
@ -571,6 +590,10 @@ impl ReversePolishNotation {
BinaryPart::MemberExpression(member_expression.clone()),
member_expression.start,
),
MathExpression::UnaryExpression(unary_expression) => (
BinaryPart::UnaryExpression(unary_expression.clone()),
unary_expression.start,
),
a => {
return Err(KclError::InvalidExpression(KclErrorDetails {
source_ranges: vec![current_token.into()],
@ -605,6 +628,10 @@ impl ReversePolishNotation {
BinaryPart::MemberExpression(member_expression.clone()),
member_expression.end,
),
MathExpression::UnaryExpression(unary_expression) => (
BinaryPart::UnaryExpression(unary_expression.clone()),
unary_expression.end,
),
a => {
return Err(KclError::InvalidExpression(KclErrorDetails {
source_ranges: vec![current_token.into()],

View File

@ -103,9 +103,9 @@ pub struct ParamsResult {
}
#[derive(Debug, PartialEq, Clone)]
struct UnaryExpressionResult {
expression: UnaryExpression,
last_index: usize,
pub struct UnaryExpressionResult {
pub expression: UnaryExpression,
pub last_index: usize,
}
#[derive(Debug, PartialEq, Clone)]
@ -731,7 +731,9 @@ impl Parser {
let maybe_operator = self.next_meaningful_token(index, None)?;
if let Some(maybe_operator_token) = maybe_operator.token {
if maybe_operator_token.token_type == TokenType::Number {
if maybe_operator_token.token_type == TokenType::Number
|| maybe_operator_token.token_type == TokenType::Word
{
return self.find_end_of_binary_expression(maybe_operator.index);
} else if maybe_operator_token.token_type != TokenType::Operator
|| maybe_operator_token.value == PIPE_OPERATOR
@ -1418,7 +1420,7 @@ impl Parser {
self.make_params(next_brace_or_comma_token.index, _previous_params)
}
fn make_unary_expression(&self, index: usize) -> Result<UnaryExpressionResult, KclError> {
pub fn make_unary_expression(&self, index: usize) -> Result<UnaryExpressionResult, KclError> {
let current_token = self.get_token(index)?;
let next_token = self.next_meaningful_token(index, None)?;
if next_token.token.is_none() {
@ -2741,6 +2743,12 @@ show(mySk1)"#;
let tokens = crate::tokeniser::lexer(code);
let parser = Parser::new(tokens);
let _end = parser.find_end_of_binary_expression(0).unwrap();
// with call expression at the end of binary expression
let code = "-legX + 2, ";
let tokens = crate::tokeniser::lexer(code);
let parser = Parser::new(tokens.clone());
let end = parser.find_end_of_binary_expression(0).unwrap();
assert_eq!(tokens[end].value, "2");
}
#[test]
@ -3079,6 +3087,20 @@ const secondExtrude = startSketchAt([0,0])
assert!(result.is_ok());
}
#[test]
fn test_parse_negative_in_array_binary_expression() {
let tokens = crate::tokeniser::lexer(
r#"const leg1 = 5
const thickness = 0.56
const bracket = [-leg2 + thickness, 0]
"#,
);
let parser = Parser::new(tokens);
let result = parser.ast();
assert!(result.is_ok());
}
#[test]
fn test_parse_nested_open_brackets() {
let tokens = crate::tokeniser::lexer(

View File

@ -720,4 +720,25 @@ mod tests {
let semantic_types = TokenType::to_semantic_token_types().unwrap();
assert!(!semantic_types.is_empty());
}
#[test]
fn test_lexer_negative_word() {
assert_eq!(
lexer("-legX"),
vec![
Token {
token_type: TokenType::Operator,
value: "-".to_string(),
start: 0,
end: 1,
},
Token {
token_type: TokenType::Word,
value: "legX".to_string(),
start: 1,
end: 5,
},
]
);
}
}