307 lines
5.0 KiB
Go
307 lines
5.0 KiB
Go
package govaluate
|
|
|
|
/*
|
|
Represents the valid symbols for operators.
|
|
|
|
*/
|
|
type OperatorSymbol int
|
|
|
|
const (
|
|
VALUE OperatorSymbol = iota
|
|
LITERAL
|
|
NOOP
|
|
EQ
|
|
NEQ
|
|
GT
|
|
LT
|
|
GTE
|
|
LTE
|
|
REQ
|
|
NREQ
|
|
IN
|
|
|
|
AND
|
|
OR
|
|
|
|
PLUS
|
|
MINUS
|
|
BITWISE_AND
|
|
BITWISE_OR
|
|
BITWISE_XOR
|
|
BITWISE_LSHIFT
|
|
BITWISE_RSHIFT
|
|
MULTIPLY
|
|
DIVIDE
|
|
MODULUS
|
|
EXPONENT
|
|
|
|
NEGATE
|
|
INVERT
|
|
BITWISE_NOT
|
|
|
|
TERNARY_TRUE
|
|
TERNARY_FALSE
|
|
COALESCE
|
|
|
|
FUNCTIONAL
|
|
SEPARATE
|
|
)
|
|
|
|
type operatorPrecedence int
|
|
|
|
const (
|
|
noopPrecedence operatorPrecedence = iota
|
|
valuePrecedence
|
|
functionalPrecedence
|
|
prefixPrecedence
|
|
exponentialPrecedence
|
|
additivePrecedence
|
|
bitwisePrecedence
|
|
bitwiseShiftPrecedence
|
|
multiplicativePrecedence
|
|
comparatorPrecedence
|
|
ternaryPrecedence
|
|
logicalAndPrecedence
|
|
logicalOrPrecedence
|
|
separatePrecedence
|
|
)
|
|
|
|
func findOperatorPrecedenceForSymbol(symbol OperatorSymbol) operatorPrecedence {
|
|
|
|
switch symbol {
|
|
case NOOP:
|
|
return noopPrecedence
|
|
case VALUE:
|
|
return valuePrecedence
|
|
case EQ:
|
|
fallthrough
|
|
case NEQ:
|
|
fallthrough
|
|
case GT:
|
|
fallthrough
|
|
case LT:
|
|
fallthrough
|
|
case GTE:
|
|
fallthrough
|
|
case LTE:
|
|
fallthrough
|
|
case REQ:
|
|
fallthrough
|
|
case NREQ:
|
|
fallthrough
|
|
case IN:
|
|
return comparatorPrecedence
|
|
case AND:
|
|
return logicalAndPrecedence
|
|
case OR:
|
|
return logicalOrPrecedence
|
|
case BITWISE_AND:
|
|
fallthrough
|
|
case BITWISE_OR:
|
|
fallthrough
|
|
case BITWISE_XOR:
|
|
return bitwisePrecedence
|
|
case BITWISE_LSHIFT:
|
|
fallthrough
|
|
case BITWISE_RSHIFT:
|
|
return bitwiseShiftPrecedence
|
|
case PLUS:
|
|
fallthrough
|
|
case MINUS:
|
|
return additivePrecedence
|
|
case MULTIPLY:
|
|
fallthrough
|
|
case DIVIDE:
|
|
fallthrough
|
|
case MODULUS:
|
|
return multiplicativePrecedence
|
|
case EXPONENT:
|
|
return exponentialPrecedence
|
|
case BITWISE_NOT:
|
|
fallthrough
|
|
case NEGATE:
|
|
fallthrough
|
|
case INVERT:
|
|
return prefixPrecedence
|
|
case COALESCE:
|
|
fallthrough
|
|
case TERNARY_TRUE:
|
|
fallthrough
|
|
case TERNARY_FALSE:
|
|
return ternaryPrecedence
|
|
case FUNCTIONAL:
|
|
return functionalPrecedence
|
|
case SEPARATE:
|
|
return separatePrecedence
|
|
}
|
|
|
|
return valuePrecedence
|
|
}
|
|
|
|
/*
|
|
Map of all valid comparators, and their string equivalents.
|
|
Used during parsing of expressions to determine if a symbol is, in fact, a comparator.
|
|
Also used during evaluation to determine exactly which comparator is being used.
|
|
*/
|
|
var comparatorSymbols = map[string]OperatorSymbol{
|
|
"==": EQ,
|
|
"!=": NEQ,
|
|
">": GT,
|
|
">=": GTE,
|
|
"<": LT,
|
|
"<=": LTE,
|
|
"=~": REQ,
|
|
"!~": NREQ,
|
|
"in": IN,
|
|
}
|
|
|
|
var logicalSymbols = map[string]OperatorSymbol{
|
|
"&&": AND,
|
|
"||": OR,
|
|
}
|
|
|
|
var bitwiseSymbols = map[string]OperatorSymbol{
|
|
"^": BITWISE_XOR,
|
|
"&": BITWISE_AND,
|
|
"|": BITWISE_OR,
|
|
}
|
|
|
|
var bitwiseShiftSymbols = map[string]OperatorSymbol{
|
|
">>": BITWISE_RSHIFT,
|
|
"<<": BITWISE_LSHIFT,
|
|
}
|
|
|
|
var additiveSymbols = map[string]OperatorSymbol{
|
|
"+": PLUS,
|
|
"-": MINUS,
|
|
}
|
|
|
|
var multiplicativeSymbols = map[string]OperatorSymbol{
|
|
"*": MULTIPLY,
|
|
"/": DIVIDE,
|
|
"%": MODULUS,
|
|
}
|
|
|
|
var exponentialSymbolsS = map[string]OperatorSymbol{
|
|
"**": EXPONENT,
|
|
}
|
|
|
|
var prefixSymbols = map[string]OperatorSymbol{
|
|
"-": NEGATE,
|
|
"!": INVERT,
|
|
"~": BITWISE_NOT,
|
|
}
|
|
|
|
var ternarySymbols = map[string]OperatorSymbol{
|
|
"?": TERNARY_TRUE,
|
|
":": TERNARY_FALSE,
|
|
"??": COALESCE,
|
|
}
|
|
|
|
// this is defined separately from additiveSymbols et al because it's needed for parsing, not stage planning.
|
|
var modifierSymbols = map[string]OperatorSymbol{
|
|
"+": PLUS,
|
|
"-": MINUS,
|
|
"*": MULTIPLY,
|
|
"/": DIVIDE,
|
|
"%": MODULUS,
|
|
"**": EXPONENT,
|
|
"&": BITWISE_AND,
|
|
"|": BITWISE_OR,
|
|
"^": BITWISE_XOR,
|
|
">>": BITWISE_RSHIFT,
|
|
"<<": BITWISE_LSHIFT,
|
|
}
|
|
|
|
var separatorSymbols = map[string]OperatorSymbol{
|
|
",": SEPARATE,
|
|
}
|
|
|
|
/*
|
|
Returns true if this operator is contained by the given array of candidate symbols.
|
|
False otherwise.
|
|
*/
|
|
func (this OperatorSymbol) IsModifierType(candidate []OperatorSymbol) bool {
|
|
|
|
for _, symbolType := range candidate {
|
|
if this == symbolType {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
/*
|
|
Generally used when formatting type check errors.
|
|
We could store the stringified symbol somewhere else and not require a duplicated codeblock to translate
|
|
OperatorSymbol to string, but that would require more memory, and another field somewhere.
|
|
Adding operators is rare enough that we just stringify it here instead.
|
|
*/
|
|
func (this OperatorSymbol) String() string {
|
|
|
|
switch this {
|
|
case NOOP:
|
|
return "NOOP"
|
|
case VALUE:
|
|
return "VALUE"
|
|
case EQ:
|
|
return "="
|
|
case NEQ:
|
|
return "!="
|
|
case GT:
|
|
return ">"
|
|
case LT:
|
|
return "<"
|
|
case GTE:
|
|
return ">="
|
|
case LTE:
|
|
return "<="
|
|
case REQ:
|
|
return "=~"
|
|
case NREQ:
|
|
return "!~"
|
|
case AND:
|
|
return "&&"
|
|
case OR:
|
|
return "||"
|
|
case IN:
|
|
return "in"
|
|
case BITWISE_AND:
|
|
return "&"
|
|
case BITWISE_OR:
|
|
return "|"
|
|
case BITWISE_XOR:
|
|
return "^"
|
|
case BITWISE_LSHIFT:
|
|
return "<<"
|
|
case BITWISE_RSHIFT:
|
|
return ">>"
|
|
case PLUS:
|
|
return "+"
|
|
case MINUS:
|
|
return "-"
|
|
case MULTIPLY:
|
|
return "*"
|
|
case DIVIDE:
|
|
return "/"
|
|
case MODULUS:
|
|
return "%"
|
|
case EXPONENT:
|
|
return "**"
|
|
case NEGATE:
|
|
return "-"
|
|
case INVERT:
|
|
return "!"
|
|
case BITWISE_NOT:
|
|
return "~"
|
|
case TERNARY_TRUE:
|
|
return "?"
|
|
case TERNARY_FALSE:
|
|
return ":"
|
|
case COALESCE:
|
|
return "??"
|
|
}
|
|
return ""
|
|
}
|