mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-13 11:04:03 +08:00
chore: upgrade coredns version (#550)
This commit is contained in:
6
vendor/github.com/expr-lang/expr/vm/debug.go
generated
vendored
Normal file
6
vendor/github.com/expr-lang/expr/vm/debug.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build expr_debug
|
||||
// +build expr_debug
|
||||
|
||||
package vm
|
||||
|
||||
const debug = true
|
6
vendor/github.com/expr-lang/expr/vm/debug_off.go
generated
vendored
Normal file
6
vendor/github.com/expr-lang/expr/vm/debug_off.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build !expr_debug
|
||||
// +build !expr_debug
|
||||
|
||||
package vm
|
||||
|
||||
const debug = false
|
370
vendor/github.com/expr-lang/expr/vm/func_types[generated].go
generated
vendored
Normal file
370
vendor/github.com/expr-lang/expr/vm/func_types[generated].go
generated
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
// Code generated by vm/func_types/main.go. DO NOT EDIT.
|
||||
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var FuncTypes = []any{
|
||||
1: new(func() time.Duration),
|
||||
2: new(func() time.Month),
|
||||
3: new(func() time.Time),
|
||||
4: new(func() time.Weekday),
|
||||
5: new(func() []interface{}),
|
||||
6: new(func() []uint8),
|
||||
7: new(func() interface{}),
|
||||
8: new(func() bool),
|
||||
9: new(func() uint8),
|
||||
10: new(func() float32),
|
||||
11: new(func() float64),
|
||||
12: new(func() int),
|
||||
13: new(func() int16),
|
||||
14: new(func() int32),
|
||||
15: new(func() int64),
|
||||
16: new(func() int8),
|
||||
17: new(func() map[string]interface{}),
|
||||
18: new(func() int32),
|
||||
19: new(func() string),
|
||||
20: new(func() uint),
|
||||
21: new(func() uint16),
|
||||
22: new(func() uint32),
|
||||
23: new(func() uint64),
|
||||
24: new(func() uint8),
|
||||
25: new(func(time.Duration) time.Duration),
|
||||
26: new(func(time.Duration) time.Time),
|
||||
27: new(func(time.Time) time.Duration),
|
||||
28: new(func(time.Time) bool),
|
||||
29: new(func([]interface{}) []interface{}),
|
||||
30: new(func([]interface{}) interface{}),
|
||||
31: new(func([]interface{}) map[string]interface{}),
|
||||
32: new(func([]interface{}, string) string),
|
||||
33: new(func([]uint8) string),
|
||||
34: new(func([]string, string) string),
|
||||
35: new(func(interface{}) []interface{}),
|
||||
36: new(func(interface{}) interface{}),
|
||||
37: new(func(interface{}) bool),
|
||||
38: new(func(interface{}) float64),
|
||||
39: new(func(interface{}) int),
|
||||
40: new(func(interface{}) map[string]interface{}),
|
||||
41: new(func(interface{}) string),
|
||||
42: new(func(interface{}, interface{}) []interface{}),
|
||||
43: new(func(interface{}, interface{}) interface{}),
|
||||
44: new(func(interface{}, interface{}) bool),
|
||||
45: new(func(interface{}, interface{}) string),
|
||||
46: new(func(bool) bool),
|
||||
47: new(func(bool) float64),
|
||||
48: new(func(bool) int),
|
||||
49: new(func(bool) string),
|
||||
50: new(func(bool, bool) bool),
|
||||
51: new(func(float32) float64),
|
||||
52: new(func(float64) bool),
|
||||
53: new(func(float64) float32),
|
||||
54: new(func(float64) float64),
|
||||
55: new(func(float64) int),
|
||||
56: new(func(float64) string),
|
||||
57: new(func(float64, float64) bool),
|
||||
58: new(func(int) bool),
|
||||
59: new(func(int) float64),
|
||||
60: new(func(int) int),
|
||||
61: new(func(int) string),
|
||||
62: new(func(int, int) bool),
|
||||
63: new(func(int, int) int),
|
||||
64: new(func(int, int) string),
|
||||
65: new(func(int16) int32),
|
||||
66: new(func(int32) float64),
|
||||
67: new(func(int32) int),
|
||||
68: new(func(int32) int64),
|
||||
69: new(func(int64) time.Time),
|
||||
70: new(func(int8) int),
|
||||
71: new(func(int8) int16),
|
||||
72: new(func(string) []uint8),
|
||||
73: new(func(string) []string),
|
||||
74: new(func(string) bool),
|
||||
75: new(func(string) float64),
|
||||
76: new(func(string) int),
|
||||
77: new(func(string) string),
|
||||
78: new(func(string, uint8) int),
|
||||
79: new(func(string, int) int),
|
||||
80: new(func(string, int32) int),
|
||||
81: new(func(string, string) bool),
|
||||
82: new(func(string, string) string),
|
||||
83: new(func(uint) float64),
|
||||
84: new(func(uint) int),
|
||||
85: new(func(uint) uint),
|
||||
86: new(func(uint16) uint),
|
||||
87: new(func(uint32) uint64),
|
||||
88: new(func(uint64) float64),
|
||||
89: new(func(uint64) int64),
|
||||
90: new(func(uint8) uint8),
|
||||
}
|
||||
|
||||
func (vm *VM) call(fn any, kind int) any {
|
||||
switch kind {
|
||||
case 1:
|
||||
return fn.(func() time.Duration)()
|
||||
case 2:
|
||||
return fn.(func() time.Month)()
|
||||
case 3:
|
||||
return fn.(func() time.Time)()
|
||||
case 4:
|
||||
return fn.(func() time.Weekday)()
|
||||
case 5:
|
||||
return fn.(func() []interface{})()
|
||||
case 6:
|
||||
return fn.(func() []uint8)()
|
||||
case 7:
|
||||
return fn.(func() interface{})()
|
||||
case 8:
|
||||
return fn.(func() bool)()
|
||||
case 9:
|
||||
return fn.(func() uint8)()
|
||||
case 10:
|
||||
return fn.(func() float32)()
|
||||
case 11:
|
||||
return fn.(func() float64)()
|
||||
case 12:
|
||||
return fn.(func() int)()
|
||||
case 13:
|
||||
return fn.(func() int16)()
|
||||
case 14:
|
||||
return fn.(func() int32)()
|
||||
case 15:
|
||||
return fn.(func() int64)()
|
||||
case 16:
|
||||
return fn.(func() int8)()
|
||||
case 17:
|
||||
return fn.(func() map[string]interface{})()
|
||||
case 18:
|
||||
return fn.(func() int32)()
|
||||
case 19:
|
||||
return fn.(func() string)()
|
||||
case 20:
|
||||
return fn.(func() uint)()
|
||||
case 21:
|
||||
return fn.(func() uint16)()
|
||||
case 22:
|
||||
return fn.(func() uint32)()
|
||||
case 23:
|
||||
return fn.(func() uint64)()
|
||||
case 24:
|
||||
return fn.(func() uint8)()
|
||||
case 25:
|
||||
arg1 := vm.pop().(time.Duration)
|
||||
return fn.(func(time.Duration) time.Duration)(arg1)
|
||||
case 26:
|
||||
arg1 := vm.pop().(time.Duration)
|
||||
return fn.(func(time.Duration) time.Time)(arg1)
|
||||
case 27:
|
||||
arg1 := vm.pop().(time.Time)
|
||||
return fn.(func(time.Time) time.Duration)(arg1)
|
||||
case 28:
|
||||
arg1 := vm.pop().(time.Time)
|
||||
return fn.(func(time.Time) bool)(arg1)
|
||||
case 29:
|
||||
arg1 := vm.pop().([]interface{})
|
||||
return fn.(func([]interface{}) []interface{})(arg1)
|
||||
case 30:
|
||||
arg1 := vm.pop().([]interface{})
|
||||
return fn.(func([]interface{}) interface{})(arg1)
|
||||
case 31:
|
||||
arg1 := vm.pop().([]interface{})
|
||||
return fn.(func([]interface{}) map[string]interface{})(arg1)
|
||||
case 32:
|
||||
arg2 := vm.pop().(string)
|
||||
arg1 := vm.pop().([]interface{})
|
||||
return fn.(func([]interface{}, string) string)(arg1, arg2)
|
||||
case 33:
|
||||
arg1 := vm.pop().([]uint8)
|
||||
return fn.(func([]uint8) string)(arg1)
|
||||
case 34:
|
||||
arg2 := vm.pop().(string)
|
||||
arg1 := vm.pop().([]string)
|
||||
return fn.(func([]string, string) string)(arg1, arg2)
|
||||
case 35:
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}) []interface{})(arg1)
|
||||
case 36:
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}) interface{})(arg1)
|
||||
case 37:
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}) bool)(arg1)
|
||||
case 38:
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}) float64)(arg1)
|
||||
case 39:
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}) int)(arg1)
|
||||
case 40:
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}) map[string]interface{})(arg1)
|
||||
case 41:
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}) string)(arg1)
|
||||
case 42:
|
||||
arg2 := vm.pop()
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}, interface{}) []interface{})(arg1, arg2)
|
||||
case 43:
|
||||
arg2 := vm.pop()
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}, interface{}) interface{})(arg1, arg2)
|
||||
case 44:
|
||||
arg2 := vm.pop()
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}, interface{}) bool)(arg1, arg2)
|
||||
case 45:
|
||||
arg2 := vm.pop()
|
||||
arg1 := vm.pop()
|
||||
return fn.(func(interface{}, interface{}) string)(arg1, arg2)
|
||||
case 46:
|
||||
arg1 := vm.pop().(bool)
|
||||
return fn.(func(bool) bool)(arg1)
|
||||
case 47:
|
||||
arg1 := vm.pop().(bool)
|
||||
return fn.(func(bool) float64)(arg1)
|
||||
case 48:
|
||||
arg1 := vm.pop().(bool)
|
||||
return fn.(func(bool) int)(arg1)
|
||||
case 49:
|
||||
arg1 := vm.pop().(bool)
|
||||
return fn.(func(bool) string)(arg1)
|
||||
case 50:
|
||||
arg2 := vm.pop().(bool)
|
||||
arg1 := vm.pop().(bool)
|
||||
return fn.(func(bool, bool) bool)(arg1, arg2)
|
||||
case 51:
|
||||
arg1 := vm.pop().(float32)
|
||||
return fn.(func(float32) float64)(arg1)
|
||||
case 52:
|
||||
arg1 := vm.pop().(float64)
|
||||
return fn.(func(float64) bool)(arg1)
|
||||
case 53:
|
||||
arg1 := vm.pop().(float64)
|
||||
return fn.(func(float64) float32)(arg1)
|
||||
case 54:
|
||||
arg1 := vm.pop().(float64)
|
||||
return fn.(func(float64) float64)(arg1)
|
||||
case 55:
|
||||
arg1 := vm.pop().(float64)
|
||||
return fn.(func(float64) int)(arg1)
|
||||
case 56:
|
||||
arg1 := vm.pop().(float64)
|
||||
return fn.(func(float64) string)(arg1)
|
||||
case 57:
|
||||
arg2 := vm.pop().(float64)
|
||||
arg1 := vm.pop().(float64)
|
||||
return fn.(func(float64, float64) bool)(arg1, arg2)
|
||||
case 58:
|
||||
arg1 := vm.pop().(int)
|
||||
return fn.(func(int) bool)(arg1)
|
||||
case 59:
|
||||
arg1 := vm.pop().(int)
|
||||
return fn.(func(int) float64)(arg1)
|
||||
case 60:
|
||||
arg1 := vm.pop().(int)
|
||||
return fn.(func(int) int)(arg1)
|
||||
case 61:
|
||||
arg1 := vm.pop().(int)
|
||||
return fn.(func(int) string)(arg1)
|
||||
case 62:
|
||||
arg2 := vm.pop().(int)
|
||||
arg1 := vm.pop().(int)
|
||||
return fn.(func(int, int) bool)(arg1, arg2)
|
||||
case 63:
|
||||
arg2 := vm.pop().(int)
|
||||
arg1 := vm.pop().(int)
|
||||
return fn.(func(int, int) int)(arg1, arg2)
|
||||
case 64:
|
||||
arg2 := vm.pop().(int)
|
||||
arg1 := vm.pop().(int)
|
||||
return fn.(func(int, int) string)(arg1, arg2)
|
||||
case 65:
|
||||
arg1 := vm.pop().(int16)
|
||||
return fn.(func(int16) int32)(arg1)
|
||||
case 66:
|
||||
arg1 := vm.pop().(int32)
|
||||
return fn.(func(int32) float64)(arg1)
|
||||
case 67:
|
||||
arg1 := vm.pop().(int32)
|
||||
return fn.(func(int32) int)(arg1)
|
||||
case 68:
|
||||
arg1 := vm.pop().(int32)
|
||||
return fn.(func(int32) int64)(arg1)
|
||||
case 69:
|
||||
arg1 := vm.pop().(int64)
|
||||
return fn.(func(int64) time.Time)(arg1)
|
||||
case 70:
|
||||
arg1 := vm.pop().(int8)
|
||||
return fn.(func(int8) int)(arg1)
|
||||
case 71:
|
||||
arg1 := vm.pop().(int8)
|
||||
return fn.(func(int8) int16)(arg1)
|
||||
case 72:
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string) []uint8)(arg1)
|
||||
case 73:
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string) []string)(arg1)
|
||||
case 74:
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string) bool)(arg1)
|
||||
case 75:
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string) float64)(arg1)
|
||||
case 76:
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string) int)(arg1)
|
||||
case 77:
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string) string)(arg1)
|
||||
case 78:
|
||||
arg2 := vm.pop().(uint8)
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string, uint8) int)(arg1, arg2)
|
||||
case 79:
|
||||
arg2 := vm.pop().(int)
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string, int) int)(arg1, arg2)
|
||||
case 80:
|
||||
arg2 := vm.pop().(int32)
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string, int32) int)(arg1, arg2)
|
||||
case 81:
|
||||
arg2 := vm.pop().(string)
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string, string) bool)(arg1, arg2)
|
||||
case 82:
|
||||
arg2 := vm.pop().(string)
|
||||
arg1 := vm.pop().(string)
|
||||
return fn.(func(string, string) string)(arg1, arg2)
|
||||
case 83:
|
||||
arg1 := vm.pop().(uint)
|
||||
return fn.(func(uint) float64)(arg1)
|
||||
case 84:
|
||||
arg1 := vm.pop().(uint)
|
||||
return fn.(func(uint) int)(arg1)
|
||||
case 85:
|
||||
arg1 := vm.pop().(uint)
|
||||
return fn.(func(uint) uint)(arg1)
|
||||
case 86:
|
||||
arg1 := vm.pop().(uint16)
|
||||
return fn.(func(uint16) uint)(arg1)
|
||||
case 87:
|
||||
arg1 := vm.pop().(uint32)
|
||||
return fn.(func(uint32) uint64)(arg1)
|
||||
case 88:
|
||||
arg1 := vm.pop().(uint64)
|
||||
return fn.(func(uint64) float64)(arg1)
|
||||
case 89:
|
||||
arg1 := vm.pop().(uint64)
|
||||
return fn.(func(uint64) int64)(arg1)
|
||||
case 90:
|
||||
arg1 := vm.pop().(uint8)
|
||||
return fn.(func(uint8) uint8)(arg1)
|
||||
|
||||
}
|
||||
panic(fmt.Sprintf("unknown function kind (%v)", kind))
|
||||
}
|
88
vendor/github.com/expr-lang/expr/vm/opcodes.go
generated
vendored
Normal file
88
vendor/github.com/expr-lang/expr/vm/opcodes.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package vm
|
||||
|
||||
type Opcode byte
|
||||
|
||||
const (
|
||||
OpInvalid Opcode = iota
|
||||
OpPush
|
||||
OpInt
|
||||
OpPop
|
||||
OpStore
|
||||
OpLoadVar
|
||||
OpLoadConst
|
||||
OpLoadField
|
||||
OpLoadFast
|
||||
OpLoadMethod
|
||||
OpLoadFunc
|
||||
OpLoadEnv
|
||||
OpFetch
|
||||
OpFetchField
|
||||
OpMethod
|
||||
OpTrue
|
||||
OpFalse
|
||||
OpNil
|
||||
OpNegate
|
||||
OpNot
|
||||
OpEqual
|
||||
OpEqualInt
|
||||
OpEqualString
|
||||
OpJump
|
||||
OpJumpIfTrue
|
||||
OpJumpIfFalse
|
||||
OpJumpIfNil
|
||||
OpJumpIfNotNil
|
||||
OpJumpIfEnd
|
||||
OpJumpBackward
|
||||
OpIn
|
||||
OpLess
|
||||
OpMore
|
||||
OpLessOrEqual
|
||||
OpMoreOrEqual
|
||||
OpAdd
|
||||
OpSubtract
|
||||
OpMultiply
|
||||
OpDivide
|
||||
OpModulo
|
||||
OpExponent
|
||||
OpRange
|
||||
OpMatches
|
||||
OpMatchesConst
|
||||
OpContains
|
||||
OpStartsWith
|
||||
OpEndsWith
|
||||
OpSlice
|
||||
OpCall
|
||||
OpCall0
|
||||
OpCall1
|
||||
OpCall2
|
||||
OpCall3
|
||||
OpCallN
|
||||
OpCallFast
|
||||
OpCallSafe
|
||||
OpCallTyped
|
||||
OpCallBuiltin1
|
||||
OpArray
|
||||
OpMap
|
||||
OpLen
|
||||
OpCast
|
||||
OpDeref
|
||||
OpIncrementIndex
|
||||
OpDecrementIndex
|
||||
OpIncrementCount
|
||||
OpGetIndex
|
||||
OpGetCount
|
||||
OpGetLen
|
||||
OpGetAcc
|
||||
OpSetAcc
|
||||
OpSetIndex
|
||||
OpPointer
|
||||
OpThrow
|
||||
OpCreate
|
||||
OpGroupBy
|
||||
OpSortBy
|
||||
OpSort
|
||||
OpProfileStart
|
||||
OpProfileEnd
|
||||
OpBegin
|
||||
OpEnd // This opcode must be at the end of this list.
|
||||
)
|
382
vendor/github.com/expr-lang/expr/vm/program.go
generated
vendored
Normal file
382
vendor/github.com/expr-lang/expr/vm/program.go
generated
vendored
Normal file
@@ -0,0 +1,382 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/expr-lang/expr/ast"
|
||||
"github.com/expr-lang/expr/builtin"
|
||||
"github.com/expr-lang/expr/file"
|
||||
"github.com/expr-lang/expr/vm/runtime"
|
||||
)
|
||||
|
||||
// Program represents a compiled expression.
|
||||
type Program struct {
|
||||
Bytecode []Opcode
|
||||
Arguments []int
|
||||
Constants []any
|
||||
|
||||
source file.Source
|
||||
node ast.Node
|
||||
locations []file.Location
|
||||
variables int
|
||||
functions []Function
|
||||
debugInfo map[string]string
|
||||
span *Span
|
||||
}
|
||||
|
||||
// NewProgram returns a new Program. It's used by the compiler.
|
||||
func NewProgram(
|
||||
source file.Source,
|
||||
node ast.Node,
|
||||
locations []file.Location,
|
||||
variables int,
|
||||
constants []any,
|
||||
bytecode []Opcode,
|
||||
arguments []int,
|
||||
functions []Function,
|
||||
debugInfo map[string]string,
|
||||
span *Span,
|
||||
) *Program {
|
||||
return &Program{
|
||||
source: source,
|
||||
node: node,
|
||||
locations: locations,
|
||||
variables: variables,
|
||||
Constants: constants,
|
||||
Bytecode: bytecode,
|
||||
Arguments: arguments,
|
||||
functions: functions,
|
||||
debugInfo: debugInfo,
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
|
||||
// Source returns origin file.Source.
|
||||
func (program *Program) Source() file.Source {
|
||||
return program.source
|
||||
}
|
||||
|
||||
// Node returns origin ast.Node.
|
||||
func (program *Program) Node() ast.Node {
|
||||
return program.node
|
||||
}
|
||||
|
||||
// Locations returns a slice of bytecode's locations.
|
||||
func (program *Program) Locations() []file.Location {
|
||||
return program.locations
|
||||
}
|
||||
|
||||
// Disassemble returns opcodes as a string.
|
||||
func (program *Program) Disassemble() string {
|
||||
var buf bytes.Buffer
|
||||
w := tabwriter.NewWriter(&buf, 0, 0, 2, ' ', 0)
|
||||
program.DisassembleWriter(w)
|
||||
_ = w.Flush()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// DisassembleWriter takes a writer and writes opcodes to it.
|
||||
func (program *Program) DisassembleWriter(w io.Writer) {
|
||||
ip := 0
|
||||
for ip < len(program.Bytecode) {
|
||||
pp := ip
|
||||
op := program.Bytecode[ip]
|
||||
arg := program.Arguments[ip]
|
||||
ip += 1
|
||||
|
||||
code := func(label string) {
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\n", pp, label)
|
||||
}
|
||||
jump := func(label string) {
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t(%v)\n", pp, label, arg, ip+arg)
|
||||
}
|
||||
jumpBack := func(label string) {
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t(%v)\n", pp, label, arg, ip-arg)
|
||||
}
|
||||
argument := func(label string) {
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\n", pp, label, arg)
|
||||
}
|
||||
argumentWithInfo := func(label string, prefix string) {
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t%v\n", pp, label, arg, program.debugInfo[fmt.Sprintf("%s_%d", prefix, arg)])
|
||||
}
|
||||
constant := func(label string) {
|
||||
var c any
|
||||
if arg < len(program.Constants) {
|
||||
c = program.Constants[arg]
|
||||
} else {
|
||||
c = "out of range"
|
||||
}
|
||||
if r, ok := c.(*regexp.Regexp); ok {
|
||||
c = r.String()
|
||||
}
|
||||
if field, ok := c.(*runtime.Field); ok {
|
||||
c = fmt.Sprintf("{%v %v}", strings.Join(field.Path, "."), field.Index)
|
||||
}
|
||||
if method, ok := c.(*runtime.Method); ok {
|
||||
c = fmt.Sprintf("{%v %v}", method.Name, method.Index)
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t%v\n", pp, label, arg, c)
|
||||
}
|
||||
builtinArg := func(label string) {
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t%v\n", pp, label, arg, builtin.Builtins[arg].Name)
|
||||
}
|
||||
|
||||
switch op {
|
||||
case OpInvalid:
|
||||
code("OpInvalid")
|
||||
|
||||
case OpPush:
|
||||
constant("OpPush")
|
||||
|
||||
case OpInt:
|
||||
argument("OpInt")
|
||||
|
||||
case OpPop:
|
||||
code("OpPop")
|
||||
|
||||
case OpStore:
|
||||
argumentWithInfo("OpStore", "var")
|
||||
|
||||
case OpLoadVar:
|
||||
argumentWithInfo("OpLoadVar", "var")
|
||||
|
||||
case OpLoadConst:
|
||||
constant("OpLoadConst")
|
||||
|
||||
case OpLoadField:
|
||||
constant("OpLoadField")
|
||||
|
||||
case OpLoadFast:
|
||||
constant("OpLoadFast")
|
||||
|
||||
case OpLoadMethod:
|
||||
constant("OpLoadMethod")
|
||||
|
||||
case OpLoadFunc:
|
||||
argumentWithInfo("OpLoadFunc", "func")
|
||||
|
||||
case OpLoadEnv:
|
||||
code("OpLoadEnv")
|
||||
|
||||
case OpFetch:
|
||||
code("OpFetch")
|
||||
|
||||
case OpFetchField:
|
||||
constant("OpFetchField")
|
||||
|
||||
case OpMethod:
|
||||
constant("OpMethod")
|
||||
|
||||
case OpTrue:
|
||||
code("OpTrue")
|
||||
|
||||
case OpFalse:
|
||||
code("OpFalse")
|
||||
|
||||
case OpNil:
|
||||
code("OpNil")
|
||||
|
||||
case OpNegate:
|
||||
code("OpNegate")
|
||||
|
||||
case OpNot:
|
||||
code("OpNot")
|
||||
|
||||
case OpEqual:
|
||||
code("OpEqual")
|
||||
|
||||
case OpEqualInt:
|
||||
code("OpEqualInt")
|
||||
|
||||
case OpEqualString:
|
||||
code("OpEqualString")
|
||||
|
||||
case OpJump:
|
||||
jump("OpJump")
|
||||
|
||||
case OpJumpIfTrue:
|
||||
jump("OpJumpIfTrue")
|
||||
|
||||
case OpJumpIfFalse:
|
||||
jump("OpJumpIfFalse")
|
||||
|
||||
case OpJumpIfNil:
|
||||
jump("OpJumpIfNil")
|
||||
|
||||
case OpJumpIfNotNil:
|
||||
jump("OpJumpIfNotNil")
|
||||
|
||||
case OpJumpIfEnd:
|
||||
jump("OpJumpIfEnd")
|
||||
|
||||
case OpJumpBackward:
|
||||
jumpBack("OpJumpBackward")
|
||||
|
||||
case OpIn:
|
||||
code("OpIn")
|
||||
|
||||
case OpLess:
|
||||
code("OpLess")
|
||||
|
||||
case OpMore:
|
||||
code("OpMore")
|
||||
|
||||
case OpLessOrEqual:
|
||||
code("OpLessOrEqual")
|
||||
|
||||
case OpMoreOrEqual:
|
||||
code("OpMoreOrEqual")
|
||||
|
||||
case OpAdd:
|
||||
code("OpAdd")
|
||||
|
||||
case OpSubtract:
|
||||
code("OpSubtract")
|
||||
|
||||
case OpMultiply:
|
||||
code("OpMultiply")
|
||||
|
||||
case OpDivide:
|
||||
code("OpDivide")
|
||||
|
||||
case OpModulo:
|
||||
code("OpModulo")
|
||||
|
||||
case OpExponent:
|
||||
code("OpExponent")
|
||||
|
||||
case OpRange:
|
||||
code("OpRange")
|
||||
|
||||
case OpMatches:
|
||||
code("OpMatches")
|
||||
|
||||
case OpMatchesConst:
|
||||
constant("OpMatchesConst")
|
||||
|
||||
case OpContains:
|
||||
code("OpContains")
|
||||
|
||||
case OpStartsWith:
|
||||
code("OpStartsWith")
|
||||
|
||||
case OpEndsWith:
|
||||
code("OpEndsWith")
|
||||
|
||||
case OpSlice:
|
||||
code("OpSlice")
|
||||
|
||||
case OpCall:
|
||||
argument("OpCall")
|
||||
|
||||
case OpCall0:
|
||||
argumentWithInfo("OpCall0", "func")
|
||||
|
||||
case OpCall1:
|
||||
argumentWithInfo("OpCall1", "func")
|
||||
|
||||
case OpCall2:
|
||||
argumentWithInfo("OpCall2", "func")
|
||||
|
||||
case OpCall3:
|
||||
argumentWithInfo("OpCall3", "func")
|
||||
|
||||
case OpCallN:
|
||||
argument("OpCallN")
|
||||
|
||||
case OpCallFast:
|
||||
argument("OpCallFast")
|
||||
|
||||
case OpCallSafe:
|
||||
argument("OpCallSafe")
|
||||
|
||||
case OpCallTyped:
|
||||
signature := reflect.TypeOf(FuncTypes[arg]).Elem().String()
|
||||
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t%v\n", pp, "OpCallTyped", arg, signature)
|
||||
|
||||
case OpCallBuiltin1:
|
||||
builtinArg("OpCallBuiltin1")
|
||||
|
||||
case OpArray:
|
||||
code("OpArray")
|
||||
|
||||
case OpMap:
|
||||
code("OpMap")
|
||||
|
||||
case OpLen:
|
||||
code("OpLen")
|
||||
|
||||
case OpCast:
|
||||
argument("OpCast")
|
||||
|
||||
case OpDeref:
|
||||
code("OpDeref")
|
||||
|
||||
case OpIncrementIndex:
|
||||
code("OpIncrementIndex")
|
||||
|
||||
case OpDecrementIndex:
|
||||
code("OpDecrementIndex")
|
||||
|
||||
case OpIncrementCount:
|
||||
code("OpIncrementCount")
|
||||
|
||||
case OpGetIndex:
|
||||
code("OpGetIndex")
|
||||
|
||||
case OpGetCount:
|
||||
code("OpGetCount")
|
||||
|
||||
case OpGetLen:
|
||||
code("OpGetLen")
|
||||
|
||||
case OpGetAcc:
|
||||
code("OpGetAcc")
|
||||
|
||||
case OpSetAcc:
|
||||
code("OpSetAcc")
|
||||
|
||||
case OpSetIndex:
|
||||
code("OpSetIndex")
|
||||
|
||||
case OpPointer:
|
||||
code("OpPointer")
|
||||
|
||||
case OpThrow:
|
||||
code("OpThrow")
|
||||
|
||||
case OpCreate:
|
||||
argument("OpCreate")
|
||||
|
||||
case OpGroupBy:
|
||||
code("OpGroupBy")
|
||||
|
||||
case OpSortBy:
|
||||
code("OpSortBy")
|
||||
|
||||
case OpSort:
|
||||
code("OpSort")
|
||||
|
||||
case OpProfileStart:
|
||||
code("OpProfileStart")
|
||||
|
||||
case OpProfileEnd:
|
||||
code("OpProfileEnd")
|
||||
|
||||
case OpBegin:
|
||||
code("OpBegin")
|
||||
|
||||
case OpEnd:
|
||||
code("OpEnd")
|
||||
|
||||
default:
|
||||
_, _ = fmt.Fprintf(w, "%v\t%#x (unknown)\n", ip, op)
|
||||
}
|
||||
}
|
||||
}
|
3718
vendor/github.com/expr-lang/expr/vm/runtime/helpers[generated].go
generated
vendored
Normal file
3718
vendor/github.com/expr-lang/expr/vm/runtime/helpers[generated].go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
394
vendor/github.com/expr-lang/expr/vm/runtime/runtime.go
generated
vendored
Normal file
394
vendor/github.com/expr-lang/expr/vm/runtime/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
package runtime
|
||||
|
||||
//go:generate sh -c "go run ./helpers > ./helpers[generated].go"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/expr-lang/expr/internal/deref"
|
||||
)
|
||||
|
||||
func Fetch(from, i any) any {
|
||||
v := reflect.ValueOf(from)
|
||||
if v.Kind() == reflect.Invalid {
|
||||
panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
|
||||
}
|
||||
|
||||
// Methods can be defined on any type.
|
||||
if v.NumMethod() > 0 {
|
||||
if methodName, ok := i.(string); ok {
|
||||
method := v.MethodByName(methodName)
|
||||
if method.IsValid() {
|
||||
return method.Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Structs, maps, and slices can be access through a pointer or through
|
||||
// a value, when they are accessed through a pointer we don't want to
|
||||
// copy them to a value.
|
||||
// De-reference everything if necessary (interface and pointers)
|
||||
v = deref.Value(v)
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.String:
|
||||
index := ToInt(i)
|
||||
l := v.Len()
|
||||
if index < 0 {
|
||||
index = l + index
|
||||
}
|
||||
if index < 0 || index >= l {
|
||||
panic(fmt.Sprintf("index out of range: %v (array length is %v)", index, l))
|
||||
}
|
||||
value := v.Index(index)
|
||||
if value.IsValid() {
|
||||
return value.Interface()
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
var value reflect.Value
|
||||
if i == nil {
|
||||
value = v.MapIndex(reflect.Zero(v.Type().Key()))
|
||||
} else {
|
||||
value = v.MapIndex(reflect.ValueOf(i))
|
||||
}
|
||||
if value.IsValid() {
|
||||
return value.Interface()
|
||||
} else {
|
||||
elem := reflect.TypeOf(from).Elem()
|
||||
return reflect.Zero(elem).Interface()
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
fieldName := i.(string)
|
||||
value := v.FieldByNameFunc(func(name string) bool {
|
||||
field, _ := v.Type().FieldByName(name)
|
||||
if field.Tag.Get("expr") == fieldName {
|
||||
return true
|
||||
}
|
||||
return name == fieldName
|
||||
})
|
||||
if value.IsValid() {
|
||||
return value.Interface()
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
Index []int
|
||||
Path []string
|
||||
}
|
||||
|
||||
func FetchField(from any, field *Field) any {
|
||||
v := reflect.ValueOf(from)
|
||||
if v.Kind() != reflect.Invalid {
|
||||
v = reflect.Indirect(v)
|
||||
|
||||
// We can use v.FieldByIndex here, but it will panic if the field
|
||||
// is not exists. And we need to recover() to generate a more
|
||||
// user-friendly error message.
|
||||
// Also, our fieldByIndex() function is slightly faster than the
|
||||
// v.FieldByIndex() function as we don't need to verify what a field
|
||||
// is a struct as we already did it on compilation step.
|
||||
value := fieldByIndex(v, field)
|
||||
if value.IsValid() {
|
||||
return value.Interface()
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("cannot get %v from %T", field.Path[0], from))
|
||||
}
|
||||
|
||||
func fieldByIndex(v reflect.Value, field *Field) reflect.Value {
|
||||
if len(field.Index) == 1 {
|
||||
return v.Field(field.Index[0])
|
||||
}
|
||||
for i, x := range field.Index {
|
||||
if i > 0 {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
panic(fmt.Sprintf("cannot get %v from %v", field.Path[i], field.Path[i-1]))
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
}
|
||||
v = v.Field(x)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
type Method struct {
|
||||
Index int
|
||||
Name string
|
||||
}
|
||||
|
||||
func FetchMethod(from any, method *Method) any {
|
||||
v := reflect.ValueOf(from)
|
||||
kind := v.Kind()
|
||||
if kind != reflect.Invalid {
|
||||
// Methods can be defined on any type, no need to dereference.
|
||||
method := v.Method(method.Index)
|
||||
if method.IsValid() {
|
||||
return method.Interface()
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("cannot fetch %v from %T", method.Name, from))
|
||||
}
|
||||
|
||||
func Slice(array, from, to any) any {
|
||||
v := reflect.ValueOf(array)
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.String:
|
||||
length := v.Len()
|
||||
a, b := ToInt(from), ToInt(to)
|
||||
if a < 0 {
|
||||
a = length + a
|
||||
}
|
||||
if a < 0 {
|
||||
a = 0
|
||||
}
|
||||
if b < 0 {
|
||||
b = length + b
|
||||
}
|
||||
if b < 0 {
|
||||
b = 0
|
||||
}
|
||||
if b > length {
|
||||
b = length
|
||||
}
|
||||
if a > b {
|
||||
a = b
|
||||
}
|
||||
value := v.Slice(a, b)
|
||||
if value.IsValid() {
|
||||
return value.Interface()
|
||||
}
|
||||
|
||||
case reflect.Ptr:
|
||||
value := v.Elem()
|
||||
if value.IsValid() {
|
||||
return Slice(value.Interface(), from, to)
|
||||
}
|
||||
|
||||
}
|
||||
panic(fmt.Sprintf("cannot slice %v", from))
|
||||
}
|
||||
|
||||
func In(needle any, array any) bool {
|
||||
if array == nil {
|
||||
return false
|
||||
}
|
||||
v := reflect.ValueOf(array)
|
||||
|
||||
switch v.Kind() {
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
value := v.Index(i)
|
||||
if value.IsValid() {
|
||||
if Equal(value.Interface(), needle) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
case reflect.Map:
|
||||
var value reflect.Value
|
||||
if needle == nil {
|
||||
value = v.MapIndex(reflect.Zero(v.Type().Key()))
|
||||
} else {
|
||||
value = v.MapIndex(reflect.ValueOf(needle))
|
||||
}
|
||||
if value.IsValid() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
case reflect.Struct:
|
||||
n := reflect.ValueOf(needle)
|
||||
if !n.IsValid() || n.Kind() != reflect.String {
|
||||
panic(fmt.Sprintf("cannot use %T as field name of %T", needle, array))
|
||||
}
|
||||
value := v.FieldByName(n.String())
|
||||
if value.IsValid() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
case reflect.Ptr:
|
||||
value := v.Elem()
|
||||
if value.IsValid() {
|
||||
return In(needle, value.Interface())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf(`operator "in" not defined on %T`, array))
|
||||
}
|
||||
|
||||
func Len(a any) int {
|
||||
v := reflect.ValueOf(a)
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
|
||||
return v.Len()
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid argument for len (type %T)", a))
|
||||
}
|
||||
}
|
||||
|
||||
func Negate(i any) any {
|
||||
switch v := i.(type) {
|
||||
case float32:
|
||||
return -v
|
||||
case float64:
|
||||
return -v
|
||||
case int:
|
||||
return -v
|
||||
case int8:
|
||||
return -v
|
||||
case int16:
|
||||
return -v
|
||||
case int32:
|
||||
return -v
|
||||
case int64:
|
||||
return -v
|
||||
case uint:
|
||||
return -v
|
||||
case uint8:
|
||||
return -v
|
||||
case uint16:
|
||||
return -v
|
||||
case uint32:
|
||||
return -v
|
||||
case uint64:
|
||||
return -v
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid operation: - %T", v))
|
||||
}
|
||||
}
|
||||
|
||||
func Exponent(a, b any) float64 {
|
||||
return math.Pow(ToFloat64(a), ToFloat64(b))
|
||||
}
|
||||
|
||||
func MakeRange(min, max int) []int {
|
||||
size := max - min + 1
|
||||
if size <= 0 {
|
||||
return []int{}
|
||||
}
|
||||
rng := make([]int, size)
|
||||
for i := range rng {
|
||||
rng[i] = min + i
|
||||
}
|
||||
return rng
|
||||
}
|
||||
|
||||
func ToInt(a any) int {
|
||||
switch x := a.(type) {
|
||||
case float32:
|
||||
return int(x)
|
||||
case float64:
|
||||
return int(x)
|
||||
case int:
|
||||
return x
|
||||
case int8:
|
||||
return int(x)
|
||||
case int16:
|
||||
return int(x)
|
||||
case int32:
|
||||
return int(x)
|
||||
case int64:
|
||||
return int(x)
|
||||
case uint:
|
||||
return int(x)
|
||||
case uint8:
|
||||
return int(x)
|
||||
case uint16:
|
||||
return int(x)
|
||||
case uint32:
|
||||
return int(x)
|
||||
case uint64:
|
||||
return int(x)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid operation: int(%T)", x))
|
||||
}
|
||||
}
|
||||
|
||||
func ToInt64(a any) int64 {
|
||||
switch x := a.(type) {
|
||||
case float32:
|
||||
return int64(x)
|
||||
case float64:
|
||||
return int64(x)
|
||||
case int:
|
||||
return int64(x)
|
||||
case int8:
|
||||
return int64(x)
|
||||
case int16:
|
||||
return int64(x)
|
||||
case int32:
|
||||
return int64(x)
|
||||
case int64:
|
||||
return x
|
||||
case uint:
|
||||
return int64(x)
|
||||
case uint8:
|
||||
return int64(x)
|
||||
case uint16:
|
||||
return int64(x)
|
||||
case uint32:
|
||||
return int64(x)
|
||||
case uint64:
|
||||
return int64(x)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid operation: int64(%T)", x))
|
||||
}
|
||||
}
|
||||
|
||||
func ToFloat64(a any) float64 {
|
||||
switch x := a.(type) {
|
||||
case float32:
|
||||
return float64(x)
|
||||
case float64:
|
||||
return x
|
||||
case int:
|
||||
return float64(x)
|
||||
case int8:
|
||||
return float64(x)
|
||||
case int16:
|
||||
return float64(x)
|
||||
case int32:
|
||||
return float64(x)
|
||||
case int64:
|
||||
return float64(x)
|
||||
case uint:
|
||||
return float64(x)
|
||||
case uint8:
|
||||
return float64(x)
|
||||
case uint16:
|
||||
return float64(x)
|
||||
case uint32:
|
||||
return float64(x)
|
||||
case uint64:
|
||||
return float64(x)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid operation: float(%T)", x))
|
||||
}
|
||||
}
|
||||
|
||||
func IsNil(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
r := reflect.ValueOf(v)
|
||||
switch r.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
|
||||
return r.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
45
vendor/github.com/expr-lang/expr/vm/runtime/sort.go
generated
vendored
Normal file
45
vendor/github.com/expr-lang/expr/vm/runtime/sort.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package runtime
|
||||
|
||||
type SortBy struct {
|
||||
Desc bool
|
||||
Array []any
|
||||
Values []any
|
||||
}
|
||||
|
||||
func (s *SortBy) Len() int {
|
||||
return len(s.Array)
|
||||
}
|
||||
|
||||
func (s *SortBy) Swap(i, j int) {
|
||||
s.Array[i], s.Array[j] = s.Array[j], s.Array[i]
|
||||
s.Values[i], s.Values[j] = s.Values[j], s.Values[i]
|
||||
}
|
||||
|
||||
func (s *SortBy) Less(i, j int) bool {
|
||||
a, b := s.Values[i], s.Values[j]
|
||||
if s.Desc {
|
||||
return Less(b, a)
|
||||
}
|
||||
return Less(a, b)
|
||||
}
|
||||
|
||||
type Sort struct {
|
||||
Desc bool
|
||||
Array []any
|
||||
}
|
||||
|
||||
func (s *Sort) Len() int {
|
||||
return len(s.Array)
|
||||
}
|
||||
|
||||
func (s *Sort) Swap(i, j int) {
|
||||
s.Array[i], s.Array[j] = s.Array[j], s.Array[i]
|
||||
}
|
||||
|
||||
func (s *Sort) Less(i, j int) bool {
|
||||
a, b := s.Array[i], s.Array[j]
|
||||
if s.Desc {
|
||||
return Less(b, a)
|
||||
}
|
||||
return Less(a, b)
|
||||
}
|
37
vendor/github.com/expr-lang/expr/vm/utils.go
generated
vendored
Normal file
37
vendor/github.com/expr-lang/expr/vm/utils.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
Function = func(params ...any) (any, error)
|
||||
SafeFunction = func(params ...any) (any, uint, error)
|
||||
)
|
||||
|
||||
var (
|
||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
)
|
||||
|
||||
type Scope struct {
|
||||
Array reflect.Value
|
||||
Index int
|
||||
Len int
|
||||
Count int
|
||||
Acc any
|
||||
}
|
||||
|
||||
type groupBy = map[any][]any
|
||||
|
||||
type Span struct {
|
||||
Name string `json:"name"`
|
||||
Expression string `json:"expression"`
|
||||
Duration int64 `json:"duration"`
|
||||
Children []*Span `json:"children"`
|
||||
start time.Time
|
||||
}
|
||||
|
||||
func GetSpan(program *Program) *Span {
|
||||
return program.span
|
||||
}
|
617
vendor/github.com/expr-lang/expr/vm/vm.go
generated
vendored
Normal file
617
vendor/github.com/expr-lang/expr/vm/vm.go
generated
vendored
Normal file
@@ -0,0 +1,617 @@
|
||||
package vm
|
||||
|
||||
//go:generate sh -c "go run ./func_types > ./func_types[generated].go"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/expr-lang/expr/builtin"
|
||||
"github.com/expr-lang/expr/conf"
|
||||
"github.com/expr-lang/expr/file"
|
||||
"github.com/expr-lang/expr/internal/deref"
|
||||
"github.com/expr-lang/expr/vm/runtime"
|
||||
)
|
||||
|
||||
func Run(program *Program, env any) (any, error) {
|
||||
if program == nil {
|
||||
return nil, fmt.Errorf("program is nil")
|
||||
}
|
||||
vm := VM{}
|
||||
return vm.Run(program, env)
|
||||
}
|
||||
|
||||
func Debug() *VM {
|
||||
vm := &VM{
|
||||
debug: true,
|
||||
step: make(chan struct{}, 0),
|
||||
curr: make(chan int, 0),
|
||||
}
|
||||
return vm
|
||||
}
|
||||
|
||||
type VM struct {
|
||||
Stack []any
|
||||
Scopes []*Scope
|
||||
Variables []any
|
||||
MemoryBudget uint
|
||||
ip int
|
||||
memory uint
|
||||
debug bool
|
||||
step chan struct{}
|
||||
curr chan int
|
||||
}
|
||||
|
||||
func (vm *VM) Run(program *Program, env any) (_ any, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
var location file.Location
|
||||
if vm.ip-1 < len(program.locations) {
|
||||
location = program.locations[vm.ip-1]
|
||||
}
|
||||
f := &file.Error{
|
||||
Location: location,
|
||||
Message: fmt.Sprintf("%v", r),
|
||||
}
|
||||
if err, ok := r.(error); ok {
|
||||
f.Wrap(err)
|
||||
}
|
||||
err = f.Bind(program.source)
|
||||
}
|
||||
}()
|
||||
|
||||
if vm.Stack == nil {
|
||||
vm.Stack = make([]any, 0, 2)
|
||||
} else {
|
||||
vm.Stack = vm.Stack[0:0]
|
||||
}
|
||||
if vm.Scopes != nil {
|
||||
vm.Scopes = vm.Scopes[0:0]
|
||||
}
|
||||
if len(vm.Variables) < program.variables {
|
||||
vm.Variables = make([]any, program.variables)
|
||||
}
|
||||
|
||||
if vm.MemoryBudget == 0 {
|
||||
vm.MemoryBudget = conf.DefaultMemoryBudget
|
||||
}
|
||||
vm.memory = 0
|
||||
vm.ip = 0
|
||||
|
||||
for vm.ip < len(program.Bytecode) {
|
||||
if debug && vm.debug {
|
||||
<-vm.step
|
||||
}
|
||||
|
||||
op := program.Bytecode[vm.ip]
|
||||
arg := program.Arguments[vm.ip]
|
||||
vm.ip += 1
|
||||
|
||||
switch op {
|
||||
|
||||
case OpInvalid:
|
||||
panic("invalid opcode")
|
||||
|
||||
case OpPush:
|
||||
vm.push(program.Constants[arg])
|
||||
|
||||
case OpInt:
|
||||
vm.push(arg)
|
||||
|
||||
case OpPop:
|
||||
vm.pop()
|
||||
|
||||
case OpStore:
|
||||
vm.Variables[arg] = vm.pop()
|
||||
|
||||
case OpLoadVar:
|
||||
vm.push(vm.Variables[arg])
|
||||
|
||||
case OpLoadConst:
|
||||
vm.push(runtime.Fetch(env, program.Constants[arg]))
|
||||
|
||||
case OpLoadField:
|
||||
vm.push(runtime.FetchField(env, program.Constants[arg].(*runtime.Field)))
|
||||
|
||||
case OpLoadFast:
|
||||
vm.push(env.(map[string]any)[program.Constants[arg].(string)])
|
||||
|
||||
case OpLoadMethod:
|
||||
vm.push(runtime.FetchMethod(env, program.Constants[arg].(*runtime.Method)))
|
||||
|
||||
case OpLoadFunc:
|
||||
vm.push(program.functions[arg])
|
||||
|
||||
case OpFetch:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Fetch(a, b))
|
||||
|
||||
case OpFetchField:
|
||||
a := vm.pop()
|
||||
vm.push(runtime.FetchField(a, program.Constants[arg].(*runtime.Field)))
|
||||
|
||||
case OpLoadEnv:
|
||||
vm.push(env)
|
||||
|
||||
case OpMethod:
|
||||
a := vm.pop()
|
||||
vm.push(runtime.FetchMethod(a, program.Constants[arg].(*runtime.Method)))
|
||||
|
||||
case OpTrue:
|
||||
vm.push(true)
|
||||
|
||||
case OpFalse:
|
||||
vm.push(false)
|
||||
|
||||
case OpNil:
|
||||
vm.push(nil)
|
||||
|
||||
case OpNegate:
|
||||
v := runtime.Negate(vm.pop())
|
||||
vm.push(v)
|
||||
|
||||
case OpNot:
|
||||
v := vm.pop().(bool)
|
||||
vm.push(!v)
|
||||
|
||||
case OpEqual:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Equal(a, b))
|
||||
|
||||
case OpEqualInt:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(a.(int) == b.(int))
|
||||
|
||||
case OpEqualString:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(a.(string) == b.(string))
|
||||
|
||||
case OpJump:
|
||||
vm.ip += arg
|
||||
|
||||
case OpJumpIfTrue:
|
||||
if vm.current().(bool) {
|
||||
vm.ip += arg
|
||||
}
|
||||
|
||||
case OpJumpIfFalse:
|
||||
if !vm.current().(bool) {
|
||||
vm.ip += arg
|
||||
}
|
||||
|
||||
case OpJumpIfNil:
|
||||
if runtime.IsNil(vm.current()) {
|
||||
vm.ip += arg
|
||||
}
|
||||
|
||||
case OpJumpIfNotNil:
|
||||
if !runtime.IsNil(vm.current()) {
|
||||
vm.ip += arg
|
||||
}
|
||||
|
||||
case OpJumpIfEnd:
|
||||
scope := vm.scope()
|
||||
if scope.Index >= scope.Len {
|
||||
vm.ip += arg
|
||||
}
|
||||
|
||||
case OpJumpBackward:
|
||||
vm.ip -= arg
|
||||
|
||||
case OpIn:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.In(a, b))
|
||||
|
||||
case OpLess:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Less(a, b))
|
||||
|
||||
case OpMore:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.More(a, b))
|
||||
|
||||
case OpLessOrEqual:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.LessOrEqual(a, b))
|
||||
|
||||
case OpMoreOrEqual:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.MoreOrEqual(a, b))
|
||||
|
||||
case OpAdd:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Add(a, b))
|
||||
|
||||
case OpSubtract:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Subtract(a, b))
|
||||
|
||||
case OpMultiply:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Multiply(a, b))
|
||||
|
||||
case OpDivide:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Divide(a, b))
|
||||
|
||||
case OpModulo:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Modulo(a, b))
|
||||
|
||||
case OpExponent:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
vm.push(runtime.Exponent(a, b))
|
||||
|
||||
case OpRange:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
min := runtime.ToInt(a)
|
||||
max := runtime.ToInt(b)
|
||||
size := max - min + 1
|
||||
if size <= 0 {
|
||||
size = 0
|
||||
}
|
||||
vm.memGrow(uint(size))
|
||||
vm.push(runtime.MakeRange(min, max))
|
||||
|
||||
case OpMatches:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
if runtime.IsNil(a) || runtime.IsNil(b) {
|
||||
vm.push(false)
|
||||
break
|
||||
}
|
||||
match, err := regexp.MatchString(b.(string), a.(string))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.push(match)
|
||||
|
||||
case OpMatchesConst:
|
||||
a := vm.pop()
|
||||
if runtime.IsNil(a) {
|
||||
vm.push(false)
|
||||
break
|
||||
}
|
||||
r := program.Constants[arg].(*regexp.Regexp)
|
||||
vm.push(r.MatchString(a.(string)))
|
||||
|
||||
case OpContains:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
if runtime.IsNil(a) || runtime.IsNil(b) {
|
||||
vm.push(false)
|
||||
break
|
||||
}
|
||||
vm.push(strings.Contains(a.(string), b.(string)))
|
||||
|
||||
case OpStartsWith:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
if runtime.IsNil(a) || runtime.IsNil(b) {
|
||||
vm.push(false)
|
||||
break
|
||||
}
|
||||
vm.push(strings.HasPrefix(a.(string), b.(string)))
|
||||
|
||||
case OpEndsWith:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
if runtime.IsNil(a) || runtime.IsNil(b) {
|
||||
vm.push(false)
|
||||
break
|
||||
}
|
||||
vm.push(strings.HasSuffix(a.(string), b.(string)))
|
||||
|
||||
case OpSlice:
|
||||
from := vm.pop()
|
||||
to := vm.pop()
|
||||
node := vm.pop()
|
||||
vm.push(runtime.Slice(node, from, to))
|
||||
|
||||
case OpCall:
|
||||
fn := reflect.ValueOf(vm.pop())
|
||||
size := arg
|
||||
in := make([]reflect.Value, size)
|
||||
for i := int(size) - 1; i >= 0; i-- {
|
||||
param := vm.pop()
|
||||
if param == nil {
|
||||
in[i] = reflect.Zero(fn.Type().In(i))
|
||||
} else {
|
||||
in[i] = reflect.ValueOf(param)
|
||||
}
|
||||
}
|
||||
out := fn.Call(in)
|
||||
if len(out) == 2 && out[1].Type() == errorType && !out[1].IsNil() {
|
||||
panic(out[1].Interface().(error))
|
||||
}
|
||||
vm.push(out[0].Interface())
|
||||
|
||||
case OpCall0:
|
||||
out, err := program.functions[arg]()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.push(out)
|
||||
|
||||
case OpCall1:
|
||||
a := vm.pop()
|
||||
out, err := program.functions[arg](a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.push(out)
|
||||
|
||||
case OpCall2:
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
out, err := program.functions[arg](a, b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.push(out)
|
||||
|
||||
case OpCall3:
|
||||
c := vm.pop()
|
||||
b := vm.pop()
|
||||
a := vm.pop()
|
||||
out, err := program.functions[arg](a, b, c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.push(out)
|
||||
|
||||
case OpCallN:
|
||||
fn := vm.pop().(Function)
|
||||
size := arg
|
||||
in := make([]any, size)
|
||||
for i := int(size) - 1; i >= 0; i-- {
|
||||
in[i] = vm.pop()
|
||||
}
|
||||
out, err := fn(in...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.push(out)
|
||||
|
||||
case OpCallFast:
|
||||
fn := vm.pop().(func(...any) any)
|
||||
size := arg
|
||||
in := make([]any, size)
|
||||
for i := int(size) - 1; i >= 0; i-- {
|
||||
in[i] = vm.pop()
|
||||
}
|
||||
vm.push(fn(in...))
|
||||
|
||||
case OpCallSafe:
|
||||
fn := vm.pop().(SafeFunction)
|
||||
size := arg
|
||||
in := make([]any, size)
|
||||
for i := int(size) - 1; i >= 0; i-- {
|
||||
in[i] = vm.pop()
|
||||
}
|
||||
out, mem, err := fn(in...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.memGrow(mem)
|
||||
vm.push(out)
|
||||
|
||||
case OpCallTyped:
|
||||
vm.push(vm.call(vm.pop(), arg))
|
||||
|
||||
case OpCallBuiltin1:
|
||||
vm.push(builtin.Builtins[arg].Fast(vm.pop()))
|
||||
|
||||
case OpArray:
|
||||
size := vm.pop().(int)
|
||||
vm.memGrow(uint(size))
|
||||
array := make([]any, size)
|
||||
for i := size - 1; i >= 0; i-- {
|
||||
array[i] = vm.pop()
|
||||
}
|
||||
vm.push(array)
|
||||
|
||||
case OpMap:
|
||||
size := vm.pop().(int)
|
||||
vm.memGrow(uint(size))
|
||||
m := make(map[string]any)
|
||||
for i := size - 1; i >= 0; i-- {
|
||||
value := vm.pop()
|
||||
key := vm.pop()
|
||||
m[key.(string)] = value
|
||||
}
|
||||
vm.push(m)
|
||||
|
||||
case OpLen:
|
||||
vm.push(runtime.Len(vm.current()))
|
||||
|
||||
case OpCast:
|
||||
switch arg {
|
||||
case 0:
|
||||
vm.push(runtime.ToInt(vm.pop()))
|
||||
case 1:
|
||||
vm.push(runtime.ToInt64(vm.pop()))
|
||||
case 2:
|
||||
vm.push(runtime.ToFloat64(vm.pop()))
|
||||
}
|
||||
|
||||
case OpDeref:
|
||||
a := vm.pop()
|
||||
vm.push(deref.Interface(a))
|
||||
|
||||
case OpIncrementIndex:
|
||||
vm.scope().Index++
|
||||
|
||||
case OpDecrementIndex:
|
||||
scope := vm.scope()
|
||||
scope.Index--
|
||||
|
||||
case OpIncrementCount:
|
||||
scope := vm.scope()
|
||||
scope.Count++
|
||||
|
||||
case OpGetIndex:
|
||||
vm.push(vm.scope().Index)
|
||||
|
||||
case OpGetCount:
|
||||
scope := vm.scope()
|
||||
vm.push(scope.Count)
|
||||
|
||||
case OpGetLen:
|
||||
scope := vm.scope()
|
||||
vm.push(scope.Len)
|
||||
|
||||
case OpGetAcc:
|
||||
vm.push(vm.scope().Acc)
|
||||
|
||||
case OpSetAcc:
|
||||
vm.scope().Acc = vm.pop()
|
||||
|
||||
case OpSetIndex:
|
||||
scope := vm.scope()
|
||||
scope.Index = vm.pop().(int)
|
||||
|
||||
case OpPointer:
|
||||
scope := vm.scope()
|
||||
vm.push(scope.Array.Index(scope.Index).Interface())
|
||||
|
||||
case OpThrow:
|
||||
panic(vm.pop().(error))
|
||||
|
||||
case OpCreate:
|
||||
switch arg {
|
||||
case 1:
|
||||
vm.push(make(groupBy))
|
||||
case 2:
|
||||
scope := vm.scope()
|
||||
var desc bool
|
||||
switch vm.pop().(string) {
|
||||
case "asc":
|
||||
desc = false
|
||||
case "desc":
|
||||
desc = true
|
||||
default:
|
||||
panic("unknown order, use asc or desc")
|
||||
}
|
||||
vm.push(&runtime.SortBy{
|
||||
Desc: desc,
|
||||
Array: make([]any, 0, scope.Len),
|
||||
Values: make([]any, 0, scope.Len),
|
||||
})
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown OpCreate argument %v", arg))
|
||||
}
|
||||
|
||||
case OpGroupBy:
|
||||
scope := vm.scope()
|
||||
key := vm.pop()
|
||||
item := scope.Array.Index(scope.Index).Interface()
|
||||
scope.Acc.(groupBy)[key] = append(scope.Acc.(groupBy)[key], item)
|
||||
|
||||
case OpSortBy:
|
||||
scope := vm.scope()
|
||||
value := vm.pop()
|
||||
item := scope.Array.Index(scope.Index).Interface()
|
||||
sortable := scope.Acc.(*runtime.SortBy)
|
||||
sortable.Array = append(sortable.Array, item)
|
||||
sortable.Values = append(sortable.Values, value)
|
||||
|
||||
case OpSort:
|
||||
scope := vm.scope()
|
||||
sortable := scope.Acc.(*runtime.SortBy)
|
||||
sort.Sort(sortable)
|
||||
vm.memGrow(uint(scope.Len))
|
||||
vm.push(sortable.Array)
|
||||
|
||||
case OpProfileStart:
|
||||
span := program.Constants[arg].(*Span)
|
||||
span.start = time.Now()
|
||||
|
||||
case OpProfileEnd:
|
||||
span := program.Constants[arg].(*Span)
|
||||
span.Duration += time.Since(span.start).Nanoseconds()
|
||||
|
||||
case OpBegin:
|
||||
a := vm.pop()
|
||||
array := reflect.ValueOf(a)
|
||||
vm.Scopes = append(vm.Scopes, &Scope{
|
||||
Array: array,
|
||||
Len: array.Len(),
|
||||
})
|
||||
|
||||
case OpEnd:
|
||||
vm.Scopes = vm.Scopes[:len(vm.Scopes)-1]
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown bytecode %#x", op))
|
||||
}
|
||||
|
||||
if debug && vm.debug {
|
||||
vm.curr <- vm.ip
|
||||
}
|
||||
}
|
||||
|
||||
if debug && vm.debug {
|
||||
close(vm.curr)
|
||||
close(vm.step)
|
||||
}
|
||||
|
||||
if len(vm.Stack) > 0 {
|
||||
return vm.pop(), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (vm *VM) push(value any) {
|
||||
vm.Stack = append(vm.Stack, value)
|
||||
}
|
||||
|
||||
func (vm *VM) current() any {
|
||||
return vm.Stack[len(vm.Stack)-1]
|
||||
}
|
||||
|
||||
func (vm *VM) pop() any {
|
||||
value := vm.Stack[len(vm.Stack)-1]
|
||||
vm.Stack = vm.Stack[:len(vm.Stack)-1]
|
||||
return value
|
||||
}
|
||||
|
||||
func (vm *VM) memGrow(size uint) {
|
||||
vm.memory += size
|
||||
if vm.memory >= vm.MemoryBudget {
|
||||
panic("memory budget exceeded")
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *VM) scope() *Scope {
|
||||
return vm.Scopes[len(vm.Scopes)-1]
|
||||
}
|
||||
|
||||
func (vm *VM) Step() {
|
||||
vm.step <- struct{}{}
|
||||
}
|
||||
|
||||
func (vm *VM) Position() chan int {
|
||||
return vm.curr
|
||||
}
|
Reference in New Issue
Block a user