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