package vm import ( "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/value" ) func (vm *VM) createCoreNullType() value.Type { return value.Type{ Kind: value.NullType, } } func (vm *VM) createCoreIntType() value.Type { return value.Type{ Kind: value.IntType, } } func (vm *VM) createCoreFloatType() value.Type { return value.Type{ Kind: value.FloatType, } } func (vm *VM) createCoreStringType() value.Type { return value.Type{ Kind: value.StringType, } } func (vm *VM) createCoreBoolType() value.Type { return value.Type{ Kind: value.BoolType, } } func (vm *VM) createCoreArrayType() value.Type { return value.Type{ Kind: value.ArrayType, Methods: map[string]value.FunctionData{ "length": makeCoreFn(vm.coreArrayLength, 0), }, } } func (vm *VM) createCoreFunctionType() value.Type { return value.Type{ Kind: value.FunctionType, } } func (vm *VM) createCoreTypeRefType() value.Type { return value.Type{ Kind: value.TypeRefType, Methods: map[string]value.FunctionData{ "$add_method": makeCoreFn(vm.coreTypeRefIntrAddMethod, 2), }, } } func (vm *VM) coreArrayLength(args []value.Value) (value.Value, error) { a, err := ensureTypeThis[value.ArrayData](vm, value.ArrayType) if err != nil { return value.Value{}, err } len, err := a.Len(vm.memory) if err != nil { return value.Value{}, err } res := value.NewInt(int64(len)) return res, nil } func (vm *VM) coreTypeRefIntrAddMethod(args []value.Value) (value.Value, error) { ref, err := ensureTypeThis[value.TypeRefData](vm, value.TypeRefType) if err != nil { return value.Value{}, err } fn, err := ensureType[value.FunctionData](args[0], value.FunctionType) if err != nil { return value.Value{}, err } nameData, err := ensureType[value.StringData](args[1], value.StringType) if err != nil { return value.Value{}, err } name, err := nameData.RawString(vm.memory) if err != nil { return value.Value{}, err } return value.Value{}, ref.AddMethod(vm.memory, name, fn) } func ensureTypeThis[D value.Data](vm *VM, t value.TypeKind) (D, error) { this, err := vm.getThis() if err != nil { return *new(D), err } return ensureType[D](this, t) } func ensureType[D value.Data](val value.Value, t value.TypeKind) (D, error) { if val.Type() != t { return *new(D), ErrInvalidOperandType{ Op: code.OpNop, // TODO: Add error not dependent on op. X: val.Type(), } } return val.Data().(D), nil } func makeCoreFn(f value.NativeFunc, argCount uint) value.FunctionData { return value.NewNativeFunction(f, argCount).Data().(value.FunctionData) } func (vm *VM) getThis() (value.Value, error) { err := vm.execGetEnv(0) if err != nil { return value.Value{}, err } // Take it back! this, err := vm.popAndDrop() if err != nil { return value.Value{}, err } return this, nil }