| 52 | } |
| 53 | |
| 54 | func (vm *VM) Run(program *Program, env any) (_ any, err error) { |
| 55 | defer func() { |
| 56 | if r := recover(); r != nil { |
| 57 | var location file.Location |
| 58 | if vm.ip-1 < len(program.locations) { |
| 59 | location = program.locations[vm.ip-1] |
| 60 | } |
| 61 | f := &file.Error{ |
| 62 | Location: location, |
| 63 | Message: fmt.Sprintf("%v", r), |
| 64 | } |
| 65 | if err, ok := r.(error); ok { |
| 66 | f.Wrap(err) |
| 67 | } |
| 68 | err = f.Bind(program.source) |
| 69 | } |
| 70 | }() |
| 71 | |
| 72 | if vm.Stack == nil { |
| 73 | vm.Stack = make([]any, 0, 2) |
| 74 | } else { |
| 75 | clearSlice(vm.Stack) |
| 76 | vm.Stack = vm.Stack[0:0] |
| 77 | } |
| 78 | if vm.Scopes != nil { |
| 79 | clearSlice(vm.Scopes) |
| 80 | vm.Scopes = vm.Scopes[0:0] |
| 81 | } |
| 82 | vm.scopePoolIdx = 0 // Reset pool index for reuse |
| 83 | vm.currScope = nil |
| 84 | if len(vm.Variables) < program.variables { |
| 85 | vm.Variables = make([]any, program.variables) |
| 86 | } |
| 87 | if vm.MemoryBudget == 0 { |
| 88 | vm.MemoryBudget = conf.DefaultMemoryBudget |
| 89 | } |
| 90 | vm.memory = 0 |
| 91 | vm.ip = 0 |
| 92 | |
| 93 | var fnArgsBuf []any |
| 94 | |
| 95 | for vm.ip < len(program.Bytecode) { |
| 96 | if debug && vm.debug { |
| 97 | <-vm.step |
| 98 | } |
| 99 | |
| 100 | op := program.Bytecode[vm.ip] |
| 101 | arg := program.Arguments[vm.ip] |
| 102 | vm.ip += 1 |
| 103 | |
| 104 | switch op { |
| 105 | |
| 106 | case OpInvalid: |
| 107 | panic("invalid opcode") |
| 108 | |
| 109 | case OpPush: |
| 110 | vm.push(program.Constants[arg]) |
| 111 | |