mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-12 18:51:02 +08:00
383 lines
6.7 KiB
Go
383 lines
6.7 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|