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
|
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) {
|
const fn calculate_mask(&mut self, other: &BoolSlice) {
|
||||||
if other.masked_num && self.number {
|
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;
|
self.masked_num = true;
|
||||||
} else if other.masked_var && self.variable {
|
} 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;
|
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_num = self.number;
|
||||||
self.masked_var = self.variable;
|
self.masked_var = self.variable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn splitable(&self, c: &char, other: &BoolSlice, split: &SplitType) -> bool {
|
/// Determines if we should split (insert implicit multiplication) before current char
|
||||||
if (*c == '*') | (matches!(split, &SplitType::Term) && other.open_parens) {
|
const fn splitable(&self, c: &char, prev: &BoolSlice, split: &SplitType) -> bool {
|
||||||
true
|
// Always split on explicit multiplication
|
||||||
} else if other.closing_parens {
|
if *c == '*' {
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
return true;
|
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