about summary refs log tree commit diff
path: root/pkg/lang/modules/core/natives.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang/modules/core/natives.go')
-rw-r--r--pkg/lang/modules/core/natives.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/pkg/lang/modules/core/natives.go b/pkg/lang/modules/core/natives.go
new file mode 100644
index 0000000..3035b80
--- /dev/null
+++ b/pkg/lang/modules/core/natives.go
@@ -0,0 +1,166 @@
+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
+		}
+
+		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(exe.Mem())
+		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
+}