| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // Author: simon
- // Author: ynwdlxm@163.com
- // Date: 2022/10/22 13:55
- // Desc: Stack VM implement
- package vm
- import (
- "fmt"
- "github/runnignwater/monkey/code"
- "github/runnignwater/monkey/compiler"
- "github/runnignwater/monkey/object"
- )
- const StackSize = 2048
- var True = &object.Boolean{Value: true}
- var False = &object.Boolean{Value: false}
- type VM struct {
- constants []object.Object
- instructions code.Instructions
- stack []object.Object
- sp int // Always points to the next value. Top of stack is stack[sp-1]
- }
- func New(byteCode *compiler.ByteCode) *VM {
- return &VM{
- instructions: byteCode.Instructions,
- constants: byteCode.Constants,
- stack: make([]object.Object, StackSize),
- sp: 0,
- }
- }
- // func (vm *VM) StackTop() object.Object {
- // if vm.sp == 0 {
- // return nil
- // }
- // return vm.stack[vm.sp-1]
- // }
- func (vm *VM) Run() error {
- for ip := 0; ip < len(vm.instructions); ip++ {
- op := code.Opcode(vm.instructions[ip])
- switch op {
- case code.OpConstant:
- constIndex := code.ReadUint16(vm.instructions[ip+1:])
- ip += 2
- // 执行
- err := vm.push(vm.constants[constIndex])
- if err != nil {
- return err
- }
- case code.OpTrue:
- err := vm.push(True)
- if err != nil {
- return err
- }
- case code.OpFalse:
- err := vm.push(False)
- if err != nil {
- return err
- }
- case code.OpAdd, code.OpSub, code.OpMul, code.OpDiv:
- err := vm.executeBinaryOperation(op)
- if err != nil {
- return err
- }
- case code.OpEqual, code.OpNotEqual, code.OpGreaterThan:
- err := vm.executeComparison(op)
- if err != nil {
- return err
- }
- case code.OpMinus:
- err := vm.executeMinusOperator()
- if err != nil {
- return err
- }
- case code.OpBang:
- err := vm.executeBangOperator()
- if err != nil {
- return err
- }
- case code.OpPop:
- vm.pop()
- }
- }
- return nil
- }
- func (vm *VM) push(o object.Object) error {
- if vm.sp >= StackSize {
- return fmt.Errorf("stack overflow")
- }
- vm.stack[vm.sp] = o
- vm.sp++
- return nil
- }
- func (vm *VM) pop() object.Object {
- o := vm.stack[vm.sp-1]
- vm.sp--
- return o
- }
- func (vm *VM) executeBinaryOperation(op code.Opcode) error {
- right := vm.pop()
- left := vm.pop()
- leftType := left.Type()
- rightType := right.Type()
- if leftType == object.IntegerObj && rightType == object.IntegerObj {
- return vm.executeBinaryIntegerOperation(op, left, right)
- }
- return fmt.Errorf("unsupported types of binary operation: %s %s", leftType, rightType)
- }
- func (vm *VM) executeComparison(op code.Opcode) error {
- right := vm.pop()
- left := vm.pop()
- if left.Type() == object.IntegerObj || right.Type() == object.IntegerObj {
- return vm.executeIntegerComparison(op, left, right)
- }
- switch op {
- case code.OpEqual:
- return vm.push(nativeBoolToBooleanObject(right == left))
- case code.OpNotEqual:
- return vm.push(nativeBoolToBooleanObject(right != left))
- default:
- return fmt.Errorf("unknown operator: %d (%s %s)", op, left.Type(), right.Type())
- }
- }
- func (vm *VM) LastPopStackElem() object.Object {
- return vm.stack[vm.sp]
- }
- func (vm *VM) executeBinaryIntegerOperation(
- op code.Opcode,
- left, right object.Object,
- ) error {
- leftValue := left.(*object.Integer).Value
- rightValue := right.(*object.Integer).Value
- var result int64
- switch op {
- case code.OpAdd:
- result = leftValue + rightValue
- case code.OpSub:
- result = leftValue - rightValue
- case code.OpMul:
- result = leftValue * rightValue
- case code.OpDiv:
- result = leftValue / rightValue
- default:
- return fmt.Errorf("unknown integer operator: %d", op)
- }
- return vm.push(&object.Integer{Value: result})
- }
- func (vm *VM) executeIntegerComparison(
- op code.Opcode,
- left, right object.Object,
- ) error {
- leftValue := left.(*object.Integer).Value
- rightValue := right.(*object.Integer).Value
- switch op {
- case code.OpEqual:
- return vm.push(nativeBoolToBooleanObject(rightValue == leftValue))
- case code.OpNotEqual:
- return vm.push(nativeBoolToBooleanObject(rightValue != leftValue))
- case code.OpGreaterThan:
- return vm.push(nativeBoolToBooleanObject(leftValue > rightValue))
- default:
- return fmt.Errorf("unknown operator: %d", op)
- }
- }
- func (vm *VM) executeMinusOperator() error {
- operand := vm.pop()
- if operand.Type() != object.IntegerObj {
- return fmt.Errorf("unsupported type for nagation: %s", operand.Type())
- }
- value := operand.(*object.Integer).Value
- return vm.push(&object.Integer{Value: -value})
- }
- func (vm *VM) executeBangOperator() error {
- operand := vm.pop()
- switch operand {
- case True:
- return vm.push(False)
- case False:
- return vm.push(True)
- default:
- return vm.push(False)
- }
- }
- func nativeBoolToBooleanObject(input bool) *object.Boolean {
- if input {
- return True
- }
- return False
- }
|