package value import ( "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/mem" ) type Value struct { t TypeKind d Data outlet mem.Ptr } func NewInt(x int64) Value { return Value{t: IntType, d: IntData(x)} } func NewFloat(x float64) Value { return Value{t: FloatType, d: FloatData(x)} } func NewString(m mem.Mem, str string) (Value, error) { ptr, err := m.Allocate(mem.CellKindString) if err != nil { return Value{}, err } if err = m.Set(ptr, StringCell(str)); err != nil { return Value{}, err } return Value{t: StringType, d: StringData{data: ptr}}, nil } func NewBool(b bool) Value { return Value{t: BoolType, d: BoolData(b)} } func NewArray(m mem.Mem, arr []Value) (Value, error) { ptr, err := m.Allocate(mem.CellKindArray) if err != nil { return Value{}, err } if err = m.Set(ptr, ArrayCell(arr)); err != nil { return Value{}, err } return Value{t: ArrayType, d: ArrayData{data: ptr}}, nil } func NewNull() Value { return Value{t: NullType, d: NullData{}} } func NewFunction(pos code.Pos, args uint) Value { return Value{t: FunctionType, d: FunctionData{pos: pos, args: args}} } func NewNativeFunction(f NativeFunc, args uint) Value { return Value{t: FunctionType, d: FunctionData{native: f, args: args}} } func NewObject(m mem.Mem, t mem.Ptr) (Value, error) { ptr, err := m.Allocate(mem.CellKindObject) if err != nil { return Value{}, err } if err = m.Set(ptr, ObjectCell{make(map[string]Value)}); err != nil { return Value{}, err } return Value{t: ObjectType, d: ObjectData{t: t, obj: ptr}}, nil } func NewType(m mem.Mem, name string) (Value, error) { ptr, err := m.Allocate(mem.CellKindType) if err != nil { return Value{}, err } t := Type{Kind: ObjectType, Name: name, Methods: make(map[string]FunctionData), Statics: make(map[string]Value)} if err = m.Set(ptr, TypeCell(t)); err != nil { return Value{}, err } return Value{t: TypeRefType, d: TypeRefData{typeRef: ptr}}, nil } func (v Value) Type() TypeKind { return v.t } func (v Value) TypePtr() mem.Ptr { switch v.t { case IntType: return CORE_TYPE_INT case FloatType: return CORE_TYPE_FLOAT case StringType: return CORE_TYPE_STRING case BoolType: return CORE_TYPE_BOOL case ArrayType: return CORE_TYPE_ARRAY case NullType: return CORE_TYPE_NULL case FunctionType: return CORE_TYPE_FUNCTION case TypeRefType: return CORE_TYPE_TYPE_REF case ObjectType: return v.d.(ObjectData).t default: return mem.NullPtr } } func (v Value) WithType(t TypeKind) Value { return Value{t: t, d: v.d, outlet: v.outlet} } func (v Value) Data() Data { return v.d } func (v Value) WithData(d Data) Value { return Value{t: v.t, d: d, outlet: v.outlet} } func (v Value) Outlet() mem.Ptr { return v.outlet } func (v Value) WithOutlet(outlet mem.Ptr) Value { return Value{t: v.t, d: v.d, outlet: outlet} } func (v Value) IsEmpty() bool { return v == Value{} } func (v Value) Clone(m mem.Mem) Value { if v.t == StringType { str := v.d.(StringData) m.Retain(str.data) } if v.t == ArrayType { arr := v.d.(ArrayData) m.Retain(arr.data) } if v.t == FunctionType { fn := v.d.(FunctionData) m.Retain(fn.env) } // If value has an outlet don't copy it into the clone, // otherwise when the clone is dropped it will also drop the outlet. // I don't know if this fixes the entire problem, but it seems to work. v.outlet = mem.NullPtr return v } func (v Value) Drop(m mem.Mem) { // If value has an outlet, don't drop it and instead move it to the outlet. if !v.outlet.IsNull() { m.Set(v.outlet, OutletCell(v)) return } if v.t == StringType { str := v.d.(StringData) m.Release(str.data) } if v.t == ArrayType { arr := v.d.(ArrayData) m.Release(arr.data) } if v.t == FunctionType { f := v.d.(FunctionData) m.Release(f.env) } }