package core import ( "fmt" "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/executor" "jinx/pkg/lang/vm/value" ) var Natives = []any{ n(":core:setup_type", 1, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { // Add the very important "$add_method" method to the Type type. // Without it no other methods can be created. typeRef, err := ensureType[value.TypeRefData](args[0], value.TypeRefType) if err != nil { return value.Value{}, err } addMethodGlobal, ok, err := exe.GetGlobal(":core:Type:$add_method#native") if err != nil { return value.Value{}, err } if !ok { panic("missing Type:$add_method implementation") } addMethodFn, err := ensureType[value.FunctionData](addMethodGlobal, value.FunctionType) if err != nil { return value.Value{}, err } typeRef.AddMethod( exe.Mem(), "$add_method", value.NewNativeFunction(addMethodFn.Native(), 2).Data().(value.FunctionData), ) return value.Value{}, nil }), n(":core:Type:$add_method", 2, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { ref, err := ensureTypeThis[value.TypeRefData](exe, value.TypeRefType) if err != nil { return value.Value{}, err } nameData, err := ensureType[value.StringData](args[0], value.StringType) if err != nil { return value.Value{}, err } name, err := nameData.RawString(exe.Mem()) if err != nil { return value.Value{}, err } fn, err := ensureType[value.FunctionData](args[1], value.FunctionType) if err != nil { return value.Value{}, err } return value.Value{}, ref.AddMethod(exe.Mem(), name, fn) }), n(":core:Int:$init", 0, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { return value.NewInt(0), nil }), n(":core:Float:$init", 0, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { return value.NewFloat(0.0), nil }), n(":core:String:$init", 0, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { return value.NewString(exe.Mem(), "") }), n(":core:Bool:$init", 0, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { return value.NewBool(false), nil }), n(":core:Array:$init", 0, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { return value.NewArray(exe.Mem(), args) }), n(":core:Function:$init", 0, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { return value.NewFunction(code.NewPos(0, 0), 0), nil }), n(":core:Type:$init", 0, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { return value.NewType(exe.Mem(), "") }), n(":core:Array:push", 2, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { array, err := ensureType[value.ArrayData](args[0], value.ArrayType) if err != nil { return value.Value{}, err } element := args[1] return value.Value{}, array.Push(exe.Mem(), element) }), n(":core:Array:pop", 1, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { array, err := ensureType[value.ArrayData](args[0], value.ArrayType) if err != nil { return value.Value{}, err } return array.Pop(exe.Mem()) }), n(":core:Array:length", 1, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { array, err := ensureType[value.ArrayData](args[0], value.ArrayType) if err != nil { return value.Value{}, err } length, err := array.Len(exe.Mem()) if err != nil { return value.Value{}, err } return value.NewInt(int64(length)), nil }), n(":core:say", 1, func(exe executor.Exectutor, args []value.Value) (value.Value, error) { message := args[0] s, err := message.Data().String(exe.Mem()) if err != nil { return value.Value{}, err } fmt.Println(s) return value.Value{}, nil }), } type native struct { name string argCount int fn executor.NativeFunc } func n(name string, argCount int, fn executor.NativeFunc) native { return native{name, argCount, fn} } func (n native) Name() string { return n.name } func (n native) ArgCount() int { return n.argCount } func (n native) Fn() executor.NativeFunc { return n.fn } func ensureTypeThis[D value.Data](exe executor.Exectutor, t value.TypeKind) (D, error) { this, err := exe.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), fmt.Errorf("expected type %s, got %s", t, val.Type()) } return val.Data().(D), nil }