Implement not operator

This commit is contained in:
mschae23
2025-09-27 14:29:30 +02:00
parent 7749a12a0a
commit 510029af40

View File

@@ -44,6 +44,20 @@ export enum SkipRuleOperator {
const SKIP_RULE_ATTRIBUTES = Object.values(SkipRuleAttribute);
const SKIP_RULE_OPERATORS = Object.values(SkipRuleOperator);
const INVERTED_SKIP_RULE_OPERATORS = {
"<=": SkipRuleOperator.Greater,
"<": SkipRuleOperator.GreaterOrEqual,
">=": SkipRuleOperator.Less,
">": SkipRuleOperator.LessOrEqual,
"!=": SkipRuleOperator.Equal,
"==": SkipRuleOperator.NotEqual,
"!*=": SkipRuleOperator.Contains,
"*=": SkipRuleOperator.NotContains,
"!~=": SkipRuleOperator.Regex,
"~=": SkipRuleOperator.NotRegex,
"!~i=": SkipRuleOperator.RegexIgnoreCase,
"~i=": SkipRuleOperator.NotRegexIgnoreCase,
};
const WORD_EXTRA_CHARACTER = /[a-zA-Z0-9.]/;
const OPERATOR_EXTRA_CHARACTER = /[<>=!~*&|-]/;
const ANY_EXTRA_CHARACTER = /[a-zA-Z0-9<>=!~*&|.-]/;
@@ -225,7 +239,7 @@ type TokenType =
| "disabled" | "show overlay" | "manual skip" | "auto skip" // Skip option
| `${SkipRuleAttribute}` // Segment attributes
| `${SkipRuleOperator}` // Segment attribute operators
| "and" | "or" // Expression operators
| "and" | "or" | "not" // Expression operators
| "(" | ")" | "comment" // Syntax
| "string" | "number" // Literal values
| "eof" | "error"; // Sentinel and special tokens
@@ -396,7 +410,7 @@ class Lexer {
}
const keyword = this.expectKeyword([
"if", "and", "or",
"if", "and", "or", "not",
"(", ")",
"//",
].concat(SKIP_RULE_ATTRIBUTES)
@@ -415,7 +429,8 @@ class Lexer {
switch (keyword) {
case "if": // Fallthrough
case "and": // Fallthrough
case "or": kind = "word"; type = keyword as TokenType; break;
case "or": // Fallthrough
case "not": kind = "word"; type = keyword as TokenType; break;
case "(": return this.makeToken("(");
case ")": return this.makeToken(")");
@@ -820,10 +835,10 @@ class Parser {
}
private parseAnd(): AdvancedSkipPredicate | null {
let left = this.parsePrimary();
let left = this.parseUnary();
while (this.match(["and"])) {
const right = this.parsePrimary();
const right = this.parseUnary();
left = {
kind: "operator",
@@ -835,6 +850,33 @@ class Parser {
return left;
}
private static invertPredicate(predicate: AdvancedSkipPredicate): AdvancedSkipPredicate {
if (predicate.kind === "check") {
return {
...predicate,
operator: INVERTED_SKIP_RULE_OPERATORS[predicate.operator],
};
} else {
// not (a and b) == (not a or not b)
// not (a or b) == (not a and not b)
return {
kind: "operator",
operator: predicate.operator === "and" ? PredicateOperator.Or : PredicateOperator.And,
left: predicate.left ? Parser.invertPredicate(predicate.left) : null,
right: predicate.right ? Parser.invertPredicate(predicate.right) : null,
};
}
}
private parseUnary(): AdvancedSkipPredicate | null {
if (this.match(["not"])) {
const predicate = this.parseUnary();
return predicate ? Parser.invertPredicate(predicate) : null;
}
return this.parsePrimary();
}
private parsePrimary(): AdvancedSkipPredicate | null {
if (this.match(["("])) {
const predicate = this.parsePredicate();