package vm import ( "errors" "fmt" "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/text" "jinx/pkg/lang/vm/value" ) type Error struct { Pc int Err error } func (e Error) Error() string { return fmt.Sprintf("vm error at pc %d: %s", e.Pc, e.Err) } // Fatal errors var ( ErrCallStackOverflow = errors.New("call stack overflow (max depth: 1000)") ErrLocalStackOverflow = errors.New("local stack overflow (max depth: 1000)") ErrNoPreviousCallFrame = errors.New("no previous call frame") ErrCantPopRootFrame = errors.New("cannot pop root frame") ErrCallFrameEmpty = errors.New("current call frame is empty") ) type ErrLocalIndexOutOfBounds struct { Index int Len int } func (e ErrLocalIndexOutOfBounds) Error() string { return fmt.Sprintf("local index out of bounds: %d (len: %d)", e.Index, e.Len) } type ErrInvalidOp struct { Op uint8 } func (e ErrInvalidOp) Error() string { return fmt.Sprintf("invalid opcode: %d", e.Op) } // Non-fatal errors, which will later be implemented as catchable exceptions type ErrInvalidOperandType struct { Op code.Op X value.Type } func (e ErrInvalidOperandType) Error() string { return fmt.Sprintf("invalid operand type for op %s: %v", text.OpToString(e.Op), e.X) } type ErrInvalidOperandTypes struct { Op code.Op X value.Type Y value.Type } func (e ErrInvalidOperandTypes) Error() string { return fmt.Sprintf("invalid operand types for op %s: %v, %v", text.OpToString(e.Op), e.X, e.Y) } type ErrArrayIndexOutOfBounds struct { Index int Len int } func (e ErrArrayIndexOutOfBounds) Error() string { return fmt.Sprintf("array index out of bounds: %d (len: %d)", e.Index, e.Len) }