mirror of
https://codeberg.org/superseriousbusiness/gotosocial.git
synced 2024-12-27 03:18:16 +03:00
246 lines
6.2 KiB
Go
246 lines
6.2 KiB
Go
|
package expr
|
||
|
|
||
|
import (
|
||
|
`fmt`
|
||
|
)
|
||
|
|
||
|
// Type is tyep expression type.
|
||
|
type Type int
|
||
|
|
||
|
const (
|
||
|
// CONST indicates that the expression is a constant.
|
||
|
CONST Type = iota
|
||
|
|
||
|
// TERM indicates that the expression is a Term reference.
|
||
|
TERM
|
||
|
|
||
|
// EXPR indicates that the expression is a unary or binary expression.
|
||
|
EXPR
|
||
|
)
|
||
|
|
||
|
var typeNames = map[Type]string {
|
||
|
EXPR : "Expr",
|
||
|
TERM : "Term",
|
||
|
CONST : "Const",
|
||
|
}
|
||
|
|
||
|
// String returns the string representation of a Type.
|
||
|
func (self Type) String() string {
|
||
|
if v, ok := typeNames[self]; ok {
|
||
|
return v
|
||
|
} else {
|
||
|
return fmt.Sprintf("expr.Type(%d)", self)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Operator represents an operation to perform when Type is EXPR.
|
||
|
type Operator uint8
|
||
|
|
||
|
const (
|
||
|
// ADD performs "Add Expr.Left and Expr.Right".
|
||
|
ADD Operator = iota
|
||
|
|
||
|
// SUB performs "Subtract Expr.Left by Expr.Right".
|
||
|
SUB
|
||
|
|
||
|
// MUL performs "Multiply Expr.Left by Expr.Right".
|
||
|
MUL
|
||
|
|
||
|
// DIV performs "Divide Expr.Left by Expr.Right".
|
||
|
DIV
|
||
|
|
||
|
// MOD performs "Modulo Expr.Left by Expr.Right".
|
||
|
MOD
|
||
|
|
||
|
// AND performs "Bitwise AND Expr.Left and Expr.Right".
|
||
|
AND
|
||
|
|
||
|
// OR performs "Bitwise OR Expr.Left and Expr.Right".
|
||
|
OR
|
||
|
|
||
|
// XOR performs "Bitwise XOR Expr.Left and Expr.Right".
|
||
|
XOR
|
||
|
|
||
|
// SHL performs "Bitwise Shift Expr.Left to the Left by Expr.Right Bits".
|
||
|
SHL
|
||
|
|
||
|
// SHR performs "Bitwise Shift Expr.Left to the Right by Expr.Right Bits".
|
||
|
SHR
|
||
|
|
||
|
// POW performs "Raise Expr.Left to the power of Expr.Right"
|
||
|
POW
|
||
|
|
||
|
// NOT performs "Bitwise Invert Expr.Left".
|
||
|
NOT
|
||
|
|
||
|
// NEG performs "Negate Expr.Left".
|
||
|
NEG
|
||
|
)
|
||
|
|
||
|
var operatorNames = map[Operator]string {
|
||
|
ADD : "Add",
|
||
|
SUB : "Subtract",
|
||
|
MUL : "Multiply",
|
||
|
DIV : "Divide",
|
||
|
MOD : "Modulo",
|
||
|
AND : "And",
|
||
|
OR : "Or",
|
||
|
XOR : "ExclusiveOr",
|
||
|
SHL : "ShiftLeft",
|
||
|
SHR : "ShiftRight",
|
||
|
POW : "Power",
|
||
|
NOT : "Invert",
|
||
|
NEG : "Negate",
|
||
|
}
|
||
|
|
||
|
// String returns the string representation of a Type.
|
||
|
func (self Operator) String() string {
|
||
|
if v, ok := operatorNames[self]; ok {
|
||
|
return v
|
||
|
} else {
|
||
|
return fmt.Sprintf("expr.Operator(%d)", self)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Expr represents an expression node.
|
||
|
type Expr struct {
|
||
|
Type Type
|
||
|
Term Term
|
||
|
Op Operator
|
||
|
Left *Expr
|
||
|
Right *Expr
|
||
|
Const int64
|
||
|
}
|
||
|
|
||
|
// Ref creates an expression from a Term.
|
||
|
func Ref(t Term) (p *Expr) {
|
||
|
p = newExpression()
|
||
|
p.Term = t
|
||
|
p.Type = TERM
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Int creates an expression from an integer.
|
||
|
func Int(v int64) (p *Expr) {
|
||
|
p = newExpression()
|
||
|
p.Type = CONST
|
||
|
p.Const = v
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (self *Expr) clear() {
|
||
|
if self.Term != nil { self.Term.Free() }
|
||
|
if self.Left != nil { self.Left.Free() }
|
||
|
if self.Right != nil { self.Right.Free() }
|
||
|
}
|
||
|
|
||
|
// Free returns the Expr into pool.
|
||
|
// Any operation performed after Free is undefined behavior.
|
||
|
func (self *Expr) Free() {
|
||
|
self.clear()
|
||
|
freeExpression(self)
|
||
|
}
|
||
|
|
||
|
// Evaluate evaluates the expression into an integer.
|
||
|
// It also implements the Term interface.
|
||
|
func (self *Expr) Evaluate() (int64, error) {
|
||
|
switch self.Type {
|
||
|
case EXPR : return self.eval()
|
||
|
case TERM : return self.Term.Evaluate()
|
||
|
case CONST : return self.Const, nil
|
||
|
default : panic("invalid expression type: " + self.Type.String())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Expression Combinator **/
|
||
|
|
||
|
func combine(a *Expr, op Operator, b *Expr) (r *Expr) {
|
||
|
r = newExpression()
|
||
|
r.Op = op
|
||
|
r.Type = EXPR
|
||
|
r.Left = a
|
||
|
r.Right = b
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (self *Expr) Add(v *Expr) *Expr { return combine(self, ADD, v) }
|
||
|
func (self *Expr) Sub(v *Expr) *Expr { return combine(self, SUB, v) }
|
||
|
func (self *Expr) Mul(v *Expr) *Expr { return combine(self, MUL, v) }
|
||
|
func (self *Expr) Div(v *Expr) *Expr { return combine(self, DIV, v) }
|
||
|
func (self *Expr) Mod(v *Expr) *Expr { return combine(self, MOD, v) }
|
||
|
func (self *Expr) And(v *Expr) *Expr { return combine(self, AND, v) }
|
||
|
func (self *Expr) Or (v *Expr) *Expr { return combine(self, OR , v) }
|
||
|
func (self *Expr) Xor(v *Expr) *Expr { return combine(self, XOR, v) }
|
||
|
func (self *Expr) Shl(v *Expr) *Expr { return combine(self, SHL, v) }
|
||
|
func (self *Expr) Shr(v *Expr) *Expr { return combine(self, SHR, v) }
|
||
|
func (self *Expr) Pow(v *Expr) *Expr { return combine(self, POW, v) }
|
||
|
func (self *Expr) Not() *Expr { return combine(self, NOT, nil) }
|
||
|
func (self *Expr) Neg() *Expr { return combine(self, NEG, nil) }
|
||
|
|
||
|
/** Expression Evaluator **/
|
||
|
|
||
|
var binaryEvaluators = [256]func(int64, int64) (int64, error) {
|
||
|
ADD: func(a, b int64) (int64, error) { return a + b, nil },
|
||
|
SUB: func(a, b int64) (int64, error) { return a - b, nil },
|
||
|
MUL: func(a, b int64) (int64, error) { return a * b, nil },
|
||
|
DIV: idiv,
|
||
|
MOD: imod,
|
||
|
AND: func(a, b int64) (int64, error) { return a & b, nil },
|
||
|
OR: func(a, b int64) (int64, error) { return a | b, nil },
|
||
|
XOR: func(a, b int64) (int64, error) { return a ^ b, nil },
|
||
|
SHL: func(a, b int64) (int64, error) { return a << b, nil },
|
||
|
SHR: func(a, b int64) (int64, error) { return a >> b, nil },
|
||
|
POW: ipow,
|
||
|
}
|
||
|
|
||
|
func (self *Expr) eval() (int64, error) {
|
||
|
var lhs int64
|
||
|
var rhs int64
|
||
|
var err error
|
||
|
var vfn func(int64, int64) (int64, error)
|
||
|
|
||
|
/* evaluate LHS */
|
||
|
if lhs, err = self.Left.Evaluate(); err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
|
||
|
/* check for unary operators */
|
||
|
switch self.Op {
|
||
|
case NOT: return self.unaryNot(lhs)
|
||
|
case NEG: return self.unaryNeg(lhs)
|
||
|
}
|
||
|
|
||
|
/* check for operators */
|
||
|
if vfn = binaryEvaluators[self.Op]; vfn == nil {
|
||
|
panic("invalid operator: " + self.Op.String())
|
||
|
}
|
||
|
|
||
|
/* must be a binary expression */
|
||
|
if self.Right == nil {
|
||
|
panic("operator " + self.Op.String() + " is a binary operator")
|
||
|
}
|
||
|
|
||
|
/* evaluate RHS, and call the operator */
|
||
|
if rhs, err = self.Right.Evaluate(); err != nil {
|
||
|
return 0, err
|
||
|
} else {
|
||
|
return vfn(lhs, rhs)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (self *Expr) unaryNot(v int64) (int64, error) {
|
||
|
if self.Right == nil {
|
||
|
return ^v, nil
|
||
|
} else {
|
||
|
panic("operator Invert is an unary operator")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (self *Expr) unaryNeg(v int64) (int64, error) {
|
||
|
if self.Right == nil {
|
||
|
return -v, nil
|
||
|
} else {
|
||
|
panic("operator Negate is an unary operator")
|
||
|
}
|
||
|
}
|