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