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 ""
|
||
|
}
|