func EvaluateUnaryExpr(expr *ast.UnaryExpr, context *Context) ast.Value { var val ast.Value = nil switch t := expr.Expr.(type) { case *ast.BinaryExpr: val = EvaluateBinaryExpr(t, context) case *ast.UnaryExpr: val = EvaluateUnaryExpr(t, context) case *ast.Variable: if varVal, ok := context.GetVariable(t.Name); ok { val = varVal.(ast.Expr) } default: val = ast.Value(t) } switch expr.Op.Type { case ast.T_NOP: // do nothing case ast.T_LOGICAL_NOT: if bVal, ok := val.(ast.BooleanValue); ok { val = ast.NewBoolean(bVal.Boolean()) } case ast.T_MINUS: switch n := val.(type) { case *ast.Number: n.Value = -n.Value } } return val }
/* EvaluateBinaryExpr recursively. */ func EvaluateBinaryExpr(expr *ast.BinaryExpr, context *Context) ast.Value { var lval ast.Value = nil var rval ast.Value = nil switch expr := expr.Left.(type) { case *ast.BinaryExpr: lval = EvaluateBinaryExpr(expr, context) case *ast.UnaryExpr: lval = EvaluateUnaryExpr(expr, context) case *ast.Variable: if varVal, ok := context.GetVariable(expr.Name); ok { lval = varVal.(ast.Expr) } default: lval = ast.Value(expr) } switch expr := expr.Right.(type) { case *ast.UnaryExpr: rval = EvaluateUnaryExpr(expr, context) case *ast.BinaryExpr: rval = EvaluateBinaryExpr(expr, context) case *ast.Variable: if varVal, ok := context.GetVariable(expr.Name); ok { rval = varVal.(ast.Expr) } default: rval = ast.Value(expr) } if lval != nil && rval != nil { return Compute(expr.Op, lval, rval) } return nil }
/* EvaluateExpr calls EvaluateBinaryExpr. except EvaluateExpr prevents calculate css slash as division. otherwise it's the same as EvaluateBinaryExpr. */ func EvaluateExpr(expr ast.Expr, context *Context) ast.Value { switch t := expr.(type) { case *ast.BinaryExpr: // For binary expression that is a CSS slash, we evaluate the expression as a literal string (unquoted) if t.IsCssSlash() { // return string object without quote return ast.NewString(0, t.Left.(*ast.Number).String()+"/"+t.Right.(*ast.Number).String(), nil) } return EvaluateBinaryExpr(t, context) case *ast.UnaryExpr: return EvaluateUnaryExpr(t, context) default: return ast.Value(expr) } }
func EvaluateUnaryExprInBooleanContext(expr *ast.UnaryExpr, context *Context) ast.Value { var val ast.Value = nil switch t := expr.Expr.(type) { case *ast.BinaryExpr: val = EvaluateBinaryExpr(t, context) case *ast.UnaryExpr: val = EvaluateUnaryExpr(t, context) default: val = ast.Value(t) } switch expr.Op.Type { case ast.T_LOGICAL_NOT: if bval, ok := val.(ast.BooleanValue); ok { return ast.NewBoolean(bval.Boolean()) } else { panic(fmt.Errorf("BooleanValue interface is not support for %+v", val)) } } return val }