parser: simplify BoolSlice logic with descriptive helper methods
This commit is contained in:
parent
3305227ffe
commit
3288752dfb
@ -62,46 +62,73 @@ impl BoolSlice {
|
||||
self.number && !self.masked_num
|
||||
}
|
||||
|
||||
/// Returns true if this char is a function name letter (not a standalone variable)
|
||||
const fn is_function_letter(&self) -> bool {
|
||||
self.letter && !self.is_unmasked_variable()
|
||||
}
|
||||
|
||||
/// Returns true if this is a "term" - something that can be multiplied
|
||||
const fn is_term(&self) -> bool {
|
||||
self.is_unmasked_number() || self.is_unmasked_variable() || self.letter
|
||||
}
|
||||
|
||||
const fn calculate_mask(&mut self, other: &BoolSlice) {
|
||||
if other.masked_num && self.number {
|
||||
// If previous char was a masked number, and current char is a number, mask current char's variable status
|
||||
// Propagate number masking through consecutive digits
|
||||
self.masked_num = true;
|
||||
} else if other.masked_var && self.variable {
|
||||
// If previous char was a masked variable, and current char is a variable, mask current char's variable status
|
||||
// Propagate variable masking through consecutive variables
|
||||
self.masked_var = true;
|
||||
} else if other.letter && !other.is_unmasked_variable() {
|
||||
} else if other.is_function_letter() {
|
||||
// After a function letter, mask following numbers/variables as part of function name
|
||||
self.masked_num = self.number;
|
||||
self.masked_var = self.variable;
|
||||
}
|
||||
}
|
||||
|
||||
const fn splitable(&self, c: &char, other: &BoolSlice, split: &SplitType) -> bool {
|
||||
if (*c == '*') | (matches!(split, &SplitType::Term) && other.open_parens) {
|
||||
true
|
||||
} else if other.closing_parens {
|
||||
// Cases like `)x`, `)2`, and `)(`
|
||||
return (*c == '(')
|
||||
| (self.letter && !self.is_unmasked_variable())
|
||||
| self.is_unmasked_variable()
|
||||
| self.is_unmasked_number();
|
||||
} else if *c == '(' {
|
||||
// Cases like `x(` and `2(`
|
||||
return (other.is_unmasked_variable() | other.is_unmasked_number()) && !other.letter;
|
||||
} else if other.is_unmasked_number() {
|
||||
// Cases like `2x` and `2sin(x)`
|
||||
return self.is_unmasked_variable() | self.letter;
|
||||
} else if self.is_unmasked_variable() | self.letter {
|
||||
// Cases like `e2` and `xx`
|
||||
return other.is_unmasked_number()
|
||||
| (other.is_unmasked_variable() && self.is_unmasked_variable())
|
||||
| other.is_unmasked_variable();
|
||||
} else if (self.is_unmasked_number() | self.letter | self.is_unmasked_variable())
|
||||
&& (other.is_unmasked_number() | other.letter)
|
||||
{
|
||||
/// Determines if we should split (insert implicit multiplication) before current char
|
||||
const fn splitable(&self, c: &char, prev: &BoolSlice, split: &SplitType) -> bool {
|
||||
// Always split on explicit multiplication
|
||||
if *c == '*' {
|
||||
return true;
|
||||
} else {
|
||||
return self.is_unmasked_number() && other.is_unmasked_variable();
|
||||
}
|
||||
|
||||
// For Term split type, also split after open parens
|
||||
if matches!(split, &SplitType::Term) && prev.open_parens {
|
||||
return true;
|
||||
}
|
||||
|
||||
// After closing paren: split before `(`, letters, variables, or numbers
|
||||
// e.g., `)x`, `)2`, `)(`, `)sin`
|
||||
if prev.closing_parens {
|
||||
return *c == '(' || self.is_term();
|
||||
}
|
||||
|
||||
// Before open paren: split if previous was a standalone number or variable
|
||||
// e.g., `x(`, `2(` but not `sin(`
|
||||
if *c == '(' {
|
||||
return (prev.is_unmasked_variable() || prev.is_unmasked_number()) && !prev.letter;
|
||||
}
|
||||
|
||||
// After a number: split before variables or function letters
|
||||
// e.g., `2x`, `2sin`
|
||||
if prev.is_unmasked_number() {
|
||||
return self.is_unmasked_variable() || self.letter;
|
||||
}
|
||||
|
||||
// Current is a variable or letter: split if previous was a number or variable
|
||||
// e.g., `e2`, `xx`, `xe`
|
||||
if self.is_unmasked_variable() || self.letter {
|
||||
return prev.is_unmasked_number() || prev.is_unmasked_variable();
|
||||
}
|
||||
|
||||
// Current is a number after a variable
|
||||
// e.g., `x2`
|
||||
if self.is_unmasked_number() && prev.is_unmasked_variable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user