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 Line int Err error } func (e Error) Error() string { if e.Line == -1 { return fmt.Sprintf("vm error at pc %d, unknown line: %v", e.Pc, e.Err) } return fmt.Sprintf("vm error at pc %d, line %d: %v", e.Pc, e.Line, e.Err) } // Fatal errors var ( ErrStackOverflow = errors.New("stack overflow (max depth: 1000)") ErrStackUnderflow = errors.New("local stack underflow") ErrReachedMaxCallDepth = errors.New("reached max call depth (max depth: 1000)") ErrReachedRootCallFrame = errors.New("reached root call frame") ErrCallBaseCantBeNegative = errors.New("call base cannot be negative") ) 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) }