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 FromData(d Data) Value { return Value{t: d.DataType(), d: d} } func (v Value) Type() TypeKind { return v.t } func (v Value) TypePtr(corePtrs *CorePtrs) mem.Ptr { switch v.t { case IntType: return corePtrs.CoreTypeInt case FloatType: return corePtrs.CoreTypeFloat case StringType: return corePtrs.CoreTypeFloat case BoolType: return corePtrs.CoreTypeBool case ArrayType: return corePtrs.CoreTypeArray case NullType: return corePtrs.CoreTypeNull case FunctionType: return corePtrs.CoreTypeFunction case TypeRefType: return corePtrs.CoreTypeTypeRef 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, error) { if v.t == StringType { str := v.d.(StringData) if err := m.Retain(str.data); err != nil { return Value{}, err } } if v.t == ArrayType { arr := v.d.(ArrayData) if err := m.Retain(arr.data); err != nil { return Value{}, err } } if v.t == FunctionType { fn := v.d.(FunctionData) if !fn.env.IsNull() { if err := m.Retain(fn.env); err != nil { return Value{}, err } } } // 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, nil } func (v Value) Drop(m mem.Mem) error { // If value has an outlet, don't drop it and instead move it to the outlet. if !v.outlet.IsNull() { outlet := v.outlet v.outlet = mem.NullPtr // Reset outlet to null return m.Set(outlet, OutletCell(v)) } if v.t == StringType { str := v.d.(StringData) return m.Release(str.data) } if v.t == ArrayType { arr := v.d.(ArrayData) return m.Release(arr.data) } if v.t == FunctionType { fn := v.d.(FunctionData) if !fn.env.IsNull() { return m.Release(fn.env) } } return nil }