batteries

package
v0.2.57 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: BSD-3-Clause Imports: 101 Imported by: 0

Documentation

Overview

builtins_error_handling.go

builtins.go

builtins.go

builtins_trees.go

Index

Constants

View Source
const MODE_PSQL = 2 // Uses $1, $2, etc. placeholders
View Source
const MODE_SQLITE = 1 // Uses ? placeholders

SQL mode constants for different database parameter styles

View Source
const TYPE_CODE int = 2
View Source
const TYPE_SUBNODE int = 1

Variables

View Source
var Builtins_bcrypt = map[string]*env.Builtin{

	"bcrypt-hash": {
		Argsn: 1,
		Doc:   "Generates a bcrypt hash from a password string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __bcrypt_hash(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"bcrypt-check": {
		Argsn: 2,
		Doc:   "Compares a bcrypt hash with a plain text password.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __bcrypt_check(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"generate-token": {
		Argsn: 1,
		Doc:   "Generates a cryptographically secure random token of the specified length in bytes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __generate_token(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},
}
View Source
var Builtins_bson = map[string]*env.Builtin{

	"from-bson": {
		Argsn: 1,
		Doc:   "Decodes BSON data into Rye values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var val map[string]any

			err := bson.Unmarshal(arg0.(env.Bytes).Value, &val)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "from-bson")
			}

			return BsonToValue_Map(ps, val["val"], val["typ"].(string), val["met"], true)

		},
	},

	"to-bson": {
		Argsn: 1,
		Doc:   "Encodes a Rye value into BSON format.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			value := ValueToBSON(arg0, true)
			encoded, err := bson.Marshal(value)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "to-bson")
			}
			return *env.NewBytes(encoded)
		},
	},
}
View Source
var Builtins_chitosocket = map[string]*env.Builtin{

	"chitosocket": {
		Argsn: 1,
		Doc:   "Creates a new ChitoSocket WebSocket server with the specified number of CPU cores.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cores := arg0.(type) {
			case env.Integer:
				socket, err := chitosocket.StartUp(int(cores.Value))
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "chitosocket")
				}
				return *env.NewNative(ps.Idx, socket, "Chitosocket-server")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "chitosocket")
			}
		},
	},

	"Chitosocket-server//close": {
		Argsn: 1,
		Doc:   "Closes the ChitoSocket server and releases resources.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				sock := server.Value.(*chitosocket.Socket)
				err := sock.Close()
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "Chitosocket-server//close")
				}
				return *env.NewInteger(1)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//close")
			}
		},
	},

	"Chitosocket-server//on": {
		Argsn: 3,
		Doc:   "Registers an event handler for the specified event name. Handler receives subscriber and data as arguments.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch eventName := arg1.(type) {
				case env.String:
					switch handler := arg2.(type) {
					case env.Function:
						sock := server.Value.(*chitosocket.Socket)
						sock.On[eventName.Value] = func(sub *chitosocket.Subscriber, data []byte) {

							ps.FailureFlag = false
							ps.ErrorFlag = false
							ps.ReturnFlag = false

							subNative := *env.NewNative(ps.Idx, sub, "Chitosocket-subscriber")
							dataStr := *env.NewString(string(data))

							evaldo.CallFunctionArgs2(handler, ps, subNative, dataStr, nil)
						}
						return arg0
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType}, "Chitosocket-server//on")
					}
				case env.Word:
					switch handler := arg2.(type) {
					case env.Function:
						sock := server.Value.(*chitosocket.Socket)
						eventNameStr := ps.Idx.GetWord(eventName.Index)
						sock.On[eventNameStr] = func(sub *chitosocket.Subscriber, data []byte) {
							ps.FailureFlag = false
							ps.ErrorFlag = false
							ps.ReturnFlag = false

							subNative := *env.NewNative(ps.Idx, sub, "Chitosocket-subscriber")
							dataStr := *env.NewString(string(data))

							evaldo.CallFunctionArgs2(handler, ps, subNative, dataStr, nil)
						}
						return arg0
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType}, "Chitosocket-server//on")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType, env.WordType}, "Chitosocket-server//on")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//on")
			}
		},
	},

	"Chitosocket-server//upgrade-connection": {
		Argsn: 3,
		Doc:   "Upgrades an HTTP connection to WebSocket. Returns a block with connection, response writer, and subscriber.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch req := arg1.(type) {
				case env.Native:
					switch w := arg2.(type) {
					case env.Native:
						sock := server.Value.(*chitosocket.Socket)

						httpReq, ok1 := req.Value.(*http.Request)
						httpWriter, ok2 := w.Value.(http.ResponseWriter)

						if !ok1 || !ok2 {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "Invalid HTTP request or response writer types", "Chitosocket-server//upgrade-connection")
						}

						conn, rw, sub, err := sock.UpgradeConnection(httpReq, httpWriter)
						if err != nil {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, err.Error(), "Chitosocket-server//upgrade-connection")
						}

						result := make([]env.Object, 3)
						result[0] = *env.NewNative(ps.Idx, conn, "Chitosocket-connection")
						result[1] = *env.NewNative(ps.Idx, rw, "Chitosocket-response-writer")
						result[2] = *env.NewNative(ps.Idx, sub, "Chitosocket-subscriber")

						return *env.NewBlock(*env.NewTSeries(result))
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.NativeType}, "Chitosocket-server//upgrade-connection")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Chitosocket-server//upgrade-connection")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//upgrade-connection")
			}
		},
	},

	"Chitosocket-server//emit-direct": {
		Argsn: 4,
		Doc:   "Emits an event directly to a specific subscriber with the given data.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch sub := arg1.(type) {
				case env.Native:
					switch eventName := arg2.(type) {
					case env.String:
						sock := server.Value.(*chitosocket.Socket)
						subscriber := sub.Value.(*chitosocket.Subscriber)

						var dataBytes []byte
						switch data := arg3.(type) {
						case env.String:
							dataBytes = []byte(data.Value)
						case env.Dict:
							jsonData, err := json.Marshal(data.Data)
							if err != nil {
								ps.FailureFlag = true
								return evaldo.MakeBuiltinError(ps, err.Error(), "Chitosocket-server//emit-direct")
							}
							dataBytes = jsonData
						default:
							dataBytes = []byte(arg3.Inspect(*ps.Idx))
						}

						sock.EmitDirect(subscriber, eventName.Value, dataBytes)
						return *env.NewInteger(1)
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "Chitosocket-server//emit-direct")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Chitosocket-server//emit-direct")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//emit-direct")
			}
		},
	},

	"Chitosocket-server//emit": {
		Argsn: 4,
		Doc:   "Emits an event to all subscribers in a specific room (excluding none).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch eventName := arg1.(type) {
				case env.String:
					switch room := arg3.(type) {
					case env.String:
						sock := server.Value.(*chitosocket.Socket)

						var dataBytes []byte
						switch data := arg2.(type) {
						case env.String:
							dataBytes = []byte(data.Value)
						case env.Dict:
							jsonData, err := json.Marshal(data.Data)
							if err != nil {
								ps.FailureFlag = true
								return evaldo.MakeBuiltinError(ps, err.Error(), "Chitosocket-server//emit")
							}
							dataBytes = jsonData
						default:
							dataBytes = []byte(arg2.Inspect(*ps.Idx))
						}

						sock.Emit(eventName.Value, nil, dataBytes, room.Value)
						return *env.NewInteger(1)
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 4, []env.Type{env.StringType}, "Chitosocket-server//emit")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Chitosocket-server//emit")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//emit")
			}
		},
	},

	"Chitosocket-server//broadcast": {
		Argsn: 3,
		Doc:   "Broadcasts an event to all connected subscribers.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch eventName := arg1.(type) {
				case env.String:
					sock := server.Value.(*chitosocket.Socket)

					var dataBytes []byte
					switch data := arg2.(type) {
					case env.String:
						dataBytes = []byte(data.Value)
					case env.Dict:
						jsonData, err := json.Marshal(data.Data)
						if err != nil {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, err.Error(), "Chitosocket-server//broadcast")
						}
						dataBytes = jsonData
					default:
						dataBytes = []byte(arg2.Inspect(*ps.Idx))
					}

					sock.Broadcast(eventName.Value, dataBytes)
					return *env.NewInteger(1)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Chitosocket-server//broadcast")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//broadcast")
			}
		},
	},

	"Chitosocket-server//add-to-room": {
		Argsn: 3,
		Doc:   "Adds a subscriber to a room.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch sub := arg1.(type) {
				case env.Native:
					switch room := arg2.(type) {
					case env.String:
						sock := server.Value.(*chitosocket.Socket)
						subscriber := sub.Value.(*chitosocket.Subscriber)
						sock.AddToRoom(subscriber, room.Value)
						return *env.NewInteger(1)
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "Chitosocket-server//add-to-room")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Chitosocket-server//add-to-room")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//add-to-room")
			}
		},
	},

	"Chitosocket-server//remove-from-room": {
		Argsn: 3,
		Doc:   "Removes a subscriber from a room.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch sub := arg1.(type) {
				case env.Native:
					switch room := arg2.(type) {
					case env.String:
						sock := server.Value.(*chitosocket.Socket)
						subscriber := sub.Value.(*chitosocket.Subscriber)
						sock.RemoveFromRoom(subscriber, room.Value)
						return *env.NewInteger(1)
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "Chitosocket-server//remove-from-room")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Chitosocket-server//remove-from-room")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//remove-from-room")
			}
		},
	},

	"Chitosocket-server//room-count?": {
		Argsn: 2,
		Doc:   "Returns the number of subscribers in a room.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch room := arg1.(type) {
				case env.String:
					sock := server.Value.(*chitosocket.Socket)
					count := sock.GetRoomCount(room.Value)
					return *env.NewInteger(int64(count))
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Chitosocket-server//room-count?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//room-count?")
			}
		},
	},

	"Chitosocket-subscriber//id?": {
		Argsn: 1,
		Doc:   "Returns the unique ID of the subscriber.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch sub := arg0.(type) {
			case env.Native:
				subscriber := sub.Value.(*chitosocket.Subscriber)
				return *env.NewString(subscriber.ID)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-subscriber//id?")
			}
		},
	},

	"Chitosocket-server//handler?": {
		Argsn: 2,
		Doc:   "Returns the handler function for a specific event, or void if not set.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch eventName := arg1.(type) {
				case env.String:
					sock := server.Value.(*chitosocket.Socket)
					if handler, ok := sock.On[eventName.Value]; ok {
						return *env.NewNative(ps.Idx, handler, "Chitosocket-handler")
					}
					return env.Void{}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Chitosocket-server//handler?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//handler?")
			}
		},
	},

	"Chitosocket-handler//call": {
		Argsn: 3,
		Doc:   "Calls a handler function with the given subscriber and data.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch handler := arg0.(type) {
			case env.Native:
				switch sub := arg1.(type) {
				case env.Native:
					handlerFn := handler.Value.(chitosocket.HandlerFunc)
					subscriber := sub.Value.(*chitosocket.Subscriber)

					var dataBytes []byte
					switch data := arg2.(type) {
					case env.String:
						dataBytes = []byte(data.Value)
					case env.Void:
						dataBytes = nil
					default:
						dataBytes = []byte(arg2.Inspect(*ps.Idx))
					}

					handlerFn(subscriber, dataBytes)
					return *env.NewInteger(1)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Chitosocket-handler//call")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-handler//call")
			}
		},
	},

	"Chitosocket-server//remove": {
		Argsn: 2,
		Doc:   "Removes a subscriber from the server.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch sub := arg1.(type) {
				case env.Native:
					sock := server.Value.(*chitosocket.Socket)
					subscriber := sub.Value.(*chitosocket.Subscriber)
					err := sock.Remove(subscriber)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "Chitosocket-server//remove")
					}
					return *env.NewInteger(1)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Chitosocket-server//remove")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Chitosocket-server//remove")
			}
		},
	},
}

Builtins_chitosocket provides WebSocket server functionality with room support

View Source
var Builtins_cli = map[string]*env.Builtin{

	"parse-args": {
		Argsn: 2,
		Doc:   "Parses command line arguments according to a specification block, returning a dictionary with the parsed values.",
		Fn: func(es *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return BuiParseArgs(es, arg0, arg1)
		},
	},

	"parse-args\\ctx": {
		Argsn: 2,
		Doc:   "Parses command line arguments according to a specification block, returning a context for easy field access.",
		Fn: func(es *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			result := BuiParseArgs(es, arg0, arg1)
			if es.FailureFlag {
				return result
			}
			switch dict := result.(type) {
			case env.Dict:

				ctx := env.NewEnv(nil)
				for k, v := range dict.Data {
					idx := es.Idx.IndexWord(k)
					if obj, ok := v.(env.Object); ok {
						ctx.Set(idx, obj)
					} else {
						ctx.Set(idx, env.ToRyeValue(v))
					}
				}
				return ctx
			default:
				return result
			}
		},
	},

	"generate-help": {
		Argsn: 1,
		Doc:   "Generates help text from a CLI specification block.",
		Fn: func(es *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			spec, ok := arg0.(env.Block)
			if !ok {
				es.FailureFlag = true
				return evaldo.MakeArgError(es, 1, []env.Type{env.BlockType}, "generate-help")
			}

			cliSpec, err := CLI_ParseSpec(es, spec)
			if err != nil {
				es.FailureFlag = true
				return env.NewError2(400, "spec error: "+err.Error())
			}

			helpText := generateHelpText(es, cliSpec, nil)
			return *env.NewString(helpText)
		},
	},

	"generate-help\\command": {
		Argsn: 2,
		Doc:   "Generates help text for a specific subcommand.",
		Fn: func(es *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			spec, ok := arg0.(env.Block)
			if !ok {
				es.FailureFlag = true
				return evaldo.MakeArgError(es, 1, []env.Type{env.BlockType}, "generate-help\\command")
			}

			cmdPath := make([]string, 0)
			switch cmd := arg1.(type) {
			case env.String:
				if cmd.Value != "" {
					cmdPath = strings.Split(cmd.Value, " ")
				}
			case env.Block:
				ser := cmd.Series
				ser.Reset()
				for ser.Pos() < ser.Len() {
					obj := ser.Pop()
					if s, ok := obj.(env.String); ok {
						cmdPath = append(cmdPath, s.Value)
					} else if w, ok := obj.(env.Word); ok {
						cmdPath = append(cmdPath, es.Idx.GetWord(w.Index))
					}
				}
			default:
				es.FailureFlag = true
				return evaldo.MakeArgError(es, 2, []env.Type{env.StringType, env.BlockType}, "generate-help\\command")
			}

			cliSpec, err := CLI_ParseSpec(es, spec)
			if err != nil {
				es.FailureFlag = true
				return env.NewError2(400, "spec error: "+err.Error())
			}

			helpText := generateHelpText(es, cliSpec, cmdPath)
			return *env.NewString(helpText)
		},
	},

	"format-parse-errors": {
		Argsn: 1,
		Doc:   "Formats parse errors into human-readable messages.",
		Fn: func(es *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch errObj := arg0.(type) {
			case env.Dict:
				errors := make(map[string]env.Object)
				for k, v := range errObj.Data {
					if obj, ok := v.(env.Object); ok {
						errors[k] = obj
					}
				}
				return *env.NewString(formatParseErrors(errors))
			case *env.Error:

				if errObj.Values != nil {
					return *env.NewString(formatParseErrors(errObj.Values))
				}
				return *env.NewString(errObj.Message)
			default:
				es.FailureFlag = true
				return evaldo.MakeArgError(es, 1, []env.Type{env.DictType}, "format-parse-errors")
			}
		},
	},
}
View Source
var Builtins_cmd = map[string]*env.Builtin{

	"cmd": {
		Argsn: 1,
		Doc:   "Create a command.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var args []string
			var pipe []*exec.Cmd
			switch input := arg0.(type) {
			case env.List:
				newArgs, err := listToCmdArgs(ps, input.Data...)
				if err != nil {
					return err
				}
				args = append(args, newArgs...)
			case env.Block:
				for _, c := range input.Series.S {
					switch it := c.(type) {
					case env.Word:
						args = append(args, it.Print(*ps.Idx))
					case env.Pipeword:
						word := it.ToWord().Print(*ps.Idx)
						if len(args) == 0 {
							return evaldo.MakeBuiltinError(ps, "missing command before pipe", "cmd")
						}
						pipecmd := exec.Command(args[0], args[1:]...)
						pipecmd.Stdin = os.Stdin
						pipecmd.Stderr = os.Stderr
						pipe = append(pipe, pipecmd)
						args = []string{word}
					case env.Getword:
						evaldo.EvalGetword(ps, it, nil, false)
						if ps.ErrorFlag {
							return ps.Res
						}
						newArgs, err := listToCmdArgs(ps, ps.Res)
						if err != nil {
							return err
						}
						args = append(args, newArgs...)
					case env.Block:
						ser := ps.Ser
						ps.Ser = it.Series
						ps.BlockFile = it.FileName
						ps.BlockLine = it.Line
						evaldo.Eval(ps)
						evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "cmd")
						if ps.ErrorFlag {
							ps.Ser = ser
							return ps.Res
						}
						ps.Ser = ser
						newArgs, err := listToCmdArgs(ps, ps.Res)
						if err != nil {

							return err
						}
						args = append(args, newArgs...)
					default:
						newArgs, err := listToCmdArgs(ps, it)
						if err != nil {

							return err
						}
						args = append(args, newArgs...)
					}
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType}, "cmd")
			}

			if len(args) == 0 {
				return evaldo.MakeBuiltinError(ps, "missing command", "cmd")
			}
			cmd := exec.Command(args[0], args[1:]...)
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			return *env.NewNative(ps.Idx, &command{cmd: cmd, pipe: pipe}, "command")
		},
	},

	"command//Dir!": {
		Argsn: 2,
		Doc:   "Change the working directory of a command.",
		Fn: commandFn("Dir!", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg1.(type) {
			case env.Uri:
				c.cmd.Dir = s.Path
				return arg0
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "Dir!")
			}
		}),
	},

	"command//Stdin!": {
		Argsn: 2,
		Doc:   "Change the standard input of a command.",
		Fn: commandFn("Stdin!", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			out, ret := commandInputFd(ps, c, arg1)
			if ret != nil {
				return ret
			}
			c.cmd.Stdin = out
			return arg0
		}),
	},

	"command//Stdout!": {
		Argsn: 2,
		Doc:   "Change the standard output of a command.",
		Fn: commandFn("Stdout!", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			out, ret := commandOutputFd(ps, c, arg1)
			if ret != nil {
				return ret
			}
			c.cmd.Stdout = out
			return arg0
		}),
	},

	"command//Stderr!": {
		Argsn: 2,
		Doc:   "Change the standard error of a command.",
		Fn: commandFn("Stderr!", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			out, ret := commandOutputFd(ps, c, arg1)
			if ret != nil {
				return ret
			}
			c.cmd.Stderr = out
			return arg0
		}),
	},

	"command//Pipe": {
		Argsn: 2,
		Doc:   "Pipe the output of the first command to the input of the second command.",
		Fn: commandFn("Pipe", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch it := arg1.(type) {
			case env.Native:
				if c2, ok := it.Value.(*command); ok {
					return *env.NewNative(ps.Idx, pipeCommands(c, c2), "command")
				} else {
					return evaldo.MakeBuiltinError(ps, "arg1 must be of kind command", "Pipe!")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Pipe")
			}
		}),
	},

	"command//Run": {
		Argsn: 1,
		Doc:   "Start a command and wait for it to finish.",
		Fn: commandFn("Run", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			defer c.Close()
			err := c.StartPipe()
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "Run")
			}
			err = c.cmd.Run()
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "Run")
			}
			return *env.NewBoolean(true)
		}),
	},

	"command//Status": {
		Argsn: 1,
		Doc:   "Start a command, wait for it to finish, and return its exit status.",
		Fn: commandFn("Status", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			err := c.StartPipe()
			if err != nil {
				c.Close()
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "Status")
			}
			err = c.cmd.Run()
			c.Close()
			status := c.cmd.ProcessState.ExitCode()
			if err != nil && status == -1 {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "Status")
			}
			if len(c.pipe) > 0 {
				var statusList []any
				for _, cmd := range c.pipe {
					statusList = append(statusList, *env.NewInteger(int64(cmd.ProcessState.ExitCode())))
				}
				statusList = append(statusList, *env.NewInteger(int64(status)))
				return *env.NewList(statusList)
			}
			return *env.NewInteger(int64(status))
		}),
	},

	"command//Output": {
		Argsn: 1,
		Doc:   "Start a command, wait for it to finish, and return its standard output",
		Fn: commandFn("Output", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			defer c.Close()
			err := c.StartPipe()
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "Output")
			}
			c.cmd.Stdout = nil
			out, err := c.cmd.Output()
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "Output")
			}
			return *env.NewString(string(out))
		}),
	},

	"command//CombinedOutput": {
		Argsn: 1,
		Doc:   "Start a command, wait for it to finish, and return its combined standard output and error",
		Fn: commandFn("CombinedOutput", func(ps *env.ProgramState, c *command, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			defer c.Close()
			err := c.StartPipe()
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "CombinedOutput")
			}
			c.cmd.Stdout = nil
			c.cmd.Stderr = nil
			out, err := c.cmd.CombinedOutput()
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "CombinedOutput")
			}
			return *env.NewString(string(out))
		}),
	},
}
View Source
var Builtins_complex = map[string]*env.Builtin{

	"complex": {
		Argsn: 2,
		Doc:   "Creates a complex number from real and imaginary parts.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var real, imag float64

			switch r := arg0.(type) {
			case env.Integer:
				real = float64(r.Value)
			case env.Decimal:
				real = r.Value
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "complex")
			}

			switch i := arg1.(type) {
			case env.Integer:
				imag = float64(i.Value)
			case env.Decimal:
				imag = i.Value
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "complex")
			}

			return *env.NewComplexFromParts(real, imag)
		},
	},

	"complex?": {
		Argsn: 1,
		Doc:   "Checks if a value is a complex number.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			_, ok := arg0.(env.Complex)
			return *env.NewBoolean(ok)
		},
	},

	"real": {
		Argsn: 1,
		Doc:   "Returns the real part of a complex number.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch c := arg0.(type) {
			case env.Complex:
				return *env.NewDecimal(real(c.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ComplexType}, "real")
			}
		},
	},

	"imag": {
		Argsn: 1,
		Doc:   "Returns the imaginary part of a complex number.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch c := arg0.(type) {
			case env.Complex:
				return *env.NewDecimal(imag(c.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ComplexType}, "imag")
			}
		},
	},

	"complex-conj": {
		Argsn: 1,
		Doc:   "Returns the complex conjugate of a complex number.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch z := arg0.(type) {
			case env.Complex:
				return *env.NewComplex(cmplx.Conj(z.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ComplexType}, "complex-conj")
			}
		},
	},

	"complex-phase": {
		Argsn: 1,
		Doc:   "Returns the phase (argument) of a complex number.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch z := arg0.(type) {
			case env.Complex:
				return *env.NewDecimal(cmplx.Phase(z.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ComplexType}, "complex-phase")
			}
		},
	},
}
View Source
var Builtins_console = map[string]*env.Builtin{

	"enter-console": {
		Argsn: 1,
		Doc:   "Stops execution and gives you an interactive Rye console to test code in the current environment.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch name := arg0.(type) {
			case env.String:
				ser := ps.Ser

				fmt.Println("Welcome to console: \033[1m" + name.Value + "\033[0m")
				fmt.Println("* use \033[1mlc\033[0m to list current context")
				fmt.Println("-------------------------------------------------------------")

				console.DoRyeRepl(ps, "rye", evaldo.ShowResults, false, "")
				fmt.Println("-------------------------------------------------------------")
				ps.Ser = ser
				return ps.Res
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "enter-console")
			}
		},
	},
}
View Source
var Builtins_conversion = map[string]*env.Builtin{

	"convert": {
		Argsn: 2,
		Doc:   "Converts value from one kind to another based on a conversion specification block.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return BuiConvert(ps, arg0, arg1)
		},
	},

	"converter": {
		Argsn: 3,
		Doc:   "Registers a converter between two kinds of objects.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch obj1 := arg0.(type) {
			case env.Kind:
				switch obj2 := arg1.(type) {
				case env.Kind:
					switch spec := arg2.(type) {
					case env.Block:
						obj2.SetConverter(obj1.Kind.Index, spec)
						return obj2
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "converter")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.KindType, env.BlockType}, "converter")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.KindType}, "converter")
			}
		},
	},
}
View Source
var Builtins_crypto = map[string]*env.Builtin{

	"decode\\hex": {
		Argsn: 1,
		Doc:   "Decodes a hexadecimal string to a bytes native value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.String:
				r, err := hex.DecodeString(addr.Value)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failure to decode string.", "decode\\hex")
				}
				return *env.NewBytes(r)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "decode\\hex")
			}
		},
	},

	"encode-to\\hex": {
		Argsn: 1,
		Doc:   "Encodes a bytes native value to a hexadecimal string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.Bytes:
				return *env.NewString(hex.EncodeToString(addr.Value))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BytesType}, "bytes//to-string")
			}
		},
	},

	"Ed25519-pub-key//To-string": {
		Argsn: 1,
		Doc:   "Converts an Ed25519 public key to its hexadecimal string representation.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.Native:
				return *env.NewString(hex.EncodeToString(addr.Value.(ed25519.PublicKey)))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Ed25519-pub-key//To-string")
			}
		},
	},

	"Ed25519-priv-key//To-string": {
		Argsn: 1,
		Doc:   "Converts an Ed25519 private key to its hexadecimal string representation.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.Native:
				return *env.NewString(hex.EncodeToString(addr.Value.(ed25519.PrivateKey)))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Ed25519-priv-key//To-string")
			}
		},
	},

	"ed25519-generate-keys": {
		Argsn: 0,
		Doc:   "Generates a new Ed25519 key pair and returns them in a block with public key first, then private key.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			keys := make([]env.Object, 2)
			puk, pvk, err := ed25519.GenerateKey(nil)
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "Failed to generate keys.", "ed25519-generate-keys")
			}
			keys[0] = *env.NewNative(ps.Idx, puk, "Ed25519-pub-key")
			keys[1] = *env.NewNative(ps.Idx, pvk, "Ed25519-priv-key")
			ser := *env.NewTSeries(keys)
			return *env.NewBlock(ser)
		},
	},

	"ed25519-private-key": {
		Argsn: 1,
		Doc:   "Creates an Ed25519 private key from a hexadecimal string or bytes value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var pkey []byte
			var err error
			switch server := arg0.(type) {
			case env.Native:
				pkey = server.Value.([]byte)
			case env.String:
				pkey, err = hex.DecodeString(server.Value)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in decoding string.", "ed25519-private-key")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType, env.StringType}, "ed25519-private-key")
			}
			return *env.NewNative(ps.Idx, ed25519.PrivateKey(pkey), "Ed25519-priv-key")

		},
	},

	"ed25519-public-key": {
		Argsn: 1,
		Doc:   "Creates an Ed25519 public key from a hexadecimal string or bytes value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var pkey []byte
			var err error
			switch server := arg0.(type) {
			case env.Native:
				pkey = server.Value.([]byte)
			case env.String:
				pkey, err = hex.DecodeString(server.Value)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in decoding string.", "ed25519-public-key")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType, env.StringType}, "ed25519-public-key")
			}
			return *env.NewNative(ps.Idx, ed25519.PublicKey(pkey), "Ed25519-pub-key")

		},
	},

	"Ed25519-priv-key//Sign": {
		Argsn: 2,
		Doc:   "Signs a string message with an Ed25519 private key and returns the signature as bytes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch pvk := arg0.(type) {
			case env.Native:
				switch buff := arg1.(type) {
				case env.String:
					sigb := ed25519.Sign(pvk.Value.(ed25519.PrivateKey), []byte(buff.Value))
					return *env.NewBytes(sigb)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "Ed25519-priv-key//Sign")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Ed25519-priv-key//Sign")
			}
		},
	},

	"sha512": {
		Argsn: 1,
		Doc:   "Calculates the SHA-512 hash of a string and returns the result as a hexadecimal string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.String:
				h := sha512.New()
				h.Write([]byte(s.Value))
				bs := h.Sum(nil)
				return *env.NewString(hex.EncodeToString(bs[:]))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "sha512")
			}
		},
	},

	"age-generate-keys": {
		Argsn: 0,
		Doc:   "Generates a new age key pair (identity and recipient).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			identity, err := age.GenerateX25519Identity()
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "Failed to generate key pair.", "age-generate-keys")
			}
			keys := make([]env.Object, 2)
			keys[0] = *env.NewNative(ps.Idx, identity, "age-identity")
			keys[1] = *env.NewNative(ps.Idx, identity.Recipient(), "age-recipient")
			ser := *env.NewTSeries(keys)
			return *env.NewBlock(ser)
		},
	},

	"age-identity": {
		Argsn: 1,
		Doc:   "Creates an age identity from a string or bytes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var identity *age.X25519Identity
			var err error
			switch ident := arg0.(type) {
			case env.Bytes:
				identity, err = age.ParseX25519Identity(hex.EncodeToString(ident.Value))
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in parsing identity: "+err.Error(), "age-identity")
				}
			case env.String:
				identity, err = age.ParseX25519Identity(ident.Value)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in decoding string: "+err.Error(), "age-identity")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BytesType, env.StringType}, "age-identity")
			}
			return *env.NewNative(ps.Idx, identity, "age-identity")
		},
	},

	"age-recipient": {
		Argsn: 1,
		Doc:   "Creates an age recipient from a string or bytes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var recipient *age.X25519Recipient
			var err error
			switch rec := arg0.(type) {
			case env.Bytes:
				recipient, err = age.ParseX25519Recipient(hex.EncodeToString(rec.Value))
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in parsing recipient: "+err.Error(), "age-recipient")
				}
			case env.String:
				recipient, err = age.ParseX25519Recipient(rec.Value)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in decoding string: "+err.Error(), "age-recipient")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BytesType, env.StringType}, "age-recipient")
			}
			return *env.NewNative(ps.Idx, recipient, "age-recipient")
		},
	},

	"age-encrypt": {
		Argsn: 2,
		Doc:   "Encrypts a reader with age for the provided age recipient or string password and returns a reader.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch r := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(r.GetKind()) != "reader" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "age-encrypt")
				}
				reader := r.Value.(io.Reader)
				var recipient age.Recipient
				switch rec := arg1.(type) {
				case env.Native:
					if ps.Idx.GetWord(rec.GetKind()) != "age-recipient" {
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "age-encrypt")
					}
					recipient = rec.Value.(*age.X25519Recipient)
				case env.String:
					var err error
					recipient, err = age.NewScryptRecipient(rec.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Error in creating recipient: "+err.Error(), "age-encrypt")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType, env.StringType}, "age-encrypt")
				}
				buf := new(bytes.Buffer)
				w, err := age.Encrypt(buf, recipient)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in encrypting: "+err.Error(), "age-encrypt")
				}

				data, err := io.ReadAll(reader)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error reading from reader: "+err.Error(), "age-encrypt")
				}

				if _, err := w.Write(data); err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in writing to buffer: "+err.Error(), "age-encrypt")
				}
				w.Close()
				return *env.NewNative(ps.Idx, bytes.NewReader(buf.Bytes()), "reader")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "age-encrypt")
			}
		},
	},

	"age-decrypt": {
		Argsn: 2,
		Doc:   "Decrypts a reader with age using the provided age identity or string password and returns a reader with the decrypted content.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch r := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(r.GetKind()) != "reader" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "age-decrypt")
				}
				reader := r.Value.(io.Reader)
				var identity age.Identity
				switch ident := arg1.(type) {
				case env.Native:
					if ps.Idx.GetWord(ident.GetKind()) != "age-identity" {
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "age-decrypt")
					}
					identity = ident.Value.(*age.X25519Identity)
				case env.String:
					var err error
					identity, err = age.NewScryptIdentity(ident.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Error in creating identity: "+err.Error(), "age-decrypt")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType, env.StringType}, "age-decrypt")
				}
				decrypted, err := age.Decrypt(reader, identity)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in decrypting: "+err.Error(), "age-decrypt")
				}
				return *env.NewNative(ps.Idx, decrypted, "reader")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "age-decrypt")
			}
		},
	},

	"pkcs12-to-pem": {
		Argsn: 2,
		Doc:   "Converts a PKCS#12 (.p12) file bytes to PEM blocks using the provided password. Returns a block of pem-block native values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p12Data := arg0.(type) {
			case env.Bytes:
				switch password := arg1.(type) {
				case env.String:
					blocks, err := pkcs12.ToPEM(p12Data.Value, password.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to convert .p12 to PEM: %v", err), "pkcs12-to-pem")
					}

					objects := make([]env.Object, len(blocks))
					for i, block := range blocks {
						objects[i] = *env.NewNative(ps.Idx, block, "pem-block")
					}
					ser := *env.NewTSeries(objects)
					return *env.NewBlock(ser)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "pkcs12-to-pem")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BytesType}, "pkcs12-to-pem")
			}
		},
	},

	"pkcs12-decode": {
		Argsn: 2,
		Doc:   "Decodes a PKCS#12 (.p12) file bytes into private key and certificates using the provided password. Returns a block with [private-key, certificates, ca-certificates].",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p12Data := arg0.(type) {
			case env.Bytes:
				switch password := arg1.(type) {
				case env.String:
					key, cert, caCerts, err := sslmate.DecodeChain(p12Data.Value, password.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to decode .p12: %v", err), "pkcs12-decode")
					}

					certObjects := make([]env.Object, 0)
					if cert != nil {
						certObjects = append(certObjects, *env.NewNative(ps.Idx, cert, "x509-certificate"))
					}
					certSer := *env.NewTSeries(certObjects)
					certBlock := *env.NewBlock(certSer)

					caCertObjects := make([]env.Object, len(caCerts))
					for i, caCert := range caCerts {
						caCertObjects[i] = *env.NewNative(ps.Idx, caCert, "x509-certificate")
					}
					caCertSer := *env.NewTSeries(caCertObjects)
					caCertBlock := *env.NewBlock(caCertSer)

					objects := make([]env.Object, 3)
					if key != nil {
						objects[0] = *env.NewNative(ps.Idx, key, "private-key")
					} else {
						objects[0] = *env.NewNative(ps.Idx, nil, "private-key")
					}
					objects[1] = certBlock
					objects[2] = caCertBlock
					ser := *env.NewTSeries(objects)
					return *env.NewBlock(ser)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "pkcs12-decode")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BytesType}, "pkcs12-decode")
			}
		},
	},

	"pem-block//Block-type?": {
		Argsn: 1,
		Doc:   "Returns the type of a PEM block as a string (e.g., 'CERTIFICATE', 'RSA PRIVATE KEY').",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch certData := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(certData.GetKind()) != "pem-block" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-parse-certificate")
				}
				pb, ok := certData.Value.(*pem.Block)
				if ok {
					return *env.NewString(pb.Type)
				}
				return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to parse certificate"), "x509-parse-certificate")

			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-parse-certificate")
			}
		},
	},

	"pem-block//Headers?": {
		Argsn: 1,
		Doc:   "Returns the headers of a PEM block as a dictionary.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch certData := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(certData.GetKind()) != "pem-block" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-parse-certificate")
				}
				pb, ok := certData.Value.(*pem.Block)
				if ok {
					headers := make(map[string]interface{}, len(pb.Headers))
					for k, v := range pb.Headers {
						headers[k] = v
					}
					return *env.NewDict(headers)
				}
				return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to parse certificate"), "x509-parse-certificate")

			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-parse-certificate")
			}
		},
	},

	"x509-parse-certificate": {
		Argsn: 1,
		Doc:   "Parses a PEM block into an X.509 certificate native value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch certData := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(certData.GetKind()) != "pem-block" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-parse-certificate")
				}
				pb, ok := certData.Value.(*pem.Block)
				if ok {
					cert, err := x509.ParseCertificate(pb.Bytes)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to parse certificate: %v", err), "x509-parse-certificate")
					}
					return *env.NewNative(ps.Idx, cert, "x509-certificate")
				}
				return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to parse certificate"), "x509-parse-certificate")

			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-parse-certificate")
			}
		},
	},

	"x509-certificate//Not-after?": {
		Argsn: 1,
		Doc:   "Returns the expiration date (NotAfter) of an X.509 certificate as a time value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//is-expired")
				}
				c := cert.Value.(*x509.Certificate)
				return *env.NewTime(c.NotAfter)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//is-expired")
			}
		},
	},

	"x509-certificate//Not-before?": {
		Argsn: 1,
		Doc:   "Returns the start date (NotBefore) of an X.509 certificate as a time value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//is-expired")
				}
				c := cert.Value.(*x509.Certificate)
				return *env.NewTime(c.NotBefore)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//is-expired")
			}
		},
	},

	"x509-certificate//Is-expired": {
		Argsn: 1,
		Doc:   "Checks if an X.509 certificate has expired. Returns 1 if expired, 0 otherwise.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//is-expired")
				}
				c := cert.Value.(*x509.Certificate)
				if time.Now().After(c.NotAfter) {
					return env.Integer{1}
				}
				return env.Integer{0}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//is-expired")
			}
		},
	},

	"generate-self-signed-certificate": {
		Argsn: 2,
		Doc:   "Generates a self-signed X.509 certificate with a new RSA key pair.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch keySize := arg0.(type) {
			case env.Integer:
				if keySize.Value < 2048 {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Key size must be at least 2048 bits", "generate-self-signed-certificate")
				}

				switch subjectDict := arg1.(type) {
				case env.Dict:

					privateKey, err := rsa.GenerateKey(rand.Reader, int(keySize.Value))
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to generate RSA key: %v", err), "generate-self-signed-certificate")
					}

					serialNumber, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
					template := x509.Certificate{
						SerialNumber: serialNumber,
						Subject:      pkix.Name{},
						NotBefore:    time.Now(),
						NotAfter:     time.Now().Add(365 * 24 * time.Hour),
						KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
						ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
						IsCA:         true,
					}

					if cn, ok := subjectDict.Data["CommonName"]; ok {
						if cnStr, ok := cn.(string); ok {
							template.Subject.CommonName = cnStr
						}
					}
					if org, ok := subjectDict.Data["Organization"]; ok {
						if orgStr, ok := org.(string); ok {
							template.Subject.Organization = []string{orgStr}
						}
					}

					certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to create certificate: %v", err), "generate-self-signed-certificate")
					}

					objects := []env.Object{
						*env.NewNative(ps.Idx, &x509.Certificate{Raw: certBytes}, "x509-certificate"),
						*env.NewNative(ps.Idx, privateKey, "rsa-private-key"),
					}
					ser := *env.NewTSeries(objects)
					return *env.NewBlock(ser)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.DictType}, "generate-self-signed-certificate")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "generate-self-signed-certificate")
			}
		},
	},

	"encode-to-pem": {
		Argsn: 2,
		Doc:   "Encodes a certificate and private key as PEM-formatted data.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch certObj := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(certObj.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "encode-to-pem")
				}
				cert := certObj.Value.(*x509.Certificate)
				switch keyObj := arg1.(type) {
				case env.Native:
					if ps.Idx.GetWord(keyObj.GetKind()) != "rsa-private-key" {
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "encode-to-pem")
					}
					privateKey := keyObj.Value.(*rsa.PrivateKey)

					certPEM := &bytes.Buffer{}
					err := pem.Encode(certPEM, &pem.Block{
						Type:  "CERTIFICATE",
						Bytes: cert.Raw,
					})
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to encode certificate to PEM: %v", err), "encode-to-pem")
					}

					keyPEM := &bytes.Buffer{}
					err = pem.Encode(keyPEM, &pem.Block{
						Type:  "RSA PRIVATE KEY",
						Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
					})
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to encode private key to PEM: %v", err), "encode-to-pem")
					}

					objects := []env.Object{
						*env.NewNative(ps.Idx, certPEM.Bytes(), "Go-bytes"),
						*env.NewNative(ps.Idx, keyPEM.Bytes(), "Go-bytes"),
					}
					ser := *env.NewTSeries(objects)
					return *env.NewBlock(ser)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "encode-to-pem")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "encode-to-pem")
			}
		},
	},

	"encode-to-p12": {
		Argsn: 3,
		Doc:   "Encodes a certificate and private key into a PKCS#12 (.p12) file with password protection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch certObj := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(certObj.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "encode-to-p12")
				}
				cert := certObj.Value.(*x509.Certificate)
				switch keyObj := arg1.(type) {
				case env.Native:
					if ps.Idx.GetWord(keyObj.GetKind()) != "rsa-private-key" {
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "encode-to-p12")
					}
					privateKey := keyObj.Value.(*rsa.PrivateKey)
					switch password := arg2.(type) {
					case env.String:
						p12Bytes, err := sslmate.Encode(rand.Reader, privateKey, cert, nil, password.Value)
						if err != nil {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to encode to .p12: %v", err), "encode-to-p12")
						}
						return *env.NewNative(ps.Idx, p12Bytes, "Go-bytes")
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "encode-to-p12")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "encode-to-p12")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "encode-to-p12")
			}
		},
	},

	"x509-certificate//Subject?": {
		Argsn: 1,
		Doc:   "Returns the subject Distinguished Name (DN) of an X.509 certificate as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//Subject?")
				}
				c := cert.Value.(*x509.Certificate)
				return *env.NewString(c.Subject.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//Subject?")
			}
		},
	},

	"x509-certificate//Issuer?": {
		Argsn: 1,
		Doc:   "Returns the issuer Distinguished Name (DN) of an X.509 certificate as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//issuer?")
				}
				c := cert.Value.(*x509.Certificate)
				return *env.NewString(c.Issuer.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//issuer?")
			}
		},
	},

	"x509-certificate//Serial-number?": {
		Argsn: 1,
		Doc:   "Returns the serial number of an X.509 certificate as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//serial-number?")
				}
				c := cert.Value.(*x509.Certificate)
				return *env.NewString(c.SerialNumber.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//serial-number?")
			}
		},
	},

	"x509-certificate//Signature-algorithm?": {
		Argsn: 1,
		Doc:   "Returns the signature algorithm of an X.509 certificate as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//signature-algorithm?")
				}
				c := cert.Value.(*x509.Certificate)
				return *env.NewString(c.SignatureAlgorithm.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//signature-algorithm?")
			}
		},
	},

	"x509-certificate//Public-key-algorithm?": {
		Argsn: 1,
		Doc:   "Returns the public key algorithm of an X.509 certificate as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//public-key-algorithm?")
				}
				c := cert.Value.(*x509.Certificate)
				return *env.NewString(c.PublicKeyAlgorithm.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//public-key-algorithm?")
			}
		},
	},

	"x509-certificate//Key-usage?": {
		Argsn: 1,
		Doc:   "Returns the key usage flags of an X.509 certificate as a block of strings.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//key-usage?")
				}
				c := cert.Value.(*x509.Certificate)
				var usages []env.Object
				if c.KeyUsage&x509.KeyUsageDigitalSignature > 0 {
					usages = append(usages, *env.NewString("Digital Signature"))
				}
				if c.KeyUsage&x509.KeyUsageContentCommitment > 0 {
					usages = append(usages, *env.NewString("Content Commitment"))
				}
				if c.KeyUsage&x509.KeyUsageKeyEncipherment > 0 {
					usages = append(usages, *env.NewString("Key Encipherment"))
				}
				if c.KeyUsage&x509.KeyUsageDataEncipherment > 0 {
					usages = append(usages, *env.NewString("Data Encipherment"))
				}
				if c.KeyUsage&x509.KeyUsageKeyAgreement > 0 {
					usages = append(usages, *env.NewString("Key Agreement"))
				}
				if c.KeyUsage&x509.KeyUsageCertSign > 0 {
					usages = append(usages, *env.NewString("Cert Sign"))
				}
				if c.KeyUsage&x509.KeyUsageCRLSign > 0 {
					usages = append(usages, *env.NewString("CRL Sign"))
				}
				if c.KeyUsage&x509.KeyUsageEncipherOnly > 0 {
					usages = append(usages, *env.NewString("Encipher Only"))
				}
				if c.KeyUsage&x509.KeyUsageDecipherOnly > 0 {
					usages = append(usages, *env.NewString("Decipher Only"))
				}
				ser := *env.NewTSeries(usages)
				return *env.NewBlock(ser)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//key-usage?")
			}
		},
	},

	"x509-certificate//Extended-key-usage?": {
		Argsn: 1,
		Doc:   "Returns the extended key usage flags of an X.509 certificate as a block of strings.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//extended-key-usage?")
				}
				c := cert.Value.(*x509.Certificate)
				usages := make([]env.Object, len(c.ExtKeyUsage))
				for i, extKeyUsage := range c.ExtKeyUsage {
					var usageStr string
					switch extKeyUsage {
					case x509.ExtKeyUsageServerAuth:
						usageStr = "Server Authentication"
					case x509.ExtKeyUsageClientAuth:
						usageStr = "Client Authentication"
					case x509.ExtKeyUsageCodeSigning:
						usageStr = "Code Signing"
					case x509.ExtKeyUsageEmailProtection:
						usageStr = "Email Protection"
					case x509.ExtKeyUsageTimeStamping:
						usageStr = "Time Stamping"
					case x509.ExtKeyUsageOCSPSigning:
						usageStr = "OCSP Signing"
					default:
						usageStr = fmt.Sprintf("Unknown (%d)", int(extKeyUsage))
					}
					usages[i] = *env.NewString(usageStr)
				}
				ser := *env.NewTSeries(usages)
				return *env.NewBlock(ser)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//extended-key-usage?")
			}
		},
	},

	"x509-certificate//Dns-names?": {
		Argsn: 1,
		Doc:   "Returns the DNS names from Subject Alternative Names of an X.509 certificate as a block of strings.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//dns-names?")
				}
				c := cert.Value.(*x509.Certificate)
				names := make([]env.Object, len(c.DNSNames))
				for i, name := range c.DNSNames {
					names[i] = *env.NewString(name)
				}
				ser := *env.NewTSeries(names)
				return *env.NewBlock(ser)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//dns-names?")
			}
		},
	},

	"x509-certificate//Ip-addresses?": {
		Argsn: 1,
		Doc:   "Returns the IP addresses from Subject Alternative Names of an X.509 certificate as a block of strings.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//ip-addresses?")
				}
				c := cert.Value.(*x509.Certificate)
				addresses := make([]env.Object, len(c.IPAddresses))
				for i, addr := range c.IPAddresses {
					addresses[i] = *env.NewString(addr.String())
				}
				ser := *env.NewTSeries(addresses)
				return *env.NewBlock(ser)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//ip-addresses?")
			}
		},
	},

	"x509-certificate//Email-addresses?": {
		Argsn: 1,
		Doc:   "Returns the email addresses from Subject Alternative Names of an X.509 certificate as a block of strings.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//email-addresses?")
				}
				c := cert.Value.(*x509.Certificate)
				emails := make([]env.Object, len(c.EmailAddresses))
				for i, email := range c.EmailAddresses {
					emails[i] = *env.NewString(email)
				}
				ser := *env.NewTSeries(emails)
				return *env.NewBlock(ser)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//email-addresses?")
			}
		},
	},

	"x509-certificate//To-pem": {
		Argsn: 1,
		Doc:   "Converts an X.509 certificate to PEM-encoded string format.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//to-pem")
				}
				c := cert.Value.(*x509.Certificate)
				pemBlock := &pem.Block{Type: "CERTIFICATE", Bytes: c.Raw}
				pemBytes := pem.EncodeToMemory(pemBlock)
				return *env.NewString(string(pemBytes))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//to-pem")
			}
		},
	},

	"private-key//Type?": {
		Argsn: 1,
		Doc:   "Returns the type of a private key as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch key := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(key.GetKind()) != "private-key" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "private-key//type?")
				}
				return *env.NewString(fmt.Sprintf("%T", key.Value))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "private-key//type?")
			}
		},
	},

	"x509-certificate//To-dict": {
		Argsn: 1,
		Doc:   "Converts an X.509 certificate to a dictionary containing all certificate information for easy display and manipulation.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cert := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(cert.GetKind()) != "x509-certificate" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//to-dict")
				}
				c := cert.Value.(*x509.Certificate)

				certDict := make(map[string]interface{})

				certDict["Subject"] = c.Subject.String()
				certDict["Issuer"] = c.Issuer.String()
				certDict["SerialNumber"] = c.SerialNumber.String()
				certDict["NotBefore"] = c.NotBefore.Format("2006-01-02 15:04:05 MST")
				certDict["NotAfter"] = c.NotAfter.Format("2006-01-02 15:04:05 MST")
				certDict["SignatureAlgorithm"] = c.SignatureAlgorithm.String()
				certDict["PublicKeyAlgorithm"] = c.PublicKeyAlgorithm.String()
				certDict["Version"] = int64(c.Version)
				certDict["IsCA"] = c.IsCA

				// Key Usage
				var keyUsages []interface{}
				if c.KeyUsage&x509.KeyUsageDigitalSignature > 0 {
					keyUsages = append(keyUsages, "Digital Signature")
				}
				if c.KeyUsage&x509.KeyUsageContentCommitment > 0 {
					keyUsages = append(keyUsages, "Content Commitment")
				}
				if c.KeyUsage&x509.KeyUsageKeyEncipherment > 0 {
					keyUsages = append(keyUsages, "Key Encipherment")
				}
				if c.KeyUsage&x509.KeyUsageDataEncipherment > 0 {
					keyUsages = append(keyUsages, "Data Encipherment")
				}
				if c.KeyUsage&x509.KeyUsageKeyAgreement > 0 {
					keyUsages = append(keyUsages, "Key Agreement")
				}
				if c.KeyUsage&x509.KeyUsageCertSign > 0 {
					keyUsages = append(keyUsages, "Cert Sign")
				}
				if c.KeyUsage&x509.KeyUsageCRLSign > 0 {
					keyUsages = append(keyUsages, "CRL Sign")
				}
				if c.KeyUsage&x509.KeyUsageEncipherOnly > 0 {
					keyUsages = append(keyUsages, "Encipher Only")
				}
				if c.KeyUsage&x509.KeyUsageDecipherOnly > 0 {
					keyUsages = append(keyUsages, "Decipher Only")
				}
				certDict["KeyUsage"] = keyUsages

				// Extended Key Usage
				var extKeyUsages []interface{}
				for _, extKeyUsage := range c.ExtKeyUsage {
					var usageStr string
					switch extKeyUsage {
					case x509.ExtKeyUsageServerAuth:
						usageStr = "Server Authentication"
					case x509.ExtKeyUsageClientAuth:
						usageStr = "Client Authentication"
					case x509.ExtKeyUsageCodeSigning:
						usageStr = "Code Signing"
					case x509.ExtKeyUsageEmailProtection:
						usageStr = "Email Protection"
					case x509.ExtKeyUsageTimeStamping:
						usageStr = "Time Stamping"
					case x509.ExtKeyUsageOCSPSigning:
						usageStr = "OCSP Signing"
					default:
						usageStr = fmt.Sprintf("Unknown (%d)", int(extKeyUsage))
					}
					extKeyUsages = append(extKeyUsages, usageStr)
				}
				certDict["ExtendedKeyUsage"] = extKeyUsages

				// Subject Alternative Names
				var dnsNames []interface{}
				for _, name := range c.DNSNames {
					dnsNames = append(dnsNames, name)
				}
				certDict["DNSNames"] = dnsNames

				var ipAddresses []interface{}
				for _, addr := range c.IPAddresses {
					ipAddresses = append(ipAddresses, addr.String())
				}
				certDict["IPAddresses"] = ipAddresses

				var emailAddresses []interface{}
				for _, email := range c.EmailAddresses {
					emailAddresses = append(emailAddresses, email)
				}
				certDict["EmailAddresses"] = emailAddresses

				pemBlock := &pem.Block{Type: "CERTIFICATE", Bytes: c.Raw}
				pemBytes := pem.EncodeToMemory(pemBlock)
				certDict["PEM"] = string(pemBytes)

				certDict["IsExpired"] = time.Now().After(c.NotAfter)

				return *env.NewDict(certDict)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "x509-certificate//to-dict")
			}
		},
	},
}
View Source
var Builtins_echarts = map[string]*env.Builtin{

	"bar-chart": {
		Argsn: 0,
		Doc:   "Creates a new ECharts bar chart instance.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			bar := charts.NewBar()
			return *env.NewNative(ps.Idx, bar, "echarts-bar")
		},
	},

	"bar-data": {
		Argsn: 1,
		Doc:   "Converts a block of numbers into ECharts bar data items.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch blk := arg0.(type) {
			case env.Block:
				items, err := blockToBarData(ps, blk)
				if err != nil {
					return err
				}
				return *env.NewNative(ps.Idx, items, "echarts-bar-data")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "bar-data")
			}
		},
	},

	"title-opts": {
		Argsn: 2,
		Doc:   "Creates ECharts title options with title and subtitle.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			title, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "title-opts")
			}
			subtitle, ok := arg1.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "title-opts")
			}
			titleOpts := opts.Title{
				Title:    title.Value,
				Subtitle: subtitle.Value,
			}
			return *env.NewNative(ps.Idx, titleOpts, "echarts-title-opts")
		},
	},

	"with-title-opts": {
		Argsn: 1,
		Doc:   "Wraps title options into a chart global option.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch nat := arg0.(type) {
			case env.Native:
				titleOpts, ok := nat.Value.(opts.Title)
				if !ok {
					return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-title-opts"}, "with-title-opts")
				}
				opt := charts.WithTitleOpts(titleOpts)
				return *env.NewNative(ps.Idx, opt, "echarts-global-opts")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "with-title-opts")
			}
		},
	},

	"echarts-bar//Global-options!": {
		Argsn: 2,
		Doc:   "Sets global options on an ECharts bar chart. Accepts a single option or a block of options.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			barNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-bar//Global-options!")
			}
			bar, ok := barNat.Value.(*charts.Bar)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-bar"}, "echarts-bar//Global-options!")
			}

			// Collect options
			var gopts []charts.GlobalOpts
			switch opt := arg1.(type) {
			case env.Native:
				gopt, ok := opt.Value.(charts.GlobalOpts)
				if !ok {
					return evaldo.MakeNativeArgError(ps, 2, []string{"echarts-global-opts"}, "echarts-bar//Global-options!")
				}
				gopts = append(gopts, gopt)
			case env.Block:
				for i := 0; i < opt.Series.Len(); i++ {
					obj := opt.Series.Get(i)
					nat, ok := obj.(env.Native)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain native echarts-global-opts", "echarts-bar//Global-options!")
					}
					gopt, ok := nat.Value.(charts.GlobalOpts)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain echarts-global-opts natives", "echarts-bar//Global-options!")
					}
					gopts = append(gopts, gopt)
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType, env.BlockType}, "echarts-bar//Global-options!")
			}

			bar.SetGlobalOptions(gopts...)
			return barNat
		},
	},

	"echarts-bar//X-axis!": {
		Argsn: 2,
		Doc:   "Sets the x-axis labels on an ECharts bar chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			barNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-bar//X-axis!")
			}
			bar, ok := barNat.Value.(*charts.Bar)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-bar"}, "echarts-bar//X-axis!")
			}
			switch blk := arg1.(type) {
			case env.Block:
				labels, err := blockToStringSlice(ps, blk)
				if err != nil {
					return err
				}
				bar.SetXAxis(labels)
				return barNat
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "echarts-bar//X-axis!")
			}
		},
	},

	"echarts-bar//Add-series": {
		Argsn: 3,
		Doc:   "Adds a data series to an ECharts bar chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			barNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-bar//Add-series")
			}
			bar, ok := barNat.Value.(*charts.Bar)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-bar"}, "echarts-bar//Add-series")
			}
			name, ok := arg1.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "echarts-bar//Add-series")
			}
			dataNat, ok := arg2.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 3, []env.Type{env.NativeType}, "echarts-bar//Add-series")
			}
			data, ok := dataNat.Value.([]opts.BarData)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 3, []string{"echarts-bar-data"}, "echarts-bar//Add-series")
			}
			bar.AddSeries(name.Value, data)
			return barNat
		},
	},

	"echarts-bar//Render": {
		Argsn: 2,
		Doc:   "Renders an ECharts bar chart to a writer (file, etc.).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			barNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-bar//Render")
			}
			bar, ok := barNat.Value.(*charts.Bar)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-bar"}, "echarts-bar//Render")
			}
			writerNat, ok := arg1.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "echarts-bar//Render")
			}
			writer, ok := writerNat.Value.(io.Writer)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 2, []string{"io.Writer (e.g., file)"}, "echarts-bar//Render")
			}
			err := bar.Render(writer)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "echarts-bar//Render")
			}
			return barNat
		},
	},

	"line-chart": {
		Argsn: 0,
		Doc:   "Creates a new ECharts line chart instance.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			line := charts.NewLine()
			return *env.NewNative(ps.Idx, line, "echarts-line")
		},
	},

	"line-data": {
		Argsn: 1,
		Doc:   "Converts a block of numbers into ECharts line data items.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch blk := arg0.(type) {
			case env.Block:
				items, err := blockToLineData(ps, blk)
				if err != nil {
					return err
				}
				return *env.NewNative(ps.Idx, items, "echarts-line-data")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "line-data")
			}
		},
	},

	"echarts-line//Global-options!": {
		Argsn: 2,
		Doc:   "Sets global options on an ECharts line chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			lineNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-line//Global-options!")
			}
			line, ok := lineNat.Value.(*charts.Line)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-line"}, "echarts-line//Global-options!")
			}

			var gopts []charts.GlobalOpts
			switch opt := arg1.(type) {
			case env.Native:
				gopt, ok := opt.Value.(charts.GlobalOpts)
				if !ok {
					return evaldo.MakeNativeArgError(ps, 2, []string{"echarts-global-opts"}, "echarts-line//Global-options!")
				}
				gopts = append(gopts, gopt)
			case env.Block:
				for i := 0; i < opt.Series.Len(); i++ {
					obj := opt.Series.Get(i)
					nat, ok := obj.(env.Native)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain native echarts-global-opts", "echarts-line//Global-options!")
					}
					gopt, ok := nat.Value.(charts.GlobalOpts)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain echarts-global-opts natives", "echarts-line//Global-options!")
					}
					gopts = append(gopts, gopt)
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType, env.BlockType}, "echarts-line//Global-options!")
			}

			line.SetGlobalOptions(gopts...)
			return lineNat
		},
	},

	"echarts-line//X-axis!": {
		Argsn: 2,
		Doc:   "Sets the x-axis labels on an ECharts line chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			lineNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-line//X-axis!")
			}
			line, ok := lineNat.Value.(*charts.Line)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-line"}, "echarts-line//X-axis!")
			}
			switch blk := arg1.(type) {
			case env.Block:
				labels, err := blockToStringSlice(ps, blk)
				if err != nil {
					return err
				}
				line.SetXAxis(labels)
				return lineNat
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "echarts-line//X-axis!")
			}
		},
	},

	"echarts-line//Add-series": {
		Argsn: 3,
		Doc:   "Adds a data series to an ECharts line chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			lineNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-line//Add-series")
			}
			line, ok := lineNat.Value.(*charts.Line)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-line"}, "echarts-line//Add-series")
			}
			name, ok := arg1.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "echarts-line//Add-series")
			}
			dataNat, ok := arg2.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 3, []env.Type{env.NativeType}, "echarts-line//Add-series")
			}
			data, ok := dataNat.Value.([]opts.LineData)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 3, []string{"echarts-line-data"}, "echarts-line//Add-series")
			}
			line.AddSeries(name.Value, data)
			return lineNat
		},
	},

	"echarts-line//Render": {
		Argsn: 2,
		Doc:   "Renders an ECharts line chart to a writer (file, etc.).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			lineNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-line//Render")
			}
			line, ok := lineNat.Value.(*charts.Line)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-line"}, "echarts-line//Render")
			}
			writerNat, ok := arg1.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "echarts-line//Render")
			}
			writer, ok := writerNat.Value.(io.Writer)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 2, []string{"io.Writer"}, "echarts-line//Render")
			}
			err := line.Render(writer)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "echarts-line//Render")
			}
			return lineNat
		},
	},

	"pie-chart": {
		Argsn: 0,
		Doc:   "Creates a new ECharts pie chart instance.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			pie := charts.NewPie()
			return *env.NewNative(ps.Idx, pie, "echarts-pie")
		},
	},

	"pie-data": {
		Argsn: 1,
		Doc:   "Converts a block of name-value pairs into ECharts pie data items.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch blk := arg0.(type) {
			case env.Block:
				items, err := blockToPieData(ps, blk)
				if err != nil {
					return err
				}
				return *env.NewNative(ps.Idx, items, "echarts-pie-data")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "pie-data")
			}
		},
	},

	"echarts-pie//Global-options!": {
		Argsn: 2,
		Doc:   "Sets global options on an ECharts pie chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			pieNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-pie//Global-options!")
			}
			pie, ok := pieNat.Value.(*charts.Pie)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-pie"}, "echarts-pie//Global-options!")
			}

			var gopts []charts.GlobalOpts
			switch opt := arg1.(type) {
			case env.Native:
				gopt, ok := opt.Value.(charts.GlobalOpts)
				if !ok {
					return evaldo.MakeNativeArgError(ps, 2, []string{"echarts-global-opts"}, "echarts-pie//Global-options!")
				}
				gopts = append(gopts, gopt)
			case env.Block:
				for i := 0; i < opt.Series.Len(); i++ {
					obj := opt.Series.Get(i)
					nat, ok := obj.(env.Native)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain native echarts-global-opts", "echarts-pie//Global-options!")
					}
					gopt, ok := nat.Value.(charts.GlobalOpts)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain echarts-global-opts natives", "echarts-pie//Global-options!")
					}
					gopts = append(gopts, gopt)
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType, env.BlockType}, "echarts-pie//Global-options!")
			}

			pie.SetGlobalOptions(gopts...)
			return pieNat
		},
	},

	"echarts-pie//Add-series": {
		Argsn: 2,
		Doc:   "Adds a data series to an ECharts pie chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			pieNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-pie//Add-series")
			}
			pie, ok := pieNat.Value.(*charts.Pie)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-pie"}, "echarts-pie//Add-series")
			}
			dataNat, ok := arg1.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "echarts-pie//Add-series")
			}
			data, ok := dataNat.Value.([]opts.PieData)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 2, []string{"echarts-pie-data"}, "echarts-pie//Add-series")
			}
			pie.AddSeries("pie", data)
			return pieNat
		},
	},

	"echarts-pie//Render": {
		Argsn: 2,
		Doc:   "Renders an ECharts pie chart to a writer (file, etc.).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			pieNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-pie//Render")
			}
			pie, ok := pieNat.Value.(*charts.Pie)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-pie"}, "echarts-pie//Render")
			}
			writerNat, ok := arg1.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "echarts-pie//Render")
			}
			writer, ok := writerNat.Value.(io.Writer)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 2, []string{"io.Writer"}, "echarts-pie//Render")
			}
			err := pie.Render(writer)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "echarts-pie//Render")
			}
			return pieNat
		},
	},

	"scatter-chart": {
		Argsn: 0,
		Doc:   "Creates a new ECharts scatter chart instance.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			scatter := charts.NewScatter()
			return *env.NewNative(ps.Idx, scatter, "echarts-scatter")
		},
	},

	"scatter-data": {
		Argsn: 1,
		Doc:   "Converts a block of [x y] pairs into ECharts scatter data items.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch blk := arg0.(type) {
			case env.Block:
				items, err := blockToScatterData(ps, blk)
				if err != nil {
					return err
				}
				return *env.NewNative(ps.Idx, items, "echarts-scatter-data")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "scatter-data")
			}
		},
	},

	"echarts-scatter//Global-options!": {
		Argsn: 2,
		Doc:   "Sets global options on an ECharts scatter chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			scatterNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-scatter//Global-options!")
			}
			scatter, ok := scatterNat.Value.(*charts.Scatter)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-scatter"}, "echarts-scatter//Global-options!")
			}

			var gopts []charts.GlobalOpts
			switch opt := arg1.(type) {
			case env.Native:
				gopt, ok := opt.Value.(charts.GlobalOpts)
				if !ok {
					return evaldo.MakeNativeArgError(ps, 2, []string{"echarts-global-opts"}, "echarts-scatter//Global-options!")
				}
				gopts = append(gopts, gopt)
			case env.Block:
				for i := 0; i < opt.Series.Len(); i++ {
					obj := opt.Series.Get(i)
					nat, ok := obj.(env.Native)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain native echarts-global-opts", "echarts-scatter//Global-options!")
					}
					gopt, ok := nat.Value.(charts.GlobalOpts)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "block must contain echarts-global-opts natives", "echarts-scatter//Global-options!")
					}
					gopts = append(gopts, gopt)
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType, env.BlockType}, "echarts-scatter//Global-options!")
			}

			scatter.SetGlobalOptions(gopts...)
			return scatterNat
		},
	},

	"echarts-scatter//X-axis!": {
		Argsn: 2,
		Doc:   "Sets the x-axis labels on an ECharts scatter chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			scatterNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-scatter//X-axis!")
			}
			scatter, ok := scatterNat.Value.(*charts.Scatter)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-scatter"}, "echarts-scatter//X-axis!")
			}
			switch blk := arg1.(type) {
			case env.Block:
				labels, err := blockToStringSlice(ps, blk)
				if err != nil {
					return err
				}
				scatter.SetXAxis(labels)
				return scatterNat
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "echarts-scatter//X-axis!")
			}
		},
	},

	"echarts-scatter//Add-series": {
		Argsn: 3,
		Doc:   "Adds a data series to an ECharts scatter chart.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			scatterNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-scatter//Add-series")
			}
			scatter, ok := scatterNat.Value.(*charts.Scatter)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-scatter"}, "echarts-scatter//Add-series")
			}
			name, ok := arg1.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "echarts-scatter//Add-series")
			}
			dataNat, ok := arg2.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 3, []env.Type{env.NativeType}, "echarts-scatter//Add-series")
			}
			data, ok := dataNat.Value.([]opts.ScatterData)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 3, []string{"echarts-scatter-data"}, "echarts-scatter//Add-series")
			}
			scatter.AddSeries(name.Value, data)
			return scatterNat
		},
	},

	"echarts-scatter//Render": {
		Argsn: 2,
		Doc:   "Renders an ECharts scatter chart to a writer (file, etc.).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			scatterNat, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "echarts-scatter//Render")
			}
			scatter, ok := scatterNat.Value.(*charts.Scatter)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-scatter"}, "echarts-scatter//Render")
			}
			writerNat, ok := arg1.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "echarts-scatter//Render")
			}
			writer, ok := writerNat.Value.(io.Writer)
			if !ok {
				return evaldo.MakeNativeArgError(ps, 2, []string{"io.Writer"}, "echarts-scatter//Render")
			}
			err := scatter.Render(writer)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "echarts-scatter//Render")
			}
			return scatterNat
		},
	},

	"legend-opts": {
		Argsn: 0,
		Doc:   "Creates ECharts legend options.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			legendOpts := opts.Legend{}
			return *env.NewNative(ps.Idx, legendOpts, "echarts-legend-opts")
		},
	},

	"with-legend-opts": {
		Argsn: 1,
		Doc:   "Wraps legend options into a chart global option.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch nat := arg0.(type) {
			case env.Native:
				legendOpts, ok := nat.Value.(opts.Legend)
				if !ok {
					return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-legend-opts"}, "with-legend-opts")
				}
				opt := charts.WithLegendOpts(legendOpts)
				return *env.NewNative(ps.Idx, opt, "echarts-global-opts")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "with-legend-opts")
			}
		},
	},

	"tooltip-opts": {
		Argsn: 0,
		Doc:   "Creates ECharts tooltip options.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			tooltipOpts := opts.Tooltip{}
			return *env.NewNative(ps.Idx, tooltipOpts, "echarts-tooltip-opts")
		},
	},

	"with-tooltip-opts": {
		Argsn: 1,
		Doc:   "Wraps tooltip options into a chart global option.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch nat := arg0.(type) {
			case env.Native:
				tooltipOpts, ok := nat.Value.(opts.Tooltip)
				if !ok {
					return evaldo.MakeNativeArgError(ps, 1, []string{"echarts-tooltip-opts"}, "with-tooltip-opts")
				}
				opt := charts.WithTooltipOpts(tooltipOpts)
				return *env.NewNative(ps.Idx, opt, "echarts-global-opts")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "with-tooltip-opts")
			}
		},
	},
}
View Source
var Builtins_email = map[string]*env.Builtin{

	"email-message": {
		Argsn: 0,
		Doc:   "Creates a new empty email message object that can be configured with headers, body, and attachments.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __newMessage(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"gomail-message//Set-header": {
		Argsn: 3,
		Doc:   "Sets a standard email header field such as Subject, To, From, Cc, or Bcc with the specified value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __setHeader(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"gomail-message//Set-address-header": {
		Argsn: 4,
		Doc:   "Sets an email address header with both email address and display name, commonly used for From, To, Cc, and Bcc fields.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __setAddressHeader(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"gomail-message//Set-body": {
		Argsn: 3,
		Doc:   "Sets the main body content of the email with the specified MIME content type, supporting plain text and HTML formats.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __setBody(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"gomail-message//Attach": {
		Argsn: 2,
		Doc:   "Attaches a file to the email message using a file URI, making the file available as an email attachment.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __attach(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"gomail-message//Add-alternative": {
		Argsn: 3,
		Doc:   "Adds alternative content to the email (e.g., HTML version alongside plain text), allowing email clients to choose their preferred format.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __addAlternative(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"new-email-dialer": {
		Argsn: 4,
		Doc:   "Creates a new SMTP dialer configured with server details and authentication credentials for sending emails.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __newDialer(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},

	"gomail-dialer//Dial-and-send": {
		Argsn: 2,
		Doc:   "Connects to the SMTP server and sends the specified email message, handling authentication and delivery.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return __dialAndSend(ps, arg0, arg1, arg2, arg3, arg4)
		},
	},
}
View Source
var Builtins_encoding = map[string]*env.Builtin{

	"decode\\hex-string": {
		Argsn: 1,
		Doc:   "Decodes a hexadecimal string to a UTF-8 string.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch hexStr := arg0.(type) {
			case env.String:
				decoded, err := hex.DecodeString(hexStr.Value)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to decode hex string: "+err.Error(), "hex\\decode-string")
				}
				return *env.NewString(string(decoded))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "hex\\decode-string")
			}
		},
	},

	"encode\\hex-string": {
		Argsn: 1,
		Doc:   "Encodes a string to its hexadecimal representation.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.String:
				encoded := hex.EncodeToString([]byte(str.Value))
				return *env.NewString(encoded)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "hex\\encode-string")
			}
		},
	},

	"clean\\hex-string": {
		Argsn: 1,
		Doc:   "Removes all whitespace from a hex string and ensures even length.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch hexStr := arg0.(type) {
			case env.String:
				var sb strings.Builder
				for _, r := range hexStr.Value {
					if !unicode.IsSpace(r) {
						sb.WriteRune(r)
					}
				}

				result := sb.String()
				if len(result)%2 != 0 {
					result = result[:len(result)-1]
				}
				return *env.NewString(result)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "hex\\clean-string")
			}
		},
	},

	"charmap\\windows-1250": {
		Argsn: 0,
		Doc:   "Returns the Windows-1250 (CP1250) character encoding for Central European languages.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, charmap.Windows1250, "charmap-encoding")
		},
	},

	"charmap\\iso-8859-1": {
		Argsn: 0,
		Doc:   "Returns the ISO-8859-1 (Latin-1) character encoding.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, charmap.ISO8859_1, "charmap-encoding")
		},
	},

	"charmap\\iso-8859-2": {
		Argsn: 0,
		Doc:   "Returns the ISO-8859-2 (Latin-2) character encoding for Central European languages.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, charmap.ISO8859_2, "charmap-encoding")
		},
	},

	"charmap\\windows-1252": {
		Argsn: 0,
		Doc:   "Returns the Windows-1252 character encoding for Western European languages.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, charmap.Windows1252, "charmap-encoding")
		},
	},

	"charmap\\code-page-437": {
		Argsn: 0,
		Doc:   "Returns the Code Page 437 (DOS/IBM PC) character encoding.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, charmap.CodePage437, "charmap-encoding")
		},
	},

	"charmap\\code-page-850": {
		Argsn: 0,
		Doc:   "Returns the Code Page 850 (DOS Latin-1) character encoding.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, charmap.CodePage850, "charmap-encoding")
		},
	},

	"charmap\\koi8r": {
		Argsn: 0,
		Doc:   "Returns the KOI8-R character encoding for Russian.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, charmap.KOI8R, "charmap-encoding")
		},
	},

	"charmap-encoding//Decoder": {
		Argsn: 1,
		Doc:   "Creates a new text decoder for the given character encoding.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch encoding := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(encoding.GetKind()) != "charmap-encoding" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "charmap-encoding\\new-decoder")
				}
				enc := encoding.Value.(*charmap.Charmap)
				decoder := enc.NewDecoder()
				return *env.NewNative(ps.Idx, decoder, "text-decoder")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "charmap-encoding\\new-decoder")
			}
		},
	},

	"charmap-encoding//Encoder": {
		Argsn: 1,
		Doc:   "Creates a new text encoder for the given character encoding.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch encoding := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(encoding.GetKind()) != "charmap-encoding" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "charmap-encoding\\new-encoder")
				}
				enc := encoding.Value.(*charmap.Charmap)
				encoder := enc.NewEncoder()
				return *env.NewNative(ps.Idx, encoder, "text-encoder")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "charmap-encoding\\new-encoder")
			}
		},
	},

	"text-decoder//Decode": {
		Argsn: 2,
		Doc:   "Decodes a string using the given text decoder.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch decoder := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(decoder.GetKind()) != "text-decoder" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "text-decoder\\string")
				}
				switch input := arg1.(type) {
				case env.String:
					dec := decoder.Value.(*encoding.Decoder)
					decoded, err := dec.String(input.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Failed to decode string: "+err.Error(), "text-decoder\\string")
					}
					return *env.NewString(decoded)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "text-decoder\\string")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "text-decoder\\string")
			}
		},
	},

	"text-encoder//Encode": {
		Argsn: 2,
		Doc:   "Encodes a string using the given text encoder.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch encoder := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(encoder.GetKind()) != "text-encoder" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "text-encoder\\string")
				}
				switch input := arg1.(type) {
				case env.String:
					enc := encoder.Value.(*encoding.Encoder)
					encoded, err := enc.String(input.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Failed to encode string: "+err.Error(), "text-encoder\\string")
					}
					return *env.NewString(encoded)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "text-encoder\\string")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "text-encoder\\string")
			}
		},
	},

	"is-space?": {
		Argsn: 1,
		Doc:   "Checks if a single character string is a whitespace character.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.String:
				if len(str.Value) == 0 {
					return *env.NewInteger(0)
				}

				for _, r := range str.Value {
					if unicode.IsSpace(r) {
						return *env.NewInteger(1)
					}
					return *env.NewInteger(0)
				}
				return *env.NewInteger(0)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "is-space?")
			}
		},
	},

	"remove-all-space": {
		Argsn: 1,
		Doc:   "Removes all whitespace characters from a string.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.String:
				var sb strings.Builder
				for _, r := range str.Value {
					if !unicode.IsSpace(r) {
						sb.WriteRune(r)
					}
				}
				return *env.NewString(sb.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "remove-all-space")
			}
		},
	},
}
View Source
var Builtins_error_creation = ErrorCreationBuiltins

Export the error handling builtins for registration

View Source
var Builtins_error_handling = ErrorHandlingBuiltins
View Source
var Builtins_error_inspection = ErrorInspectionBuiltins
View Source
var Builtins_eyr = map[string]*env.Builtin{

	"eyr": {
		Argsn: 1,
		Doc:   "Evaluates Rye block as Eyr (postfix) stack based code.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				dialect := ps.Dialect
				ps.Dialect = env.EyrDialect

				if ps.Stack == nil {
					ps.Stack = env.NewEyrStack()
				} else {
					ps.ResetStack()
				}
				Eyr_EvalBlock(ps, false)
				ps.Dialect = dialect
				ps.Ser = ser
				return ps.Res
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "eyr")
			}
		},
	},

	"rye0": {
		Argsn: 1,
		Doc:   "Evaluates Rye block as Rye0 dialect.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				dialect := ps.Dialect
				ps.Dialect = env.Rye0Dialect
				evaldo.Rye0_EvalBlockInj(ps, nil, false)
				ps.Dialect = dialect
				ps.Ser = ser
				return ps.Res
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "rye0")
			}
		},
	},

	"rye00": {
		Argsn: 1,
		Doc:   "Evaluates Rye block as Rye00 dialect (builtins and integers only).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				dialect := ps.Dialect
				ps.Dialect = env.Rye00Dialect
				evaldo.Rye00_EvalBlockInj(ps, nil, false)
				ps.Dialect = dialect
				ps.Ser = ser
				return ps.Res
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "rye00")
			}
		},
	},

	"eyr\\clear": {
		Argsn: 0,
		Doc:   "Clears the EYR stack.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.ResetStack()
			return env.NewBoolean(false)
		},
	},

	"eyr\\full": {
		Argsn: 1,
		Doc:   "Evaluates Rye block as Eyr (postfix) stack based code.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				dialect := ps.Dialect
				ps.Dialect = env.EyrDialect
				Eyr_EvalBlock(ps, true)
				ps.Dialect = dialect
				ps.Ser = ser
				return ps.Res
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "eyr\\full")
			}
		},
	},

	"eyr\\loop": {
		Argsn: 2,
		Doc:   "Evaluates Rye block in loop as Eyr code (postfix stack based) N times.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cond := arg0.(type) {
			case env.Integer:
				switch bloc := arg1.(type) {
				case env.Block:
					ps.Dialect = env.EyrDialect
					ser := ps.Ser
					ps.Ser = bloc.Series
					for i := 0; int64(i) < cond.Value; i++ {
						ps = Eyr_EvalBlock(ps, false)
						ps.Ser.Reset()
					}
					ps.Ser = ser
					return ps.Res
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "eyr\\loop")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "eyr\\loop")
			}
		},
	},

	"to-eyr": {
		Argsn: 1,
		Doc:   "Evaluates Rye block as Eyr (postfix) stack based code.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:
				eBlock := env.NewBlock(*env.NewTSeries(make([]env.Object, 0)))
				evaldo.CompileRyeToEyr(&bloc, ps, eBlock)
				return *eBlock
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "eyr")
			}
		},
	},
}
View Source
var Builtins_flui = map[string]*env.Builtin{
	"select": {
		Argsn: 1,
		Doc:   "Interactively displays a selection interface for Block, Dict, Table, List, or TableRow. Returns the selected item. Ctrl+C cancels and returns a failure.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.SaveCurPos()
			var obj env.Object
			var esc bool
			switch val := arg0.(type) {
			case env.Block:
				obj, esc = term.DisplayBlock(val, ps.Idx)
			case *env.Block:
				obj, esc = term.DisplayBlock(*val, ps.Idx)
			case env.Dict:
				obj, esc = term.DisplayDict(val, ps.Idx)
			case *env.Dict:
				obj, esc = term.DisplayDict(*val, ps.Idx)
			case env.List:

				bloc := env.NewBlock(*env.NewTSeries(make([]env.Object, len(val.Data))))
				for i, item := range val.Data {
					bloc.Series.S[i] = env.ToRyeValue(item)
				}
				obj, esc = term.DisplayBlock(*bloc, ps.Idx)
			case *env.List:

				bloc := env.NewBlock(*env.NewTSeries(make([]env.Object, len(val.Data))))
				for i, item := range val.Data {
					bloc.Series.S[i] = env.ToRyeValue(item)
				}
				obj, esc = term.DisplayBlock(*bloc, ps.Idx)
			case env.Table:
				obj, esc = term.DisplayTable(val, ps.Idx)
			case *env.Table:
				obj, esc = term.DisplayTable(*val, ps.Idx)
			case env.TableRow:
				obj, esc = term.DisplayTableRow(val, ps.Idx)
			case *env.TableRow:
				obj, esc = term.DisplayTableRow(*val, ps.Idx)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.DictType, env.ListType, env.TableType}, "select")
			}
			if esc {
				ps.FailureFlag = true
				return env.NewError("canceled by user")
			}
			return obj
		},
	},
	"input": {
		Argsn: 1,
		Doc:   "Interactively displays an input field. Takes the max input width, returns the entered string. Ctrl+C cancels and returns a failure.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			term.SaveCurPos()
			switch width := arg0.(type) {
			case env.Integer:
				obj, esc := term.DisplayInputField(0, int(width.Value))
				if esc {
					ps.FailureFlag = true
					return env.NewError("canceled by user")
				}
				return obj
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "input")
			}
		},
	},
	"input\\integer": {
		Argsn: 1,
		Doc:   "Interactive date input in format YYYY-MM-DD. Use arrow keys to navigate between year/month/day fields and increment/decrement values, or type digits. Returns date string. Ctrl+C cancels and returns a failure.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.SaveCurPos()
			switch initialDate := arg0.(type) {
			case env.String:
				obj, esc := term.DisplayIntInput(initialDate.Value, 0)
				if esc {
					ps.FailureFlag = true
					return env.NewError("canceled by user")
				}
				return obj
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "input\\integer")
			}
		},
	},
	"datepicker": {
		Argsn: 1,
		Doc:   "Interactive date input in format YYYY-MM-DD. Use arrow keys to navigate between year/month/day fields and increment/decrement values, or type digits. Returns date string. Ctrl+C cancels and returns a failure.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.SaveCurPos()
			switch initialDate := arg0.(type) {
			case env.String:
				obj, esc := term.DisplayDateInput(initialDate.Value, 0)
				if esc {
					ps.FailureFlag = true
					return env.NewError("canceled by user")
				}
				return obj
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "datepicker")
			}
		},
	},
	"selectbox": {
		Argsn: 1,
		Doc:   "Interactive date input in format YYYY-MM-DD. Use arrow keys to navigate between year/month/day fields and increment/decrement values, or type digits. Returns date string. Ctrl+C cancels and returns a failure.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.SaveCurPos()
			switch options := arg0.(type) {
			case env.Block:
				obj, esc := term.DisplaySelection(options, ps.Idx, 0)
				if esc {
					ps.FailureFlag = true
					return env.NewError("canceled by user")
				}
				return obj
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "datepicker")
			}
		},
	},
	"textarea": {
		Argsn: 2,
		Doc:   "Interactive multiline text input. Takes width and height (number of lines). Use arrow keys to navigate, Enter for new line, Ctrl+D to submit. Returns string with newlines. Ctrl+C cancels.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.SaveCurPos()
			switch width := arg0.(type) {
			case env.Integer:
				switch height := arg1.(type) {
				case env.Integer:
					obj, esc := term.DisplayTextArea(int(width.Value), int(height.Value), "")
					if esc {
						ps.FailureFlag = true
						return env.NewError("canceled by user")
					}
					return obj
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "textarea")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "textarea")
			}
		},
	},
	"textarea\\": {
		Argsn: 3,
		Doc:   "Interactive multiline text input with initial text. Takes width, height (number of lines), and initial text string. Use arrow keys to navigate, Enter for new line, Ctrl+D to submit. Returns string with newlines. Ctrl+C cancels.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.SaveCurPos()
			switch width := arg1.(type) {
			case env.Integer:
				switch height := arg2.(type) {
				case env.Integer:
					switch text := arg0.(type) {
					case env.String:
						obj, esc := term.DisplayTextArea(int(width.Value), int(height.Value), text.Value)
						if esc {
							ps.FailureFlag = true
							return env.NewError("canceled by user")
						}
						return obj
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "textarea\\")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "textarea\\")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "textarea\\")
			}
		},
	},
	"displayx": {
		Argsn: 1,
		Doc:   "Returns a special !!! prefixed JSON representation of a Block for Flutter UI rendering. The JSON format is [\"block\", [[\"type\", \"value\"], ...]]. Used for interactive display in Flutter clients.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Block:
				return blockToDisplayJSON(val, ps.Idx)
			case *env.Block:
				return blockToDisplayJSON(*val, ps.Idx)
			case env.List:

				bloc := env.NewBlock(*env.NewTSeries(make([]env.Object, len(val.Data))))
				for i, item := range val.Data {
					bloc.Series.S[i] = env.ToRyeValue(item)
				}
				return blockToDisplayJSON(*bloc, ps.Idx)
			case *env.List:

				bloc := env.NewBlock(*env.NewTSeries(make([]env.Object, len(val.Data))))
				for i, item := range val.Data {
					bloc.Series.S[i] = env.ToRyeValue(item)
				}
				return blockToDisplayJSON(*bloc, ps.Idx)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType}, "displayx")
			}
		},
	},
}
View Source
var Builtins_flui_v2 = map[string]*env.Builtin{

	"select": {
		Argsn: 1,
		Doc:   "Interactively displays a selection interface. Returns the selected item. Ctrl+C cancels.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			items, ok := extractItems(arg0, ps.Idx)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.DictType, env.ListType, env.TableType}, "select")
			}

			_, height, termErr := goterm.GetSize(int(os.Stdout.Fd()))
			if termErr != nil {
				height = 20
			}
			pageSize := height - 4

			term.SaveCurPos()

			var widget term.Widget
			if len(items) <= pageSize {
				widget = term.NewSelectWidget(items, ps.Idx)
			} else {
				widget = term.NewPaginatedSelectWidget(items, pageSize, ps.Idx)
			}

			result, canceled := term.RunWidget(widget)
			if canceled {
				ps.FailureFlag = true
				return env.NewError("canceled by user")
			}
			return result
		},
	},

	"input": {
		Argsn: 1,
		Doc:   "Interactively displays an input field. Takes max width, returns entered string. Ctrl+C cancels.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch width := arg0.(type) {
			case env.Integer:
				term.SaveCurPos()
				widget := term.NewInputWidget(int(width.Value), ps.Idx)
				result, canceled := term.RunWidget(widget)
				if canceled {
					ps.FailureFlag = true
					return env.NewError("canceled by user")
				}
				return result
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "input")
			}
		},
	},

	"datepicker": {
		Argsn: 1,
		Doc:   "Interactive date input. Use arrow keys to navigate/change values, or type digits. Ctrl+C cancels.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch initialDate := arg0.(type) {
			case env.String:
				term.SaveCurPos()
				widget := term.NewDateWidget(initialDate.Value, ps.Idx)
				result, canceled := term.RunWidget(widget)
				if canceled {
					ps.FailureFlag = true
					return env.NewError("canceled by user")
				}
				return result
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "datepicker")
			}
		},
	},

	"textarea": {
		Argsn: 2,
		Doc:   "Interactive multiline text input. Takes width and height. Ctrl+D to submit, Ctrl+C cancels.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch width := arg0.(type) {
			case env.Integer:
				switch height := arg1.(type) {
				case env.Integer:
					term.SaveCurPos()
					widget := term.NewTextAreaWidget(int(width.Value), int(height.Value), "", ps.Idx)
					result, canceled := term.RunWidget(widget)
					if canceled {
						ps.FailureFlag = true
						return env.NewError("canceled by user")
					}
					return result
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "textarea")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "textarea")
			}
		},
	},

	"textarea\\": {
		Argsn: 3,
		Doc:   "Interactive multiline text input with initial text. Ctrl+D to submit, Ctrl+C cancels.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch text := arg0.(type) {
			case env.String:
				switch width := arg1.(type) {
				case env.Integer:
					switch height := arg2.(type) {
					case env.Integer:
						term.SaveCurPos()
						widget := term.NewTextAreaWidget(int(width.Value), int(height.Value), text.Value, ps.Idx)
						result, canceled := term.RunWidget(widget)
						if canceled {
							ps.FailureFlag = true
							return env.NewError("canceled by user")
						}
						return result
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType}, "textarea\\")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "textarea\\")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "textarea\\")
			}
		},
	},

	"displayx": {
		Argsn: 1,
		Doc:   "Returns a !!! prefixed JSON representation for Flutter UI rendering.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Block:
				return blockToDisplayJSON(val, ps.Idx)
			case *env.Block:
				return blockToDisplayJSON(*val, ps.Idx)
			case env.List:
				return blockToDisplayJSON(*listToBlock(val), ps.Idx)
			case *env.List:
				return blockToDisplayJSON(*listToBlock(*val), ps.Idx)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType}, "displayx")
			}
		},
	},
}
View Source
var Builtins_goroutines = map[string]*env.Builtin{

	"go-with": {
		Argsn: 2,
		Doc:   "Executes a function in a separate goroutine, passing the specified value as an argument.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch arg := arg0.(type) {
			case env.Object:
				switch handler := arg1.(type) {
				case env.Function:

					psTemp := env.ProgramState{}
					err := copier.Copy(&psTemp, &ps)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("failed to copy program state: %s", err), "go-with")
					}

					psTemp.FailureFlag = false
					psTemp.ErrorFlag = false
					psTemp.ReturnFlag = false

					go func() {
						defer func() {
							if r := recover(); r != nil {

								fmt.Printf("Goroutine panic in go-with: %v\n", r)
							}
						}()
						evaldo.CallFunction_CollectArgs(handler, &psTemp, arg, false, nil)
					}()

					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.FunctionType}, "go-with")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "First argument should be object type.", "go-with")
			}
		},
	},

	"go": {
		Argsn: 1,
		Doc:   "Executes a function in a separate goroutine without passing any arguments.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch handler := arg0.(type) {
			case env.Function:

				psTemp := env.ProgramState{}
				err := copier.Copy(&psTemp, &ps)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("failed to copy program state: %s", err), "go")
				}

				psTemp.FailureFlag = false
				psTemp.ErrorFlag = false
				psTemp.ReturnFlag = false

				go func() {
					defer func() {
						if r := recover(); r != nil {

							fmt.Printf("Goroutine panic in go: %v\n", r)
						}
					}()
					evaldo.CallFunction_CollectArgs(handler, &psTemp, nil, false, nil)
				}()

				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.FunctionType}, "go")
			}
		},
	},

	"channel": {
		Argsn: 1,
		Doc:   "Creates a new channel with the specified buffer size for goroutine communication.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch buflen := arg0.(type) {
			case env.Integer:

				ch := make(chan *env.Object, int(buflen.Value))
				return *env.NewNative(ps.Idx, ch, "Rye-channel")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "channel")
			}
		},
	},

	"Rye-channel//Read": {
		Argsn: 1,
		Doc:   "Reads the next value from a channel, blocking until a value is available or the channel is closed.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch chn := arg0.(type) {
			case env.Native:

				ch, ok := chn.Value.(chan *env.Object)
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Invalid channel type", "Rye-channel//Read")
				}

				msg, ok := <-ch
				if ok {
					return *msg
				} else {
					return *env.NewError("channel closed")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-channel//Read")
			}
		},
	},

	"Rye-channel//Send": {
		Argsn: 2,
		Doc:   "Sends a value through a channel, blocking if the channel is unbuffered or full.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (result env.Object) {

			defer func() {
				if r := recover(); r != nil {
					ps.FailureFlag = true
					result = *env.NewError("send on closed channel")
				}
			}()
			switch chn := arg0.(type) {
			case env.Native:
				chn.Value.(chan *env.Object) <- &arg1
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-channel//Send")
			}
		},
	},

	"Rye-channel//Close": {
		Argsn: 1,
		Doc:   "Closes a channel, preventing further sends and causing pending/future reads to return an error.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch chn := arg0.(type) {
			case env.Native:
				close(chn.Value.(chan *env.Object))
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-channel//Close")
			}
		},
	},

	"mutex": {
		Argsn: 0,
		Doc:   "Creates a new mutex for synchronizing access to shared resources between goroutines.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			mtx := &RyeMutex{}
			return *env.NewNative(ps.Idx, mtx, "Rye-mutex")
		},
	},

	"waitgroup": {
		Argsn: 0,
		Doc:   "Creates a new waitgroup for coordinating multiple goroutines to wait for completion.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var wg sync.WaitGroup
			return *env.NewNative(ps.Idx, &wg, "Rye-waitgroup")
		},
	},

	"Rye-mutex//Lock": {
		Argsn: 1,
		Doc:   "Acquires the lock on a mutex, blocking until the lock becomes available.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch mtx := arg0.(type) {
			case env.Native:
				mtx.Value.(*RyeMutex).Lock()
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mutex//Lock")
			}
		},
	},

	"Rye-mutex//Unlock": {
		Argsn: 1,
		Doc:   "Releases the lock on a mutex, allowing other goroutines to acquire it.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch mtx := arg0.(type) {
			case env.Native:
				err := mtx.Value.(*RyeMutex).Unlock()
				if err != nil {
					ps.FailureFlag = true
					return *env.NewError(err.Error())
				}
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mutex//Unlock")
			}
		},
	},

	"Rye-waitgroup//Add": {
		Argsn: 2,
		Doc:   "Adds the specified count to the waitgroup counter, indicating how many goroutines to wait for.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch wg := arg0.(type) {
			case env.Native:
				switch count := arg1.(type) {
				case env.Integer:
					wg.Value.(*sync.WaitGroup).Add(int(count.Value))
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "Rye-waitgroup//Add")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-waitgroup//Add")
			}
		},
	},

	"Rye-waitgroup//Done": {
		Argsn: 1,
		Doc:   "Decrements the waitgroup counter by one, indicating that a goroutine has completed.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch wg := arg0.(type) {
			case env.Native:
				wg.Value.(*sync.WaitGroup).Done()
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-waitgroup//Done")
			}
		},
	},

	"Rye-waitgroup//Wait": {
		Argsn: 1,
		Doc:   "Blocks until the waitgroup counter reaches zero, meaning all goroutines have completed.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch wg := arg0.(type) {
			case env.Native:
				wg.Value.(*sync.WaitGroup).Wait()
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-waitgroup//Wait")
			}
		},
	},

	"select\\fn": {
		Argsn: 1,
		Doc:   "Performs a select operation on multiple channels, executing functions when channels are ready or a default function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch block := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = block.Series

				var hasDeafult bool
				var cases []reflect.SelectCase
				var funcs []env.Function
				for ps.Ser.Pos() < ps.Ser.Len() {
					evaldo.EvalExpression_CollectArg(ps, false, false)
					defaultFn, ok := ps.Res.(env.Function)

					if ok {
						if hasDeafult {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "select can only have one default case", "select\\fn")
						}
						if defaultFn.Argsn != 0 {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "function with 0 args required", "select\\fn")
						}
						defaultCase := make(chan struct{})
						close(defaultCase)
						cases = append(cases, reflect.SelectCase{
							Dir:  reflect.SelectRecv,
							Chan: reflect.ValueOf(defaultCase),
						})
						funcs = append(funcs, defaultFn)
						hasDeafult = true
						continue
					}

					native, ok := ps.Res.(env.Native)
					if !ok {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "first argument of a case must be a channel", "select\\fn")
					}
					ch, ok := native.Value.(chan *env.Object)
					if !ok {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "first argument of a case must be a channel", "select\\fn")
					}
					cases = append(cases, reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)})

					evaldo.EvalExpression_CollectArg(ps, false, false)
					fn, ok := ps.Res.(env.Function)
					if !ok {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "second argument of a case must be a function", "select\\fn")
					}
					if fn.Argsn > 1 {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "function with 0 or 1 arg required", "select\\fn")
					}
					funcs = append(funcs, fn)
				}
				ps.Ser = ser

				chosen, value, recvOK := reflect.Select(cases)
				fn := funcs[chosen]

				psTemp := env.ProgramState{}
				err := copier.Copy(&psTemp, &ps)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("failed to copy ps: %s", err), "select\\fn")
				}
				var arg env.Object = nil
				if recvOK {
					val, ok := value.Interface().(*env.Object)
					if !ok {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "value from channel is not an object", "select\\fn")
					}
					arg = *val
				}
				if fn.Argsn == 0 {
					arg = nil
				}
				evaldo.CallFunction_CollectArgs(fn, &psTemp, arg, false, nil)
				return psTemp.Res

			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "select\\fn")
			}
			return arg0
		},
	},

	"select": {
		Argsn: 1,
		Doc:   "Select on a message on multiple channels or default.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch block := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = block.Series

				var hasDeafult bool
				var cases []reflect.SelectCase
				var funcs []env.Block
				for ps.Ser.Pos() < ps.Ser.Len() {
					evaldo.EvalExpression_CollectArg(ps, false, false)

					switch maybeChan := ps.Res.(type) {
					case env.Native:
						ch, ok := maybeChan.Value.(chan *env.Object)
						if !ok {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "first argument of a case must be a channel", "select")
						}
						cases = append(cases, reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)})

						evaldo.EvalExpression_CollectArg(ps, false, false)
						fn, ok := ps.Res.(env.Block)
						if !ok {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "second argument of a case must be a block", "select")
						}

						funcs = append(funcs, fn)

					case env.Void:
						if hasDeafult {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "select can only have one default case", "select")
						}

						defaultCase := make(chan struct{})
						close(defaultCase)
						cases = append(cases, reflect.SelectCase{
							Dir:  reflect.SelectRecv,
							Chan: reflect.ValueOf(defaultCase),
						})
						evaldo.EvalExpression_CollectArg(ps, false, false)
						fn, ok := ps.Res.(env.Block)
						if !ok {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "second argument of a case must be a block", "select")
						}
						funcs = append(funcs, fn)
						hasDeafult = true
					}
				}
				ps.Ser = ser

				chosen, value, recvOK := reflect.Select(cases)
				fn := funcs[chosen]

				psTemp := env.ProgramState{}
				err := copier.Copy(&psTemp, &ps)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("failed to copy ps: %s", err), "select")
				}
				var arg env.Object = nil
				if recvOK {
					val, ok := value.Interface().(*env.Object)
					if !ok {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "value from channel is not an object", "select")
					}
					arg = *val
				}

				psTemp.Ser = fn.Series
				evaldo.EvalBlockInj(&psTemp, arg, true)
				evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "select")

				if psTemp.ErrorFlag {
					return psTemp.Res
				}

			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "select")
			}
			return arg0
		},
	},
}
View Source
var Builtins_html = map[string]*env.Builtin{

	"unescape\\html": {
		Argsn: 1,
		Doc:   "Converts HTML entities to their character equivalents.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			text, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "unescape\\html")
			}
			mkd := html.UnescapeString(text.Value)
			return *env.NewString(mkd)
		},
	},

	"escape\\html": {
		Argsn: 1,
		Doc:   "Converts special characters to HTML entities.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			text, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "unescape\\html")
			}
			mkd := html.EscapeString(text.Value)
			return *env.NewString(mkd)
		},
	},

	"html->markdown": {
		Argsn: 1,
		Doc:   "Converts HTML text to markdown format.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			text, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "html->markdown")
			}
			mkd, err := htmltomarkdown.ConvertString(text.Value)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "html->markdown")
			}
			return *env.NewString(mkd)
		},
	},

	"reader//Parse-html": {
		Argsn: 2,
		Doc:   "Parses HTML using a streaming approach with tag handlers.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			rm, err := load_html_Dict(ps, arg1.(env.Block))
			trace8("*** _--- GOT RM ++**")

			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "Error to load html dict.", "reader//parse-html")
			}
			return do_html(ps, arg0.(env.Native).Value.(io.Reader), rm)
		},
	},

	"rye-html-start//Attr?": {
		Argsn: 2,
		Doc:   "Retrieves an attribute value by name or index from an HTML element.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch tok1 := arg0.(type) {
			case env.Native:
				switch tok := tok1.Value.(type) {
				case html.Token:
					switch n := arg1.(type) {
					case env.Integer:
						if int(n.Value) < len(tok.Attr) {
							return *env.NewString(tok.Attr[int(n.Value)].Val)
						} else {
							return evaldo.MakeBuiltinError(ps, "Attribute index out of bounds.", "rye-html-start//Attr?")
						}
					case env.Word:
						attrName := ps.Idx.GetWord(n.Index)
						for _, a := range tok.Attr {
							if a.Key == attrName {
								return *env.NewString(a.Val)
							}
						}
						return evaldo.MakeBuiltinError(ps, "Attribute '"+attrName+"' not found.", "rye-html-start//Attr?")
					case env.String:
						attrName := n.Value
						for _, a := range tok.Attr {
							if a.Key == attrName {
								return *env.NewString(a.Val)
							}
						}
						return evaldo.MakeBuiltinError(ps, "Attribute '"+attrName+"' not found.", "rye-html-start//Attr?")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.WordType, env.StringType}, "rye-html-start//Attr?")
					}
				default:
					return evaldo.MakeBuiltinError(ps, "Token value is not matching.", "rye-html-start//Attr?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "rye-html-start//Attr?")
			}
		},
	},

	"rye-html-start//Attrs?": {
		Argsn: 1,
		Doc:   "Returns a dict of all attributes from an HTML element.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch tok1 := arg0.(type) {
			case env.Native:
				switch tok := tok1.Value.(type) {
				case html.Token:
					data := make(map[string]any)
					for _, attr := range tok.Attr {
						data[attr.Key] = *env.NewString(attr.Val)
					}
					return *env.NewDict(data)
				default:
					return evaldo.MakeBuiltinError(ps, "Token value is not matching.", "rye-html-start//Attrs?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "rye-html-start//Attrs?")
			}
		},
	},

	"rye-html-start//Name?": {
		Argsn: 1,
		Doc:   "Returns the name of an HTML element.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch tok1 := arg0.(type) {
			case env.Native:
				switch tok := tok1.Value.(type) {
				case html.Token:
					return *env.NewString(tok.Data)
				default:
					return evaldo.MakeBuiltinError(ps, "Not xml-start element.", "rye-html-start//Name?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "rye-html-start//Name?")
			}
		},
	},
}
View Source
var Builtins_http = map[string]*env.Builtin{

	"http-server": {
		Argsn: 1,
		Doc:   "Creates a new HTTP server that listens on the specified address with a 10-second read header timeout.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.String:

				server := &http.Server{Addr: addr.Value, ReadHeaderTimeout: 10 * time.Second}
				return *env.NewNative(ps.Idx, server, "Go-server")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "http-server")
			}
		},
	},

	"Go-server//Serve": {
		Argsn: 1,
		Doc:   "Starts the HTTP server listening and serving requests on the configured address (blocking call).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:

				err := server.Value.(*http.Server).ListenAndServe()
				if err != nil {
					return evaldo.MakeError(ps, err.Error())
				}
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server//Serve")
			}
		},
	},

	"Go-server//Handle": {
		Argsn: 3,
		Doc:   "Registers an HTTP handler for a specific path pattern on the server, accepting string responses, Rye functions, or native Go handlers.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg1.(type) {
			case env.String:
				switch handler := arg2.(type) {
				case env.String:

					http.HandleFunc(path.Value, func(w http.ResponseWriter, r *http.Request) {
						fmt.Fprintf(w, handler.Value)
					})
					return arg0
				case env.Function:

					http.HandleFunc(path.Value, func(w http.ResponseWriter, r *http.Request) {

						ps.FailureFlag = false
						ps.ErrorFlag = false
						ps.ReturnFlag = false

						psTemp := env.ProgramState{}
						err := copier.Copy(&psTemp, &ps)
						if err != nil {
							fmt.Println(err.Error())

						}

						evaldo.CallFunctionArgs2(handler, ps, *env.NewNative(ps.Idx, w, "Go-server-response-writer"), *env.NewNative(ps.Idx, r, "Go-server-request"), nil)

						if ps.FailureFlag || ps.ErrorFlag {
							fmt.Println("Error in HTTP handler: " + ps.Res.Inspect(*ps.Idx))
						}
					})
					return arg0
				case env.CurriedCaller:

					http.HandleFunc(path.Value, func(w http.ResponseWriter, r *http.Request) {

						ps.FailureFlag = false
						ps.ErrorFlag = false
						ps.ReturnFlag = false

						psTemp := env.ProgramState{}
						err := copier.Copy(&psTemp, &ps)
						if err != nil {
							fmt.Println(err.Error())
						}

						evaldo.CallCurriedCallerArgsN(handler, ps, *env.NewNative(ps.Idx, w, "Go-server-response-writer"), *env.NewNative(ps.Idx, r, "Go-server-request"))

						if ps.FailureFlag || ps.ErrorFlag {
							fmt.Println("Error in HTTP handler: " + ps.Res.Inspect(*ps.Idx))
						}
					})
					return arg0
				case env.Native:

					http.Handle(path.Value, handler.Value.(http.Handler))
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType, env.FunctionType, env.NativeType}, "Go-server//Handle")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server//Handle")
			}
		},
	},

	"Go-server-response-writer//Write": {
		Argsn: 2,
		Doc:   "Writes string content to the HTTP response body, used within HTTP request handlers to send response data to clients.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Native:
				switch handler := arg1.(type) {
				case env.String:

					fmt.Fprintf(path.Value.(http.ResponseWriter), handler.Value)
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-response-writer//Write")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-response-writer//Write")
			}
		},
	},

	"Go-server-response-writer//Set-content-type": {
		Argsn: 2,
		Doc:   "Sets the Content-Type header for the HTTP response, determining how the browser interprets the response data.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Native:
				switch handler := arg1.(type) {
				case env.String:

					path.Value.(http.ResponseWriter).Header().Set("Content-Type", handler.Value)
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-response-writer//Set-content-type")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-response-writer//Set-content-type")
			}
		},
	},

	"Go-server-response-writer//Set-header": {
		Argsn: 3,
		Doc:   "Sets a custom HTTP header in the response, allowing control over caching, security, and other HTTP behaviors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch writer := arg0.(type) {
			case env.Native:
				switch name := arg1.(type) {
				case env.Word:

					name_ := ps.Idx.GetWord(name.Index)
					switch value := arg2.(type) {
					case env.String:

						writer.Value.(http.ResponseWriter).Header().Set(name_, value.Value)
						return arg0
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "Go-server-response-writer//Set-header")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "Go-server-response-writer//Set-header")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-response-writer//Set-header")
			}
		},
	},

	"Go-server-response-writer//Add-header": {
		Argsn: 3,
		Doc:   "Adds a custom HTTP header value in the response, preserving existing values for multi-value headers.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch writer := arg0.(type) {
			case env.Native:
				switch name := arg1.(type) {
				case env.Word:
					name_ := ps.Idx.GetWord(name.Index)
					switch value := arg2.(type) {
					case env.String:
						writer.Value.(http.ResponseWriter).Header().Add(name_, value.Value)
						return arg0
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "Go-server-response-writer//Add-header")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "Go-server-response-writer//Add-header")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-response-writer//Add-header")
			}
		},
	},

	"Go-server-response-writer//Write-header": {
		Argsn: 2,
		Doc:   "Sets the HTTP status code for the response (must be called before writing response body).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch w := arg0.(type) {
			case env.Native:
				switch code := arg1.(type) {
				case env.Integer:

					w.Value.(http.ResponseWriter).WriteHeader(int(code.Value))
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "Go-server-response-writer//Write-header")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-response-writer//Write-header")
			}
		},
	},

	"Go-server//Handle-ws": {
		Argsn: 3,
		Doc:   "Registers a WebSocket handler for a specific path pattern on the server, upgrading HTTP connections to WebSocket protocol.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg1.(type) {
			case env.String:
				switch handler := arg2.(type) {
				case env.Function:
					http.HandleFunc(path.Value, func(w http.ResponseWriter, r *http.Request) {
						conn, _, _, err := ws.UpgradeHTTP(r, w)
						if err != nil {

							return
						}
						go func() {
							defer conn.Close()
							ps.FailureFlag = false
							ps.ErrorFlag = false
							ps.ReturnFlag = false
							psTemp := env.ProgramState{}
							err := copier.Copy(&psTemp, &ps)
							if err != nil {
								return
							}
							evaldo.CallFunctionArgs2(handler, &psTemp, *env.NewNative(psTemp.Idx, conn, "Go-server-websocket"), *env.NewNative(psTemp.Idx, "asd", "Go-server-context"), nil)
						}()
					})
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType}, "Go-server//Handle-ws")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server//Handle-ws")
			}
		},
	},

	"Go-server-websocket//Read": {
		Argsn: 1,
		Doc:   "Reads a message from a WebSocket connection, blocking until data is available or an error occurs.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch conn := arg0.(type) {
			case env.Native:
				msg, _, err := wsutil.ReadClientData(conn.Value.(io.ReadWriter))
				if err != nil {
					ps.ReturnFlag = true
					ps.FailureFlag = true
					ps.ErrorFlag = true
					return evaldo.MakeBuiltinError(ps, "Error in reading client data.", "Go-server-websocket//Read")
				}
				return env.NewString(string(msg))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-websocket//Read")
			}
		},
	},

	"Go-server-websocket//Write": {
		Argsn: 2,
		Doc:   "Writes a message to a WebSocket connection, sending data to the connected client.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch sock := arg0.(type) {
			case env.Native:
				switch message := arg1.(type) {
				case env.String:
					err := wsutil.WriteServerMessage(sock.Value.(io.Writer), ws.OpText, []byte(message.Value))
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Failed to write server message.", "Go-server-websocket//Write")
					}
					return arg1
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-websocket//Write")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-websocket//Write")
			}
		},
	},

	"Go-server-request//Query?": {
		Argsn: 2,
		Doc:   "Retrieves a query parameter value from the HTTP request URL (e.g., from ?name=value&other=data).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				switch key := arg1.(type) {
				case env.String:

					vals, ok := req.Value.(*http.Request).URL.Query()[key.Value]

					if !ok || len(vals[0]) < 1 {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Key is missing.", "Go-server-request//query?")
					}

					return *env.NewString(vals[0])
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-request//query?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//query?")
			}
		},
	},

	"Go-server-request//Header?": {
		Argsn: 2,
		Doc:   "Gets a header value from the HTTP request by name.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				switch name := arg1.(type) {
				case env.String:
					val := req.Value.(*http.Request).Header.Get(name.Value)
					return *env.NewString(val)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-request//header?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//header?")
			}
		},
	},

	"Go-server-request//Basic-auth?": {
		Argsn: 1,
		Doc:   "Gets HTTP Basic Authentication credentials from the request as [username password].",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				username, password, ok := req.Value.(*http.Request).BasicAuth()
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Basic auth credentials are missing.", "Go-server-request//basic-auth?")
				}
				pair := make([]env.Object, 2)
				pair[0] = *env.NewString(username)
				pair[1] = *env.NewString(password)
				return *env.NewBlock(*env.NewTSeries(pair))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//basic-auth?")
			}
		},
	},

	"Go-server-request//Method?": {
		Argsn: 1,
		Doc:   "Gets the HTTP request method.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				return *env.NewString(req.Value.(*http.Request).Method)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//method?")
			}
		},
	},

	"Go-server-request//Read-body": {
		Argsn: 1,
		Doc:   "Reads the HTTP request body as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				data, err := io.ReadAll(req.Value.(*http.Request).Body)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "Go-server-request//read-body")
				}
				return *env.NewString(string(data))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//read-body")
			}
		},
	},

	"Go-server-request//Headers?": {
		Argsn: 1,
		Doc:   "Gets all HTTP request headers as a dictionary.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				headers := make(map[string]any)
				for key, values := range req.Value.(*http.Request).Header {
					if len(values) == 0 {
						headers[key] = ""
					} else if len(values) == 1 {
						headers[key] = values[0]
					} else {
						vals := make([]env.Object, len(values))
						for i, v := range values {
							vals[i] = *env.NewString(v)
						}
						headers[key] = *env.NewBlock(*env.NewTSeries(vals))
					}
				}
				return *env.NewDict(headers)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//headers?")
			}
		},
	},

	"Go-server-request//Url?": {
		Argsn: 1,
		Doc:   "Extracts the URL object from an HTTP request, providing access to path, query parameters, and other URL components.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:

				vals := req.Value.(*http.Request).URL
				return *env.NewNative(ps.Idx, vals, "Go-server-url")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//url?")
			}
		},
	},

	"Go-server-url//Path?": {
		Argsn: 1,
		Doc:   "Extracts the path component from a URL object (the part after the domain and before query parameters).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:

				val := req.Value.(*url.URL).Path
				return *env.NewString(val)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-url//path?")
			}
		},
	},

	"Go-server-request//Cookie-val?": {
		Argsn: 2,
		Doc:   "Get cookie value from server request.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				switch key := arg1.(type) {
				case env.String:
					cookie, err := req.Value.(*http.Request).Cookie(key.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Cookie key is missing.", "Go-server-request//cookie-val?")
					}
					return *env.NewString(cookie.Value)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-request//cookie-val?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//cookie-val?")
			}
		},
	},

	"Go-server-request//Form?": {
		Argsn: 2,
		Doc:   "Get form field from server request.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				switch key := arg1.(type) {
				case env.String:
					r := req.Value.(*http.Request)
					err := r.ParseForm()
					if err != nil {
						return evaldo.MakeError(ps, err.Error())
					}
					val := r.FormValue(key.Value)
					if len(val) < 1 {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Value is missing.", "Go-server-request//form?")
					}
					return *env.NewString(val)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-request//form?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//form?")
			}
		},
	},

	"Go-server-request//Full-form?": {
		Argsn: 1,
		Doc:   "Get full form data as Dict from server request.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				r := req.Value.(*http.Request)
				err := r.ParseForm()
				if err != nil {
					return evaldo.MakeError(ps, err.Error())
				}
				dict := make(map[string]any)
				for key, val := range r.Form {
					dict[key] = val[0]
				}
				return *env.NewDict(dict)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//full-form?")
			}
		},
	},

	"Go-server-request//Parse-multipart-form!": {
		Argsn: 1,
		Doc:   "Parse multipart form from server request.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				r := req.Value.(*http.Request)

				err := r.ParseMultipartForm(10 << 20)
				if err != nil {
					return evaldo.MakeError(ps, err.Error())
				}
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//parse-multipart-form!")
			}
		},
	},

	"Go-server-request//Form-file?": {
		Argsn: 2,
		Doc:   "Get form file from server request as block with reader and multipart header.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				switch key := arg1.(type) {
				case env.String:
					r := req.Value.(*http.Request)
					file, handler, err := r.FormFile(key.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to read from file: '%v'", err.Error()), "Go-server-request//form-file?")
					}
					pair := make([]env.Object, 2)
					pair[0] = *env.NewNative(ps.Idx, file, "reader")
					pair[1] = *env.NewNative(ps.Idx, handler, "rye-multipart-header")
					return *env.NewBlock(*env.NewTSeries(pair))
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-request//form-file?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//form-file?")
			}
		},
	},

	"rye-multipart-header//Filename?": {
		Argsn: 1,
		Doc:   "Get filename from multipart header.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				r := req.Value.(*multipart.FileHeader)
				return *env.NewString(r.Filename)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "rye-multipart-header//filename?")
			}
		},
	},

	"cookie-store": {
		Argsn: 1,
		Doc:   "Create new cookie store.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.String:
				return *env.NewNative(ps.Idx, sessions.NewCookieStore([]byte(addr.Value)), "Http-cookie-store")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "new-cookie-store")
			}
		},
	},

	"Http-cookie-store//Get": {
		Argsn: 3,
		Doc:   "Get http cookie store.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch store := arg0.(type) {
			case env.Native:
				switch r := arg1.(type) {
				case env.Native:
					switch name := arg2.(type) {
					case env.String:

						session, err := store.Value.(*sessions.CookieStore).Get(r.Value.(*http.Request), name.Value)
						if err != nil {
							ps.FailureFlag = true
							errMsg := fmt.Sprintf("Can't get session: %v", err.Error())
							return evaldo.MakeBuiltinError(ps, errMsg, "Http-cookie-store//get")
						}

						return *env.NewNative(ps.Idx, session, "Http-session")
					default:

						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "Http-cookie-store//get")
					}
				default:

					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Http-cookie-store//get")
				}
			default:

				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Http-cookie-store//get")
			}
		},
	},

	"Http-session//Set": {
		Argsn: 3,
		Doc:   "Set http session.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch session := arg0.(type) {
			case env.Native:
				switch key := arg1.(type) {
				case env.String:
					switch val := arg2.(type) {
					case env.String:

						session.Value.(*sessions.Session).Values[key.Value] = val.Value
						return arg0
					case env.Integer:
						session.Value.(*sessions.Session).Values[key.Value] = int(val.Value)
						return arg0
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType, env.IntegerType}, "Http-session//set")
					}

				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Http-session//set")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Http-session//set")
			}
		},
	},

	"Http-session//Get": {
		Argsn: 2,
		Doc:   "Get http session.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch session := arg0.(type) {
			case env.Native:
				switch key := arg1.(type) {
				case env.String:
					val := session.Value.(*sessions.Session).Values[key.Value]
					if val != nil {
						switch val2 := val.(type) {
						case int:
							return env.NewInteger(int64(val2))
						case string:
							return env.NewString(val2)
						case env.Object:
							return val2
						default:
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "Unknown type.", "Http-session//get")
						}
					} else {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Value is empty.", "Http-session//get")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Http-session//get")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Http-session//get")
			}
		},
	},

	"Http-session//Save": {
		Argsn: 3,
		Doc:   "Save http session.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch session := arg0.(type) {
			case env.Native:
				switch r := arg1.(type) {
				case env.Native:
					switch w := arg2.(type) {
					case env.Native:
						err := session.Value.(*sessions.Session).Save(r.Value.(*http.Request), w.Value.(http.ResponseWriter))
						if err != nil {
							ps.FailureFlag = true
							errMsg := fmt.Sprintf("Can't save: %v", err.Error())
							return evaldo.MakeBuiltinError(ps, errMsg, "Http-session//save")
						}
						return *env.NewInteger(1)
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.NativeType}, "Http-session//save")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "Http-session//save")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Http-session//save")
			}
		},
	},

	"http-dir": {
		Argsn: 1,
		Doc:   "Create new http directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.Uri:
				return *env.NewNative(ps.Idx, http.Dir(addr.Path), "Go-http-dir")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "http-dir")
			}
		},
	},
	"new-static-handler": {
		Argsn: 1,
		Doc:   "Create new static handler.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.Uri:
				return *env.NewNative(ps.Idx, http.FileServer(http.Dir(addr.Path)), "Http-handler")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "new-static-handler")
			}

		},
	},

	"Http-handler//Strip-prefix": {
		Argsn: 2,
		Doc:   "Wraps an HTTP handler to strip a URL prefix from requests, useful for serving static files from a subdirectory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch prefix := arg1.(type) {
			case env.String:
				switch servr := arg0.(type) {
				case env.Native:
					return *env.NewNative(ps.Idx, http.StripPrefix(prefix.Value, servr.Value.(http.Handler)), "Http-handler")
				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Http-handler//Strip-prefix")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Http-handler//Strip-prefix")
			}
		},
	},

	"https-response//Header?": {
		Argsn: 2,
		Doc:   "Get header value from HTTP response.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch resp := arg0.(type) {
			case env.Native:
				switch headerName := arg1.(type) {
				case env.String:
					response := resp.Value.(*http.Response)
					headerValue := response.Header.Get(headerName.Value)
					return *env.NewString(headerValue)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "https-response//Header?")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-response//Header?")
			}
		},
	},

	"https-response//Status?": {
		Argsn: 1,
		Doc:   "Gets the HTTP status code from a response object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch resp := arg0.(type) {
			case env.Native:
				response := resp.Value.(*http.Response)
				return *env.NewInteger(int64(response.StatusCode))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-response//Status?")
			}
		},
	},

	"https-response//Status-text?": {
		Argsn: 1,
		Doc:   "Gets the HTTP status text from a response object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch resp := arg0.(type) {
			case env.Native:
				response := resp.Value.(*http.Response)
				return *env.NewString(response.Status)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-response//Status-text?")
			}
		},
	},
}
View Source
var Builtins_io = map[string]*env.Builtin{

	"input": {
		Argsn: 1,
		Doc:   "Prompts for and reads user input from the console.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.String:
				fmt.Print("" + str.Value)
				var input string
				fmt.Scanln(&input)

				return *env.NewString(input)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "input")
			}
		},
	},

	"file-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a file for reading.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				file, err := os.Open(s.Path)
				if err != nil {
					return evaldo.MakeError(ps, err.Error())
				}
				return *env.NewNative(ps.Idx, file, "file")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Open")
			}
		},
	},

	"file-uri//Open\\append": {
		Argsn: 1,
		Doc:   "Opens a file for appending.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			profile, exists := os.LookupEnv("RYE_SECCOMP_PROFILE")
			if exists && profile == "readonly" {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "file append operation blocked by readonly seccomp profile", "file-uri//Open\\append")
			}

			switch s := arg0.(type) {
			case env.Uri:
				file, err := os.OpenFile(s.Path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "__openFile")
				}
				return *env.NewNative(ps.Idx, file, "file")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "__openFile")
			}
		},
	},

	"file-uri//Create": {
		Argsn: 1,
		Doc:   "Creates a new file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			profile, exists := os.LookupEnv("RYE_SECCOMP_PROFILE")
			if exists && profile == "readonly" {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "file creation blocked by readonly seccomp profile", "file-uri//Create")
			}

			switch s := arg0.(type) {
			case env.Uri:

				file, err := os.Create(s.Path)
				if err != nil {
					ps.ReturnFlag = true
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "__create")
				}
				return *env.NewNative(ps.Idx, file, "file")
			default:
				ps.ReturnFlag = true
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "__create")
			}
		},
	},

	"file-uri//Ext?": {
		Argsn: 1,
		Doc:   "Gets the extension of a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				ext := filepath.Ext(s.Path)
				return *env.NewString(ext)

			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.StringType}, "Ext?")
			}
		},
	},

	"file-uri//Name?": {
		Argsn: 1,
		Doc:   "Gets the filename with extension from a file path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				filename := filepath.Base(s.Path)
				return *env.NewString(filename)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "Name?")
			}
		},
	},

	"file-uri//Stem?": {
		Argsn: 1,
		Doc:   "Gets the filename without extension from a file path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				base := filepath.Base(s.Path)
				stem := strings.TrimSuffix(base, filepath.Ext(base))
				return *env.NewString(stem)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Stem?")
			}
		},
	},

	"file-uri//Dir?": {
		Argsn: 1,
		Doc:   "Gets the directory path from a file path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				dir := filepath.Dir(s.Path)
				return *env.NewString(dir)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Dir?")
			}
		},
	},

	"file-uri//Split": {
		Argsn: 1,
		Doc:   "Splits a file path into its components.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				pathStr := s.Path
				var components []env.Object

				parts := strings.Split(pathStr, string(filepath.Separator))
				for _, part := range parts {
					if part != "" {
						components = append(components, *env.NewString(part))
					}
				}

				if filepath.IsAbs(pathStr) && len(components) > 0 {
					components = append([]env.Object{*env.NewString(string(filepath.Separator))}, components...)
				}

				return *env.NewBlock(*env.NewTSeries(components))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Split")
			}
		},
	},

	"file-uri//Is-absolute": {
		Argsn: 1,
		Doc:   "Checks if a file path is absolute.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				isAbs := filepath.IsAbs(s.Path)
				return *env.NewBoolean(isAbs)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Is-absolute")
			}
		},
	},

	"file-uri//Does-exist": {
		Argsn: 1,
		Doc:   "Checks if a file exists.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				_, err := os.Stat(s.Path)
				if err == nil {
					return *env.NewBoolean(true)
				}
				if os.IsNotExist(err) {
					return *env.NewBoolean(false)
				}

				return *env.NewBoolean(false)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Does-exist")
			}
		},
	},

	"file-uri//Delete": {
		Argsn: 1,
		Doc:   "Deletes a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			profile, exists := os.LookupEnv("RYE_SECCOMP_PROFILE")
			if exists && profile == "readonly" {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "delete operation blocked by readonly seccomp profile", "file-uri//Delete")
			}

			switch s := arg0.(type) {
			case env.Uri:
				err := os.Remove(s.Path)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "file-uri//Delete")
				}
				return *env.NewBoolean(true)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Delete")
			}
		},
	},

	"file//Reader": {
		Argsn: 1,
		Doc:   "Creates a new reader from file object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch s := arg0.(type) {
			case env.Native:
				file, ok := s.Value.(*os.File)
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error opening file.", "file//Reader")
				}
				return *env.NewNative(ps.Idx, bufio.NewReader(file), "reader")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "file//Reader")
			}
		},
	},

	"file//Writer": {
		Argsn: 1,
		Doc:   "Creates a new reader from file object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch s := arg0.(type) {
			case env.Native:
				file, ok := s.Value.(*os.File)
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error opening file.", "file//Reader")
				}
				return *env.NewNative(ps.Idx, bufio.NewWriter(file), "writer")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "file//Reader")
			}
		},
	},

	"file-uri//Reader": {
		Argsn: 1,
		Doc:   "Creates a new reader from a file uri/path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				file, err := os.Open(s.Path)

				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error opening file.", "file-uri//Reader")
				}
				return *env.NewNative(ps.Idx, bufio.NewReader(file), "reader")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Read")
			}
		},
	},

	"reader": {
		Argsn: 1,
		Doc:   "Creates a new reader from a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.String:
				return *env.NewNative(ps.Idx, bufio.NewReader(strings.NewReader(s.Value)), "reader")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "reader")
			}
		},
	},

	"stdin": {
		Argsn: 0,
		Doc:   "Gets a reader for standard input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, os.Stdin, "reader")
		},
	},

	"stdout": {
		Argsn: 0,
		Doc:   "Gets a writer for standard output.",
		Fn: func(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(env1.Idx, os.Stdout, "writer")
		},
	},

	"stderr": {
		Argsn: 0,
		Doc:   "Gets a writer for standard error.",
		Fn: func(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(env1.Idx, os.Stderr, "writer")
		},
	},

	"reader//Read\\string": {
		Argsn: 1,
		Doc:   "Reads all content from a reader as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch r := arg0.(type) {
			case env.Native:
				reader, ok := r.Value.(io.Reader)
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Not Reader", "__read\\string")
				}
				buf := new(strings.Builder)
				_, err := io.Copy(buf, reader)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "__read\\string")
				}
				return *env.NewString(buf.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "__read\\string")
			}

		},
	},

	"reader//Close": {
		Argsn: 1,
		Doc:   "Closes a reader if it implements io.Closer.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch r := arg0.(type) {
			case env.Native:

				if closer, ok := r.Value.(io.Closer); ok {
					err := closer.Close()
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "reader//Close")
					}
					return *env.NewString("")
				}

				return *env.NewString("")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "reader//Close")
			}
		},
	},

	"reader//Copy": {
		Argsn: 2,
		Doc:   "Copies all content from a reader to a writer.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch r := arg0.(type) {
			case env.Native:
				switch w := arg1.(type) {
				case env.Native:

					_, err := io.Copy(w.Value.(io.Writer), r.Value.(io.Reader))
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "__copy")
					}
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "__copy")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "__copy")
			}

		},
	},

	"file//Copy": {
		Argsn: 2,
		Doc:   "Copies content from a file to a writer.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch r := arg0.(type) {
			case env.Native:
				switch w := arg1.(type) {
				case env.Native:

					_, err := io.Copy(w.Value.(io.Writer), r.Value.(io.Reader))
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "__copy")
					}
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "__copy")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "__copy")
			}

		},
	},

	"file//Stat": {
		Argsn: 1,
		Doc:   "Gets file information (stat) for a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch r := arg0.(type) {
			case env.Native:
				info, err := r.Value.(*os.File).Stat()
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "file//Stat")
				}
				return *env.NewNative(ps.Idx, info, "file-info")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "file//Stat")
			}
		},
	},

	"file-info//Size?": {
		Argsn: 1,
		Doc:   "Gets the size of a file in bytes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Native:
				size := s.Value.(os.FileInfo).Size()
				return *env.NewInteger(size)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "file-info//Size?")
			}
		},
	},

	"file//Read": {
		Argsn: 1,
		Doc:   "Reads the entire content of a file as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Native:
				data, err := io.ReadAll(s.Value.(io.Reader))
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error reading file.", "Read")
				}
				return *env.NewString(string(data))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Read")
			}
		},
	},

	"file//Seek\\end": {
		Argsn: 1,
		Doc:   "Seeks to the end of a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Native:
				reader, ok := s.Value.(*os.File)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Native not io.Reader", "file//Seek\\end")
				}
				reader.Seek(0, os.SEEK_END)
				return arg0
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "file//Seek\\end")
			}
		},
	},

	"file//Write": {
		Argsn: 2,
		Doc:   "Writes a string directly to a file object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			profile, exists := os.LookupEnv("RYE_SECCOMP_PROFILE")
			if exists && profile == "readonly" {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "write operation blocked by readonly seccomp profile", "file//Write")
			}

			switch s := arg0.(type) {
			case env.Native:
				file, ok := s.Value.(*os.File)
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Native not os.File", "file//Write")
				}
				switch content := arg1.(type) {
				case env.String:
					_, err := file.WriteString(content.Value)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "file//Write")
					}
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "file//Write")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "file//Write")
			}
		},
	},

	"file//Close": {
		Argsn: 1,
		Doc:   "Closes an open file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Native:
				err := s.Value.(*os.File).Close()
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "__close")
				}
				return *env.NewString("")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "__close")
			}

		},
	},

	"file-uri//Read": {
		Argsn: 1,
		Doc:   "Reads the entire content of a file as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:
				data, err := os.ReadFile(f.GetPath())
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "file-uri//Read")
				}
				return *env.NewString(string(data))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Read")
			}
		},
	},

	"file-uri//Read\\bytes": {
		Argsn: 1,
		Doc:   "Reads the entire content of a file as bytes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:
				data, err := os.ReadFile(f.GetPath())
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "__fs_read_bytes")
				}
				return *env.NewBytes(data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "__fs_read_bytes")
			}
		},
	},

	"file-uri//Read\\lines": {
		Argsn: 1,
		Doc:   "Reads a file and returns its content as a block of lines.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:
				file, err := os.OpenFile(f.GetPath(), os.O_RDONLY, os.ModePerm)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "file-uri//Read\\lines")
				}
				defer file.Close()

				lines := make([]env.Object, 0)
				sc := bufio.NewScanner(file)
				for sc.Scan() {
					lines = append(lines, *env.NewString(sc.Text()))
				}
				if err := sc.Err(); err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "file-uri//Read\\lines")
				}
				return *env.NewBlock(*env.NewTSeries(lines))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Read\\lines")
			}
		},
	},

	"file-uri//Write": {
		Argsn: 2,
		Doc:   "Writes content to a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			profile, exists := os.LookupEnv("RYE_SECCOMP_PROFILE")
			if exists && profile == "readonly" {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "write operation blocked by readonly seccomp profile", "file-uri//Write")
			}

			switch f := arg0.(type) {
			case env.Uri:
				switch s := arg1.(type) {
				case env.String:
					err := os.WriteFile(f.GetPath(), []byte(s.Value), 0600)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "__fs_write")
					}
					return arg1
				case env.Native:
					err := os.WriteFile(f.GetPath(), s.Value.([]byte), 0600)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "__fs_write")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType, env.NativeType}, "__fs_write")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "__fs_write")
			}
		},
	},

	"write\\bytes": {
		Argsn: 2,
		Doc:   "Writes bytes to a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bytesObj := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(bytesObj.GetKind()) != "Go-bytes" {
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "write-file")
				}
				switch path := arg1.(type) {
				case env.String:
					err := os.WriteFile(path.Value, bytesObj.Value.([]byte), 0644)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to write file: %v", err), "write-file")
					}
					return env.Integer{1}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "write-file")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "write-file")
			}
		},
	},

	"append\\bytes": {
		Argsn: 2,
		Doc:   "Appends two byte arrays into one.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bytes1 := arg0.(type) {
			case env.Bytes:
				switch bytes2 := arg1.(type) {
				case env.Bytes:
					combined := append(bytes1.Value, bytes2.Value...)
					return *env.NewBytes(combined)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BytesType}, "append-bytes")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BytesType}, "append-bytes")
			}
		},
	},

	"writer//Write": {
		Argsn: 2,
		Doc:   "Writes a string to a writer.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			profile, exists := os.LookupEnv("RYE_SECCOMP_PROFILE")
			if exists && profile == "readonly" {

				switch ww := arg0.(type) {
				case env.Native:
					_, ok := ww.Value.(io.Writer)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "Native not io.Writer", "writer//Write")
					}
				}
			}

			switch s := arg1.(type) {
			case env.String:
				switch ww := arg0.(type) {
				case env.Native:

					if bw, ok := ww.Value.(*bufio.Writer); ok {
						_, err := bw.WriteString(s.Value)
						if err != nil {
							return evaldo.MakeBuiltinError(ps, "Error at write: "+err.Error(), "writer//Write")
						}
						return arg0
					}

					if w, ok := ww.Value.(io.Writer); ok {
						_, err := io.WriteString(w, s.Value)
						if err != nil {
							return evaldo.MakeBuiltinError(ps, "Error at write: "+err.Error(), "writer//Write")
						}
						return arg0
					}
					return evaldo.MakeBuiltinError(ps, "Native not io.Writer", "writer//Write")
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "writer//Write")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "writer//Write")
			}
		},
	},

	"https-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a HTTPS GET request and returns a reader for the response body.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:

				proto := ps.Idx.GetWord(f.GetProtocol().Index)

				req, err := http.NewRequest(http.MethodGet, proto+"://"+f.GetPath(), nil)
				if err != nil {
					ps.FailureFlag = true
					return *env.NewError(err.Error())
				}
				resp, err := http.DefaultClient.Do(req)
				if err != nil {
					ps.FailureFlag = true
					return *env.NewError(err.Error())
				}

				if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
					return *env.NewNative(ps.Idx, resp.Body, "https-uri://open")
				} else {
					ps.FailureFlag = true
					errMsg := fmt.Sprintf("Status Code: %v", resp.StatusCode)
					return evaldo.MakeBuiltinError(ps, errMsg, "https-uri://Open")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-uri://Open")
			}
		},
	},

	"https-uri//Get": {
		Argsn: 1,
		Doc:   "Makes a HTTPS GET request and returns the response body as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:
				proto := ps.Idx.GetWord(f.GetProtocol().Index)
				req, err := http.NewRequest(http.MethodGet, proto+"://"+f.GetPath(), nil)
				if err != nil {
					ps.FailureFlag = true
					return *env.NewError(err.Error())
				}
				resp, err := http.DefaultClient.Do(req)
				if err != nil {
					ps.FailureFlag = true
					return *env.NewError(err.Error())
				}
				defer resp.Body.Close()
				body, _ := io.ReadAll(resp.Body)

				if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
					return *env.NewString(string(body))
				} else {
					ps.FailureFlag = true
					errMsg := fmt.Sprintf("Status Code: %v", resp.StatusCode)
					return evaldo.MakeBuiltinError(ps, errMsg, "https-uri//Get")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "https-uri//Get")
			}
		},
	},

	"https-uri//Post": {
		Argsn: 3,
		Doc:   "Makes a HTTPS POST request and returns the response body as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:
				switch d := arg1.(type) {
				case env.String:
					var tt string

					switch t := arg2.(type) {
					case env.Word:

						tidx, terr := ps.Idx.GetIndex("json")
						tidx2, terr2 := ps.Idx.GetIndex("text")
						tidx3, terr3 := ps.Idx.GetIndex("urlencoded")
						tidx4, terr4 := ps.Idx.GetIndex("multipart")
						if terr && t.Index == tidx {
							tt = "application/json"
						} else if terr2 && t.Index == tidx2 {
							tt = "text/plain"
						} else if terr3 && t.Index == tidx3 {
							tt = "application/x-www-form-urlencoded"
						} else if terr4 && t.Index == tidx4 {
							tt = "multipart/form-data"
						} else {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "Wrong content type.", "https-uri//Post")
						}
					case env.String:

						tt = t.Value
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.WordType, env.StringType}, "https-uri//Post")
					}

					proto := ps.Idx.GetWord(f.GetProtocol().Index)
					req, err := http.NewRequest(http.MethodPost, proto+"://"+f.GetPath(), strings.NewReader(d.Value))
					if err != nil {
						ps.FailureFlag = true
						return *env.NewError(err.Error())
					}
					req.Header.Set("Content-Type", tt)
					resp, err := http.DefaultClient.Do(req)
					if err != nil {
						ps.FailureFlag = true
						return *env.NewError(err.Error())
					}
					defer resp.Body.Close()
					body, err := io.ReadAll(resp.Body)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "https-uri//Post")
					}

					if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
						return *env.NewString(string(body))
					} else {
						ps.FailureFlag = true
						return env.NewError2(resp.StatusCode, string(body))
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "https-uri//Post")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "https-uri//Post")
			}
		},
	},

	"http-uri//Get": {
		Argsn: 1,
		Doc:   "Makes a HTTP GET request and returns the response body as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:
				proto := ps.Idx.GetWord(f.GetProtocol().Index)
				req, err := http.NewRequest(http.MethodGet, proto+"://"+f.GetPath(), nil)
				if err != nil {
					ps.FailureFlag = true
					return *env.NewError(err.Error())
				}
				resp, err := http.DefaultClient.Do(req)
				if err != nil {
					ps.FailureFlag = true
					return *env.NewError(err.Error())
				}
				defer resp.Body.Close()
				body, _ := io.ReadAll(resp.Body)

				if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
					return *env.NewString(string(body))
				} else {
					ps.FailureFlag = true
					errMsg := fmt.Sprintf("Status Code: %v", resp.StatusCode)
					return evaldo.MakeBuiltinError(ps, errMsg, "http-uri//Get")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "http-uri//Get")
			}
		},
	},

	"http-uri//Post": {
		Argsn: 3,
		Doc:   "Makes a HTTP POST request and returns the response body as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Uri:
				switch t := arg2.(type) {
				case env.Word:
					switch d := arg1.(type) {
					case env.String:
						var tt string
						tidx, terr := ps.Idx.GetIndex("json")
						tidx2, terr2 := ps.Idx.GetIndex("text")
						if terr && t.Index == tidx {
							tt = "application/json"
						} else if terr2 && t.Index == tidx2 {
							tt = "text/plain"
						} else {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "Wrong content type.", "http-uri//Post")
						}

						proto := ps.Idx.GetWord(f.GetProtocol().Index)
						req, err := http.NewRequest(http.MethodPost, proto+"://"+f.GetPath(), strings.NewReader(d.Value))
						if err != nil {
							ps.FailureFlag = true
							return *env.NewError(err.Error())
						}
						req.Header.Set("Content-Type", tt)
						resp, err := http.DefaultClient.Do(req)
						if err != nil {
							ps.FailureFlag = true
							return *env.NewError(err.Error())
						}
						defer resp.Body.Close()
						body, err := io.ReadAll(resp.Body)
						if err != nil {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, err.Error(), "http-uri//Post")
						}

						if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
							return *env.NewString(string(body))
						} else {
							ps.FailureFlag = true
							return env.NewError2(resp.StatusCode, string(body))
						}
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "http-uri//Post")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 3, []env.Type{env.WordType}, "http-uri//Post")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "http-uri//Post")
			}
		},
	},

	"https-uri//Request": {
		Argsn: 3,
		Doc:   "Creates a new HTTPS request object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch uri := arg0.(type) {
			case env.Uri:
				switch method := arg1.(type) {
				case env.Word:
					method1 := ps.Idx.GetWord(method.Index)
					if !(method1 == "GET" || method1 == "POST" || method1 == "PUT" || method1 == "DELETE") {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Wrong method.", "https-uri//Request")
					}
					switch data := arg2.(type) {
					case env.String:
						data1 := strings.NewReader(data.Value)
						proto := ps.Idx.GetWord(uri.GetProtocol().Index)
						req, err := http.NewRequest(method1, proto+"://"+uri.GetPath(), data1)
						if err != nil {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, err.Error(), "https-uri//Request")
						}
						return *env.NewNative(ps.Idx, req, "https-request")
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "https-uri//Request")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "https-uri//Request")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "https-uri//Request")
			}
		},
	},

	"https-request//Header!": {
		Argsn: 3,
		Doc:   "Sets a header on a HTTPS request.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				switch method := arg1.(type) {
				case env.Word:
					name := ps.Idx.GetWord(method.Index)
					switch data := arg2.(type) {
					case env.String:
						req.Value.(*http.Request).Header.Set(name, data.Value)
						return arg0
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "https-request//Header!")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "https-request//Header!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-request//Header!")
			}
		},
	},

	"https-request//Basic-auth!": {
		Argsn: 3,
		Doc:   "Sets Basic Authentication on a HTTPS request.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				switch username := arg1.(type) {
				case env.String:
					switch password := arg2.(type) {
					case env.String:
						req.Value.(*http.Request).SetBasicAuth(username.Value, password.Value)
						return arg0
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "https-request//Basic-auth!")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "https-request//Basic-auth!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-request//Basic-auth!")
			}
		},
	},

	"https-request//Call": {
		Argsn: 1,
		Doc:   "Executes a HTTPS request and returns the response object. Always returns the response regardless of status code (200, 404, 500, etc.) - use Status? to check the code.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch req := arg0.(type) {
			case env.Native:
				client := &http.Client{}
				resp, err := client.Do(req.Value.(*http.Request))

				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "https-request//Call")
				}

				return *env.NewNative(ps.Idx, resp, "https-response")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-request//Call")
			}
		},
	},

	"https-response//Reader": {
		Argsn: 1,
		Doc:   "Gets a reader for the HTTPS response body that can be used with io.Copy.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch resp := arg0.(type) {
			case env.Native:

				return *env.NewNative(ps.Idx, resp.Value.(*http.Response).Body, "reader")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-response//Reader")
			}
		},
	},

	"https-response//Read-body": {
		Argsn: 1,
		Doc:   "Reads the body of a HTTPS response as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch resp := arg0.(type) {
			case env.Native:
				data, err := io.ReadAll(resp.Value.(*http.Response).Body)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "https-response//Read-body")
				}
				return *env.NewString(string(data))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-response//Read-body")
			}
		},
	},

	"https-response//Close-body!": {
		Argsn: 1,
		Doc:   "Closes the HTTPS response body to free network resources.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch resp := arg0.(type) {
			case env.Native:
				err := resp.Value.(*http.Response).Body.Close()
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "https-response//Close-body!")
				}
				return *env.NewString("")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-response//Close-body!")
			}
		},
	},

	"email//Send": {
		Argsn: 2,
		Doc:   "Sends an email to the specified address.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch to_ := arg0.(type) {
			case env.Email:
				switch msg := arg1.(type) {
				case env.String:
					idx, _ := ps.Idx.GetIndex("user-profile")
					uctx_, _ := ps.Ctx.Get(idx)
					uctx := uctx_.(*env.RyeCtx)
					fmt.Println(to_)
					fmt.Println(msg)
					fmt.Println(uctx)

					return *env.NewInteger(1)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "email//Send")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.EmailType}, "email//Send")
			}
		},
	},

	"ftp-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a connection to an FTP server.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch s := arg0.(type) {
			case env.Uri:
				conn, err := ftp.Dial(s.Path)
				if err != nil {
					fmt.Println("Error connecting to FTP server:", err)
					return evaldo.MakeBuiltinError(ps, "Error connecting to FTP server: "+err.Error(), "ftp-uri//Open")
				}

				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error opening file.", "ftp-uri//Open")
				}
				return *env.NewNative(ps.Idx, conn, "ftp-connection")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.StringType}, "ftp-uri//Open")
			}
		},
	},

	"ftp-connection//Login": {
		Argsn: 3,
		Doc:   "Logs in to an FTP server connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch s := arg0.(type) {
			case env.Native:
				username, ok := arg1.(env.String)
				if !ok {

					return nil
				}
				pwd, ok := arg2.(env.String)
				if !ok {

					return nil
				}
				err := s.Value.(*ftp.ServerConn).Login(username.Value, pwd.Value)
				if err != nil {

					fmt.Println("Error logging in:", err)
					return nil
				}
				return s
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.StringType}, "ftp-connection//Login")
			}
		},
	},

	"ftp-connection//Retrieve": {
		Argsn: 2,
		Doc:   "Retrieves a file from an FTP server.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch s := arg0.(type) {
			case env.Native:
				path, ok := arg1.(env.String)
				if !ok {

				}
				resp, err := s.Value.(*ftp.ServerConn).Retr(path.Value)
				if err != nil {
					fmt.Println("Error retrieving:", err)
					return nil
				}
				return *env.NewNative(ps.Idx, resp, "reader")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.StringType}, "ftp-connection//Retrieve")
			}
		},
	},

	"ftp-connection//Close": {
		Argsn: 1,
		Doc:   "Closes an FTP server connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(s.Kind.Index) != "ftp-connection" {
					return evaldo.MakeBuiltinError(ps, "Expected FTP connection.", "ftp-connection//Close")
				}
				conn, ok := s.Value.(*ftp.ServerConn)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Invalid FTP connection.", "ftp-connection//Close")
				}
				err := conn.Quit()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error closing FTP connection: %v", err.Error()), "ftp-connection//Close")
				}
				return *env.NewInteger(1)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "ftp-connection//Close")
			}
		},
	},

	"tail-file": {
		Argsn: 3,
		Doc:   "Tails a file, following it for new content. Used for monitoring log files.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var filePath string

			switch path := arg0.(type) {
			case env.Uri:
				filePath = path.GetPath()
			case env.String:
				filePath = path.Value
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.StringType}, "tail-file")
			}

			follow := true
			if arg1 != nil {
				switch f := arg1.(type) {
				case env.Boolean:
					follow = f.Value
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BooleanType}, "tail-file")
				}
			}

			reopen := true
			if arg2 != nil {
				switch r := arg2.(type) {
				case env.Boolean:
					reopen = r.Value
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BooleanType}, "tail-file")
				}
			}

			config := tail.Config{
				Follow: follow,
				ReOpen: reopen,
			}

			t, err := tail.TailFile(filePath, config)
			if err != nil {
				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, err.Error(), "tail-file")
			}

			return *env.NewNative(ps.Idx, t, "tail-file")
		},
	},

	"tail-file//Read-line": {
		Argsn: 1,
		Doc:   "Reads the next line from a tailed file. Blocks until a line is available.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch t := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(t.GetKind()) != "tail-file" {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected tail-file object", "tail-file//Read-line")
				}

				line, ok := <-t.Value.(*tail.Tail).Lines
				if !ok {

					return *env.NewVoid()
				}

				return *env.NewString(line.Text)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tail-file//Read-line")
			}
		},
	},

	"tail-file//Close": {
		Argsn: 1,
		Doc:   "Closes a tailed file, stopping the monitoring.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch t := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(t.GetKind()) != "tail-file" {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected tail-file object", "tail-file//Close")
				}

				err := t.Value.(*tail.Tail).Stop()
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "tail-file//Close")
				}

				return *env.NewString("")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tail-file//Close")
			}
		},
	},

	"unix-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a connection to a Unix domain socket.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Uri:
				conn, err := net.Dial("unix", s.Path)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error connecting to Unix socket: "+err.Error(), "unix-uri//Open")
				}
				return *env.NewNative(ps.Idx, conn, "unix-connection")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "unix-uri//Open")
			}
		},
	},

	"unix-connection//Write": {
		Argsn: 2,
		Doc:   "Writes data to a Unix domain socket connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch conn := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(conn.GetKind()) != "unix-connection" {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected unix-connection object", "unix-connection//Write")
				}
				switch data := arg1.(type) {
				case env.String:
					_, err := conn.Value.(net.Conn).Write([]byte(data.Value))
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Error writing to Unix socket: "+err.Error(), "unix-connection//Write")
					}
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "unix-connection//Write")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "unix-connection//Write")
			}
		},
	},

	"unix-connection//Read": {
		Argsn: 1,
		Doc:   "Reads data from a Unix domain socket connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch conn := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(conn.GetKind()) != "unix-connection" {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected unix-connection object", "unix-connection//Read")
				}
				buf := make([]byte, 1024)
				n, err := conn.Value.(net.Conn).Read(buf)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Error reading from Unix socket: "+err.Error(), "unix-connection//Read")
				}
				return *env.NewString(string(buf[:n]))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "unix-connection//Read")
			}
		},
	},

	"unix-connection//Close": {
		Argsn: 1,
		Doc:   "Closes a Unix domain socket connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch conn := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(conn.GetKind()) != "unix-connection" {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected unix-connection object", "unix-connection//Close")
				}
				err := conn.Value.(net.Conn).Close()
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "unix-connection//Close")
				}
				return *env.NewString("")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "unix-connection//Close")
			}
		},
	},
}
View Source
var Builtins_js_interop = map[string]*env.Builtin{}

JavaScript interop functions for Rye WASM

View Source
var Builtins_json = map[string]*env.Builtin{

	"parse-json": {
		Argsn: 1,
		Doc:   "Parses JSON string into Rye values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch input := arg0.(type) {
			case env.String:
				var m any
				err := json.Unmarshal([]byte(input.Value), &m)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Failed to Unmarshal.", "_parse_json")

				}
				return env.ToRyeValue(m)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "_parse_json")
			}
		},
	},

	"parse-json\\lines": {
		Argsn: 1,
		Doc:   "Parses JSON string into Rye values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch input := arg0.(type) {
			case env.String:
				var vals []any
				decoder := json.NewDecoder(strings.NewReader(input.Value))
				for decoder.More() {
					var m any
					err := decoder.Decode(&m)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Failed to Unmarshal.", "_parse_json\\lines")
					}
					vals = append(vals, env.ToRyeValue(m))
				}
				return *env.NewList(vals)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "_parse_json\\lines")
			}
		},
	},

	"to-json": {
		Argsn: 1,
		Doc:   "Converts a Rye value to a JSON string. Supports block (like list) and context (like dict).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(RyeToJSONWithIdxs(arg0, ps.Idx))
		},
	},

	"to-json\\lines": {
		Argsn: 1,
		Doc:   "Converts a table to JSON with each row on a separate line.",
		Fn: func(es *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(RyeToJSONLines(arg0))
		},
	},
}
View Source
var Builtins_mail = map[string]*env.Builtin{

	"reader//Parse-email": {
		Argsn: 1,
		Doc:   "Parses email data from a reader.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch reader := arg0.(type) {
			case env.Native:
				email, err := parsemail.Parse(reader.Value.(io.Reader))
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "reader//parse-email")
				}
				return *env.NewNative(ps.Idx, email, "parsed-email")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "reader//parse-email")
			}
		},
	},

	"parsed-email//Subject?": {
		Argsn: 1,
		Doc:   "Gets the subject from a parsed email.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch email := arg0.(type) {
			case env.Native:
				return *env.NewString(email.Value.(parsemail.Email).Subject)
			default:
				return *evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "parsed-email//Subject?")
			}
		},
	},

	"parsed-email//Message-id?": {
		Argsn: 1,
		Doc:   "Gets the message ID from a parsed email.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch email := arg0.(type) {
			case env.Native:
				return *env.NewString(email.Value.(parsemail.Email).MessageID)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "parsed-email//message-id?")
			}
		},
	},

	"parsed-email//Html-body?": {
		Argsn: 1,
		Doc:   "Gets the HTML body from a parsed email.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch email := arg0.(type) {
			case env.Native:
				return *env.NewString(email.Value.(parsemail.Email).HTMLBody)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "parsed-email//html-body?")
			}
		},
	},

	"parsed-email//Text-body?": {
		Argsn: 1,
		Doc:   "Gets the plain text body from a parsed email.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch email := arg0.(type) {
			case env.Native:
				return *env.NewString(email.Value.(parsemail.Email).TextBody)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "parsed-email//text-body?")
			}
		},
	},

	"parsed-email//Attachments?": {
		Argsn: 1,
		Doc:   "Gets the attachments from a parsed email.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, arg0, "smtpd")
		},
	},

	"parsed-email//Embedded-files?": {
		Argsn: 1,
		Doc:   "Gets the embedded files from a parsed email.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewNative(ps.Idx, arg0, "smtpd")
		},
	},
}
View Source
var Builtins_markdown = map[string]*env.Builtin{

	"reader//do-markdown": {
		Argsn: 2,
		Doc:   "Processes Markdown using a streaming approach with section handlers.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			rm, err := load_markdown_Dict(ps, arg1.(env.Block))
			if err != nil {
				ps.FailureFlag = true
				return err
			}
			return do_markdown(ps, arg0, rm)
		},
	},

	"markdown->html": {
		Argsn: 1,
		Doc:   "Converts Markdown text to HTML.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			text, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "markdown->html")
			}

			html, err := markdown_to_html(ps, text.Value)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "markdown->html")
			}

			return *env.NewString(html)
		},
	},

	"markdown": {
		Argsn: 1,
		Doc:   "Creates a Markdown value from a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch text := arg0.(type) {
			case env.String:
				return *env.NewMarkdown(text.Value)
			case env.Markdown:
				return text
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType, env.MarkdownType}, "markdown")
			}
		},
	},

	"markdown//text": {
		Argsn: 1,
		Doc:   "Gets the raw markdown text from a Markdown value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			md, ok := arg0.(env.Markdown)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MarkdownType}, "markdown//text")
			}
			return *env.NewString(md.Value)
		},
	},

	"markdown//length": {
		Argsn: 1,
		Doc:   "Gets the length of the markdown text in characters.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			md, ok := arg0.(env.Markdown)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MarkdownType}, "markdown//length")
			}
			return *env.NewInteger(int64(len(md.Value)))
		},
	},

	"markdown//to-html": {
		Argsn: 1,
		Doc:   "Converts a Markdown value to HTML.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			md, ok := arg0.(env.Markdown)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MarkdownType}, "markdown//to-html")
			}

			html, err := markdown_to_html(ps, md.Value)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "markdown//to-html")
			}

			return *env.NewString(html)
		},
	},

	"markdown//headings": {
		Argsn: 1,
		Doc:   "Extracts all headings from markdown text as a list of strings.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			md, ok := arg0.(env.Markdown)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MarkdownType}, "markdown//headings")
			}

			headings := extractHeadings(md.Value)
			result := make([]any, len(headings))
			for i, heading := range headings {
				result[i] = heading
			}
			return *env.NewList(result)
		},
	},

	"markdown//paragraphs": {
		Argsn: 1,
		Doc:   "Extracts all paragraphs from markdown text as a list of strings.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			md, ok := arg0.(env.Markdown)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MarkdownType}, "markdown//paragraphs")
			}

			paragraphs := extractParagraphs(md.Value)
			result := make([]any, len(paragraphs))
			for i, paragraph := range paragraphs {
				result[i] = paragraph
			}
			return *env.NewList(result)
		},
	},

	"markdown//links": {
		Argsn: 1,
		Doc:   "Extracts all links from markdown text as a list of dictionaries with 'text' and 'url' keys.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			md, ok := arg0.(env.Markdown)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MarkdownType}, "markdown//links")
			}

			links := extractLinks(md.Value)
			result := make([]any, len(links))
			for i, link := range links {
				linkDict := make(map[string]any)
				linkDict["text"] = link["text"]
				linkDict["url"] = link["url"]
				result[i] = linkDict
			}
			return *env.NewList(result)
		},
	},
}
View Source
var Builtins_match = map[string]*env.Builtin{

	"match-block": {
		Argsn: 2,
		Doc:   "Tries to match and deconstruct a value into multiple values, with support for literal values, type checking, get-words, code evaluation, and nested blocks. First argument can be any value. If it doesn't match, returns failure.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			value := arg0

			// Convert value to a block if it's not already
			var valueBlock env.Block
			switch v := value.(type) {
			case env.Block:
				valueBlock = v
			default:

				valueBlock = env.Block{
					Series: *env.NewTSeries([]env.Object{value}),
				}
			}

			switch pattern := arg1.(type) {
			case env.Block:
				return matchBlock(ps, valueBlock, pattern)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "match-block")
			}
		},
	},

	"match": {
		Argsn: 2,
		Doc:   "Matches a value against a series of pattern/action pairs. Pattern can be a single element or block. Returns the result of the first matching action, or failure if none match.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			value := arg0

			switch patternsBlock := arg1.(type) {
			case env.Block:

				if patternsBlock.Series.Len()%2 != 0 {
					return evaldo.MakeBuiltinError(ps, "Patterns block must contain an even number of elements (pairs)", "match")
				}

				for i := 0; i < patternsBlock.Series.Len(); i += 2 {
					pattern := patternsBlock.Series.Get(i)
					action := patternsBlock.Series.Get(i + 1)

					actionBlock, actionOk := action.(env.Block)
					if !actionOk {
						return evaldo.MakeBuiltinError(ps, "Action must be a block", "match")
					}

					oldFailureFlag := ps.FailureFlag
					ps.FailureFlag = false

					matchResult, _ := matchValue(ps, value, pattern, matchMode{0})

					if !ps.FailureFlag {

						ps.FailureFlag = oldFailureFlag

						ser := ps.Ser
						ps.Ser = actionBlock.Series
						evaldo.EvalBlockInj(ps, value, true)
						ps.Ser = ser
						return ps.Res
					}

					ps.FailureFlag = oldFailureFlag
					_ = matchResult
				}

				ps.FailureFlag = true
				return evaldo.MakeBuiltinError(ps, "No pattern matched the value", "match")
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "match")
			}
		},
	},
}
View Source
var Builtins_math = map[string]*env.Builtin{

	"mod": {
		Argsn: 2,
		Doc:   "Returns the remainder of dividing x by y.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			fa, fb, errPos := assureFloats(arg0, arg1)
			if errPos > 0 {
				return evaldo.MakeArgError(ps, errPos, []env.Type{env.IntegerType, env.BlockType}, "mod")
			}
			return *env.NewDecimal(math.Mod(fa, fb))
		},
	},

	"pow": {
		Argsn: 2,
		Doc:   "Returns base raised to the power of exponent.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch base := arg0.(type) {
			case env.Complex:
				switch exp := arg1.(type) {
				case env.Complex:
					return *env.NewComplex(cmplx.Pow(base.Value, exp.Value))
				case env.Integer:
					return *env.NewComplex(cmplx.Pow(base.Value, complex(float64(exp.Value), 0)))
				case env.Decimal:
					return *env.NewComplex(cmplx.Pow(base.Value, complex(exp.Value, 0)))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType}, "pow")
				}
			case env.Integer:
				switch exp := arg1.(type) {
				case env.Complex:
					return *env.NewComplex(cmplx.Pow(complex(float64(base.Value), 0), exp.Value))
				case env.Integer:
					return *env.NewDecimal(math.Pow(float64(base.Value), float64(exp.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Pow(float64(base.Value), exp.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType}, "pow")
				}
			case env.Decimal:
				switch exp := arg1.(type) {
				case env.Complex:
					return *env.NewComplex(cmplx.Pow(complex(base.Value, 0), exp.Value))
				case env.Integer:
					return *env.NewDecimal(math.Pow(base.Value, float64(exp.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Pow(base.Value, exp.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType}, "pow")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType}, "pow")
			}
		},
	},

	"log2": {
		Argsn: 1,
		Doc:   "Returns the binary logarithm (base-2) of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Log2(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Log2(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.BlockType}, "log2")
			}
		},
	},

	"log10": {
		Argsn: 1,
		Doc:   "Returns the decimal logarithm (base-10) of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Log10(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Log10(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "log10")
			}
		},
	},

	"log": {
		Argsn: 1,
		Doc:   "Returns the natural logarithm of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				if val.Value <= 0 {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Can't compute logarithm of zero or negative number.", "log")
				}
				return *env.NewDecimal(math.Log(float64(val.Value)))
			case env.Decimal:
				if val.Value <= 0 {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Can't compute logarithm of zero or negative number.", "log")
				}
				return *env.NewDecimal(math.Log(val.Value))
			case env.Complex:
				if val.Value == complex(0, 0) {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Can't compute logarithm of zero.", "log")
				}
				return *env.NewComplex(cmplx.Log(val.Value))
			case env.Vector:
				data := make(govector.Vector, len(val.Value))
				for i, v := range val.Value {
					data[i] = math.Log(v)
				}
				return *env.NewVector(data)
			case env.Matrix:
				data := make([]float64, len(val.Data))
				for i, v := range val.Data {
					data[i] = math.Log(v)
				}
				return *env.NewMatrixWithData(val.Rows, val.Cols, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType, env.VectorType, env.MatrixType}, "log")
			}
		},
	},

	"log1p": {
		Argsn: 1,
		Doc:   "Returns the natural logarithm of 1 plus its argument x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Log1p(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Log1p(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "log1p")
			}
		},
	},

	"logb": {
		Argsn: 1,
		Doc:   "Returns the binary exponent of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Logb(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Logb(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "logb")
			}
		},
	},

	"sq": {
		Argsn: 1,
		Doc:   "Returns the square of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Pow(float64(val.Value), 2.0))
			case env.Decimal:
				return *env.NewDecimal(math.Pow(val.Value, 2.0))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.BlockType}, "sq")
			}
		},
	},

	"sin": {
		Argsn: 1,
		Doc:   "Returns the sine of the radian argument.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Sin(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Sin(val.Value))
			case env.Complex:
				return *env.NewComplex(cmplx.Sin(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType}, "sin")
			}
		},
	},

	"cos": {
		Argsn: 1,
		Doc:   "Returns the cosine of the radian argument.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Cos(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Cos(val.Value))
			case env.Complex:
				return *env.NewComplex(cmplx.Cos(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType}, "cos")
			}
		},
	},

	"tan": {
		Argsn: 1,
		Doc:   "Returns the tangent of the radian argument.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Tan(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Tan(val.Value))
			case env.Complex:
				return *env.NewComplex(cmplx.Tan(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType}, "tan")
			}
		},
	},

	"sqrt": {
		Argsn: 1,
		Doc:   "Returns the square root of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Sqrt(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Sqrt(val.Value))
			case env.Complex:
				return *env.NewComplex(cmplx.Sqrt(val.Value))
			case env.Vector:
				data := make(govector.Vector, len(val.Value))
				for i, v := range val.Value {
					data[i] = math.Sqrt(v)
				}
				return *env.NewVector(data)
			case env.Matrix:
				data := make([]float64, len(val.Data))
				for i, v := range val.Data {
					data[i] = math.Sqrt(v)
				}
				return *env.NewMatrixWithData(val.Rows, val.Cols, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType, env.VectorType, env.MatrixType}, "sqrt")
			}
		},
	},

	"abs": {
		Argsn: 1,
		Doc:   "Returns the absolute value of a number.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewInteger(int64(math.Abs(float64(val.Value))))
			case env.Decimal:
				return *env.NewDecimal(math.Abs(val.Value))
			case env.Complex:
				return *env.NewDecimal(cmplx.Abs(val.Value))
			case env.Vector:
				data := make(govector.Vector, len(val.Value))
				for i, v := range val.Value {
					data[i] = math.Abs(v)
				}
				return *env.NewVector(data)
			case env.Matrix:
				data := make([]float64, len(val.Data))
				for i, v := range val.Data {
					data[i] = math.Abs(v)
				}
				return *env.NewMatrixWithData(val.Rows, val.Cols, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType, env.VectorType, env.MatrixType}, "abs")
			}
		},
	},

	"acos": {
		Argsn: 1,
		Doc:   "Returns the arccosine (inverse cosine) in radians.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				if val.Value < -1.0 || val.Value > 1.0 {
					return evaldo.MakeBuiltinError(ps, "Invalid input: Acos is only defined for -1 <= x <= 1.", "acos")
				}
				return *env.NewDecimal(math.Acos(float64(val.Value)))
			case env.Decimal:
				if val.Value < -1.0 || val.Value > 1.0 {
					return evaldo.MakeBuiltinError(ps, "Invalid input: Acos is only defined for -1 <= x <= 1.", "acos")
				}
				return *env.NewDecimal(math.Acos(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "acos")
			}
		},
	},

	"acosh": {
		Argsn: 1,
		Doc:   "Returns the inverse hyperbolic cosine.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				if val.Value < 1.0 {
					return evaldo.MakeBuiltinError(ps, " Acosh is only defined for x >= 1.", "acosh")
				}
				return *env.NewDecimal(math.Log(float64(val.Value) + math.Sqrt(float64(val.Value)*float64(val.Value)-1)))
			case env.Decimal:
				if val.Value < 1.0 {
					return evaldo.MakeBuiltinError(ps, " Acosh is only defined for x >= 1.", "acosh")
				}
				return *env.NewDecimal(math.Log(val.Value + math.Sqrt(val.Value*val.Value-1)))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "acosh")
			}
		},
	},

	"asin": {
		Argsn: 1,
		Doc:   "Returns the arcsine (inverse sine) in radians.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				if val.Value < -1.0 || val.Value > 1.0 {
					return evaldo.MakeBuiltinError(ps, "Invalid input: Asin is only defined for -1 <= x <= 1.", "asin")
				}
				return *env.NewDecimal(math.Asin(float64(val.Value)))
			case env.Decimal:
				if val.Value < -1.0 || val.Value > 1.0 {
					return evaldo.MakeBuiltinError(ps, "Invalid input: Asin is only defined for -1 <= x <= 1.", "asin")
				}
				return *env.NewDecimal(math.Asin(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "asin")
			}
		},
	},

	"asinh": {
		Argsn: 1,
		Doc:   "Returns the inverse hyperbolic sine.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Log(float64(val.Value) + math.Sqrt(float64(val.Value)*float64(val.Value)+1)))
			case env.Decimal:
				return *env.NewDecimal(math.Log(val.Value + math.Sqrt(val.Value*val.Value+1)))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "asinh")
			}
		},
	},

	"atan": {
		Argsn: 1,
		Doc:   "Returns the arctangent (inverse tangent) in radians.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Atan(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Atan(val.Value))
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "atan")
			}
		},
	},

	"atan2": {
		Argsn: 2,
		Doc:   "Returns the arc tangent of y/x, using the signs of the two to determine the quadrant of the return value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				switch val2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Atan2(float64(val.Value), float64(val2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Atan2(float64(val.Value), val2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "atan2")
				}
			case env.Decimal:
				switch val2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Atan2(val.Value, float64(val2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Atan2(val.Value, val2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "atan2")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "atan2")
			}
		},
	},

	"atanh": {
		Argsn: 1,
		Doc:   "Returns the inverse hyperbolic tangent.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Atanh(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Atanh(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "atanh")
			}
		},
	},

	"ceil": {
		Argsn: 1,
		Doc:   "Returns the least integer value greater than or equal to x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(float64(val.Value))
			case env.Decimal:
				return *env.NewDecimal(math.Ceil(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "ceil")
			}
		},
	},

	"cbrt": {
		Argsn: 1,
		Doc:   "Returns the cube root of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Cbrt(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Cbrt(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "cbrt")
			}
		},
	},

	"copysign": {
		Argsn: 2,
		Doc:   "Returns a value with the magnitude of x and the sign of y.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				switch val2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Copysign(float64(val.Value), float64(val2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Copysign(float64(val.Value), val2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "copysign")
				}
			case env.Decimal:
				switch val2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Copysign(val.Value, float64(val2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Copysign(val.Value, val2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "copysign")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "copysign")
			}
		},
	},

	"dim": {
		Argsn: 2,
		Doc:   "Returns the maximum of x-y or 0.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				switch val2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(util.GetDimValue(float64(val.Value), float64(val2.Value)))
				case env.Decimal:
					return *env.NewDecimal(util.GetDimValue(float64(val.Value), val2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "dim")
				}
			case env.Decimal:
				switch val2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(util.GetDimValue(val.Value, float64(val2.Value)))
				case env.Decimal:
					return *env.NewDecimal(util.GetDimValue(val.Value, val2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "dim")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "dim")
			}
		},
	},

	"round\\to": {
		Argsn: 2,
		Doc:   "Rounds a decimal to the specified number of decimal places.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Decimal:
				switch precision := arg1.(type) {
				case env.Integer:
					ratio := math.Pow(10, float64(precision.Value))
					return *env.NewDecimal(math.Round(val.Value*ratio) / ratio)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "round\\to")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DecimalType}, "round\\to")
			}
		},
	},

	"round": {
		Argsn: 1,
		Doc:   "Rounds a decimal to the nearest integer.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Decimal:
				return *env.NewDecimal(math.Round(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DecimalType}, "round\\to")
			}
		},
	},

	"roundtoeven": {
		Argsn: 1,
		Doc:   "Returns the nearest integer, rounding ties to even.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Decimal:
				return *env.NewDecimal(math.RoundToEven(val.Value))
			case env.Integer:
				return *env.NewDecimal(math.RoundToEven(float64(val.Value)))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DecimalType, env.IntegerType}, "roundtoeven")
			}
		},
	},

	"erf": {
		Argsn: 1,
		Doc:   "Returns the error function of value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Erf(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Erf(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "erf")
			}
		},
	},

	"erfc": {
		Argsn: 1,
		Doc:   "Returns the complementary error function of value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Erfc(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Erfc(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "erfc")
			}
		},
	},

	"erfcinv": {
		Argsn: 1,
		Doc:   "Returns the inverse of erfc(x) function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Erfcinv(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Erfcinv(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "erfcinv")
			}
		},
	},

	"erfinv": {
		Argsn: 1,
		Doc:   "Returns the inverse error function of value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Erfinv(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Erfinv(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "erfinv")
			}
		},
	},

	"exp": {
		Argsn: 1,
		Doc:   "Returns e**x, the base-e exponential of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Exp(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Exp(val.Value))
			case env.Complex:
				return *env.NewComplex(cmplx.Exp(val.Value))
			case env.Vector:
				data := make(govector.Vector, len(val.Value))
				for i, v := range val.Value {
					data[i] = math.Exp(v)
				}
				return *env.NewVector(data)
			case env.Matrix:
				data := make([]float64, len(val.Data))
				for i, v := range val.Data {
					data[i] = math.Exp(v)
				}
				return *env.NewMatrixWithData(val.Rows, val.Cols, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType, env.ComplexType, env.VectorType, env.MatrixType}, "exp")
			}
		},
	},

	"exp2": {
		Argsn: 1,
		Doc:   "Returns 2**x, the base-2 exponential of x.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Exp2(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Exp2(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "exp2")
			}
		},
	},

	"expm1": {
		Argsn: 1,
		Doc:   "Returns e**x - 1, the base-e exponential of x minus 1. It is more accurate than exp(x) - 1 when x is near zero.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Expm1(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Expm1(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "expm1")
			}
		},
	},

	"fma": {
		Argsn: 3,
		Doc:   "Returns x * y + z, computed with only one rounding. (That is, FMA returns the fused multiply-add of x, y, and z.)",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val1 := arg0.(type) {
			case env.Integer:
				switch val2 := arg1.(type) {
				case env.Integer:
					switch val3 := arg2.(type) {
					case env.Integer:
						return *env.NewDecimal(math.FMA(float64(val1.Value), float64(val2.Value), float64(val3.Value)))
					case env.Decimal:
						return *env.NewDecimal(math.FMA(float64(val1.Value), float64(val2.Value), val3.Value))
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType, env.DecimalType}, "fma")
					}
				case env.Decimal:
					switch val3 := arg2.(type) {
					case env.Integer:
						return *env.NewDecimal(math.FMA(float64(val1.Value), val2.Value, float64(val3.Value)))
					case env.Decimal:
						return *env.NewDecimal(math.FMA(float64(val1.Value), val2.Value, val3.Value))
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType, env.DecimalType}, "fma")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "fma")
				}
			case env.Decimal:
				switch val2 := arg1.(type) {
				case env.Integer:
					switch val3 := arg2.(type) {
					case env.Integer:
						return *env.NewDecimal(math.FMA(val1.Value, float64(val2.Value), float64(val3.Value)))
					case env.Decimal:
						return *env.NewDecimal(math.FMA(val1.Value, float64(val2.Value), val3.Value))
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType, env.DecimalType}, "fma")
					}
				case env.Decimal:
					switch val3 := arg2.(type) {
					case env.Integer:
						return *env.NewDecimal(math.FMA(val1.Value, val2.Value, float64(val3.Value)))
					case env.Decimal:
						return *env.NewDecimal(math.FMA(val1.Value, val2.Value, val3.Value))
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType, env.DecimalType}, "fma")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "fma")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "fma")
			}
		},
	},

	"j0": {
		Argsn: 1,
		Doc:   "Returns the order-zero Bessel function of the first kind.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.J0(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.J0(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "j0")
			}
		},
	},

	"j1": {
		Argsn: 1,
		Doc:   "Returns the order-one Bessel function of the first kind.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.J1(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.J1(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "j1")
			}
		},
	},

	"y0": {
		Argsn: 1,
		Doc:   "Returns the order-zero Bessel function of the second kind.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Y0(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Y0(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "y0")
			}
		},
	},

	"y1": {
		Argsn: 1,
		Doc:   "Returns the order-one Bessel function of the second kind.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(math.Y1(float64(val.Value)))
			case env.Decimal:
				return *env.NewDecimal(math.Y1(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "y1")
			}
		},
	},

	"yn": {
		Argsn: 2,
		Doc:   "Returns the order-n Bessel function of the second kind.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Integer:
				switch v2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Yn(int(v1.Value), float64(v2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Yn(int(v1.Value), v2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "yn")
				}
			case env.Decimal:
				switch v2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Yn(int(v1.Value), float64(v2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Yn(int(v1.Value), v2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "yn")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "yn")
			}
		},
	},

	"jn": {
		Argsn: 2,
		Doc:   "Returns the order-n Bessel function of the first kind.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Integer:
				switch v2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Jn(int(v1.Value), float64(v2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Jn(int(v1.Value), v2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "jn")
				}
			case env.Decimal:
				switch v2 := arg1.(type) {
				case env.Integer:
					return *env.NewDecimal(math.Jn(int(v1.Value), float64(v2.Value)))
				case env.Decimal:
					return *env.NewDecimal(math.Jn(int(v1.Value), v2.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.DecimalType}, "jn")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "jn")
			}
		},
	},

	"trunc": {
		Argsn: 1,
		Doc:   "Returns the integer value of input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				return *env.NewDecimal(float64(val.Value))
			case env.Decimal:
				return *env.NewDecimal(math.Trunc(val.Value))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "trunc")
			}
		},
	},

	"pi": {
		Argsn: 0,
		Doc:   "Returns the mathematical constant π (pi).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewDecimal(float64(math.Pi))
		},
	},

	"deg->rad": {
		Argsn: 1,
		Doc:   "Converts degrees to radians.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var fa float64
			switch a := arg0.(type) {
			case env.Decimal:
				fa = a.Value
			case env.Integer:
				fa = float64(a.Value)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.DecimalType}, "deg->rad")
			}
			return *env.NewDecimal(fa * float64(math.Pi) / 180.0)
		},
	},

	"is-near": {
		Argsn: 2,
		Doc:   "Returns true if two decimals are close.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			fa, fb, errPos := assureFloats(arg0, arg1)
			if errPos > 0 {
				return evaldo.MakeArgError(ps, errPos, []env.Type{env.IntegerType, env.BlockType}, "is-near")
			}
			const epsilon = 0.0000000000001 // math.SmallestNonzeroFloat64
			if math.Abs(fa-fb) <= (epsilon) {
				return env.NewBoolean(true)
			} else {
				return env.NewBoolean(false)
			}
		},
	},

	"near-zero": {
		Argsn: 1,
		Doc:   "Returns true if a decimal is close to zero.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var fa float64
			switch a := arg0.(type) {
			case env.Decimal:
				fa = a.Value
			case env.Integer:
				fa = float64(a.Value)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType, env.BlockType}, "near-zero")
			}
			// const epsilon = math.SmallestNonzeroFloat64
			const epsilon = 0.0000000000001 // math.SmallestNonzeroFloat64
			if math.Abs(fa) <= epsilon {
				return env.NewBoolean(true)
			} else {
				return env.NewBoolean(false)
			}
		},
	},

	"is-prime": {
		Argsn: 1,
		Doc:   "Returns true if the integer is a prime number.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Integer:
				if val.Value <= 1 {
					return *env.NewBoolean(false)
				}
				if primes.IsPrime(int(val.Value)) {
					return *env.NewBoolean(true)
				} else {
					return *env.NewBoolean(false)
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "is-prime")
			}
		},
	},

	"to-eyr": {
		Argsn: 1,
		Doc:   "Converts math dialect to Eyr dialect.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return DialectMath(ps, arg0)
		},
	},

	"calc": {
		Argsn: 1,
		Doc:   "Evaluates expressions in math dialect.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			res := DialectMath(ps, arg0)
			switch block := res.(type) {
			case env.Block:

				ps.ResetStack()
				ser := ps.Ser
				ps.Ser = block.Series
				Eyr_EvalBlock(ps, false)
				ps.Ser = ser
				return ps.Res
			default:
				return res
			}
		},
	},

	"gcd": {
		Argsn: 2,
		Doc:   "Returns the greatest common divisor of two integers using Euclidean algorithm.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val1 := arg0.(type) {
			case env.Integer:
				switch val2 := arg1.(type) {
				case env.Integer:
					a := val1.Value
					b := val2.Value

					if a < 0 {
						a = -a
					}
					if b < 0 {
						b = -b
					}

					for b != 0 {
						temp := b
						b = a % b
						a = temp
					}

					return *env.NewInteger(a)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "gcd")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "gcd")
			}
		},
	},

	"outer-product": {
		Argsn: 2,
		Doc:   "Computes the outer product of two vectors (blocks), returning a matrix (block of blocks) where each element [i,j] = a[i] * b[j]. Similar to numpy.outer().",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch vec1 := arg0.(type) {
			case env.Block:
				switch vec2 := arg1.(type) {
				case env.Block:

					result := make([]env.Object, vec1.Series.Len())

					for i := 0; i < vec1.Series.Len(); i++ {

						val1 := vec1.Series.Get(i)
						var f1 float64
						var isDecimal1 bool

						switch v1 := val1.(type) {
						case env.Integer:
							f1 = float64(v1.Value)
							isDecimal1 = false
						case env.Decimal:
							f1 = v1.Value
							isDecimal1 = true
						default:
							return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Element at position %d in first block must be integer or decimal", i), "outer-product")
						}

						row := make([]env.Object, vec2.Series.Len())

						for j := 0; j < vec2.Series.Len(); j++ {

							val2 := vec2.Series.Get(j)
							var f2 float64
							var isDecimal2 bool

							switch v2 := val2.(type) {
							case env.Integer:
								f2 = float64(v2.Value)
								isDecimal2 = false
							case env.Decimal:
								f2 = v2.Value
								isDecimal2 = true
							default:
								return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Element at position %d in second block must be integer or decimal", j), "outer-product")
							}

							product := f1 * f2

							if isDecimal1 || isDecimal2 {
								row[j] = *env.NewDecimal(product)
							} else {
								row[j] = *env.NewInteger(int64(product))
							}
						}

						result[i] = *env.NewBlock(*env.NewTSeries(row))
					}

					return *env.NewBlock(*env.NewTSeries(result))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "outer-product")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "outer-product")
			}
		},
	},
}
View Source
var Builtins_matrix = map[string]*env.Builtin{

	"matrix\\zeros": {
		Argsn: 2,
		Doc:   "Creates a new matrix with the given dimensions, initialized to zeros.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch rows := arg0.(type) {
			case env.Integer:
				switch cols := arg1.(type) {
				case env.Integer:
					if rows.Value <= 0 || cols.Value <= 0 {
						return evaldo.MakeBuiltinError(ps, "Matrix dimensions must be positive", "matrix")
					}
					return *env.NewMatrix(int(rows.Value), int(cols.Value))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "matrix")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "matrix")
			}
		},
	},

	"matrix": {
		Argsn: 2,
		Doc:   "Creates a matrix from a shape block and a data block.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch shape := arg0.(type) {
			case env.Block:
				if shape.Series.Len() != 2 {
					return evaldo.MakeBuiltinError(ps, "Shape must be { rows cols }", "matrix")
				}
				rowsObj := shape.Series.Get(0)
				colsObj := shape.Series.Get(1)
				rowsInt, ok1 := rowsObj.(env.Integer)
				colsInt, ok2 := colsObj.(env.Integer)
				if !ok1 || !ok2 {
					return evaldo.MakeBuiltinError(ps, "Shape must contain integers", "matrix")
				}
				rows := int(rowsInt.Value)
				cols := int(colsInt.Value)

				switch data := arg1.(type) {
				case env.Block:
					if data.Series.Len() != rows*cols {
						return evaldo.MakeBuiltinError(ps, "Data length must match rows*cols", "matrix")
					}
					floats := make([]float64, rows*cols)
					for i := 0; i < data.Series.Len(); i++ {
						switch v := data.Series.Get(i).(type) {
						case env.Decimal:
							floats[i] = v.Value
						case env.Integer:
							floats[i] = float64(v.Value)
						default:
							return evaldo.MakeBuiltinError(ps, "Data must contain numbers", "matrix")
						}
					}
					return *env.NewMatrixWithData(rows, cols, floats)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "matrix")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "matrix")
			}
		},
	},

	"matrix\\randn": {
		Argsn: 2,
		Doc:   "Creates a matrix with random normal values (mean 0, std 1).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch rows := arg0.(type) {
			case env.Integer:
				switch cols := arg1.(type) {
				case env.Integer:
					if rows.Value <= 0 || cols.Value <= 0 {
						return evaldo.MakeBuiltinError(ps, "Matrix dimensions must be positive", "matrix\\randn")
					}
					r := int(rows.Value)
					c := int(cols.Value)
					data := make([]float64, r*c)
					for i := range data {
						data[i] = rand.NormFloat64()
					}
					return *env.NewMatrixWithData(r, c, data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "matrix\\randn")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "matrix\\randn")
			}
		},
	},

	"matrix\\ones": {
		Argsn: 2,
		Doc:   "Creates a matrix filled with ones.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch rows := arg0.(type) {
			case env.Integer:
				switch cols := arg1.(type) {
				case env.Integer:
					if rows.Value <= 0 || cols.Value <= 0 {
						return evaldo.MakeBuiltinError(ps, "Matrix dimensions must be positive", "matrix\\ones")
					}
					r := int(rows.Value)
					c := int(cols.Value)
					data := make([]float64, r*c)
					for i := range data {
						data[i] = 1.0
					}
					return *env.NewMatrixWithData(r, c, data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "matrix\\ones")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "matrix\\ones")
			}
		},
	},

	"matrix\\eye": {
		Argsn: 1,
		Doc:   "Creates an identity matrix of size n×n.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch n := arg0.(type) {
			case env.Integer:
				if n.Value <= 0 {
					return evaldo.MakeBuiltinError(ps, "Matrix size must be positive", "matrix\\eye")
				}
				size := int(n.Value)
				data := make([]float64, size*size)
				for i := 0; i < size; i++ {
					data[i*size+i] = 1.0
				}
				return *env.NewMatrixWithData(size, size, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "matrix\\eye")
			}
		},
	},

	"shape?": {
		Argsn: 1,
		Doc:   "Returns the shape of a matrix as { rows cols }.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				return *env.NewBlock(*env.NewTSeries([]env.Object{
					*env.NewInteger(int64(m.Rows)),
					*env.NewInteger(int64(m.Cols)),
				}))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "shape?")
			}
		},
	},

	"rows?": {
		Argsn: 1,
		Doc:   "Returns the number of rows in a matrix.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				return *env.NewInteger(int64(m.Rows))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "rows?")
			}
		},
	},

	"cols?": {
		Argsn: 1,
		Doc:   "Returns the number of columns in a matrix.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				return *env.NewInteger(int64(m.Cols))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "cols?")
			}
		},
	},

	"mat-get": {
		Argsn: 3,
		Doc:   "Gets the element at the specified row and column (0-indexed).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				switch row := arg1.(type) {
				case env.Integer:
					switch col := arg2.(type) {
					case env.Integer:
						r := int(row.Value)
						c := int(col.Value)
						if r < 0 || r >= m.Rows || c < 0 || c >= m.Cols {
							return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Matrix indices out of bounds: row %d, col %d (matrix is %dx%d)", r, c, m.Rows, m.Cols), "mat-get")
						}
						return *env.NewDecimal(m.Get(r, c))
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType}, "mat-get")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "mat-get")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-get")
			}
		},
	},

	"mat-set!": {
		Argsn: 4,
		Doc:   "Sets the element at the specified row and column (0-indexed). Modifies matrix in place.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				switch row := arg1.(type) {
				case env.Integer:
					switch col := arg2.(type) {
					case env.Integer:
						r := int(row.Value)
						c := int(col.Value)
						if r < 0 || r >= m.Rows || c < 0 || c >= m.Cols {
							return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Matrix indices out of bounds: row %d, col %d (matrix is %dx%d)", r, c, m.Rows, m.Cols), "mat-set!")
						}
						var val float64
						switch v := arg3.(type) {
						case env.Decimal:
							val = v.Value
						case env.Integer:
							val = float64(v.Value)
						default:
							return evaldo.MakeArgError(ps, 4, []env.Type{env.DecimalType, env.IntegerType}, "mat-set!")
						}
						m.Set(r, c, val)
						return m
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType}, "mat-set!")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "mat-set!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-set!")
			}
		},
	},

	"mat-row": {
		Argsn: 2,
		Doc:   "Returns a row of the matrix as a vector.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				switch row := arg1.(type) {
				case env.Integer:
					r := int(row.Value)
					if r < 0 || r >= m.Rows {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Row index %d out of bounds (matrix has %d rows)", r, m.Rows), "mat-row")
					}
					data := make(govector.Vector, m.Cols)
					for j := 0; j < m.Cols; j++ {
						data[j] = m.Get(r, j)
					}
					return *env.NewVector(data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "mat-row")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-row")
			}
		},
	},

	"mat-col": {
		Argsn: 2,
		Doc:   "Returns a column of the matrix as a vector.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				switch col := arg1.(type) {
				case env.Integer:
					c := int(col.Value)
					if c < 0 || c >= m.Cols {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Column index %d out of bounds (matrix has %d columns)", c, m.Cols), "mat-col")
					}
					data := make(govector.Vector, m.Rows)
					for i := 0; i < m.Rows; i++ {
						data[i] = m.Get(i, c)
					}
					return *env.NewVector(data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "mat-col")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-col")
			}
		},
	},

	"mat-transpose": {
		Argsn: 1,
		Doc:   "Returns the transpose of a matrix.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				data := make([]float64, m.Rows*m.Cols)
				for i := 0; i < m.Rows; i++ {
					for j := 0; j < m.Cols; j++ {

						data[j*m.Rows+i] = m.Get(i, j)
					}
				}
				return *env.NewMatrixWithData(m.Cols, m.Rows, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-transpose")
			}
		},
	},

	"mat-mul": {
		Argsn: 2,
		Doc:   "Matrix multiplication. A (m×n) × B (n×p) = C (m×p).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch A := arg0.(type) {
			case env.Matrix:
				switch B := arg1.(type) {
				case env.Matrix:
					if A.Cols != B.Rows {
						return evaldo.MakeBuiltinError(ps, "Matrix dimensions incompatible for multiplication", "mat-mul")
					}
					m, n, p := A.Rows, A.Cols, B.Cols
					data := make([]float64, m*p)
					for i := 0; i < m; i++ {
						for j := 0; j < p; j++ {
							var sum float64
							for k := 0; k < n; k++ {
								sum += A.Get(i, k) * B.Get(k, j)
							}
							data[i*p+j] = sum
						}
					}
					return *env.NewMatrixWithData(m, p, data)
				case env.Vector:

					if A.Cols != len(B.Value) {
						return evaldo.MakeBuiltinError(ps, "Matrix columns must match vector length", "mat-mul")
					}
					result := make(govector.Vector, A.Rows)
					for i := 0; i < A.Rows; i++ {
						var sum float64
						for j := 0; j < A.Cols; j++ {
							sum += A.Get(i, j) * B.Value[j]
						}
						result[i] = sum
					}
					return *env.NewVector(result)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.MatrixType, env.VectorType}, "mat-mul")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-mul")
			}
		},
	},

	"mat-hadamard": {
		Argsn: 2,
		Doc:   "Element-wise (Hadamard) multiplication of two matrices. In the future, could have a dedicated .* operator.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch A := arg0.(type) {
			case env.Matrix:
				switch B := arg1.(type) {
				case env.Matrix:
					if A.Rows != B.Rows || A.Cols != B.Cols {
						return evaldo.MakeBuiltinError(ps, "Matrix dimensions must match", "mat-hadamard")
					}
					data := make([]float64, len(A.Data))
					for i := range A.Data {
						data[i] = A.Data[i] * B.Data[i]
					}
					return *env.NewMatrixWithData(A.Rows, A.Cols, data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.MatrixType}, "mat-hadamard")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-hadamard")
			}
		},
	},

	"mat-add": {
		Argsn: 2,
		Doc:   "Element-wise addition of two matrices. In the future, could have a dedicated .+ operator.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch A := arg0.(type) {
			case env.Matrix:
				switch B := arg1.(type) {
				case env.Matrix:
					if A.Rows != B.Rows || A.Cols != B.Cols {
						return evaldo.MakeBuiltinError(ps, "Matrix dimensions must match", "mat-add")
					}
					data := make([]float64, len(A.Data))
					for i := range A.Data {
						data[i] = A.Data[i] + B.Data[i]
					}
					return *env.NewMatrixWithData(A.Rows, A.Cols, data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.MatrixType}, "mat-add")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-add")
			}
		},
	},

	"mat-sub": {
		Argsn: 2,
		Doc:   "Element-wise subtraction of two matrices. In the future, could have a dedicated .- operator.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch A := arg0.(type) {
			case env.Matrix:
				switch B := arg1.(type) {
				case env.Matrix:
					if A.Rows != B.Rows || A.Cols != B.Cols {
						return evaldo.MakeBuiltinError(ps, "Matrix dimensions must match", "mat-sub")
					}
					data := make([]float64, len(A.Data))
					for i := range A.Data {
						data[i] = A.Data[i] - B.Data[i]
					}
					return *env.NewMatrixWithData(A.Rows, A.Cols, data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.MatrixType}, "mat-sub")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-sub")
			}
		},
	},

	"mat-scale": {
		Argsn: 2,
		Doc:   "Multiplies all elements of a matrix by a scalar.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				var scalar float64
				switch s := arg1.(type) {
				case env.Decimal:
					scalar = s.Value
				case env.Integer:
					scalar = float64(s.Value)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.DecimalType, env.IntegerType}, "mat-scale")
				}
				data := make([]float64, len(m.Data))
				for i := range m.Data {
					data[i] = m.Data[i] * scalar
				}
				return *env.NewMatrixWithData(m.Rows, m.Cols, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-scale")
			}
		},
	},

	"mat-sum-rows": {
		Argsn: 1,
		Doc:   "Returns a vector containing the sum of each row.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				result := make(govector.Vector, m.Rows)
				for i := 0; i < m.Rows; i++ {
					var sum float64
					for j := 0; j < m.Cols; j++ {
						sum += m.Get(i, j)
					}
					result[i] = sum
				}
				return *env.NewVector(result)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-sum-rows")
			}
		},
	},

	"mat-sum-cols": {
		Argsn: 1,
		Doc:   "Returns a vector containing the sum of each column.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				result := make(govector.Vector, m.Cols)
				for j := 0; j < m.Cols; j++ {
					var sum float64
					for i := 0; i < m.Rows; i++ {
						sum += m.Get(i, j)
					}
					result[j] = sum
				}
				return *env.NewVector(result)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-sum-cols")
			}
		},
	},

	"mat-max-rows": {
		Argsn: 1,
		Doc:   "Returns a vector containing the maximum of each row.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				result := make(govector.Vector, m.Rows)
				for i := 0; i < m.Rows; i++ {
					maxVal := m.Get(i, 0)
					for j := 1; j < m.Cols; j++ {
						if v := m.Get(i, j); v > maxVal {
							maxVal = v
						}
					}
					result[i] = maxVal
				}
				return *env.NewVector(result)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-max-rows")
			}
		},
	},

	"mat-max-cols": {
		Argsn: 1,
		Doc:   "Returns a vector containing the maximum of each column.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				result := make(govector.Vector, m.Cols)
				for j := 0; j < m.Cols; j++ {
					maxVal := m.Get(0, j)
					for i := 1; i < m.Rows; i++ {
						if v := m.Get(i, j); v > maxVal {
							maxVal = v
						}
					}
					result[j] = maxVal
				}
				return *env.NewVector(result)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-max-cols")
			}
		},
	},

	"mat-to-block": {
		Argsn: 1,
		Doc:   "Converts a matrix to a block of blocks (each row is a block).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				rows := make([]env.Object, m.Rows)
				for i := 0; i < m.Rows; i++ {
					row := make([]env.Object, m.Cols)
					for j := 0; j < m.Cols; j++ {
						row[j] = *env.NewDecimal(m.Get(i, j))
					}
					rows[i] = *env.NewBlock(*env.NewTSeries(row))
				}
				return *env.NewBlock(*env.NewTSeries(rows))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-to-block")
			}
		},
	},

	"block-to-mat": {
		Argsn: 1,
		Doc:   "Converts a block of blocks (rows) to a matrix.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch blk := arg0.(type) {
			case env.Block:
				if blk.Series.Len() == 0 {
					return evaldo.MakeBuiltinError(ps, "Block is empty", "block-to-mat")
				}

				firstRow, ok := blk.Series.Get(0).(env.Block)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Block must contain blocks (rows)", "block-to-mat")
				}
				rows := blk.Series.Len()
				cols := firstRow.Series.Len()
				data := make([]float64, rows*cols)

				for i := 0; i < rows; i++ {
					row, ok := blk.Series.Get(i).(env.Block)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "Block must contain blocks (rows)", "block-to-mat")
					}
					if row.Series.Len() != cols {
						return evaldo.MakeBuiltinError(ps, "All rows must have the same length", "block-to-mat")
					}
					for j := 0; j < cols; j++ {
						switch v := row.Series.Get(j).(type) {
						case env.Decimal:
							data[i*cols+j] = v.Value
						case env.Integer:
							data[i*cols+j] = float64(v.Value)
						default:
							return evaldo.MakeBuiltinError(ps, "Rows must contain numbers", "block-to-mat")
						}
					}
				}
				return *env.NewMatrixWithData(rows, cols, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "block-to-mat")
			}
		},
	},

	"vector-to-mat": {
		Argsn: 2,
		Doc:   "Converts a vector to a matrix. Use 'row for 1×n or 'col for n×1.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v := arg0.(type) {
			case env.Vector:
				switch orient := arg1.(type) {
				case env.Word:
					word := ps.Idx.GetWord(orient.Index)
					n := len(v.Value)
					data := make([]float64, n)
					copy(data, v.Value)
					if word == "row" {
						return *env.NewMatrixWithData(1, n, data)
					} else if word == "col" {
						return *env.NewMatrixWithData(n, 1, data)
					}
					return evaldo.MakeBuiltinError(ps, "Orientation must be 'row or 'col", "vector-to-mat")
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "vector-to-mat")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "vector-to-mat")
			}
		},
	},

	"mat-slice": {
		Argsn: 3,
		Doc:   "Extracts a sub-matrix. Row and column ranges are { start end } (inclusive, 0-indexed).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				switch rowRange := arg1.(type) {
				case env.Block:
					if rowRange.Series.Len() != 2 {
						return evaldo.MakeBuiltinError(ps, "Row range must be { start end }", "mat-slice")
					}
					switch colRange := arg2.(type) {
					case env.Block:
						if colRange.Series.Len() != 2 {
							return evaldo.MakeBuiltinError(ps, "Column range must be { start end }", "mat-slice")
						}
						r0, ok1 := rowRange.Series.Get(0).(env.Integer)
						r1, ok2 := rowRange.Series.Get(1).(env.Integer)
						c0, ok3 := colRange.Series.Get(0).(env.Integer)
						c1, ok4 := colRange.Series.Get(1).(env.Integer)
						if !ok1 || !ok2 || !ok3 || !ok4 {
							return evaldo.MakeBuiltinError(ps, "Ranges must contain integers", "mat-slice")
						}
						rowStart, rowEnd := int(r0.Value), int(r1.Value)
						colStart, colEnd := int(c0.Value), int(c1.Value)
						if rowStart < 0 || rowEnd >= m.Rows || rowStart > rowEnd {
							return evaldo.MakeBuiltinError(ps, "Invalid row range", "mat-slice")
						}
						if colStart < 0 || colEnd >= m.Cols || colStart > colEnd {
							return evaldo.MakeBuiltinError(ps, "Invalid column range", "mat-slice")
						}
						newRows := rowEnd - rowStart + 1
						newCols := colEnd - colStart + 1
						data := make([]float64, newRows*newCols)
						for i := 0; i < newRows; i++ {
							for j := 0; j < newCols; j++ {
								data[i*newCols+j] = m.Get(rowStart+i, colStart+j)
							}
						}
						return *env.NewMatrixWithData(newRows, newCols, data)
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "mat-slice")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "mat-slice")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-slice")
			}
		},
	},

	"mat-softmax": {
		Argsn: 1,
		Doc:   "Applies softmax to each column of the matrix. Returns a new matrix.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				data := make([]float64, m.Rows*m.Cols)
				for j := 0; j < m.Cols; j++ {

					maxVal := m.Get(0, j)
					for i := 1; i < m.Rows; i++ {
						if v := m.Get(i, j); v > maxVal {
							maxVal = v
						}
					}

					sum := 0.0
					for i := 0; i < m.Rows; i++ {
						exp := math.Exp(m.Get(i, j) - maxVal)
						data[i*m.Cols+j] = exp
						sum += exp
					}

					for i := 0; i < m.Rows; i++ {
						data[i*m.Cols+j] /= sum
					}
				}
				return *env.NewMatrixWithData(m.Rows, m.Cols, data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-softmax")
			}
		},
	},

	"mat-set-col!": {
		Argsn: 3,
		Doc:   "Sets a column of the matrix from a vector or block. Mutates in place.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch m := arg0.(type) {
			case env.Matrix:
				switch col := arg1.(type) {
				case env.Integer:
					c := int(col.Value)
					if c < 0 || c >= m.Cols {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Column index %d out of bounds (matrix has %d columns)", c, m.Cols), "mat-set-col!")
					}
					switch vals := arg2.(type) {
					case env.Vector:
						if len(vals.Value) != m.Rows {
							return evaldo.MakeBuiltinError(ps, "Vector length must match matrix rows", "mat-set-col!")
						}
						for i := 0; i < m.Rows; i++ {
							m.Set(i, c, vals.Value[i])
						}
						return m
					case env.Block:
						if vals.Series.Len() != m.Rows {
							return evaldo.MakeBuiltinError(ps, "Block length must match matrix rows", "mat-set-col!")
						}
						for i := 0; i < m.Rows; i++ {
							switch v := vals.Series.Get(i).(type) {
							case env.Decimal:
								m.Set(i, c, v.Value)
							case env.Integer:
								m.Set(i, c, float64(v.Value))
							default:
								return evaldo.MakeBuiltinError(ps, "Block must contain numbers", "mat-set-col!")
							}
						}
						return m
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.VectorType, env.BlockType}, "mat-set-col!")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "mat-set-col!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.MatrixType}, "mat-set-col!")
			}
		},
	},

	"vec-add": {
		Argsn: 2,
		Doc:   "Adds two vectors element-wise. Returns a new vector.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					if len(v1.Value) != len(v2.Value) {
						return evaldo.MakeBuiltinError(ps, "Vectors must have same length", "vec-add")
					}
					data := make(govector.Vector, len(v1.Value))
					for i := range v1.Value {
						data[i] = v1.Value[i] + v2.Value[i]
					}
					return *env.NewVector(data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "vec-add")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "vec-add")
			}
		},
	},

	"vec-sub": {
		Argsn: 2,
		Doc:   "Subtracts two vectors element-wise (v1 - v2). Returns a new vector.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					if len(v1.Value) != len(v2.Value) {
						return evaldo.MakeBuiltinError(ps, "Vectors must have same length", "vec-sub")
					}
					data := make(govector.Vector, len(v1.Value))
					for i := range v1.Value {
						data[i] = v1.Value[i] - v2.Value[i]
					}
					return *env.NewVector(data)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "vec-sub")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "vec-sub")
			}
		},
	},

	"vec-to-block": {
		Argsn: 1,
		Doc:   "Converts a vector to a block of decimal values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v := arg0.(type) {
			case env.Vector:
				items := make([]env.Object, len(v.Value))
				for i, val := range v.Value {
					items[i] = *env.NewDecimal(val)
				}
				return *env.NewBlock(*env.NewTSeries(items))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "vec-to-block")
			}
		},
	},
}
View Source
var Builtins_mcp = map[string]*env.Builtin{

	"mcp-server//Create": {
		Argsn: 2,
		Doc:   "Creates a new MCP server with the given name and version.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch name := arg0.(type) {
			case env.String:
				switch version := arg1.(type) {
				case env.String:
					mcpServerMutex.Lock()
					defer mcpServerMutex.Unlock()

					serverInfo := struct {
						Name    string
						Version string
					}{
						Name:    name.Value,
						Version: version.Value,
					}

					return *env.NewNative(ps.Idx, serverInfo, "Rye-mcp-server")
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mcp-server//create")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "mcp-server//create")
			}
		},
	},

	"mcp//Create-resource": {
		Argsn: 3,
		Doc:   "Creates a new MCP resource with the given URI, name, and MIME type.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch uri := arg0.(type) {
			case env.String:
				switch name := arg1.(type) {
				case env.String:
					switch mimeType := arg2.(type) {
					case env.String:

						resourceInfo := struct {
							URI      string
							Name     string
							MIMEType string
						}{
							URI:      uri.Value,
							Name:     name.Value,
							MIMEType: mimeType.Value,
						}

						return *env.NewNative(ps.Idx, resourceInfo, "Rye-mcp-resource")
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "mcp-resource//create")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mcp-resource//create")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "mcp-resource//create")
			}
		},
	},

	"mcp//Create-tool": {
		Argsn: 2,
		Doc:   "Creates a new MCP tool with the given name and description.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch name := arg0.(type) {
			case env.String:
				switch desc := arg1.(type) {
				case env.String:

					toolInfo := struct {
						Name        string
						Description string
					}{
						Name:        name.Value,
						Description: desc.Value,
					}

					return *env.NewNative(ps.Idx, toolInfo, "Rye-mcp-tool")
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mcp-tool//create")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "mcp-tool//create")
			}
		},
	},

	"mcp//Create-prompt": {
		Argsn: 2,
		Doc:   "Creates a new MCP prompt with the given name and description.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch name := arg0.(type) {
			case env.String:
				switch desc := arg1.(type) {
				case env.String:

					promptInfo := struct {
						Name        string
						Description string
					}{
						Name:        name.Value,
						Description: desc.Value,
					}

					return *env.NewNative(ps.Idx, promptInfo, "Rye-mcp-prompt")
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mcp-prompt//create")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "mcp-prompt//create")
			}
		},
	},

	"mcp//Protocol-version": {
		Argsn: 0,
		Doc:   "Returns the latest MCP protocol version.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return env.String{Value: "2024-11-05"}
		},
	},

	"Rye-mcp-server//Get-name": {
		Argsn: 1,
		Doc:   "Gets the name of the MCP server.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch srv := arg0.(type) {
			case env.Native:
				if srv.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-server//get-name")
				}

				serverInfo, ok := srv.Value.(struct {
					Name    string
					Version string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to server info", "Rye-mcp-server//get-name")
				}

				return env.String{Value: serverInfo.Name}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-server//get-name")
			}
		},
	},

	"Rye-mcp-server//Get-version": {
		Argsn: 1,
		Doc:   "Gets the version of the MCP server.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch srv := arg0.(type) {
			case env.Native:
				if srv.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-server//get-version")
				}

				serverInfo, ok := srv.Value.(struct {
					Name    string
					Version string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to server info", "Rye-mcp-server//get-version")
				}

				return env.String{Value: serverInfo.Version}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-server//get-version")
			}
		},
	},

	"Rye-mcp-resource//Get-uri": {
		Argsn: 1,
		Doc:   "Gets the URI of the MCP resource.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch res := arg0.(type) {
			case env.Native:
				if res.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-resource//get-uri")
				}

				resourceInfo, ok := res.Value.(struct {
					URI      string
					Name     string
					MIMEType string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to resource info", "Rye-mcp-resource//get-uri")
				}

				return env.String{Value: resourceInfo.URI}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-resource//get-uri")
			}
		},
	},

	"Rye-mcp-resource//Get-name": {
		Argsn: 1,
		Doc:   "Gets the name of the MCP resource.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch res := arg0.(type) {
			case env.Native:
				if res.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-resource//get-name")
				}

				resourceInfo, ok := res.Value.(struct {
					URI      string
					Name     string
					MIMEType string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to resource info", "Rye-mcp-resource//get-name")
				}

				return env.String{Value: resourceInfo.Name}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-resource//get-name")
			}
		},
	},

	"Rye-mcp-resource//Get-mime-type": {
		Argsn: 1,
		Doc:   "Gets the MIME type of the MCP resource.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch res := arg0.(type) {
			case env.Native:
				if res.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-resource//get-mime-type")
				}

				resourceInfo, ok := res.Value.(struct {
					URI      string
					Name     string
					MIMEType string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to resource info", "Rye-mcp-resource//get-mime-type")
				}

				return env.String{Value: resourceInfo.MIMEType}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-resource//get-mime-type")
			}
		},
	},

	"Rye-mcp-tool//Get-name": {
		Argsn: 1,
		Doc:   "Gets the name of the MCP tool.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch tool := arg0.(type) {
			case env.Native:
				if tool.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-tool//get-name")
				}

				toolInfo, ok := tool.Value.(struct {
					Name        string
					Description string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to tool info", "Rye-mcp-tool//get-name")
				}

				return env.String{Value: toolInfo.Name}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-tool//get-name")
			}
		},
	},

	"Rye-mcp-tool//Get-description": {
		Argsn: 1,
		Doc:   "Gets the description of the MCP tool.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch tool := arg0.(type) {
			case env.Native:
				if tool.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-tool//get-description")
				}

				toolInfo, ok := tool.Value.(struct {
					Name        string
					Description string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to tool info", "Rye-mcp-tool//get-description")
				}

				return env.String{Value: toolInfo.Description}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-tool//get-description")
			}
		},
	},

	"Rye-mcp-prompt//Get-name": {
		Argsn: 1,
		Doc:   "Gets the name of the MCP prompt.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch prompt := arg0.(type) {
			case env.Native:
				if prompt.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-prompt//get-name")
				}

				promptInfo, ok := prompt.Value.(struct {
					Name        string
					Description string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to prompt info", "Rye-mcp-prompt//get-name")
				}

				return env.String{Value: promptInfo.Name}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-prompt//get-name")
			}
		},
	},

	"Rye-mcp-prompt//Get-description": {
		Argsn: 1,
		Doc:   "Gets the description of the MCP prompt.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch prompt := arg0.(type) {
			case env.Native:
				if prompt.Type() != env.NativeType {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Expected native type", "Rye-mcp-prompt//get-description")
				}

				promptInfo, ok := prompt.Value.(struct {
					Name        string
					Description string
				})
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Failed to cast to prompt info", "Rye-mcp-prompt//get-description")
				}

				return env.String{Value: promptInfo.Description}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mcp-prompt//get-description")
			}
		},
	},
}
View Source
var Builtins_mqtt = map[string]*env.Builtin{

	"mqtt-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a connection to an MQTT broker.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch uri := arg0.(type) {
			case env.Uri:

				scheme := ps.Idx.GetWord(uri.Scheme.Index)
				if scheme != "mqtt" && scheme != "mqtts" {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "URI scheme must be 'mqtt' or 'mqtts'", "mqtt-uri//Open")
				}

				// Construct broker URL
				var brokerURL string
				if scheme == "mqtts" {
					brokerURL = "ssl://" + uri.Path
				} else {
					brokerURL = "tcp://" + uri.Path
				}

				clientID := "mqtt-client"
				if len(uri.Path) > 0 {

					parts := strings.Split(uri.Path, "/")
					if len(parts) > 1 && parts[1] != "" {
						clientID = parts[1]

						brokerURL = strings.Replace(brokerURL, "/"+clientID, "", 1)
					}
				}

				opts := mqtt.NewClientOptions()
				opts.AddBroker(brokerURL)
				opts.SetClientID(clientID)
				opts.SetDefaultPublishHandler(func(client mqtt.Client, msg mqtt.Message) {

				})

				client := mqtt.NewClient(opts)
				if token := client.Connect(); token.Wait() && token.Error() != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to connect to MQTT broker: %v", token.Error()), "mqtt-uri//Open")
				}

				return *env.NewNative(ps.Idx, client, "mqtt-client")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "mqtt-uri//Open")
			}
		},
	},

	"mqtt-client//Disconnect": {
		Argsn: 1,
		Doc:   "Disconnects from the MQTT broker.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				mqttClient := client.Value.(mqtt.Client)
				mqttClient.Disconnect(250)
				return *env.NewInteger(1)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Disconnect")
			}
		},
	},

	"mqtt-client//Close": {
		Argsn: 1,
		Doc:   "Closes the MQTT client connection (alias for Disconnect).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				if ps.Idx.GetWord(client.Kind.Index) != "mqtt-client" {
					return evaldo.MakeBuiltinError(ps, "Expected MQTT client connection.", "mqtt-client//Close")
				}
				mqttClient := client.Value.(mqtt.Client)
				mqttClient.Disconnect(250)
				return *env.NewInteger(1)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Close")
			}
		},
	},

	"mqtt-client//Publish": {
		Argsn: 5,
		Doc:   "Publishes a message to an MQTT topic with specified QoS and retain flag.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				switch topic := arg1.(type) {
				case env.String:
					switch payload := arg2.(type) {
					case env.String:
						switch qos := arg3.(type) {
						case env.Integer:
							switch retain := arg4.(type) {
							case env.Integer:
								mqttClient := client.Value.(mqtt.Client)
								retainBool := retain.Value != 0

								if qos.Value < 0 || qos.Value > 2 {
									ps.FailureFlag = true
									return evaldo.MakeBuiltinError(ps, "QoS must be 0, 1, or 2", "mqtt-client//Publish")
								}

								token := mqttClient.Publish(topic.Value, byte(qos.Value), retainBool, payload.Value)
								if token.Wait() && token.Error() != nil {
									ps.FailureFlag = true
									return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to publish message: %v", token.Error()), "mqtt-client//Publish")
								}

								return *env.NewInteger(1)
							default:
								ps.FailureFlag = true
								return evaldo.MakeArgError(ps, 5, []env.Type{env.IntegerType}, "mqtt-client//Publish")
							}
						default:
							ps.FailureFlag = true
							return evaldo.MakeArgError(ps, 4, []env.Type{env.IntegerType}, "mqtt-client//Publish")
						}
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "mqtt-client//Publish")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-client//Publish")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Publish")
			}
		},
	},

	"mqtt-client//Publish-simple": {
		Argsn: 3,
		Doc:   "Publishes a message to an MQTT topic with default settings (QoS 0, no retain).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				switch topic := arg1.(type) {
				case env.String:
					switch payload := arg2.(type) {
					case env.String:
						mqttClient := client.Value.(mqtt.Client)

						token := mqttClient.Publish(topic.Value, 0, false, payload.Value)
						if token.Wait() && token.Error() != nil {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to publish message: %v", token.Error()), "mqtt-client//Publish-simple")
						}

						return *env.NewInteger(1)
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "mqtt-client//Publish-simple")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-client//Publish-simple")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Publish-simple")
			}
		},
	},

	"mqtt-client//Subscribe": {
		Argsn: 4,
		Doc:   "Subscribes to an MQTT topic with a message handler function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				switch topic := arg1.(type) {
				case env.String:
					switch qos := arg2.(type) {
					case env.Integer:
						switch handler := arg3.(type) {
						case env.Function:
							mqttClient := client.Value.(mqtt.Client)

							if qos.Value < 0 || qos.Value > 2 {
								ps.FailureFlag = true
								return evaldo.MakeBuiltinError(ps, "QoS must be 0, 1, or 2", "mqtt-client//Subscribe")
							}

							callback := func(client mqtt.Client, msg mqtt.Message) {

								psCallback := *ps
								psCallback.FailureFlag = false
								psCallback.ErrorFlag = false
								psCallback.ReturnFlag = false

								msgDict := make(map[string]any)
								msgDict["topic"] = *env.NewString(msg.Topic())

								msgDict["qos"] = *env.NewInteger(int64(msg.Qos()))
								msgDict["retained"] = *env.NewBoolean(msg.Retained())
								msgDict["duplicate"] = *env.NewBoolean(msg.Duplicate())
								msgDict["message-id"] = *env.NewInteger(int64(msg.MessageID()))

								evaldo.CallFunctionArgs2(handler,
									&psCallback,
									*env.NewString(string(msg.Payload())),
									*env.NewDict(msgDict),
									nil)
								if psCallback.FailureFlag || psCallback.ErrorFlag {
									fmt.Println("********* CALLBACK ERROR MQTT")
								}
								evaldo.MaybeDisplayFailureOrError(&psCallback, psCallback.Idx, "on-mqtt-message")
							}

							token := mqttClient.Subscribe(topic.Value, byte(qos.Value), callback)
							if token.Wait() && token.Error() != nil {
								ps.FailureFlag = true
								return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to subscribe: %v", token.Error()), "mqtt-client//Subscribe")
							}

							return *env.NewInteger(1)
						default:
							fmt.Println(arg3.Inspect(*ps.Idx))
							ps.FailureFlag = true
							return evaldo.MakeArgError(ps, 4, []env.Type{env.FunctionType}, "mqtt-client//Subscribe")
						}
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.IntegerType}, "mqtt-client//Subscribe")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-client//Subscribe")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Subscribe")
			}
		},
	},

	"mqtt-client//Subscribe-simple": {
		Argsn: 3,
		Doc:   "Subscribes to an MQTT topic with default QoS 0 and a message handler function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				switch topic := arg1.(type) {
				case env.String:
					switch handler := arg2.(type) {
					case env.Function:
						mqttClient := client.Value.(mqtt.Client)

						callback := func(client mqtt.Client, msg mqtt.Message) {

							psCallback := *ps
							psCallback.FailureFlag = false
							psCallback.ErrorFlag = false
							psCallback.ReturnFlag = false

							msgDict := make(map[string]any)
							msgDict["topic"] = *env.NewString(msg.Topic())
							msgDict["qos"] = *env.NewInteger(int64(msg.Qos()))
							msgDict["retained"] = *env.NewBoolean(msg.Retained())

							evaldo.CallFunctionArgs2(handler, &psCallback, *env.NewDict(msgDict), env.Void{}, nil)
						}

						token := mqttClient.Subscribe(topic.Value, 0, callback)
						if token.Wait() && token.Error() != nil {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to subscribe: %v", token.Error()), "mqtt-client//Subscribe-simple")
						}

						return *env.NewInteger(1)
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType}, "mqtt-client//Subscribe-simple")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-client//Subscribe-simple")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Subscribe-simple")
			}
		},
	},

	"mqtt-client//Unsubscribe": {
		Argsn: 2,
		Doc:   "Unsubscribes from an MQTT topic.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				switch topic := arg1.(type) {
				case env.String:
					mqttClient := client.Value.(mqtt.Client)

					token := mqttClient.Unsubscribe(topic.Value)
					if token.Wait() && token.Error() != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to unsubscribe: %v", token.Error()), "mqtt-client//Unsubscribe")
					}

					return *env.NewInteger(1)
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-client//Unsubscribe")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Unsubscribe")
			}
		},
	},

	"mqtt-client//Is-connected": {
		Argsn: 1,
		Doc:   "Checks if the MQTT client is currently connected to the broker.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch client := arg0.(type) {
			case env.Native:
				mqttClient := client.Value.(mqtt.Client)
				if mqttClient.IsConnected() {
					return *env.NewInteger(1)
				} else {
					return *env.NewInteger(0)
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-client//Connected?")
			}
		},
	},

	"mqtt-options": {
		Argsn: 0,
		Doc:   "Creates a new MQTT client options object for advanced configuration.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			opts := mqtt.NewClientOptions()
			return *env.NewNative(ps.Idx, opts, "mqtt-options")
		},
	},

	"mqtt-options//Set-broker": {
		Argsn: 2,
		Doc:   "Sets the MQTT broker address in the options.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch opts := arg0.(type) {
			case env.Native:
				switch broker := arg1.(type) {
				case env.String:
					options := opts.Value.(*mqtt.ClientOptions)
					options.AddBroker(broker.Value)
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-options//Set-broker")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-options//Set-broker")
			}
		},
	},

	"mqtt-options//Set-client-id": {
		Argsn: 2,
		Doc:   "Sets the client ID in the MQTT options.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch opts := arg0.(type) {
			case env.Native:
				switch clientID := arg1.(type) {
				case env.String:
					options := opts.Value.(*mqtt.ClientOptions)
					options.SetClientID(clientID.Value)
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-options//Set-client-id")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-options//Set-client-id")
			}
		},
	},

	"mqtt-options//Set-keep-alive": {
		Argsn: 2,
		Doc:   "Sets the keep alive interval in seconds.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch opts := arg0.(type) {
			case env.Native:
				switch keepAlive := arg1.(type) {
				case env.Integer:
					options := opts.Value.(*mqtt.ClientOptions)
					options.SetKeepAlive(time.Duration(keepAlive.Value) * time.Second)
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "mqtt-options//Set-keep-alive")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-options//Set-keep-alive")
			}
		},
	},

	"mqtt-options//Set-username": {
		Argsn: 2,
		Doc:   "Sets the username for MQTT authentication.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch opts := arg0.(type) {
			case env.Native:
				switch username := arg1.(type) {
				case env.String:
					options := opts.Value.(*mqtt.ClientOptions)
					options.SetUsername(username.Value)
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-options//Set-username")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-options//Set-username")
			}
		},
	},

	"mqtt-options//Set-password": {
		Argsn: 2,
		Doc:   "Sets the password for MQTT authentication.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch opts := arg0.(type) {
			case env.Native:
				switch password := arg1.(type) {
				case env.String:
					options := opts.Value.(*mqtt.ClientOptions)
					options.SetPassword(password.Value)
					return arg0
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-options//Set-password")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-options//Set-password")
			}
		},
	},

	"mqtt-options//Set-will": {
		Argsn: 5,
		Doc:   "Sets the Last Will and Testament message with QoS and retain flag.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch opts := arg0.(type) {
			case env.Native:
				switch topic := arg1.(type) {
				case env.String:
					switch payload := arg2.(type) {
					case env.String:
						switch qos := arg3.(type) {
						case env.Integer:
							switch retain := arg4.(type) {
							case env.Integer:
								if qos.Value < 0 || qos.Value > 2 {
									ps.FailureFlag = true
									return evaldo.MakeBuiltinError(ps, "QoS must be 0, 1, or 2", "mqtt-options//Set-will")
								}

								options := opts.Value.(*mqtt.ClientOptions)
								retainBool := retain.Value != 0
								options.SetWill(topic.Value, payload.Value, byte(qos.Value), retainBool)
								return arg0
							default:
								ps.FailureFlag = true
								return evaldo.MakeArgError(ps, 5, []env.Type{env.IntegerType}, "mqtt-options//Set-will")
							}
						default:
							ps.FailureFlag = true
							return evaldo.MakeArgError(ps, 4, []env.Type{env.IntegerType}, "mqtt-options//Set-will")
						}
					default:
						ps.FailureFlag = true
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "mqtt-options//Set-will")
					}
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mqtt-options//Set-will")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-options//Set-will")
			}
		},
	},

	"mqtt-options//Connect-with-options": {
		Argsn: 1,
		Doc:   "Creates and connects an MQTT client using the configured options.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch opts := arg0.(type) {
			case env.Native:
				options := opts.Value.(*mqtt.ClientOptions)
				client := mqtt.NewClient(options)

				if token := client.Connect(); token.Wait() && token.Error() != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to connect to MQTT broker: %v", token.Error()), "mqtt-options//Connect-with-options")
				}

				return *env.NewNative(ps.Idx, client, "mqtt-client")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "mqtt-options//Connect-with-options")
			}
		},
	},
}
View Source
var Builtins_msgdispatcher = map[string]*env.Builtin{

	"msg-dispatcher": {
		Argsn: 2,
		Doc:   "Creates a new message dispatcher with specified buffer size and initial state.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bufSize := arg0.(type) {
			case env.Integer:
				switch initialState := arg1.(type) {
				case env.Dict:
					dispatcher := NewMessageDispatcher(int(bufSize.Value), initialState)
					return *env.NewNative(ps.Idx, dispatcher, "msg-dispatcher")
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.DictType}, "msg-dispatcher")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "msg-dispatcher")
			}
		},
	},

	"msg-dispatcher//Register": {
		Argsn: 3,
		Doc:   "Registers a message handler function for a specific message type.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch native := arg0.(type) {
			case env.Native:
				dispatcher, ok := native.Value.(*MessageDispatcher)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Expected MessageDispatcher", "Rye-msg-dispatcher//Register")
				}

				switch msgType := arg1.(type) {
				case env.String:
					switch handler := arg2.(type) {
					case env.Function:
						if handler.Argsn != 2 {
							return evaldo.MakeBuiltinError(ps, "Handler must accept 2 arguments (message, state)", "Rye-msg-dispatcher//Register")
						}
						dispatcher.RegisterHandler(msgType.Value, handler)
						return arg0
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType}, "Rye-msg-dispatcher//Register")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Rye-msg-dispatcher//Register")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-msg-dispatcher//Register")
			}
		},
	},

	"msg-dispatcher//Unregister": {
		Argsn: 2,
		Doc:   "Unregisters a message handler for a specific message type.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch native := arg0.(type) {
			case env.Native:
				dispatcher, ok := native.Value.(*MessageDispatcher)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Expected MessageDispatcher", "Rye-msg-dispatcher//Unregister")
				}

				switch msgType := arg1.(type) {
				case env.String:
					dispatcher.UnregisterHandler(msgType.Value)
					return arg0
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Rye-msg-dispatcher//Unregister")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-msg-dispatcher//Unregister")
			}
		},
	},

	"msg-dispatcher//Send": {
		Argsn: 2,
		Doc:   "Sends a message to the dispatcher for processing.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch native := arg0.(type) {
			case env.Native:
				dispatcher, ok := native.Value.(*MessageDispatcher)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Expected MessageDispatcher", "Rye-msg-dispatcher//Send")
				}

				err := dispatcher.Send(arg1)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Send failed: %v", err), "Rye-msg-dispatcher//Send")
				}
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-msg-dispatcher//Send")
			}
		},
	},

	"msg-dispatcher//State": {
		Argsn: 1,
		Doc:   "Gets the current state from the dispatcher.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch native := arg0.(type) {
			case env.Native:
				dispatcher, ok := native.Value.(*MessageDispatcher)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Expected MessageDispatcher", "Rye-msg-dispatcher//State")
				}
				return dispatcher.GetState()
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-msg-dispatcher//State")
			}
		},
	},

	"msg-dispatcher//Set-state": {
		Argsn: 2,
		Doc:   "Sets the current state in the dispatcher.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch native := arg0.(type) {
			case env.Native:
				dispatcher, ok := native.Value.(*MessageDispatcher)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Expected MessageDispatcher", "Rye-msg-dispatcher//Set-state")
				}

				switch newState := arg1.(type) {
				case env.Dict:
					dispatcher.SetState(newState)
					return arg0
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.DictType}, "Rye-msg-dispatcher//Set-state")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-msg-dispatcher//Set-state")
			}
		},
	},

	"msg-dispatcher//Start": {
		Argsn: 2,
		Doc:   "Starts the message dispatcher loop in a goroutine. Optionally takes an update callback function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch native := arg0.(type) {
			case env.Native:
				dispatcher, ok := native.Value.(*MessageDispatcher)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Expected MessageDispatcher", "Rye-msg-dispatcher//Start")
				}

				var updateCallback env.Function
				switch cb := arg1.(type) {
				case env.Function:
					if cb.Argsn != 1 {
						return evaldo.MakeBuiltinError(ps, "Update callback must accept 1 argument (state)", "Rye-msg-dispatcher//Start")
					}
					updateCallback = cb
				case env.Void:

					updateCallback = env.Function{Argsn: -1}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.FunctionType, env.VoidType}, "Rye-msg-dispatcher//Start")
				}

				dispatcher.Start(ps, updateCallback)
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-msg-dispatcher//Start")
			}
		},
	},

	"msg-dispatcher//Stop": {
		Argsn: 1,
		Doc:   "Stops the message dispatcher loop and waits for it to finish.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch native := arg0.(type) {
			case env.Native:
				dispatcher, ok := native.Value.(*MessageDispatcher)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Expected MessageDispatcher", "Rye-msg-dispatcher//Stop")
				}
				dispatcher.Stop()
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-msg-dispatcher//Stop")
			}
		},
	},
}

Builtins for message dispatcher

View Source
var Builtins_mysql = map[string]*env.Builtin{

	"mysql-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a connection to a MySQL database.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.Uri:
				db, err := sql.Open("mysql", str.Path)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error opening MySQL: %v", err.Error()), "mysql-uri//Open")
				}

				if err := db.Ping(); err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error connecting to MySQL: %v", err.Error()), "mysql-uri//Open")
				}
				return *env.NewNative(ps.Idx, db, "Rye-mysql")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "mysql-uri//Open")
			}

		},
	},

	"mysql-uri//Open\\pwd": {
		Argsn: 2,
		Doc:   "Opens a connection to a MySQL database with separate password parameter.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.Uri:
				switch pwd := arg1.(type) {
				case env.String:
					path := strings.Replace(str.Path, "@", ":"+pwd.Value+"@", 1)
					db, err := sql.Open("mysql", path)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error opening MySQL: %v", err.Error()), "mysql-uri//Open\\pwd")
					}

					if err := db.Ping(); err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error connecting to MySQL: %v", err.Error()), "mysql-uri//Open\\pwd")
					}
					return *env.NewNative(ps.Idx, db, "Rye-mysql")
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "mysql-uri//Open\\pwd")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "mysql-uri//Open\\pwd")
			}
		},
	},

	"Rye-mysql//Exec": {
		Argsn: 2,
		Doc:   "Executes a SQL statement that modifies data (INSERT, UPDATE, DELETE).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch db1 := arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0, 2)
					_, vals = SQL_EvalBlock(ps, MODE_SQLITE, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					ps.ErrorFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-mysql//Exec")
				}
				if sqlstr != "" {

					db2 := db1.Value.(*sql.DB)
					res, err := db2.Exec(sqlstr, vals...)
					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "Rye-mysql//Exec")
					} else {
						num, _ := res.RowsAffected()
						if num > 0 {
							return env.NewInteger(1)
						} else {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "No rows affected.", "Rye-mysql//Exec")
						}
					}
				} else {
					return evaldo.MakeBuiltinError(ps, "SQL string is blank.", "Rye-mysql//Exec")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mysql//Exec")
			}
		},
	},

	"Rye-mysql//Query": {
		Argsn: 2,
		Doc:   "Executes a SQL query and returns results as a table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch db1 := arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:

					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0, 2)
					_, vals = SQL_EvalBlock(ps, MODE_SQLITE, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					ps.ErrorFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-mysql//Query")
				}
				if sqlstr != "" {

					rows, err := db1.Value.(*sql.DB).Query(sqlstr, vals...)

					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "Rye-mysql//Query")
					} else {
						cols, _ := rows.Columns()
						spr := env.NewTable(cols)
						i := 0
						for rows.Next() {

							var sr env.TableRow

							columns := make([]any, len(cols))
							columnPointers := make([]any, len(cols))
							for i := range columns {
								columnPointers[i] = &columns[i]
							}

							if err := rows.Scan(columnPointers...); err != nil {
								ps.FailureFlag = true
								return evaldo.MakeBuiltinError(ps, err.Error(), "Rye-mysql//Query")
							}

							m := make(map[string]any)
							for i, colName := range cols {
								val := *columnPointers[i].(*any)
								switch vval := val.(type) {
								case []uint8:

									m[colName] = env.ToRyeValue(string(vval))
									sr.Values = append(sr.Values, env.ToRyeValue(string(vval)))
								default:
									m[colName] = env.ToRyeValue(vval)
									sr.Values = append(sr.Values, env.ToRyeValue(vval))
								}
							}
							spr.AddRow(sr)

							i++
						}
						rows.Close()

						if i == 0 {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "No data.", "Rye-mysql//Query")
						}
						return *spr

					}
				} else {
					return evaldo.MakeBuiltinError(ps, "Empty SQL.", "Rye-mysql//Query")
				}

			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mysql//Query")
			}
		},
	},

	"Rye-mysql//Close": {
		Argsn: 1,
		Doc:   "Closes the MySQL database connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch db := arg0.(type) {
			case env.Native:
				mysqlKind, _ := ps.Idx.GetIndex("Rye-mysql")
				if db.Kind.Index != mysqlKind {
					return evaldo.MakeBuiltinError(ps, "Expected MySQL database connection.", "Rye-mysql//Close")
				}
				sqlDB, ok := db.Value.(*sql.DB)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Invalid database connection.", "Rye-mysql//Close")
				}
				err := sqlDB.Close()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error closing database: %v", err.Error()), "Rye-mysql//Close")
				}
				return *env.NewInteger(1)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-mysql//Close")
			}
		},
	},
}
View Source
var Builtins_os = map[string]*env.Builtin{

	"cwd?": {
		Argsn: 0,
		Doc:   "Gets the current working directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			path, err := os.Getwd()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "cwd?")
			}
			return *env.NewUri1(ps.Idx, "file://"+path)
		},
	},

	"does-exist": {
		Argsn: 1,
		Doc:   "Checks if a file or directory exists.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := filepath.Join(ps.WorkingPath, path.GetPath())
				res := FileExists(filePath)
				if res == -1 {
					return evaldo.MakeBuiltinError(ps, "Error checking if path exists: "+filePath, "does-exists")
				}
				return *env.NewBoolean(res == 1)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "does-exist")
			}
		},
	},

	"cd": {
		Argsn: 1,
		Doc:   "Changes the current working directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:

				err := os.Chdir(path.GetPath())
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "cd")
				}
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "cd")
			}
		},
	},

	"env?": {
		Argsn: 1,
		Doc:   "Gets the value of an environment variable.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch variable_name := arg0.(type) {
			case env.String:

				val, ok := os.LookupEnv(variable_name.Value)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Environment variable not found: "+variable_name.Value, "env?")
				}
				return *env.NewString(val)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "env?")
			}
		},
	},

	"mkdir": {
		Argsn: 1,
		Doc:   "Creates a new directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				newDir := filepath.Join(ps.WorkingPath, path.GetPath())

				err := os.Mkdir(newDir, 0755)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error creating directory: "+err.Error(), "mkdir")
				} else {
					return arg0
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "mkdir")
			}
		},
	},

	"mktmp": {
		Argsn: 0,
		Doc:   "Creates a new temporary directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			dir, err := os.MkdirTemp("", "rye-tmp-")
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error creating temporary directory: "+err.Error(), "mktmp")
			}
			return *env.NewUri1(ps.Idx, "file://"+dir)
		},
	},

	"rm": {
		Argsn: 1,
		Doc:   "Removes a file or empty directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := filepath.Join(ps.WorkingPath, path.GetPath())
				err := os.Remove(filePath)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error removing file: "+err.Error(), "rm")
				}
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "rm")
			}
		},
	},

	"rmdir": {
		Argsn: 1,
		Doc:   "Removes a directory and all its contents recursively.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				dirPath := filepath.Join(ps.WorkingPath, path.GetPath())
				err := os.RemoveAll(dirPath)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error removing directory: "+err.Error(), "rmdir")
				}
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "rmdir")
			}
		},
	},

	"cp": {
		Argsn: 2,
		Doc:   "Copies a file to a new location.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch dst := arg1.(type) {
				case env.Uri:
					srcPath := filepath.Join(ps.WorkingPath, src.GetPath())
					dstPath := filepath.Join(ps.WorkingPath, dst.GetPath())

					data, err := os.ReadFile(srcPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error reading source file: "+err.Error(), "cp")
					}

					srcInfo, err := os.Stat(srcPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error getting source file info: "+err.Error(), "cp")
					}

					err = os.WriteFile(dstPath, data, srcInfo.Mode())
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error writing destination file: "+err.Error(), "cp")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "cp")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "cp")
			}
		},
	},

	"file-info?": {
		Argsn: 1,
		Doc:   "Gets detailed information about a file or directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := filepath.Join(ps.WorkingPath, path.GetPath())
				info, err := os.Stat(filePath)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error getting file info: "+err.Error(), "file-info?")
				}
				r := env.NewDict(make(map[string]any, 5))
				r.Data["name"] = *env.NewString(info.Name())
				r.Data["size"] = *env.NewInteger(info.Size())
				r.Data["mode"] = *env.NewString(info.Mode().String())
				r.Data["mod-time"] = *env.NewDate(info.ModTime())
				r.Data["is-dir"] = *env.NewBoolean(info.IsDir())
				return *r
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-info?")
			}
		},
	},

	"is-dir?": {
		Argsn: 1,
		Doc:   "Checks if a path is a directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := filepath.Join(ps.WorkingPath, path.GetPath())
				info, err := os.Stat(filePath)
				if err != nil {
					if os.IsNotExist(err) {
						return *env.NewBoolean(false)
					}
					return evaldo.MakeBuiltinError(ps, "Error checking path: "+err.Error(), "is-dir?")
				}
				return *env.NewBoolean(info.IsDir())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "is-dir?")
			}
		},
	},

	"is-file?": {
		Argsn: 1,
		Doc:   "Checks if a path is a regular file (not a directory).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := filepath.Join(ps.WorkingPath, path.GetPath())
				info, err := os.Stat(filePath)
				if err != nil {
					if os.IsNotExist(err) {
						return *env.NewBoolean(false)
					}
					return evaldo.MakeBuiltinError(ps, "Error checking path: "+err.Error(), "is-file?")
				}
				return *env.NewBoolean(info.Mode().IsRegular())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "is-file?")
			}
		},
	},

	"home-dir?": {
		Argsn: 0,
		Doc:   "Gets the current user's home directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			dir, err := os.UserHomeDir()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error getting home directory: "+err.Error(), "home-dir?")
			}
			return *env.NewUri1(ps.Idx, "file://"+dir)
		},
	},

	"tmp-dir?": {
		Argsn: 0,
		Doc:   "Gets the system's default temporary directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			dir := os.TempDir()
			return *env.NewUri1(ps.Idx, "file://"+dir)
		},
	},

	"glob": {
		Argsn: 1,
		Doc:   "Returns files matching a glob pattern.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch pattern := arg0.(type) {
			case env.String:
				patternPath := filepath.Join(ps.WorkingPath, pattern.Value)
				matches, err := filepath.Glob(patternPath)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error in glob pattern: "+err.Error(), "glob")
				}
				items := make([]env.Object, len(matches))
				for i, match := range matches {
					items[i] = *env.NewUri1(ps.Idx, "file://"+match)
				}
				return *env.NewBlock(*env.NewTSeries(items))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "glob")
			}
		},
	},

	"mv": {
		Argsn: 2,
		Doc:   "Moves or renames a file or directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch dst := arg1.(type) {
				case env.Uri:
					oldPath := filepath.Join(ps.WorkingPath, src.GetPath())
					newPath := filepath.Join(ps.WorkingPath, dst.GetPath())
					err := os.Rename(oldPath, newPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error moving file: "+err.Error(), "mv")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "mv")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "mv")
			}
		},
	},

	"ls": {
		Argsn: 0,
		Doc:   "Lists files and directories in the current directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			files, err := os.ReadDir(".")
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error reading directory:"+err.Error(), "ls")
			}

			items := make([]env.Object, len(files))

			for i, file := range files {

				items[i] = *env.NewUri1(ps.Idx, "file://"+file.Name())
			}
			return *env.NewBlock(*env.NewTSeries(items))
		},
	},

	"ls\\": {
		Argsn: 1,
		Doc:   "Lists files or directories with absolute paths when possible. If argument is a file-uri, lists that directory (or returns failure if not a directory). Otherwise filters current directory: 'dirs' for directories only, 'files' for files only, a string for partial name matching, or a regexp to match names.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var targetDir string = "."
			var doFiltering bool = true
			var filterArg env.Object = arg0

			if uri, ok := arg0.(env.Uri); ok {
				targetPath := resolvePath(ps.WorkingPath, uri.GetPath())

				info, err := os.Stat(targetPath)
				if err != nil {
					if os.IsNotExist(err) {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("path doesn't exist: %s", uri.GetPath()), "ls\\")
					}
					if os.IsPermission(err) {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("permission denied: %s", uri.GetPath()), "ls\\")
					}
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("error accessing path %s: %s", uri.GetPath(), err.Error()), "ls\\")
				}

				if !info.IsDir() {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("not a directory (is file): %s", uri.GetPath()), "ls\\")
				}

				targetDir = targetPath
				doFiltering = false
			}

			files, err := os.ReadDir(targetDir)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error reading directory:"+err.Error(), "ls\\")
			}

			var items []env.Object

			if !doFiltering {

				for _, file := range files {
					absPath, err := filepath.Abs(filepath.Join(targetDir, file.Name()))
					if err != nil {

						items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
					} else {
						items = append(items, *env.NewUri1(ps.Idx, "file://"+absPath))
					}
				}
			} else {

				switch filterArg := filterArg.(type) {
				case env.Word:
					filter := ps.Idx.GetWord(filterArg.Index)
					if filter != "dirs" && filter != "files" {
						return evaldo.MakeBuiltinError(ps, "Word filter must be 'dirs' or 'files'", "ls\\")
					}

					for _, file := range files {
						include := false
						if filter == "dirs" {
							include = file.IsDir()
						} else if filter == "files" {
							include = !file.IsDir()
						}

						if include {
							absPath, err := filepath.Abs(filepath.Join(targetDir, file.Name()))
							if err != nil {

								items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
							} else {
								items = append(items, *env.NewUri1(ps.Idx, "file://"+absPath))
							}
						}
					}

				case env.String:

					pattern := filterArg.Value
					for _, file := range files {
						if strings.Contains(file.Name(), pattern) {
							absPath, err := filepath.Abs(filepath.Join(targetDir, file.Name()))
							if err != nil {

								items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
							} else {
								items = append(items, *env.NewUri1(ps.Idx, "file://"+absPath))
							}
						}
					}

				case env.Native:

					if ps.Idx.GetWord(filterArg.Kind.Index) != "regexp" {
						return evaldo.MakeBuiltinError(ps, "Native object must be a regexp", "ls\\")
					}

					regex := filterArg.Value.(*regexp.Regexp)
					for _, file := range files {
						if regex.MatchString(file.Name()) {
							absPath, err := filepath.Abs(filepath.Join(targetDir, file.Name()))
							if err != nil {

								items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
							} else {
								items = append(items, *env.NewUri1(ps.Idx, "file://"+absPath))
							}
						}
					}

				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.WordType, env.StringType, env.NativeType}, "ls\\")
				}
			}

			return *env.NewBlock(*env.NewTSeries(items))
		},
	},

	"ls\\dirs": {
		Argsn: 0,
		Doc:   "Lists only directories in the current directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			files, err := os.ReadDir(".")
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error reading directory:"+err.Error(), "ls\\dirs")
			}

			var items []env.Object
			for _, file := range files {
				if file.IsDir() {
					items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
				}
			}
			return *env.NewBlock(*env.NewTSeries(items))
		},
	},

	"ls\\files": {
		Argsn: 0,
		Doc:   "Lists only files (non-directories) in the current directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			files, err := os.ReadDir(".")
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error reading directory:"+err.Error(), "ls\\files")
			}

			var items []env.Object
			for _, file := range files {
				if !file.IsDir() {
					items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
				}
			}
			return *env.NewBlock(*env.NewTSeries(items))
		},
	},

	"ls\\dirs\\": {
		Argsn: 1,
		Doc:   "Lists directories in the current directory with filtering. Use a string for partial name matching, or a regexp to match names.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			files, err := os.ReadDir(".")
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error reading directory:"+err.Error(), "ls\\dirs\\")
			}

			var items []env.Object

			switch filterArg := arg0.(type) {
			case env.String:

				pattern := filterArg.Value
				for _, file := range files {
					if file.IsDir() && strings.Contains(file.Name(), pattern) {
						items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
					}
				}

			case env.Native:

				if ps.Idx.GetWord(filterArg.Kind.Index) != "regexp" {
					return evaldo.MakeBuiltinError(ps, "Native object must be a regexp", "ls\\dirs\\")
				}

				regex := filterArg.Value.(*regexp.Regexp)
				for _, file := range files {
					if file.IsDir() && regex.MatchString(file.Name()) {
						items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
					}
				}

			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType, env.NativeType}, "ls\\dirs\\")
			}

			return *env.NewBlock(*env.NewTSeries(items))
		},
	},

	"ls\\files\\": {
		Argsn: 1,
		Doc:   "Lists files (non-directories) in the current directory with filtering. Use a string for partial name matching, or a regexp to match names.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			files, err := os.ReadDir(".")
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error reading directory:"+err.Error(), "ls\\files\\")
			}

			var items []env.Object

			switch filterArg := arg0.(type) {
			case env.String:

				pattern := filterArg.Value
				for _, file := range files {
					if !file.IsDir() && strings.Contains(file.Name(), pattern) {
						items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
					}
				}

			case env.Native:

				if ps.Idx.GetWord(filterArg.Kind.Index) != "regexp" {
					return evaldo.MakeBuiltinError(ps, "Native object must be a regexp", "ls\\files\\")
				}

				regex := filterArg.Value.(*regexp.Regexp)
				for _, file := range files {
					if !file.IsDir() && regex.MatchString(file.Name()) {
						items = append(items, *env.NewUri1(ps.Idx, "file://"+file.Name()))
					}
				}

			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType, env.NativeType}, "ls\\files\\")
			}

			return *env.NewBlock(*env.NewTSeries(items))
		},
	},

	"symlink": {
		Argsn: 2,
		Doc:   "Creates a symbolic link.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch link := arg1.(type) {
				case env.Uri:
					srcPath := resolvePath(ps.WorkingPath, src.GetPath())
					linkPath := resolvePath(ps.WorkingPath, link.GetPath())
					err := os.Symlink(srcPath, linkPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error creating symlink: "+err.Error(), "symlink")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "symlink")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "symlink")
			}
		},
	},

	"is-symlink?": {
		Argsn: 1,
		Doc:   "Checks if a path is a symbolic link.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := resolvePath(ps.WorkingPath, path.GetPath())
				info, err := os.Lstat(filePath)
				if err != nil {
					if os.IsNotExist(err) {
						return *env.NewBoolean(false)
					}
					return evaldo.MakeBuiltinError(ps, "Error checking path: "+err.Error(), "is-symlink?")
				}
				return *env.NewBoolean(info.Mode()&os.ModeSymlink != 0)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "is-symlink?")
			}
		},
	},

	"readlink": {
		Argsn: 1,
		Doc:   "Reads the target of a symbolic link.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				linkPath := resolvePath(ps.WorkingPath, path.GetPath())
				target, err := os.Readlink(linkPath)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error reading symlink: "+err.Error(), "readlink")
				}
				return *env.NewUri1(ps.Idx, "file://"+target)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "readlink")
			}
		},
	},

	"chmod": {
		Argsn: 2,
		Doc:   "Changes file or directory permissions.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				switch mode := arg1.(type) {
				case env.Integer:
					filePath := resolvePath(ps.WorkingPath, path.GetPath())
					err := os.Chmod(filePath, os.FileMode(mode.Value))
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error changing permissions: "+err.Error(), "chmod")
					}
					return arg0
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "chmod")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "chmod")
			}
		},
	},

	"abs-path": {
		Argsn: 1,
		Doc:   "Returns the absolute path for a given path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				absPath, err := filepath.Abs(resolvePath(ps.WorkingPath, path.GetPath()))
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error getting absolute path: "+err.Error(), "abs-path")
				}
				return *env.NewUri1(ps.Idx, "file://"+absPath)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "abs-path")
			}
		},
	},

	"dirname": {
		Argsn: 1,
		Doc:   "Returns the directory part of a path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				dir := filepath.Dir(path.GetPath())
				return *env.NewUri1(ps.Idx, "file://"+dir)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "dirname")
			}
		},
	},

	"basename": {
		Argsn: 1,
		Doc:   "Returns the filename part of a path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				base := filepath.Base(path.GetPath())
				return *env.NewString(base)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "basename")
			}
		},
	},

	"file-ext": {
		Argsn: 1,
		Doc:   "Returns the file extension of a path (including the dot).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				ext := filepath.Ext(path.GetPath())
				return *env.NewString(ext)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-ext")
			}
		},
	},

	"join-path": {
		Argsn: 1,
		Doc:   "Joins path elements into a single path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch paths := arg0.(type) {
			case env.Block:
				pathStrs := make([]string, paths.Series.Len())
				for i := 0; i < paths.Series.Len(); i++ {
					item := paths.Series.Get(i)
					switch p := item.(type) {
					case env.Uri:
						pathStrs[i] = p.GetPath()
					case env.String:
						pathStrs[i] = p.Value
					default:
						return evaldo.MakeBuiltinError(ps, "Block must contain only uris or strings", "join-path")
					}
				}
				joined := filepath.Join(pathStrs...)
				return *env.NewUri1(ps.Idx, "file://"+joined)
			case env.Uri:

				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.BlockType}, "join-path")
			}
		},
	},

	"whoami": {
		Argsn: 0,
		Doc:   "Returns the current user's username.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			username := os.Getenv("USER")
			if username == "" {
				username = os.Getenv("USERNAME")
			}
			if username == "" {
				return evaldo.MakeBuiltinError(ps, "Unable to determine username", "whoami")
			}
			return *env.NewString(username)
		},
	},

	"which": {
		Argsn: 1,
		Doc:   "Finds the path to an executable command.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cmd := arg0.(type) {
			case env.String:
				path, err := findExecutable(cmd.Value)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Command not found: "+cmd.Value, "which")
				}
				return *env.NewUri1(ps.Idx, "file://"+path)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "which")
			}
		},
	},

	"cp-r": {
		Argsn: 2,
		Doc:   "Recursively copies a directory and all its contents.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch dst := arg1.(type) {
				case env.Uri:
					srcPath := resolvePath(ps.WorkingPath, src.GetPath())
					dstPath := resolvePath(ps.WorkingPath, dst.GetPath())
					err := copyRecursive(srcPath, dstPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error copying recursively: "+err.Error(), "cp-r")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "cp-r")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "cp-r")
			}
		},
	},

	"mkdir-p": {
		Argsn: 1,
		Doc:   "Creates a directory and any necessary parent directories.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				dirPath := resolvePath(ps.WorkingPath, path.GetPath())
				err := os.MkdirAll(dirPath, 0755)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error creating directory: "+err.Error(), "mkdir-p")
				}
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "mkdir-p")
			}
		},
	},

	"host-info?": {
		Argsn: 0,
		Doc:   "Gets information about the host system.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			v, err := host.Info()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "host-info?")
			}
			r := env.NewDict(make(map[string]any, 10))
			r.Data["hostname"] = *env.NewString(v.Hostname)
			r.Data["uptime"] = *env.NewInteger(int64(v.Uptime))
			r.Data["boot-time"] = *env.NewInteger(int64(v.BootTime))
			r.Data["procs"] = *env.NewInteger(int64(v.Procs))
			r.Data["os"] = *env.NewString(v.OS)
			r.Data["platform"] = *env.NewString(v.Platform)
			r.Data["platform-family"] = *env.NewString(v.PlatformFamily)
			r.Data["platform-version"] = *env.NewString(v.PlatformVersion)
			r.Data["kernel-version"] = *env.NewString(v.KernelVersion)
			r.Data["virtualization-system"] = *env.NewString(v.VirtualizationSystem)
			return *r
		},
	},

	"users?": {
		Argsn: 0,
		Doc:   "Gets information about users currently logged into the system.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			users, err := host.Users()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "users?")
			}
			s := env.NewTable([]string{"User", "Terminal", "Host", "Started"})
			for _, user := range users {
				vals := []any{
					*env.NewString(user.User),
					*env.NewString(user.Terminal),
					*env.NewString(user.Host),
					*env.NewInteger(int64(user.Started)),
				}
				s.AddRow(*env.NewTableRow(vals, s))
			}
			return *s
		},
	},

	"load-avg?": {
		Argsn: 0,
		Doc:   "Gets the system load average over the last 1, 5, and 15 minutes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			v, err := load.Avg()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "load-avg?")
			}
			r := env.NewDict(make(map[string]any, 3))
			r.Data["1"] = *env.NewDecimal(v.Load1)
			r.Data["5"] = *env.NewDecimal(v.Load5)
			r.Data["15"] = *env.NewDecimal(v.Load15)
			return *r
		},
	},

	"virtual-memory?": {
		Argsn: 0,
		Doc:   "Gets information about virtual memory usage.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			v, err := mem.VirtualMemory()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "virtual-memory?")
			}
			r := env.NewDict(make(map[string]any, 3))
			r.Data["total"] = *env.NewInteger(int64(v.Total))
			r.Data["free"] = *env.NewInteger(int64(v.Free))
			r.Data["used-percent"] = *env.NewDecimal(v.UsedPercent)
			return *r
		},
	},

	"disk-usage?": {
		Argsn: 0,
		Doc:   "Gets disk usage information for all partitions.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			partitions, err := disk.Partitions(true)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "disk-usage?")
			}
			s := env.NewTable([]string{"Filesystem", "Size", "Used", "Available", "Capacity", "iused", "ifree", "%iused", "Mounted on"})
			for _, partition := range partitions {
				usage, err := disk.Usage(partition.Mountpoint)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "disk-usage?")
				}
				vals := []any{
					*env.NewString(partition.Device),
					*env.NewInteger(int64(usage.Total)),
					*env.NewInteger(int64(usage.Used)),
					*env.NewInteger(int64(usage.Free)),
					*env.NewDecimal(usage.UsedPercent),
					*env.NewInteger(int64(usage.InodesUsed)),
					*env.NewInteger(int64(usage.InodesFree)),
					*env.NewInteger(int64(usage.InodesUsedPercent)),
					*env.NewString(usage.Path),
				}
				s.AddRow(*env.NewTableRow(vals, s))
			}
			return *s
		},
	},

	"pids?": {
		Argsn: 0,
		Doc:   "Gets a list of all process IDs currently running.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			pids, err := process.Pids()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "pids?")
			}

			pids2 := make([]env.Object, len(pids))
			for i, p := range pids {
				pids2[i] = env.NewInteger(int64(p))
			}
			return *env.NewBlock(*env.NewTSeries(pids2))
		},
	},

	"processes?": {
		Argsn: 0,
		Doc:   "Gets detailed information about all running processes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			processes, err := process.Processes()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "processes?")
			}
			s := proccesTableBase()
			for _, process := range processes {
				processTableAdd(s, process)
			}
			return *s
		},
	},

	"process": {
		Argsn: 1,
		Doc:   "Gets detailed information about a specific process by PID.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch pid := arg0.(type) {
			case env.Integer:
				process, err := process.NewProcess(int32(pid.Value))
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "process")
				}
				s := proccesTableBase()
				processTableAdd(s, process)
				return s.Rows[0].ToDict()
			default:
				return *evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "process")
			}
		},
	},

	"lookup-address": {
		Argsn: 1,
		Doc:   "Performs a reverse DNS lookup to get hostnames for an IP address.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch ip := arg0.(type) {
			case env.String:
				names, err := net.LookupAddr(ip.Value)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "lookup-address")
				}
				items := make([]env.Object, len(names))
				for i, name := range names {
					items[i] = *env.NewString(name)
				}
				return *env.NewBlock(*env.NewTSeries(items))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "lookup-address")
			}
		},
	},

	"lookup-ip": {
		Argsn: 1,
		Doc:   "Performs a DNS lookup to get IP addresses for a hostname.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch hostname := arg0.(type) {
			case env.String:
				ips, err := net.LookupIP(hostname.Value)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "lookup-ip")
				}
				items := make([]env.Object, len(ips))
				for i, ip := range ips {
					items[i] = *env.NewString(ip.String())
				}
				return *env.NewBlock(*env.NewTSeries(items))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "lookup-ip")
			}
		},
	},

	"write\\clipboard": {
		Argsn: 1,
		Doc:   "Writes a string value to the system clipboard.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.String:
				err := clipboard.WriteAll(val.Value)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, err.Error(), "write\\clipboard")
				}
				return arg0
			default:
				return *evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "write\\clipboard")
			}
		},
	},

	"read\\clipboard": {
		Argsn: 0,
		Doc:   "Reads the current contents of the system clipboard.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			val, err := clipboard.ReadAll()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "read\\clipboard")
			}
			return *env.NewString(val)
		},
	},

	"tgz": {
		Argsn: 2,
		Doc:   "Creates a .tar.gz archive from a file or directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch dst := arg1.(type) {
				case env.Uri:
					srcPath := resolvePath(ps.WorkingPath, src.GetPath())
					dstPath := resolvePath(ps.WorkingPath, dst.GetPath())
					err := createTarGz(srcPath, dstPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error creating tar.gz: "+err.Error(), "tgz")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "tgz")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "tgz")
			}
		},
	},

	"un-tgz": {
		Argsn: 2,
		Doc:   "Extracts a .tar.gz archive to a directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch dst := arg1.(type) {
				case env.Uri:
					srcPath := resolvePath(ps.WorkingPath, src.GetPath())
					dstPath := resolvePath(ps.WorkingPath, dst.GetPath())
					err := extractTarGz(srcPath, dstPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error extracting tar.gz: "+err.Error(), "un-tgz")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "un-tgz")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "un-tgz")
			}
		},
	},

	"zip": {
		Argsn: 2,
		Doc:   "Creates a .zip archive from a file or directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch dst := arg1.(type) {
				case env.Uri:
					srcPath := resolvePath(ps.WorkingPath, src.GetPath())
					dstPath := resolvePath(ps.WorkingPath, dst.GetPath())
					err := createZip(srcPath, dstPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error creating zip: "+err.Error(), "zip")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "zip")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "zip")
			}
		},
	},

	"unzip": {
		Argsn: 2,
		Doc:   "Extracts a .zip archive to a directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch dst := arg1.(type) {
				case env.Uri:
					srcPath := resolvePath(ps.WorkingPath, src.GetPath())
					dstPath := resolvePath(ps.WorkingPath, dst.GetPath())
					err := extractZip(srcPath, dstPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error extracting zip: "+err.Error(), "unzip")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "unzip")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "unzip")
			}
		},
	},

	"find": {
		Argsn: 1,
		Doc:   "Creates a new file finder starting from the given path(s).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				finder := find.NewFind(path.GetPath())
				return *env.NewNative(ps.Idx, finder, "finder")
			case env.Block:
				paths := make([]string, 0, path.Series.Len())
				for i := 0; i < path.Series.Len(); i++ {
					item := path.Series.Get(i)
					switch p := item.(type) {
					case env.Uri:
						paths = append(paths, p.GetPath())
					case env.String:
						paths = append(paths, p.Value)
					default:
						return evaldo.MakeBuiltinError(ps, "Block must contain only uris or strings", "find")
					}
				}
				finder := find.NewFind(paths...)
				return *env.NewNative(ps.Idx, finder, "finder")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType, env.BlockType}, "find")
			}
		},
	},

	"finder//min-depth!": {
		Argsn: 2,
		Doc:   "Sets the minimum depth for file traversal.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					switch depth := arg1.(type) {
					case env.Integer:
						finder.MinDepth(int(depth.Value))
						return arg0
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "finder//min-depth!")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//min-depth!")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//min-depth!")
			}
		},
	},

	"finder//max-depth!": {
		Argsn: 2,
		Doc:   "Sets the maximum depth for file traversal.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					switch depth := arg1.(type) {
					case env.Integer:
						finder.MaxDepth(int(depth.Value))
						return arg0
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "finder//max-depth!")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//max-depth!")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//max-depth!")
			}
		},
	},

	"finder//type": {
		Argsn: 2,
		Doc:   "Filters results by type: 'file (or \"f\") for files, 'dir (or \"d\") for directories.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					var typeStr string
					switch t := arg1.(type) {
					case env.Word:
						word := ps.Idx.GetWord(t.Index)
						switch word {
						case "file":
							typeStr = "f"
						case "dir":
							typeStr = "d"
						default:
							return evaldo.MakeBuiltinError(ps, "Type must be 'file or 'dir", "finder//type")
						}
					case env.String:
						if t.Value != "f" && t.Value != "d" {
							return evaldo.MakeBuiltinError(ps, "Type must be \"f\" or \"d\"", "finder//type")
						}
						typeStr = t.Value
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "finder//type")
					}
					finder.Type(typeStr)
					return arg0
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//type")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//type")
			}
		},
	},

	"finder//name": {
		Argsn: 2,
		Doc:   "Filters results by file name using a glob pattern.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					switch pattern := arg1.(type) {
					case env.String:
						finder.Name(pattern.Value)
						return arg0
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "finder//name")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//name")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//name")
			}
		},
	},

	"finder//whole-name": {
		Argsn: 2,
		Doc:   "Filters results by full path using a glob pattern.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					switch pattern := arg1.(type) {
					case env.String:
						finder.WholeName(pattern.Value)
						return arg0
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "finder//whole-name")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//whole-name")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//whole-name")
			}
		},
	},

	"finder//regex": {
		Argsn: 2,
		Doc:   "Filters results by regular expression on the full path.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					switch r := arg1.(type) {
					case env.Native:
						if regex, ok := r.Value.(*regexp.Regexp); ok {
							finder.Regex(regex)
							return arg0
						}
						return evaldo.MakeBuiltinError(ps, "Expected regexp object", "finder//regex")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "finder//regex")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//regex")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//regex")
			}
		},
	},

	"finder//empty": {
		Argsn: 1,
		Doc:   "Filters for empty files or directories.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					finder.Empty()
					return arg0
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//empty")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//empty")
			}
		},
	},

	"finder//eval": {
		Argsn: 1,
		Doc:   "Executes the find operation and returns matching paths as uris.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch f := arg0.(type) {
			case env.Native:
				if finder, ok := f.Value.(*find.Find); ok {
					results, err := finder.Evaluate()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error evaluating find: "+err.Error(), "finder//eval")
					}
					items := make([]env.Object, len(results))
					for i, path := range results {
						items[i] = *env.NewUri1(ps.Idx, "file://"+path)
					}
					return *env.NewBlock(*env.NewTSeries(items))
				}
				return evaldo.MakeBuiltinError(ps, "Expected finder object", "finder//eval")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "finder//eval")
			}
		},
	},

	"file-size": {
		Argsn: 1,
		Doc:   "Gets the size of a file in bytes.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := resolvePath(ps.WorkingPath, path.GetPath())
				info, err := os.Stat(filePath)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error getting file size: "+err.Error(), "file-size")
				}
				return *env.NewInteger(info.Size())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-size")
			}
		},
	},

	"touch": {
		Argsn: 1,
		Doc:   "Creates a file if it doesn't exist, or updates its access time if it does.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				filePath := resolvePath(ps.WorkingPath, path.GetPath())
				now := time.Now()
				err := os.Chtimes(filePath, now, now)
				if os.IsNotExist(err) {

					file, err := os.Create(filePath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error creating file: "+err.Error(), "touch")
					}
					file.Close()
				} else if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error touching file: "+err.Error(), "touch")
				}
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "touch")
			}
		},
	},

	"hardlink": {
		Argsn: 2,
		Doc:   "Creates a hard link to a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch src := arg0.(type) {
			case env.Uri:
				switch link := arg1.(type) {
				case env.Uri:
					srcPath := resolvePath(ps.WorkingPath, src.GetPath())
					linkPath := resolvePath(ps.WorkingPath, link.GetPath())
					err := os.Link(srcPath, linkPath)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Error creating hard link: "+err.Error(), "hardlink")
					}
					return arg1
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "hardlink")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "hardlink")
			}
		},
	},

	"count-dir": {
		Argsn: 1,
		Doc:   "Counts the number of files and directories in a directory.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var dirPath string
			switch path := arg0.(type) {
			case env.Uri:
				dirPath = resolvePath(ps.WorkingPath, path.GetPath())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "count-dir")
			}

			files, err := os.ReadDir(dirPath)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Error reading directory: "+err.Error(), "count-dir")
			}
			return *env.NewInteger(int64(len(files)))
		},
	},

	"pid": {
		Argsn: 0,
		Doc:   "Gets the current process ID.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewInteger(int64(os.Getpid()))
		},
	},

	"ppid": {
		Argsn: 0,
		Doc:   "Gets the parent process ID.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewInteger(int64(os.Getppid()))
		},
	},

	"sleep": {
		Argsn: 1,
		Doc:   "Sleeps for the specified number of seconds.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch seconds := arg0.(type) {
			case env.Integer:
				time.Sleep(time.Duration(seconds.Value) * time.Second)
				return arg0
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "sleep")
			}
		},
	},

	"tmux-available?": {
		Argsn: 0,
		Doc:   "Checks if tmux is available on the system.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			_, err := exec.LookPath("tmux")
			return *env.NewBoolean(err == nil)
		},
	},

	"tmux-new-session": {
		Argsn: 1,
		Doc:   "Creates a new tmux session with the given name using gotmux library.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			tmux, err := gotmux.DefaultTmux()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Failed to connect to tmux: "+err.Error(), "tmux-new-session")
			}

			switch name := arg0.(type) {
			case env.String:
				session, err := tmux.NewSession(&gotmux.SessionOptions{
					Name: name.Value,
				})
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Failed to create session: "+err.Error(), "tmux-new-session")
				}
				return *env.NewNative(ps.Idx, session, "tmux-session")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "tmux-new-session")
			}
		},
	},

	"tmux-list-sessions": {
		Argsn: 0,
		Doc:   "Lists all tmux sessions using gotmux library.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			tmux, err := gotmux.DefaultTmux()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Failed to connect to tmux: "+err.Error(), "tmux-list-sessions")
			}

			sessions, err := tmux.ListSessions()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Failed to list sessions: "+err.Error(), "tmux-list-sessions")
			}

			items := make([]env.Object, len(sessions))
			for i, session := range sessions {
				items[i] = *env.NewNative(ps.Idx, session, "tmux-session")
			}
			return *env.NewBlock(*env.NewTSeries(items))
		},
	},

	"tmux-get-session": {
		Argsn: 1,
		Doc:   "Gets a tmux session by name using gotmux library.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			tmux, err := gotmux.DefaultTmux()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Failed to connect to tmux: "+err.Error(), "tmux-get-session")
			}

			switch name := arg0.(type) {
			case env.String:
				session, err := tmux.GetSessionByName(name.Value)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Failed to get session: "+err.Error(), "tmux-get-session")
				}
				return *env.NewNative(ps.Idx, session, "tmux-session")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "tmux-get-session")
			}
		},
	},

	"tmux-new-window": {
		Argsn: 1,
		Doc:   "Creates a new window in the given tmux session.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch sess := arg0.(type) {
			case env.Native:
				if session, ok := sess.Value.(*gotmux.Session); ok {
					window, err := session.New()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Failed to create window: "+err.Error(), "tmux-new-window")
					}
					return *env.NewNative(ps.Idx, window, "tmux-window")
				}
				return evaldo.MakeBuiltinError(ps, "Expected tmux-session object", "tmux-new-window")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tmux-new-window")
			}
		},
	},

	"tmux-new-window-named": {
		Argsn: 2,
		Doc:   "Creates a new window in the given tmux session with a specific name.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch sess := arg0.(type) {
			case env.Native:
				if session, ok := sess.Value.(*gotmux.Session); ok {
					switch name := arg1.(type) {
					case env.String:
						window, err := session.NewWindow(&gotmux.NewWindowOptions{
							WindowName: name.Value,
						})
						if err != nil {
							return evaldo.MakeBuiltinError(ps, "Failed to create named window: "+err.Error(), "tmux-new-window-named")
						}
						return *env.NewNative(ps.Idx, window, "tmux-window")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "tmux-new-window-named")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected tmux-session object", "tmux-new-window-named")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tmux-new-window-named")
			}
		},
	},

	"tmux-list-windows": {
		Argsn: 1,
		Doc:   "Lists all windows in the given tmux session.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch sess := arg0.(type) {
			case env.Native:
				if session, ok := sess.Value.(*gotmux.Session); ok {
					windows, err := session.ListWindows()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Failed to list windows: "+err.Error(), "tmux-list-windows")
					}

					items := make([]env.Object, len(windows))
					for i, window := range windows {
						items[i] = *env.NewNative(ps.Idx, window, "tmux-window")
					}
					return *env.NewBlock(*env.NewTSeries(items))
				}
				return evaldo.MakeBuiltinError(ps, "Expected tmux-session object", "tmux-list-windows")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tmux-list-windows")
			}
		},
	},

	"tmux-get-pane": {
		Argsn: 2,
		Doc:   "Gets a pane from a tmux window by index.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch win := arg0.(type) {
			case env.Native:
				if window, ok := win.Value.(*gotmux.Window); ok {
					switch idx := arg1.(type) {
					case env.Integer:
						pane, err := window.GetPaneByIndex(int(idx.Value))
						if err != nil {
							return evaldo.MakeBuiltinError(ps, "Failed to get pane: "+err.Error(), "tmux-get-pane")
						}
						return *env.NewNative(ps.Idx, pane, "tmux-pane")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "tmux-get-pane")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected tmux-window object", "tmux-get-pane")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tmux-get-pane")
			}
		},
	},

	"tmux-split-pane": {
		Argsn: 1,
		Doc:   "Splits a tmux pane horizontally.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				if pane, ok := p.Value.(*gotmux.Pane); ok {
					err := pane.Split()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Failed to split pane: "+err.Error(), "tmux-split-pane")
					}
					return arg0
				}
				return evaldo.MakeBuiltinError(ps, "Expected tmux-pane object", "tmux-split-pane")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tmux-split-pane")
			}
		},
	},

	"tmux-send-keys": {
		Argsn: 2,
		Doc:   "Sends keys/command to a tmux pane.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				if pane, ok := p.Value.(*gotmux.Pane); ok {
					switch cmd := arg1.(type) {
					case env.String:
						err := pane.SendKeys(cmd.Value)
						if err != nil {
							return evaldo.MakeBuiltinError(ps, "Failed to send keys: "+err.Error(), "tmux-send-keys")
						}
						return arg0
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "tmux-send-keys")
					}
				}
				return evaldo.MakeBuiltinError(ps, "Expected tmux-pane object", "tmux-send-keys")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tmux-send-keys")
			}
		},
	},

	"tmux-kill-session": {
		Argsn: 1,
		Doc:   "Kills/destroys a tmux session.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch sess := arg0.(type) {
			case env.Native:
				if session, ok := sess.Value.(*gotmux.Session); ok {
					err := session.Kill()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Failed to kill session: "+err.Error(), "tmux-kill-session")
					}
					return arg0
				}
				return evaldo.MakeBuiltinError(ps, "Expected tmux-session object", "tmux-kill-session")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tmux-kill-session")
			}
		},
	},

	"net-interface?": {
		Argsn: 1,
		Doc:   "Looks up a network interface by name and returns it as a native object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch name := arg0.(type) {
			case env.String:
				iface, err := net.InterfaceByName(name.Value)
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "net-interface?")
				}
				return *env.NewNative(ps.Idx, iface, "net-iface")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "net-interface?")
			}
		},
	},

	"net-iface//Addrs?": {
		Argsn: 1,
		Doc:   "Returns a block of network addresses assigned to the interface.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch iface := arg0.(type) {
			case env.Native:
				addrs, err := iface.Value.(*net.Interface).Addrs()
				if err != nil {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, err.Error(), "net-iface//Addrs?")
				}
				items := make([]env.Object, len(addrs))
				for i, addr := range addrs {
					items[i] = *env.NewNative(ps.Idx, addr, "net-addr")
				}
				return *env.NewBlock(*env.NewTSeries(items))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "net-iface//Addrs?")
			}
		},
	},

	"net-addr//IPNet?": {
		Argsn: 1,
		Doc:   "Type-asserts a network address to *net.IPNet (CIDR form). Returns failure if the address is not an IP network.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch addr := arg0.(type) {
			case env.Native:
				ipnet, ok := addr.Value.(net.Addr).(*net.IPNet)
				if !ok {
					ps.FailureFlag = true
					return evaldo.MakeBuiltinError(ps, "Address is not an *net.IPNet.", "net-addr//IPNet?")
				}
				return *env.NewNative(ps.Idx, ipnet, "net-ipnet")
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "net-addr//IPNet?")
			}
		},
	},

	"net-ipnet//Loopback?": {
		Argsn: 1,
		Doc:   "Reports whether the IP address in the IPNet is a loopback address.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch ipnet := arg0.(type) {
			case env.Native:
				return *env.NewBoolean(ipnet.Value.(*net.IPNet).IP.IsLoopback())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "net-ipnet//Loopback?")
			}
		},
	},

	"net-ipnet//IPv4?": {
		Argsn: 1,
		Doc:   "Reports whether the IP address in the IPNet is an IPv4 address (IP.To4() != nil).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch ipnet := arg0.(type) {
			case env.Native:
				return *env.NewBoolean(ipnet.Value.(*net.IPNet).IP.To4() != nil)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "net-ipnet//IPv4?")
			}
		},
	},

	"net-ipnet//IP-string?": {
		Argsn: 1,
		Doc:   "Returns the IP address contained in the IPNet as a dotted-decimal (or colon-separated) string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch ipnet := arg0.(type) {
			case env.Native:
				return *env.NewString(ipnet.Value.(*net.IPNet).IP.String())
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "net-ipnet//IP-string")
			}
		},
	},
}
View Source
var Builtins_pipes = map[string]*env.Builtin{

	"cat": {
		Argsn: 1,
		Doc:   "Creates a new pipe object from a file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				p := script.File(path.GetPath())
				return *env.NewNative(ps.Idx, p, "script-pipe")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "p-new-file")
			}
		},
	},

	"find": {
		Argsn: 1,
		Doc:   "Creates a pipe object listing all the files in the directory and its subdirectories recursively, one per line.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				p := script.FindFiles(path.GetPath())
				return *env.NewNative(ps.Idx, p, "script-pipe")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "p-new-find-files")
			}
		},
	},

	"list": {
		Argsn: 1,
		Doc:   "Creates a pipe object listing all the files in the directory, one per line. Accepts and URI or glob pattern.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				p := script.ListFiles(path.GetPath())
				return *env.NewNative(ps.Idx, p, "script-pipe")
			case env.String:
				p := script.ListFiles(path.Value)
				return *env.NewNative(ps.Idx, p, "script-pipe")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "p-new-list-files")
			}
		},
	},

	"from-block": {
		Argsn: 1,
		Doc:   "Creates a pipe object from a block of strings, one per line.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch block := arg0.(type) {
			case env.Block:
				strs := make([]string, len(block.Series.S))
				for i, item := range block.Series.S {
					switch s := item.(type) {
					case env.String:
						strs[i] = s.Value
					default:
						return evaldo.MakeBuiltinError(ps, "Block must contain only strings", "p-new-block")
					}
				}
				p := script.Slice(strs)
				return *env.NewNative(ps.Idx, p, "script-pipe")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "p-new-block")
			}
		},
	},

	"echo": {
		Argsn: 1,
		Doc:   "Creates a pipe object from a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.String:
				p := script.Echo(s.Value)
				return *env.NewNative(ps.Idx, p, "script-pipe")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "p-new-echo")
			}
		},
	},

	"cat\\opt": {
		Argsn: 1,
		Doc:   "Creates a pipe object from a file if it exists, otherwise returns an empty pipe object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch path := arg0.(type) {
			case env.Uri:
				p := script.IfExists(path.GetPath())
				return *env.NewNative(ps.Idx, p, "script-pipe")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "p-new-if-exists")
			}
		},
	},

	"exec": {
		Argsn: 1,
		Doc:   "Creates a pipe object from a command that is executed.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cmd := arg0.(type) {
			case env.String:
				p := script.Exec(cmd.Value)
				return *env.NewNative(ps.Idx, p, "script-pipe")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "p-new-exec")
			}
		},
	},

	"exec\\in": {
		Argsn: 2,
		Doc:   "Executes a command by sending it the contents of the pipe as input and returns a pipe object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch cmd := arg1.(type) {
					case env.String:
						newPipe := pipe.Exec(cmd.Value)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-exec")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-exec")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-exec")
			}
		},
	},

	"exec\\each": {
		Argsn: 2,
		Doc:   "Executes a command from a Go template for each line in the pipe and returns a pipe object with the output of each command.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch cmd := arg1.(type) {
					case env.String:
						newPipe := pipe.ExecForEach(cmd.Value)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-exec-for-each")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-exec-for-each")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-exec-for-each")
			}
		},
	},

	"into-string": {
		Argsn: 1,
		Doc:   "Returns pipe contents as a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					str, err := pipe.String()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "p-string")
					}
					return *env.NewString(str)
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-string")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-string")
			}
		},
	},

	"into-file": {
		Argsn: 2,
		Doc:   "Writes pipe contents to a file and returns the number of bytes written.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch path := arg1.(type) {
					case env.Uri:
						i, err := pipe.WriteFile(path.GetPath())
						if err != nil {
							return evaldo.MakeBuiltinError(ps, err.Error(), "p-write-file")
						}
						return *env.NewInteger(i)
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType}, "p-write-file")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-write-file")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-write-file")
			}
		},
	},

	"out": {
		Argsn: 1,
		Doc:   "Prints pipe contents to stdout and returns the number of bytes written.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					i, err := pipe.Stdout()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "p-stdout")
					}
					return *env.NewInteger(int64(i))
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-stdout")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-stdout")
			}
		},
	},

	"head": {
		Argsn: 2,
		Doc:   "Returns a pipe with the first n lines from the pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch n := arg1.(type) {
					case env.Integer:
						newPipe := pipe.First(int(n.Value))
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "p-first-n")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-first-n")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-first-n")
			}
		},
	},

	"tail": {
		Argsn: 2,
		Doc:   "Returns a pipe with the last n lines from the pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch n := arg1.(type) {
					case env.Integer:
						newPipe := pipe.Last(int(n.Value))
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "p-last-n")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-last-n")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-last-n")
			}
		},
	},

	"dirname": {
		Argsn: 1,
		Doc:   "Reads paths from the pipe, one per line, and returns the directory component of each.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Dirname()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-dirname")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-dirname")
			}
		},
	},

	"basename": {
		Argsn: 1,
		Doc:   "Reads paths from the pipe, one per line, and removes any leading directory components from each.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Basename()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-basename")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-basename")
			}
		},
	},

	"wc\\l": {
		Argsn: 1,
		Doc:   "Returns the number of lines in a pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					n, err := pipe.CountLines()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "p-count-lines")
					}
					return *env.NewInteger(int64(n))
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-count-lines")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-count-lines")
			}
		},
	},

	"freq": {
		Argsn: 1,
		Doc:   "Returns a pipe object with the frequency of each line in a pipe in descending order.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Freq()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-freq")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-freq")
			}
		},
	},

	"column": {
		Argsn: 2,
		Doc:   "Returns a pipe object with the column of each line of input, where the first column is column 1, and columns are delimited by Unicode whitespace.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch n := arg1.(type) {
					case env.Integer:
						newPipe := pipe.Column(int(n.Value))
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "p-column")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-column")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-column")
			}
		},
	},

	"jq": {
		Argsn: 2,
		Doc:   "Executes the jq command on the pipe whose contents are presumed to be JSON and returns a new pipe object with the output.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch jq := arg1.(type) {
					case env.String:
						newPipe := pipe.JQ(jq.Value)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-jq")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-jq")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-jq")
			}
		},
	},

	"match": {
		Argsn: 2,
		Doc:   "Returns a pipe object with lines that match the string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch s := arg1.(type) {
					case env.String:
						newPipe := pipe.Match(s.Value)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-match")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-match")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-match")
			}
		},
	},

	"match\\regexp": {
		Argsn: 2,
		Doc:   "Returns a pipe object with lines that match the regular expression.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch r := arg1.(type) {
					case env.Native:
						switch regxp := r.Value.(type) {
						case *regexp.Regexp:
							newPipe := pipe.MatchRegexp(regxp)
							return *env.NewNative(ps.Idx, newPipe, "script-pipe")
						default:
							return evaldo.MakeNativeArgError(ps, 2, []string{"regexp"}, "p-match-regexp")
						}
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "p-match-regexp")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-match-regexp")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-match-regexp")
			}
		},
	},

	"not-match": {
		Argsn: 2,
		Doc:   "Returns a pipe object with lines that do not match the string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch s := arg1.(type) {
					case env.String:
						newPipe := pipe.Reject(s.Value)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-not-match")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-not-match")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-not-match")
			}
		},
	},

	"not-match\\regexp": {
		Argsn: 2,
		Doc:   "Returns a pipe object with lines that do not match the regular expression.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch r := arg1.(type) {
					case env.Native:
						switch regxp := r.Value.(type) {
						case *regexp.Regexp:
							newPipe := pipe.RejectRegexp(regxp)
							return *env.NewNative(ps.Idx, newPipe, "script-pipe")
						default:
							return evaldo.MakeNativeArgError(ps, 2, []string{"regexp"}, "p-not-match-regexp")
						}
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "p-not-match-regexp")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-not-match-regexp")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-not-match-regexp")
			}
		},
	},

	"replace": {
		Argsn: 3,
		Doc:   "Replaces all occurrences of a string with another string in the pipe and returns a new pipe object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch search := arg1.(type) {
					case env.String:
						switch replace := arg2.(type) {
						case env.String:
							newPipe := pipe.Replace(search.Value, replace.Value)
							return *env.NewNative(ps.Idx, newPipe, "script-pipe")
						default:
							return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "p-replace")
						}
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-replace")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-replace")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-replace")
			}
		},
	},

	"replace\\regexp": {
		Argsn: 3,
		Doc:   "Replaces all occurrences of strings that match the regexp pattern with a string in the pipe and returns a new pipe object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch searchR := arg1.(type) {
					case env.Native:
						switch searchRegexp := searchR.Value.(type) {
						case *regexp.Regexp:
							switch replace := arg2.(type) {
							case env.String:
								newPipe := pipe.ReplaceRegexp(searchRegexp, replace.Value)
								return *env.NewNative(ps.Idx, newPipe, "script-pipe")
							default:
								return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "p-replace-regexp")
							}
						default:
							return evaldo.MakeNativeArgError(ps, 2, []string{"regexp"}, "p-replace-regexp")
						}
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "p-replace-regexp")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-replace-regexp")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-replace-regexp")
			}
		},
	},

	"into-block": {
		Argsn: 1,
		Doc:   "Returns a block of strings with the contents of the pipe, one per line.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					lines, err := pipe.Slice()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "p-block")
					}
					items := make([]env.Object, len(lines))
					for i, line := range lines {
						items[i] = *env.NewString(line)
					}
					return *env.NewBlock(*env.NewTSeries(items))
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-block")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-block")
			}
		},
	},

	"error\\opt": {
		Argsn: 1,
		Doc:   "Returns the error from the pipe, if any.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					err := pipe.Error()
					if err != nil {
						return *env.NewError(err.Error())
					}
					return env.Void{}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-error")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-error")
			}
		},
	},

	"sha256sum": {
		Argsn: 1,
		Doc:   "Returns the hex-encoded SHA-256 hash of the entire contents of the pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					sha256, err := pipe.SHA256Sum()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "pipes/sha256sum")
					}
					return *env.NewString(sha256)
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "pipes/sha256sum")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "pipes/sha256sum")
			}
		},
	},

	"sha256sums": {
		Argsn: 1,
		Doc:   "Reads paths from the pipe, one per line, and produces the hex-encoded SHA-256 hash of each corresponding file, one per line.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.SHA256Sums()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "pipes/sha256sums")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "pipes/sha256sums")
			}
		},
	},

	"decodeBase64": {
		Argsn: 1,
		Doc:   "decodeBase64 produces the string represented by the base64 encoded input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.DecodeBase64()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "decodeBase64")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "decodeBase64")
			}
		},
	},

	"encodeBase64": {
		Argsn: 1,
		Doc:   "encodeBase64 produces the base64 encoding of the input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.EncodeBase64()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "encodeBase64")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "encodeBase64")
			}
		},
	},

	"join": {
		Argsn: 1,
		Doc:   "joins all the lines in the pipe's contents into a single space-separated string, which will always end with a newline.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Join()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-join")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-join")
			}
		},
	},

	"exit-status": {
		Argsn: 1,
		Doc:   "Returns the integer exit status of a previous command. This will be zero unless the pipe's error status is set and the error matches the pattern.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					status := pipe.ExitStatus()
					return *env.NewInteger(int64(status))
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-exit-status")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-exit-status")
			}
		},
	},

	"args": {
		Argsn: 0,
		Doc:   "Creates a pipe containing the program's command-line arguments from os.Args, excluding the program name, one per line.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			newPipe := script.Args()
			return *env.NewNative(ps.Idx, newPipe, "script-pipe")
		},
	},

	"concat": {
		Argsn: 1,
		Doc:   "concat reads paths from the pipe, one per line, and produces the contents of all the corresponding files in sequence. If there are any errors (for example, non-existent files), these will be ignored, execution will continue, and the pipe's error status will not be set.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Concat()
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-concat")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-concat")
			}
		},
	},

	"close": {
		Argsn: 1,
		Doc:   "Closes the pipe's associated reader.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					closeErr := pipe.Close()
					if closeErr != nil {
						return *env.NewError("Error closing pipe")
					}
					return *env.NewInteger(0)
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-close")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-close")
			}
		},
	},

	"get": {
		Argsn: 2,
		Doc:   "Get makes an HTTP GET request to url, sending the contents of the pipe as the request body, and produces the server's response.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch s := arg1.(type) {
					case env.String:
						newPipe := pipe.Get(s.Value)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-get")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-get")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-get")
			}
		},
	},

	"post": {
		Argsn: 2,
		Doc:   "Post makes an HTTP POST request to url, using the contents of the pipe as the request body, and produces the server's response.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch s := arg1.(type) {
					case env.String:
						newPipe := pipe.Post(s.Value)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-post")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-post")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-post")
			}
		},
	},

	"new": {
		Argsn: 0,
		Doc:   "new creates a new pipe with an empty reader.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			newPipe := script.NewPipe()
			return *env.NewNative(ps.Idx, newPipe, "script-pipe")
		},
	},

	"wait": {
		Argsn: 1,
		Doc:   "Wait reads the pipe to completion and returns any error present on the pipe, or 0 otherwise..",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					waitErr := pipe.Wait()
					if waitErr != nil {
						return *env.NewError("Error in pipe during waiting")
					}
					return *env.NewInteger(0)
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-wait")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-wait")
			}
		},
	},

	"append-to-file": {
		Argsn: 2,
		Doc:   "append-to-file appends the contents of the pipe to the file path, creating it if necessary, and returns the number of bytes successfully written, or an error.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch s := arg1.(type) {
					case env.String:
						writtenBytes, err := pipe.AppendFile(s.Value)
						if err != nil {
							return *env.NewError("Error while appending data to files.")
						}
						return *env.NewInteger(writtenBytes)
					case env.Uri:
						writtenBytes, err := pipe.AppendFile(s.Path)
						if err != nil {
							return *env.NewError("Error while appending data to rey-file.")
						}
						return *env.NewInteger(writtenBytes)
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType, env.UriType}, "p-append-to-file")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-append-to-file")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-append-to-file")
			}
		},
	},

	"stdin": {
		Argsn: 0,
		Doc:   "Stdin creates a pipe that reads from os.Stdin.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			newPipe := script.Stdin()
			return *env.NewNative(ps.Idx, newPipe, "script-pipe")
		},
	},

	"error": {
		Argsn: 1,
		Doc:   "error - returns any error present on the pipe, or 0 otherwise.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					waitErr := pipe.Error()
					if waitErr != nil {
						return *env.NewError("Error in pipe: " + waitErr.Error())
					}
					return *env.NewInteger(0)
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-error")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-error")
			}
		},
	},

	"set-error": {
		Argsn: 2,
		Doc:   "set-error sets the error err on the pipe and return it.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch errStr := arg1.(type) {
					case env.String:
						err := errors.New(errStr.Value)
						pipe.SetError(err)
						return *env.NewNative(ps.Idx, pipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "p-set-error")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "p-set-error")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "p-set-error")
			}
		},
	},

	"extract\\regexp": {
		Argsn: 2,
		Doc:   "For each line in the pipe, extracts all regexp matches (capture group 1 if present, otherwise the whole match) and outputs each match on a separate line. Equivalent to grep -oP with a capture group.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch r := arg1.(type) {
					case env.Native:
						switch rx := r.Value.(type) {
						case *regexp.Regexp:
							newPipe := pipe.Filter(func(r io.Reader, w io.Writer) error {
								scanner := bufio.NewScanner(r)
								for scanner.Scan() {
									line := scanner.Text()
									matches := rx.FindAllStringSubmatch(line, -1)
									for _, match := range matches {
										if len(match) > 1 {
											fmt.Fprintln(w, match[1])
										} else {
											fmt.Fprintln(w, match[0])
										}
									}
								}
								return scanner.Err()
							})
							return *env.NewNative(ps.Idx, newPipe, "script-pipe")
						default:
							return evaldo.MakeNativeArgError(ps, 2, []string{"regexp"}, "extract\\regexp")
						}
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "extract\\regexp")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "extract\\regexp")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "extract\\regexp")
			}
		},
	},

	"sort": {
		Argsn: 1,
		Doc:   "Sorts the lines of the pipe alphabetically in ascending order.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Filter(func(r io.Reader, w io.Writer) error {
						scanner := bufio.NewScanner(r)
						var lines []string
						for scanner.Scan() {
							lines = append(lines, scanner.Text())
						}
						if err := scanner.Err(); err != nil {
							return err
						}
						sort.Strings(lines)
						for _, line := range lines {
							fmt.Fprintln(w, line)
						}
						return nil
					})
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "sort")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "sort")
			}
		},
	},

	"sort\\reverse": {
		Argsn: 1,
		Doc:   "Sorts the lines of the pipe alphabetically in descending (reverse) order.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Filter(func(r io.Reader, w io.Writer) error {
						scanner := bufio.NewScanner(r)
						var lines []string
						for scanner.Scan() {
							lines = append(lines, scanner.Text())
						}
						if err := scanner.Err(); err != nil {
							return err
						}
						sort.Sort(sort.Reverse(sort.StringSlice(lines)))
						for _, line := range lines {
							fmt.Fprintln(w, line)
						}
						return nil
					})
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "sort\\reverse")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "sort\\reverse")
			}
		},
	},

	"uniq": {
		Argsn: 1,
		Doc:   "Removes consecutive duplicate lines from the pipe, like the Unix uniq command. Combine with sort to remove all duplicates.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Filter(func(r io.Reader, w io.Writer) error {
						scanner := bufio.NewScanner(r)
						last := ""
						first := true
						for scanner.Scan() {
							line := scanner.Text()
							if first || line != last {
								fmt.Fprintln(w, line)
								last = line
								first = false
							}
						}
						return scanner.Err()
					})
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "uniq")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "uniq")
			}
		},
	},

	"trim-lines": {
		Argsn: 1,
		Doc:   "Trims leading and trailing whitespace from each line in the pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.FilterLine(func(line string) string {
						return strings.TrimSpace(line)
					})
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "trim-lines")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "trim-lines")
			}
		},
	},

	"prefix-lines": {
		Argsn: 2,
		Doc:   "Prepends a string to the beginning of each line in the pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch prefix := arg1.(type) {
					case env.String:
						newPipe := pipe.FilterLine(func(line string) string {
							return prefix.Value + line
						})
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "prefix-lines")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "prefix-lines")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "prefix-lines")
			}
		},
	},

	"skip": {
		Argsn: 2,
		Doc:   "Skips the first n lines from the pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch n := arg1.(type) {
					case env.Integer:
						skipCount := int(n.Value)
						newPipe := pipe.Filter(func(r io.Reader, w io.Writer) error {
							scanner := bufio.NewScanner(r)
							lineNum := 0
							for scanner.Scan() {
								lineNum++
								if lineNum > skipCount {
									fmt.Fprintln(w, scanner.Text())
								}
							}
							return scanner.Err()
						})
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "skip")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "skip")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "skip")
			}
		},
	},

	"number-lines": {
		Argsn: 1,
		Doc:   "Prefixes each line with its line number (1-indexed).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					newPipe := pipe.Filter(func(r io.Reader, w io.Writer) error {
						scanner := bufio.NewScanner(r)
						lineNum := 0
						for scanner.Scan() {
							lineNum++
							fmt.Fprintf(w, "%d: %s\n", lineNum, scanner.Text())
						}
						return scanner.Err()
					})
					return *env.NewNative(ps.Idx, newPipe, "script-pipe")
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "number-lines")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "number-lines")
			}
		},
	},

	"count-matches": {
		Argsn: 2,
		Doc:   "Counts the number of lines containing the given string. This is a sink operation that consumes the pipe.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch s := arg1.(type) {
					case env.String:
						lines, err := pipe.Slice()
						if err != nil {
							return evaldo.MakeBuiltinError(ps, err.Error(), "count-matches")
						}
						count := 0
						for _, line := range lines {
							if strings.Contains(line, s.Value) {
								count++
							}
						}
						return *env.NewInteger(int64(count))
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "count-matches")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "count-matches")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "count-matches")
			}
		},
	},

	"between": {
		Argsn: 3,
		Doc:   "Returns lines between start and end marker lines (exclusive). Can handle multiple ranges.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch startStr := arg1.(type) {
					case env.String:
						switch endStr := arg2.(type) {
						case env.String:
							newPipe := pipe.Filter(func(r io.Reader, w io.Writer) error {
								scanner := bufio.NewScanner(r)
								inside := false
								for scanner.Scan() {
									line := scanner.Text()
									if strings.Contains(line, endStr.Value) {
										inside = false
										continue
									}
									if inside {
										fmt.Fprintln(w, line)
									}
									if strings.Contains(line, startStr.Value) {
										inside = true
									}
								}
								return scanner.Err()
							})
							return *env.NewNative(ps.Idx, newPipe, "script-pipe")
						default:
							return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "between")
						}
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "between")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "between")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "between")
			}
		},
	},

	"tee\\file": {
		Argsn: 2,
		Doc:   "Writes the pipe contents to a file while also passing them through. Like the Unix tee command.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch path := arg1.(type) {
					case env.Uri:
						file, err := os.Create(path.GetPath())
						if err != nil {
							return evaldo.MakeBuiltinError(ps, err.Error(), "tee\\file")
						}
						newPipe := pipe.Tee(file)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					case env.String:
						file, err := os.Create(path.Value)
						if err != nil {
							return evaldo.MakeBuiltinError(ps, err.Error(), "tee\\file")
						}
						newPipe := pipe.Tee(file)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.UriType, env.StringType}, "tee\\file")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "tee\\file")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tee\\file")
			}
		},
	},

	"map-each": {
		Argsn: 2,
		Doc:   "Transforms each line by evaluating a Rye block with the line injected. The block should return a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch block := arg1.(type) {
					case env.Block:

						lines, err := pipe.Slice()
						if err != nil {
							return evaldo.MakeBuiltinError(ps, err.Error(), "map-each")
						}

						result := make([]string, 0, len(lines))
						ser := ps.Ser
						for _, line := range lines {
							ps.Ser = block.Series
							ps.Ser.SetPos(0)
							evaldo.EvalBlockInj(ps, *env.NewString(line), true)
							if ps.ErrorFlag {
								ps.Ser = ser
								return evaldo.MakeBuiltinError(ps, "Error during evaluation of block", "map-each")
							}
							if ps.FailureFlag {
								ps.Ser = ser
								return ps.Res
							}

							switch res := ps.Res.(type) {
							case env.String:
								result = append(result, res.Value)
							default:

								result = append(result, ps.Res.Print(*ps.Idx))
							}
						}
						ps.Ser = ser

						newPipe := script.Slice(result)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "map-each")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "map-each")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "map-each")
			}
		},
	},

	"filter-each": {
		Argsn: 2,
		Doc:   "Filters lines by evaluating a Rye block with each line injected. Only lines for which the block returns truthy are kept.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch p := arg0.(type) {
			case env.Native:
				switch pipe := p.Value.(type) {
				case *script.Pipe:
					switch block := arg1.(type) {
					case env.Block:

						lines, err := pipe.Slice()
						if err != nil {
							return evaldo.MakeBuiltinError(ps, err.Error(), "filter-each")
						}

						result := make([]string, 0)
						ser := ps.Ser
						for _, line := range lines {
							ps.Ser = block.Series
							ps.Ser.SetPos(0)
							evaldo.EvalBlockInj(ps, *env.NewString(line), true)
							if ps.ErrorFlag {
								ps.Ser = ser
								return evaldo.MakeBuiltinError(ps, "Error during evaluation of block", "filter-each")
							}
							if ps.FailureFlag {
								ps.Ser = ser
								return ps.Res
							}

							if util.IsTruthy(ps.Res) {
								result = append(result, line)
							}
						}
						ps.Ser = ser

						newPipe := script.Slice(result)
						return *env.NewNative(ps.Idx, newPipe, "script-pipe")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "filter-each")
					}
				default:
					return evaldo.MakeNativeArgError(ps, 1, []string{"script-pipe"}, "filter-each")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "filter-each")
			}
		},
	},
}
View Source
var Builtins_prometheus = map[string]*env.Builtin{

	"new-counter": {
		Argsn: 3,
		Doc:   "Creates a new Prometheus counter with the given name, help text, and optional labels.",
		Fn:    __prometheus_new_counter,
	},
	"prometheus-counter//Inc": {
		Argsn: 1,
		Doc:   "Increments a Prometheus counter by 1.",
		Fn:    __prometheus_counter_inc,
	},
	"prometheus-counter//Add": {
		Argsn: 2,
		Doc:   "Adds the given value to a Prometheus counter.",
		Fn:    __prometheus_counter_add,
	},

	"new-gauge": {
		Argsn: 3,
		Doc:   "Creates a new Prometheus gauge with the given name, help text, and optional labels.",
		Fn:    __prometheus_new_gauge,
	},
	"prometheus-gauge//Set": {
		Argsn: 2,
		Doc:   "Sets a Prometheus gauge to the given value.",
		Fn:    __prometheus_gauge_set,
	},
	"prometheus-gauge//Inc": {
		Argsn: 1,
		Doc:   "Increments a Prometheus gauge by 1.",
		Fn:    __prometheus_gauge_inc,
	},
	"prometheus-gauge//Dec": {
		Argsn: 1,
		Doc:   "Decrements a Prometheus gauge by 1.",
		Fn:    __prometheus_gauge_dec,
	},
	"prometheus-gauge//Add": {
		Argsn: 2,
		Doc:   "Adds the given value to a Prometheus gauge.",
		Fn:    __prometheus_gauge_add,
	},
	"prometheus-gauge//Sub": {
		Argsn: 2,
		Doc:   "Subtracts the given value from a Prometheus gauge.",
		Fn:    __prometheus_gauge_sub,
	},

	"new-histogram": {
		Argsn: 4,
		Doc:   "Creates a new Prometheus histogram with the given name, help text, optional buckets, and optional labels.",
		Fn:    __prometheus_new_histogram,
	},
	"prometheus-histogram//Observe": {
		Argsn: 2,
		Doc:   "Observes the given value in a Prometheus histogram.",
		Fn:    __prometheus_histogram_observe,
	},

	"new-summary": {
		Argsn: 4,
		Doc:   "Creates a new Prometheus summary with the given name, help text, optional objectives, and optional labels.",
		Fn:    __prometheus_new_summary,
	},
	"prometheus-summary//Observe": {
		Argsn: 2,
		Doc:   "Observes the given value in a Prometheus summary.",
		Fn:    __prometheus_summary_observe,
	},

	"start-http-server": {
		Argsn: 1,
		Doc:   "Starts a Prometheus HTTP server on the given address (e.g., ':8080').",
		Fn:    __prometheus_start_http_server,
	},

	"new-mutex": {
		Argsn: 0,
		Doc:   "Creates a new mutex for protecting metrics from concurrent access.",
		Fn:    __prometheus_new_mutex,
	},
	"prometheus-mutex//Lock": {
		Argsn: 1,
		Doc:   "Locks a mutex.",
		Fn:    __prometheus_mutex_lock,
	},
	"prometheus-mutex//Unlock": {
		Argsn: 1,
		Doc:   "Unlocks a mutex.",
		Fn:    __prometheus_mutex_unlock,
	},

	"must-register": {
		Argsn: 1,
		Doc:   "Registers a Prometheus collector using MustRegister. Will panic if registration fails.",
		Fn:    __prometheus_must_register,
	},
	"handler": {
		Argsn: 0,
		Doc:   "Returns a Prometheus HTTP handler for custom HTTP server setups.",
		Fn:    __prometheus_handler,
	},
}

Map of Prometheus builtins

View Source
var Builtins_psql = map[string]*env.Builtin{

	"postgres-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a connection to a PostgreSQL database.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.Uri:
				db, err := sql.Open("postgres", "postgresql://"+str.Path)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error opening PostgreSQL: %v", err.Error()), "postgres-uri//Open")
				}

				if err := db.Ping(); err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error connecting to PostgreSQL: %v", err.Error()), "postgres-uri//Open")
				}
				return *env.NewNative(ps.Idx, db, "Rye-psql")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "postgres-uri//Open")
			}

		},
	},

	"Rye-psql//Exec": {
		Argsn: 2,
		Doc:   "Executes a SQL statement that modifies data (INSERT, UPDATE, DELETE).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch db1 := arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0, 2)
					_, vals = SQL_EvalBlock(ps, MODE_PSQL, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					ps.ErrorFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-psql//Exec")
				}
				if sqlstr != "" {

					db2 := db1.Value.(*sql.DB)
					res, err := db2.Exec(sqlstr, vals...)
					if err != nil {
						ps.FailureFlag = true
						return env.NewError("Error" + err.Error())
					} else {
						num, _ := res.RowsAffected()
						return *env.NewInteger(num)

					}
				} else {
					return evaldo.MakeBuiltinError(ps, "Sql string is empty.", "Rye-psql//Exec")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-psql//Exec")
			}
		},
	},

	"Rye-psql//Query": {
		Argsn: 2,
		Doc:   "Executes a SQL query and returns results as a table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch db1 := arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:

					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0, 2)
					_, vals = SQL_EvalBlock(ps, MODE_PSQL, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					ps.ErrorFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-psql//Query")
				}
				if sqlstr != "" {

					rows, err := db1.Value.(*sql.DB).Query(sqlstr, vals...)

					if err != nil {
						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, err.Error(), "Rye-psql//Query")
					} else {
						cols, _ := rows.Columns()
						spr := env.NewTable(cols)
						i := 0
						for rows.Next() {

							var sr env.TableRow

							columns := make([]any, len(cols))
							columnPointers := make([]any, len(cols))
							for i := range columns {
								columnPointers[i] = &columns[i]
							}

							if err := rows.Scan(columnPointers...); err != nil {
								ps.FailureFlag = true
								return evaldo.MakeBuiltinError(ps, "Error scanning row: "+err.Error(), "Rye-psql//Query")
							}

							m := make(map[string]any)
							for i, colName := range cols {
								val := columnPointers[i].(*any)
								// Convert nil (SQL NULL) values to Void{} for proper Rye handling
								var ryeVal env.Object
								if *val == nil {
									ryeVal = env.Void{}
								} else {
									ryeVal = env.ToRyeValue(*val)
								}
								m[colName] = ryeVal
								sr.Values = append(sr.Values, ryeVal)
							}
							spr.AddRow(sr)

							i++
						}
						rows.Close()

						if i == 0 {
							ps.FailureFlag = true
							return evaldo.MakeBuiltinError(ps, "No data.", "Rye-psql//Query")
						}
						return *spr

					}
				} else {
					return evaldo.MakeBuiltinError(ps, "Empty SQL.", "Rye-psql//Query")
				}

			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-psql//Query")
			}
		},
	},

	"Rye-psql//Show-SQL": {
		Argsn: 2,
		Doc:   "Generates and returns the SQL string without executing it.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0, 2)
					_, vals = SQL_EvalBlock(ps, MODE_PSQL, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					ps.ErrorFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-psql//Show-SQL")
				}
				if sqlstr != "" {

					if len(vals) > 0 {
						result := sqlstr + "\n-- Parameters: "
						for i, val := range vals {
							if i > 0 {
								result += ", "
							}
							result += fmt.Sprintf("$%d = %v", i+1, val)
						}
						return *env.NewString(result)
					}
					return *env.NewString(sqlstr)
				} else {
					return evaldo.MakeBuiltinError(ps, "Empty SQL.", "Rye-psql//Show-SQL")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-psql//Show-SQL")
			}
		},
	},

	"Rye-psql//Close": {
		Argsn: 1,
		Doc:   "Closes the PostgreSQL database connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch db := arg0.(type) {
			case env.Native:
				psqlKind, _ := ps.Idx.GetIndex("Rye-psql")
				if db.Kind.Index != psqlKind {
					return evaldo.MakeBuiltinError(ps, "Expected PostgreSQL database connection.", "Rye-psql//Close")
				}
				sqlDB, ok := db.Value.(*sql.DB)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Invalid database connection.", "Rye-psql//Close")
				}
				err := sqlDB.Close()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error closing database: %v", err.Error()), "Rye-psql//Close")
				}
				return *env.NewInteger(1)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-psql//Close")
			}
		},
	},
}
View Source
var Builtins_regexp = map[string]*env.Builtin{

	"regexp": {
		Argsn: 1,
		Doc:   "Creates a compiled regular expression object from a pattern string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.String:
				val, err := regexp.Compile(s.Value)
				if err != nil {
					return evaldo.MakeError(ps, err.Error())
				}
				return *env.NewNative(ps.Idx, val, "regexp")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "regexp")
			}
		},
	},

	"re": {
		Argsn: 1,
		Doc:   "Creates a compiled regular expression object from a pattern string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.String:
				val, err := regexp.Compile(s.Value)
				if err != nil {
					return evaldo.MakeError(ps, err.Error())
				}
				return *env.NewNative(ps.Idx, val, "regexp")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "regexp")
			}
		},
	},

	"regexp//Is-match": {
		Argsn: 2,
		Doc:   "Tests if a string matches the regular expression pattern.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg1.(type) {
			case env.String:
				switch s := arg0.(type) {
				case env.Native:
					res := s.Value.(*regexp.Regexp).MatchString(val.Value)
					if res {
						return *env.NewBoolean(true)
					} else {
						return *env.NewBoolean(false)
					}
				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "regexp//Is-match")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "regexp//Is-match")
			}
		},
	},

	"regexp//Submatch?": {
		Argsn: 2,
		Doc:   "Extracts the first captured group from a string using the regular expression.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg1.(type) {
			case env.String:
				switch s := arg0.(type) {
				case env.Native:
					res := s.Value.(*regexp.Regexp).FindStringSubmatch(val.Value)
					if len(res) > 1 {
						return *env.NewString(res[1])
					} else {
						return evaldo.MakeBuiltinError(ps, "No submatch.", "regexp//Submatch?")
					}
				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "regexp//Submatch?")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "regexp//Submatch?")
			}
		},
	},

	"regexp//Submatches?": {
		Argsn: 2,
		Doc:   "Extracts all captured groups from the first match as a block of strings.",
		Fn: func(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg1.(type) {
			case env.String:
				switch s := arg0.(type) {
				case env.Native:
					res := s.Value.(*regexp.Regexp).FindStringSubmatch(val.Value)
					if len(res) > 0 {
						col1 := make([]env.Object, len(res)-1)
						for i, row := range res {
							if i > 0 {
								col1[i-1] = *env.NewString(row)
							}
						}
						return *env.NewBlock(*env.NewTSeries(col1))
					}
					return evaldo.MakeBuiltinError(env1, "No results", "Submatches?")
				default:
					return evaldo.MakeError(env1, "Arg2 not Native")
				}
			default:
				return evaldo.MakeError(env1, "Arg1 not String")
			}
		},
	},

	"regexp//Submatches\\all?": {
		Argsn: 2,
		Doc:   "Extracts all captured groups from all matches as a nested block structure.",
		Fn: func(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg1.(type) {
			case env.String:
				switch s := arg0.(type) {
				case env.Native:
					res := s.Value.(*regexp.Regexp).FindAllStringSubmatch(val.Value, -1)
					if len(res) > 0 {
						blks := make([]env.Object, len(res))
						for i, mtch := range res {
							strs := make([]env.Object, len(mtch)-1)
							for j, row := range mtch {
								if j > 0 {
									strs[j-1] = *env.NewString(row)
								}
							}
							blks[i] = *env.NewBlock(*env.NewTSeries(strs))
						}
						return *env.NewBlock(*env.NewTSeries(blks))
					}
					return evaldo.MakeBuiltinError(env1, "No results", "Submatches?")
				default:
					return evaldo.MakeError(env1, "Arg2 not Native")
				}
			default:
				return evaldo.MakeError(env1, "Arg1 not String")
			}
		},
	},

	"regexp//Find-all": {
		Argsn: 2,
		Doc:   "Finds all substrings matching the regular expression and returns them as a block.",
		Fn: func(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg1.(type) {
			case env.String:
				switch s := arg0.(type) {
				case env.Native:
					res := s.Value.(*regexp.Regexp).FindAllString(val.Value, -1)
					if len(res) > 0 {
						col1 := make([]env.Object, len(res))
						for i, row := range res {
							col1[i] = *env.NewString(row)
						}
						return *env.NewBlock(*env.NewTSeries(col1))
					}
					return evaldo.MakeBuiltinError(env1, "No results", "Find-all")
				default:
					return evaldo.MakeError(env1, "Arg2 not Native")
				}
			default:
				return evaldo.MakeError(env1, "Arg1 not String")
			}
		},
	},

	"regexp//Match?": {
		Argsn: 2,
		Doc:   "Finds the first substring matching the regular expression.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg1.(type) {
			case env.String:
				switch s := arg0.(type) {
				case env.Native:
					res := s.Value.(*regexp.Regexp).FindString(val.Value)
					if len(res) > 0 {
						return *env.NewString(res)
					}
					return evaldo.MakeBuiltinError(ps, "No result", "Match?")
				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "regexp//Match?")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "regexp//Match?")
			}
		},
	},

	"regexp//Replace-all": {
		Argsn: 3,
		Doc:   "Replaces all occurrences of the regular expression pattern with the specified replacement string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch re := arg0.(type) {
			case env.Native:
				switch val := arg1.(type) {
				case env.String:
					switch replac := arg2.(type) {
					case env.String:
						res := re.Value.(*regexp.Regexp).ReplaceAllString(val.Value, replac.Value)
						return *env.NewString(res)
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "regexp//Replace-all")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "regexp//Replace-all")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "regexp//Replace-all")
			}
		},
	},
}
View Source
var Builtins_smtpd = map[string]*env.Builtin{

	"smtp-server": {
		Argsn: 1,
		Doc:   "Creates a new SMTP server that can receive incoming email messages on the specified address.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			return *env.NewNative(ps.Idx, arg0, "smtpd")
		},
	},

	"smtpd//Serve": {
		Argsn: 4,
		Doc:   "Starts the SMTP server listening for incoming emails and calls the handler function for each received message.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch server := arg0.(type) {
			case env.Native:
				switch handler := arg1.(type) {
				case env.Function:
					switch name := arg2.(type) {
					case env.String:

						err := smtpd.ListenAndServe(server.Value.(env.String).Value,
							func(origin net.Addr, from string, to []string, data []byte) error {

								ps.FailureFlag = false
								ps.ErrorFlag = false
								ps.ReturnFlag = false

								psTemp := env.ProgramState{}
								err := copier.Copy(&psTemp, &ps)
								if err != nil {
									fmt.Println(err.Error())
								}

								lstTo := make([]any, len(to))
								for i, v := range to {
									lstTo[i] = v
								}

								evaldo.CallFunctionArgs4(handler, ps,
									*env.NewNative(ps.Idx, bytes.NewReader(data), "reader"),
									env.NewString(from),
									*env.NewList(lstTo),
									*env.NewNative(ps.Idx, origin, "new-addr"), nil)
								return nil
							}, name.Value, "")
						if err != nil {
							return evaldo.MakeError(ps, err.Error())
						}
						return arg0
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "smtpd//serve")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.FunctionType}, "smtpd//serve")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "smtpd//serve")
			}
		},
	},
}
View Source
var Builtins_sqlite = map[string]*env.Builtin{

	"sqlite-uri//Open": {
		Argsn: 1,
		Doc:   "Opens a connection to a SQLite database file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.Uri:
				db, err := sql.Open("sqlite", str.GetPath())
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error opening SQLite: %v", err.Error()), "sqlite-uri//Open")
				}

				if err := db.Ping(); err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error connecting to SQLite: %v", err.Error()), "sqlite-uri//Open")
				}
				return *env.NewNative(ps.Idx, db, "Rye-sqlite")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "sqlite-uri//Open")
			}

		},
	},

	"htmlize": {
		Argsn: 1,
		Doc:   "Converts a table to HTML format.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch str := arg0.(type) {
			case env.Table:
				return *env.NewString(str.ToHtml())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "htmlize")
			}

		},
	},

	"Rye-sqlite//Exec": {
		Argsn: 2,
		Doc:   "Executes a SQL statement that doesn't return rows.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch db1 := arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:

					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0)
					_, vals = SQL_EvalBlock(ps, MODE_SQLITE, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-sqlite//Exec")
				}
				if sqlstr != "" {
					db2 := db1.Value.(*sql.DB)
					_, err := db2.Exec(sqlstr, vals...)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "Rye-sqlite//Exec")
					}

					return arg0
				} else {
					return evaldo.MakeBuiltinError(ps, "sql string not found.", "Rye-sqlite//Exec")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-sqlite//Exec")
			}
		},
	},

	"Rye-sqlite//Query": {
		Argsn: 2,
		Doc:   "Executes a SQL query and returns results as a table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch db1 := arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:

					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0)
					_, vals = SQL_EvalBlock(ps, MODE_SQLITE, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-sqlite//Query")
				}
				if sqlstr != "" {
					rows, err := db1.Value.(*sql.DB).Query(sqlstr, vals...)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "Rye-sqlite//Query")
					}
					columns, _ := rows.Columns()
					spr := env.NewTable(columns)

					if err != nil {
						fmt.Println(err.Error())
					} else {
						cols, _ := rows.Columns()
						for rows.Next() {
							var sr env.TableRow
							columns := make([]any, len(cols))
							columnPointers := make([]any, len(cols))
							for i := range columns {
								columnPointers[i] = &columns[i]
							}

							if err := rows.Scan(columnPointers...); err != nil {
								return env.NewError(err.Error())
							}

							m := make(map[string]any)
							for i, colName := range cols {
								val := columnPointers[i].(*any)
								// Convert nil (SQL NULL) values to Void{} for proper Rye handling
								var ryeVal env.Object
								if *val == nil {
									ryeVal = env.Void{}
								} else {
									ryeVal = env.ToRyeValue(*val)
								}
								m[colName] = ryeVal
								sr.Values = append(sr.Values, ryeVal)
								sr.Uplink = spr
							}
							spr.AddRow(sr)

						}
						rows.Close()

						return *spr
					}
					return evaldo.MakeBuiltinError(ps, "Empty SQL.", "Rye-sqlite//Query")
				} else {
					return evaldo.MakeBuiltinError(ps, "Sql string not found.", "Rye-sqlite//Query")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-sqlite//Query")
			}
		},
	},

	"Rye-sqlite//Show-SQL": {
		Argsn: 2,
		Doc:   "Generates and returns the SQL string without executing it.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var sqlstr string
			var vals []any
			switch arg0.(type) {
			case env.Native:
				switch str := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = str.Series
					values := make([]any, 0)
					_, vals = SQL_EvalBlock(ps, MODE_SQLITE, values)
					sqlstr = ps.Res.(env.String).Value
					ps.Ser = ser
				case env.String:
					sqlstr = str.Value
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.StringType}, "Rye-sqlite//Show-SQL")
				}
				if sqlstr != "" {

					if len(vals) > 0 {
						result := sqlstr + "\n-- Parameters: "
						for i, val := range vals {
							if i > 0 {
								result += ", "
							}
							result += fmt.Sprintf("? = %v", val)
						}
						return *env.NewString(result)
					}
					return *env.NewString(sqlstr)
				} else {
					return evaldo.MakeBuiltinError(ps, "Empty SQL.", "Rye-sqlite//Show-SQL")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-sqlite//Show-SQL")
			}
		},
	},

	"Rye-sqlite//Close": {
		Argsn: 1,
		Doc:   "Closes the SQLite database connection.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch db := arg0.(type) {
			case env.Native:
				sqliteKind, _ := ps.Idx.GetIndex("Rye-sqlite")
				if db.Kind.Index != sqliteKind {
					return evaldo.MakeBuiltinError(ps, "Expected SQLite database connection.", "Rye-sqlite//Close")
				}
				sqlDB, ok := db.Value.(*sql.DB)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Invalid database connection.", "Rye-sqlite//Close")
				}
				err := sqlDB.Close()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Error closing database: %v", err.Error()), "Rye-sqlite//Close")
				}
				return *env.NewInteger(1)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "Rye-sqlite//Close")
			}
		},
	},
}
View Source
var Builtins_ssh = map[string]*env.Builtin{}
View Source
var Builtins_stackless = map[string]*env.Builtin{

	"ry0": {
		Argsn: 1,
		Doc:   "TODODOC",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				Stck_EvalBlock(ps)
				ps.Ser = ser
				return ps.Res
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "ry0")
			}
		},
	},

	"ry0-loop": {
		Argsn: 2,
		Doc:   "TODODOC",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cond := arg0.(type) {
			case env.Integer:
				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					for i := 0; int64(i) < cond.Value; i++ {
						ps = Stck_EvalBlock(ps)
						ps.Ser.Reset()
					}
					ps.Ser = ser
					return ps.Res
				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "ry0-loop")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "ry0-loop")
			}
		},
	},
}
View Source
var Builtins_structures = map[string]*env.Builtin{

	"dict->struct": {
		Argsn: 2,
		Doc:   "Converts a Rye Dict to a Go struct using reflection. Takes a Dict and a Native containing a pointer to a struct.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch dict := arg0.(type) {
			case env.Dict:

				switch native := arg1.(type) {
				case env.Native:

					return dictToStruct(ps, dict, native.Value)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "dict->struct")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DictType}, "dict->struct")
			}
		},
	},

	"dict->new-struct": {
		Argsn: 2,
		Doc:   "Creates a new Go struct type at runtime based on a Rye Dict and populates it with values. Takes a Dict and a string for the struct name.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch dict := arg0.(type) {
			case env.Dict:

				switch nameObj := arg1.(type) {
				case env.String:

					structPtr, err := dictToNewStruct(ps, dict, nameObj.Value)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "dict->new-struct")
					}

					return *env.NewNative(ps.Idx, structPtr, nameObj.Value)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "dict->new-struct")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DictType}, "dict->new-struct")
			}
		},
	},

	"struct->dict": {
		Argsn: 1,
		Doc:   "Converts a Go struct to a Rye Dict using reflection. Takes a Native containing a struct or pointer to a struct.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {

			switch native := arg0.(type) {
			case env.Native:

				return structToDict(ps, native.Value)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "struct->dict")
			}
		},
	},

	"process": {
		Argsn: 2,
		Doc:   "TODODOC",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			rm, err := load_structures_Dict(ps, arg1.(env.Block))

			if err != nil {
				ps.FailureFlag = true
				return err
			}
			switch data := arg0.(type) {
			case env.Dict:
				return do_structures(ps, data, rm)
			}
			return nil
		},
	},
}
View Source
var Builtins_sxml = map[string]*env.Builtin{

	"reader//Do-sxml": {
		Argsn: 2,
		Doc:   "Processes XML using a streaming SAX-like approach with tag handlers.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			rm, err := load_saxml_Dict(ps, arg1.(env.Block))

			if err != nil {
				ps.FailureFlag = true
				return err
			}
			return do_sxml(ps, arg0.(env.Native).Value.(io.Reader), rm)
		},
	},

	"rye-sxml-start//Attr?": {
		Argsn: 2,
		Doc:   "Retrieves an attribute by index or name from an XML start element.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch obj := arg0.(type) {
			case env.Native:
				switch obj1 := obj.Value.(type) {
				case xml.StartElement:
					switch n := arg1.(type) {
					case env.Integer:
						if int(n.Value) < len(obj1.Attr) {
							attr := obj1.Attr[int(n.Value)]
							return *env.NewList([]any{
								*env.NewString(attr.Name.Space),
								*env.NewString(attr.Name.Local),
								*env.NewString(attr.Value),
							})
						} else {
							return evaldo.MakeBuiltinError(ps, "Attribute index out of bounds.", "rye-sxml-start//Attr?")
						}
					case env.Word:
						attrName := ps.Idx.GetWord(n.Index)
						for _, attr := range obj1.Attr {
							if attr.Name.Local == attrName {

								return *env.NewString(attr.Value)
							}
						}
						return evaldo.MakeBuiltinError(ps, "Attribute '"+attrName+"' not found.", "rye-sxml-start//Attr?")
					case env.String:
						attrName := n.Value

						namespaceAndName := strings.Split(attrName, ":")
						if len(namespaceAndName) == 2 {

							targetNS := namespaceAndName[0]
							targetLocal := namespaceAndName[1]
							for _, attr := range obj1.Attr {
								if attr.Name.Space == targetNS && attr.Name.Local == targetLocal {
									return *env.NewString(attr.Value)
								}
							}
						} else {

							for _, attr := range obj1.Attr {
								if attr.Name.Local == attrName {
									return *env.NewString(attr.Value)
								}
							}
						}
						return evaldo.MakeBuiltinError(ps, "Attribute '"+attrName+"' not found.", "rye-sxml-start//Attr?")
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType, env.WordType, env.StringType}, "rye-sxml-start//Attr?")
					}
				default:
					return evaldo.MakeBuiltinError(ps, "Not xml-start element.", "rye-sxml-start//Attr?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "rye-sxml-start//Attr?")
			}
		},
	},

	"rye-sxml-start//Attrs?": {
		Argsn: 1,
		Doc:   "Returns a dict of all attributes from an XML start element.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch obj := arg0.(type) {
			case env.Native:
				switch obj1 := obj.Value.(type) {
				case xml.StartElement:
					data := make(map[string]any)
					for _, attr := range obj1.Attr {
						var key string
						if attr.Name.Space != "" {
							key = attr.Name.Space + ":" + attr.Name.Local
						} else {
							key = attr.Name.Local
						}
						data[key] = *env.NewString(attr.Value)
					}
					return *env.NewDict(data)
				default:
					return evaldo.MakeBuiltinError(ps, "Not xml-start element.", "rye-sxml-start//Attrs?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "rye-sxml-start//Attrs?")
			}
		},
	},

	"rye-sxml-start//Name?": {
		Argsn: 1,
		Doc:   "Returns the name of an XML start element.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch obj := arg0.(type) {
			case env.Native:
				switch obj1 := obj.Value.(type) {
				case xml.StartElement:
					return *env.NewString(obj1.Name.Local)
				default:
					return evaldo.MakeBuiltinError(ps, "Not xml-start element.", "rye-sxml-start//Name?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "rye-sxml-start//Name?")
			}
		},
	},
}
View Source
var Builtins_table = map[string]*env.Builtin{

	"table": {
		Argsn: 2,
		Doc:   "Creates a table by accepting block of column names and flat block of values",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch header1 := arg0.(type) {
			case env.Block:
				hlen := header1.Series.Len()
				cols, err := ColNames(ps, header1, "table")
				if err != nil {
					return err
				}
				spr := env.NewTable(cols)
				switch data1 := arg1.(type) {
				case env.Block:
					rdata := data1.Series.S

					if hlen > 0 {
						for i := 0; i < len(rdata)/hlen; i++ {
							rowd := make([]any, hlen)
							for ii := 0; ii < hlen; ii++ {
								rowd[ii] = rdata[i*hlen+ii]
							}
							spr.AddRow(*env.NewTableRow(rowd, spr))
						}
					}
					return *spr
				case env.List:
					rdata := data1.Data
					for i := 0; i < len(rdata)/hlen; i++ {
						rowd := make([]any, hlen)
						for ii := 0; ii < hlen; ii++ {
							rowd[ii] = rdata[i*hlen+ii]
						}
						spr.AddRow(*env.NewTableRow(rowd, spr))
					}
					return *spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "table")
				}

			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "table")
			}
		},
	},

	"table\\columns": {
		Argsn: 2,
		Doc:   "Creats a table by accepting a block of columns",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			return SheetFromColumns(ps, arg0, arg1)
		},
	},

	"table\\rows": {
		Argsn: 2,
		Doc:   "Creates a table by accepting a block or list of rows",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			cols, err := ColNames(ps, arg0, "table\\rows	")
			if err != nil {
				return err
			}
			spr := env.NewTable(cols)
			switch rows := arg1.(type) {
			case env.Block:
				for _, objRow := range rows.Series.S {
					row, err := TableRowsFromBlockOrList(ps, spr, len(cols), objRow)
					if err != nil {
						return err
					}
					spr.AddRow(*row)
				}
				return *spr
			case env.List:
				for _, listRow := range rows.Data {
					row, err := TableRowsFromBlockOrList(ps, spr, len(cols), listRow)
					if err != nil {
						return err
					}
					spr.AddRow(*row)
				}
				return *spr
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.ListType}, "table\\rows")
			}
		},
	},

	"to-table": {
		Argsn: 1,
		Doc:   "Creates a table by accepting block or list of dicts",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			switch block := arg0.(type) {
			case env.Block:
				data := block.Series
				if data.Len() == 0 {
					return evaldo.MakeBuiltinError(ps, "Block is empty", "to-table")
				}
				k := make(map[string]struct{})
				for _, obj := range data.S {
					switch dict := obj.(type) {
					case env.Dict:
						for key := range dict.Data {
							k[key] = struct{}{}
						}
					default:
						return evaldo.MakeBuiltinError(ps, "Block must contain only dicts", "to-table")
					}
				}
				var keys []string
				for key := range k {
					keys = append(keys, key)
				}
				spr := env.NewTable(keys)
				for _, obj := range data.S {
					switch dict := obj.(type) {
					case env.Dict:
						row := make([]any, len(keys))
						for i, key := range keys {
							data, ok := dict.Data[key]
							if !ok {
								data = env.Void{}
							}
							row[i] = data
						}
						spr.AddRow(*env.NewTableRow(row, spr))
					}
				}
				return *spr

			case env.List:
				data := block.Data
				if len(data) == 0 {
					return evaldo.MakeBuiltinError(ps, "List is empty", "to-table")
				}
				k := make(map[string]struct{})
				for _, obj := range data {
					switch dict := obj.(type) {
					case map[string]any:
						for key := range dict {
							k[key] = struct{}{}
						}
					case env.Dict:
						for key := range dict.Data {
							k[key] = struct{}{}
						}
					default:
						return evaldo.MakeBuiltinError(ps, "List must contain only dicts", "to-table")
					}
				}
				var keys []string
				for key := range k {
					keys = append(keys, key)
				}
				spr := env.NewTable(keys)
				for _, obj := range data {
					row := make([]any, len(keys))
					switch dict := obj.(type) {
					case map[string]any:
						for i, key := range keys {
							data, ok := dict[key]
							if !ok {
								data = env.Void{}
							}
							row[i] = env.ToRyeValue(data)
						}
						spr.AddRow(*env.NewTableRow(row, spr))
					case env.Dict:
						row := make([]any, len(keys))
						for i, key := range keys {
							data, ok := dict.Data[key]
							if !ok {
								data = env.Void{}
							}
							row[i] = env.ToRyeValue(data)
						}
						spr.AddRow(*env.NewTableRow(row, spr))
					}
				}
				return *spr

			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.ListType}, "to-table")
			}
		},
	},

	"to-dict": {
		Argsn: 1,
		Doc:   "Creates a dict from a two-column table, using the first column as keys and the second column as values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch s := arg0.(type) {
			case env.Table:
				spr = &s
			case *env.Table:
				spr = s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "to-dict")
			}
			if len(spr.Cols) != 2 {
				return evaldo.MakeBuiltinError(ps, fmt.Sprintf("to-dict requires a table with exactly 2 columns, got %d", len(spr.Cols)), "to-dict")
			}
			data := make(map[string]any, len(spr.Rows))
			for _, row := range spr.Rows {
				keyObj := env.ToRyeValue(row.Values[0])
				var keyStr string
				switch k := keyObj.(type) {
				case env.String:
					keyStr = k.Value
				case env.Word:
					keyStr = ps.Idx.GetWord(k.Index)
				case env.Integer:
					keyStr = fmt.Sprintf("%d", k.Value)
				case env.Decimal:
					keyStr = fmt.Sprintf("%g", k.Value)
				default:
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("to-dict: key column values must be strings or numbers, got %s", keyObj.Inspect(*ps.Idx)), "to-dict")
				}
				data[keyStr] = env.ToRyeValue(row.Values[1])
			}
			return *env.NewDict(data)
		},
	},

	"where-equal": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum is equal to given value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch s := arg0.(type) {
			case *env.Table:
				spr = s
			case env.Table:
				spr = &s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-equal")
			}
			switch col := arg1.(type) {
			case env.Word:
				return WhereEquals(ps, spr, ps.Idx.GetWord(col.Index), arg2)
			case env.String:
				return WhereEquals(ps, spr, col.Value, arg2)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-equal")
			}
		},
	},

	"where-not-equal": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum is not equal to given value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch s := arg0.(type) {
			case *env.Table:
				spr = s
			case env.Table:
				spr = &s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-not-equal")
			}
			switch col := arg1.(type) {
			case env.Word:
				return WhereNotEquals(ps, spr, ps.Idx.GetWord(col.Index), arg2)
			case env.String:
				return WhereNotEquals(ps, spr, col.Value, arg2)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-not-equal")
			}
		},
	},

	"where-void": {
		Argsn: 2,
		Doc:   "Returns table of rows where specific colum is void.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch s := arg0.(type) {
			case *env.Table:
				spr = s
			case env.Table:
				spr = &s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-void")
			}
			switch col := arg1.(type) {
			case env.Word:
				return WhereEquals(ps, spr, ps.Idx.GetWord(col.Index), env.NewVoid())
			case env.String:
				return WhereEquals(ps, spr, col.Value, env.NewVoid())
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-void")
			}
		},
	},

	"where-match": {
		Argsn: 3,
		Doc:   "Returns table of rows where a specific colum matches a regex.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			var spr *env.Table
			switch sheet := arg0.(type) {
			case env.Table:
				spr = &sheet
			case *env.Table:
				spr = sheet
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-match")
			}
			switch reNative := arg2.(type) {
			case env.Native:
				re, ok := reNative.Value.(*regexp.Regexp)
				if !ok {
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "where-match")
				}
				switch col := arg1.(type) {
				case env.Word:
					return WhereMatch(ps, spr, ps.Idx.GetWord(col.Index), re)
				case env.String:
					return WhereMatch(ps, spr, col.Value, re)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-match")
				}
			default:
				return evaldo.MakeArgError(ps, 3, []env.Type{env.NativeType}, "where-match")
			}
		},
	},

	"where-contains": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum contains a given string value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			var spr *env.Table
			switch sheet := arg0.(type) {
			case env.Table:
				spr = &sheet
			case *env.Table:
				spr = sheet
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-contains")
			}
			switch s := arg2.(type) {
			case env.String:
				switch col := arg1.(type) {
				case env.Word:
					return WhereContains(ps, spr, ps.Idx.GetWord(col.Index), s.Value, false)
				case env.String:
					return WhereContains(ps, spr, col.Value, s.Value, false)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-contains")
				}
			default:
				return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "where-contains")
			}
		},
	},

	"where-not-contains": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum does not contain a given string value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			var spr *env.Table
			switch sheet := arg0.(type) {
			case env.Table:
				spr = &sheet
			case *env.Table:
				spr = sheet
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-not-contains")
			}
			switch s := arg2.(type) {
			case env.String:
				switch col := arg1.(type) {
				case env.Word:
					return WhereContains(ps, spr, ps.Idx.GetWord(col.Index), s.Value, true)
				case env.String:
					return WhereContains(ps, spr, col.Value, s.Value, true)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-not-contains")
				}
			default:
				return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "where-not-contains")
			}
		},
	},

	"where-greater": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum is greater than given value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch sheet := arg0.(type) {
			case env.Table:
				spr = &sheet
			case *env.Table:
				spr = sheet
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-greater")
			}
			switch col := arg1.(type) {
			case env.Word:
				return WhereGreater(ps, spr, ps.Idx.GetWord(col.Index), arg2)
			case env.String:
				return WhereGreater(ps, spr, col.Value, arg2)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-greater")
			}
		},
	},

	"where-lesser": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum is lesser than given value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch sheet := arg0.(type) {
			case env.Table:
				spr = &sheet
			case *env.Table:
				spr = sheet
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-lesser")
			}
			switch col := arg1.(type) {
			case env.Word:
				return WhereLesser(ps, spr, ps.Idx.GetWord(col.Index), arg2)
			case env.String:
				return WhereLesser(ps, spr, col.Value, arg2)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-lesser")
			}
		},
	},

	"where-between": {
		Argsn: 4,
		Doc:   "Returns table of rows where specific colum is between given values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			var spr *env.Table
			switch sheet := arg0.(type) {
			case env.Table:
				spr = &sheet
			case *env.Table:
				spr = sheet
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-between")
			}
			switch col := arg1.(type) {
			case env.Word:
				return WhereBetween(ps, spr, ps.Idx.GetWord(col.Index), arg2, arg3, false)
			case env.String:
				return WhereBetween(ps, spr, col.Value, arg2, arg3, false)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-between")
			}
		},
	},

	"where-between\\inclusive": {
		Argsn: 4,
		Doc:   "Returns table of rows where specific colum is between given values (inclusive).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			var spr *env.Table
			switch sheet := arg0.(type) {
			case env.Table:
				spr = &sheet
			case *env.Table:
				spr = sheet
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-between\\inclusive")
			}
			switch col := arg1.(type) {
			case env.Word:
				return WhereBetween(ps, spr, ps.Idx.GetWord(col.Index), arg2, arg3, true)
			case env.String:
				return WhereBetween(ps, spr, col.Value, arg2, arg3, true)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-between\\inclusive")
			}
		},
	},

	"where-in": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum value is found in block of values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			var spr *env.Table
			switch s := arg0.(type) {
			case env.Table:
				spr = &s
			case *env.Table:
				spr = s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-in")
			}
			switch vals := arg2.(type) {
			case env.Block:
				switch col := arg1.(type) {
				case env.Word:
					return WhereIn(ps, spr, ps.Idx.GetWord(col.Index), vals.Series.S)
				case env.String:
					return WhereIn(ps, spr, col.Value, vals.Series.S)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-in")
				}
			default:
				return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "where-in")
			}
		},
	},

	"where-not-in": {
		Argsn: 3,
		Doc:   "Returns table of rows where specific colum value is not found in block of values.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			var spr *env.Table
			switch s := arg0.(type) {
			case env.Table:
				spr = &s
			case *env.Table:
				spr = s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where-not-in")
			}
			switch vals := arg2.(type) {
			case env.Block:
				switch col := arg1.(type) {
				case env.Word:
					return WhereNotIn(ps, spr, ps.Idx.GetWord(col.Index), vals.Series.S)
				case env.String:
					return WhereNotIn(ps, spr, col.Value, vals.Series.S)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "where-not-in")
				}
			default:
				return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "where-not-in")
			}
		},
	},

	"where": {
		Argsn: 3,
		Doc:   "Returns table of rows where code block evaluates to true for the column value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch table := arg0.(type) {
			case env.Table:
				spr = &table
			case *env.Table:
				spr = table
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "where")
			}

			switch col := arg1.(type) {
			case env.Word:
				colName := ps.Idx.GetWord(col.Index)
				switch block := arg2.(type) {
				case env.Block:
					return WhereBlock(ps, spr, colName, block)
				case env.Builtin:
					return WhereBuiltin(ps, spr, colName, block)
				case env.Function:
					return WhereFunction(ps, spr, colName, block)
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType, env.BuiltinType, env.FunctionType}, "where")
				}
			case env.String:
				colName := col.Value
				switch block := arg2.(type) {
				case env.Block:
					return WhereBlock(ps, spr, colName, block)
				case env.Builtin:
					return WhereBuiltin(ps, spr, colName, block)
				case env.Function:
					return WhereFunction(ps, spr, colName, block)
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType, env.BuiltinType, env.FunctionType}, "where")
				}
			case env.Block:
				switch block := arg2.(type) {
				case env.Block:
					return WhereBlockMultiCol(ps, spr, col, block)
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "where")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType, env.BlockType}, "where")
			}
		},
	},

	"distinct": {
		Argsn: 2,
		Doc:   "Returns table with duplicate rows removed based on specified column(s).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch s := arg0.(type) {
			case env.Table:
				spr = &s
			case *env.Table:
				spr = s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "distinct")
			}
			switch col := arg1.(type) {
			case env.Word:
				return Distinct(ps, spr, []string{ps.Idx.GetWord(col.Index)})
			case env.String:
				return Distinct(ps, spr, []string{col.Value})
			case env.Block:
				var cols []string
				for _, word := range col.Series.S {
					switch w := word.(type) {
					case env.Word:
						cols = append(cols, ps.Idx.GetWord(w.Index))
					case env.Tagword:
						cols = append(cols, ps.Idx.GetWord(w.Index))
					case env.String:
						cols = append(cols, w.Value)
					default:
						return evaldo.MakeBuiltinError(ps, "Column names block must contain only words or strings.", "distinct")
					}
				}
				return Distinct(ps, spr, cols)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType, env.BlockType}, "distinct")
			}
		},
	},

	"fill-void": {
		Argsn: 3,
		Doc:   "Returns table with void values in specified column replaced with given value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch s := arg0.(type) {
			case env.Table:
				spr = &s
			case *env.Table:
				spr = s
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "fill-void")
			}
			var colName string
			switch col := arg1.(type) {
			case env.Word:
				colName = ps.Idx.GetWord(col.Index)
			case env.String:
				colName = col.Value
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "fill-void")
			}
			return FillVoid(ps, spr, colName, arg2)
		},
	},

	"count-where": {
		Argsn: 3,
		Doc:   "Returns count of rows where code block evaluates to true for the column value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var spr *env.Table
			switch table := arg0.(type) {
			case env.Table:
				spr = &table
			case *env.Table:
				spr = table
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "count-where")
			}

			switch col := arg1.(type) {
			case env.Word:
				colName := ps.Idx.GetWord(col.Index)
				switch block := arg2.(type) {
				case env.Block:
					return CountWhereBlock(ps, spr, colName, block)
				case env.Builtin:
					return CountWhereBuiltin(ps, spr, colName, block)
				case env.Function:
					return CountWhereFunction(ps, spr, colName, block)
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType, env.BuiltinType, env.FunctionType}, "count-where")
				}
			case env.String:
				colName := col.Value
				switch block := arg2.(type) {
				case env.Block:
					return CountWhereBlock(ps, spr, colName, block)
				case env.Builtin:
					return CountWhereBuiltin(ps, spr, colName, block)
				case env.Function:
					return CountWhereFunction(ps, spr, colName, block)
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType, env.BuiltinType, env.FunctionType}, "count-where")
				}
			case env.Block:
				switch block := arg2.(type) {
				case env.Block:
					return CountWhereBlockMultiCol(ps, spr, col, block)
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "count-where")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType, env.BlockType}, "count-where")
			}
		},
	},

	"add-row": {
		Argsn: 2,
		Doc:   "Returns a table with new-row added to it",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch table := arg0.(type) {
			case env.Table:
				switch bloc := arg1.(type) {
				case env.Block:
					vals := make([]any, bloc.Series.Len())
					for i := 0; i < bloc.Series.Len(); i++ {
						vals[i] = bloc.Series.Get(i)
					}
					table.AddRow(*env.NewTableRow(vals, &table))
					return table
				case env.List:
					vals := make([]any, len(bloc.Data))
					for i, v := range bloc.Data {
						vals[i] = env.ToRyeValue(v)
					}
					table.AddRow(*env.NewTableRow(vals, &table))
					return table
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.ListType}, "add-row")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "add-row")
			}
		},
	},

	"get-rows": {
		Argsn: 1,
		Doc:   "Get rows as a native. This value can be used in `add-rows` and `add-rows!`",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				rows := spr.GetRows()
				return *env.NewNative(ps.Idx, rows, "table-rows")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "get-rows")
			}
		},
	},

	"add-rows": {
		Argsn: 2,
		Doc:   "Add one or more rows to a table",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				switch data1 := arg1.(type) {
				case env.Block:
					data := data1.Series
					for data.Pos() < data.Len() {
						rowd := make([]any, len(spr.Cols))
						for ii := 0; ii < len(spr.Cols); ii++ {
							k1 := data.Pop()
							rowd[ii] = k1
						}
						spr.AddRow(*env.NewTableRow(rowd, &spr))
					}
					return spr
				case env.List:
					data := data1.Data
					for item := range data {
						rowd := make([]any, len(spr.Cols))
						for ii := 0; ii < len(spr.Cols); ii++ {
							k1 := item
							rowd[ii] = k1
						}
						spr.AddRow(*env.NewTableRow(rowd, &spr))
					}
					return spr
				case env.Native:
					spr.Rows = append(spr.Rows, data1.Value.([]env.TableRow)...)
					return spr
				default:
					fmt.Println(data1.Inspect(*ps.Idx))
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.NativeType}, "add-rows")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "add-rows")
			}
		},
	},

	"add-rows!": {
		Argsn: 2,
		Doc:   "Add one or more rows to a table ref",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case *env.Table:
				switch data1 := arg1.(type) {
				case env.Block:
					data := data1.Series
					for data.Pos() < data.Len() {
						rowd := make([]any, len(spr.Cols))
						for ii := 0; ii < len(spr.Cols); ii++ {
							k1 := data.Pop()
							rowd[ii] = k1
						}
						spr.AddRow(*env.NewTableRow(rowd, spr))
					}
					return spr
				case env.Native:
					spr.Rows = append(spr.Rows, data1.Value.([]env.TableRow)...)
					return spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.NativeType}, "add-rows!")
				}
			case *env.PersistentTable:
				switch data1 := arg1.(type) {
				case env.Block:
					data := data1.Series
					for data.Pos() < data.Len() {
						rowd := make([]any, len(spr.Cols))
						for ii := 0; ii < len(spr.Cols); ii++ {
							k1 := data.Pop()
							rowd[ii] = k1
						}
						spr.AddRow(*env.NewTableRow(rowd, spr))
					}
					return spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "add-rows!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType, env.PersistentTableType}, "add-rows!")
			}
		},
	},

	"update-row!": {
		Argsn: 3,
		Doc:   `Update the row at the given index.`,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case *env.Table:
				switch idx := arg1.(type) {
				case env.Integer:
					if idx.Value < 1 || (idx.Value-1) > int64(len(spr.Rows)) {
						errMsg := fmt.Sprintf("update-row! called with row index %d, but table only has %d rows", idx.Value, len(spr.Rows))
						return evaldo.MakeError(ps, errMsg)
					}
					switch updater := arg2.(type) {
					case env.Function:
						evaldo.CallFunction_CollectArgs(updater, ps, spr.Rows[idx.Value-1], false, ps.Ctx)
						ret := ps.Res
						if ok, err, row := RyeValueToTableRow(spr, ret); ok {
							spr.Rows[idx.Value-1] = *row
							return spr
						} else if len(err) > 0 {
							return evaldo.MakeError(ps, err)
						} else {
							return evaldo.MakeError(ps, fmt.Sprintf(
								"Function given to update-row! should have returned a Dict or a TableRow, but returned a %s %#v instead",
								evaldo.NameOfRyeType(ret.Type()), ret,
							))
						}
					case env.Dict:

						row := spr.Rows[idx.Value-1]

						for keyStr, val := range updater.Data {
							index := spr.GetColumnIndex(keyStr)
							if index < 0 {
								return evaldo.MakeError(ps, "Column "+keyStr+" was not found")
							}
							row.Values[index] = val
						}
						return spr
					case env.TableRow:
						spr.Rows[idx.Value-1] = updater
						return spr
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType, env.DictType, env.TableRowType}, "update-row!")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "update-row!")
				}
			default:
				return evaldo.MakeNeedsThawedArgError(ps, "update-row!")
			}

		},
	},

	"remove-row!": {
		Argsn: 2,
		Doc:   "Remove a row from a table by index",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case *env.Table:
				switch data1 := arg1.(type) {
				case env.Integer:
					if data1.Value > 0 && data1.Value <= int64(len(spr.Rows)) {
						spr.RemoveRowByIndex(data1.Value - 1)
						return spr
					} else {
						return evaldo.MakeError(ps, fmt.Sprintf("Table had less then %d rows", data1.Value))
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType, env.NativeType}, "remove-row!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "remove-row!")
			}
		},
	},

	"columns?": {
		Argsn: 2,
		Doc:   "Returns table with just given columns. Use lsetwords (:newName) to rename the previous column.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				switch col := arg1.(type) {
				case env.Block:
					cols := make([]string, 0)
					colNames := make([]string, 0)

					for _, obj := range col.Series.S {
						switch ww := obj.(type) {
						case env.String:
							cols = append(cols, ww.Value)
							colNames = append(colNames, ww.Value)
						case env.Tagword:
							colName := ps.Idx.GetWord(ww.Index)
							cols = append(cols, colName)
							colNames = append(colNames, colName)
						case env.LSetword:

							if len(colNames) == 0 {
								return evaldo.MakeBuiltinError(ps, "LSetword :"+ps.Idx.GetWord(ww.Index)+" found but no previous column to rename", "columns?")
							}

							newName := ps.Idx.GetWord(ww.Index)
							colNames[len(colNames)-1] = newName
						default:
							return evaldo.MakeBuiltinError(ps, "Expected string, tagword, or lsetword in columns specification", "columns?")
						}
					}
					return spr.ColumnsRenamed(ps, cols, colNames)
				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "columns?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "columns?")
			}
		},
	},

	"header?": {
		Argsn: 1,
		Doc:   "Gets the column names (header) as block.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case *env.Table:
				return spr.GetColumns()
			case env.Table:
				return spr.GetColumns()
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "headers?")
			}
		},
	},

	"column?": {
		Argsn: 2,
		Doc:   "Gets all values of a column as a block.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			switch spr := arg0.(type) {
			case env.Table:
				switch col := arg1.(type) {
				case env.Word:
					res := spr.GetColumn(ps.Idx.GetWord(col.Index))
					if _, isErr := res.(*env.Error); isErr {
						ps.FailureFlag = true
					}
					return res
				case env.String:
					res := spr.GetColumn(col.Value)
					if _, isErr := res.(*env.Error); isErr {
						ps.FailureFlag = true
					}
					return res
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "column?")
				}
			case env.Block:
				switch col := arg1.(type) {
				case env.Integer:
					col1 := make([]env.Object, len(spr.Series.S))
					if col.Value < 0 {
						return evaldo.MakeBuiltinError(ps, "Index can't be negative", "column?")
					}
					for i, item_ := range spr.Series.S {
						switch item := item_.(type) {
						case env.Block:
							if len(item.Series.S) < int(col.Value) {
								return evaldo.MakeBuiltinError(ps, "index out of bounds for item: "+strconv.Itoa(i), "column?")
							}
							col1[i] = item.Series.S[col.Value]
						}
					}
					return *env.NewBlock(*env.NewTSeries(col1))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "column?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "column?")
			}
		},
	},

	"drop-column": {
		Argsn: 2,
		Doc:   "Remove a column from a table. Returns new table",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				switch rmCol := arg1.(type) {
				case env.Word:
					return DropColumn(ps, spr, *env.NewString(ps.Idx.GetWord(rmCol.Index)))
				case env.String:
					return DropColumn(ps, spr, rmCol)
				case env.Block:
					return DropColumnBlock(ps, spr, rmCol)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType, env.BlockType}, "drop-column")
				}
			}
			return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "drop-column")
		},
	},

	"rename-column!": {
		Argsn: 3,
		Doc:   "Remove a column from a table. Returns new table",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case *env.Table:
				switch oldName := arg1.(type) {
				case env.String:
					switch newName := arg2.(type) {
					case env.String:
						return RenameColumn(ps, spr, oldName, newName)
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.BlockType}, "rename-column")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.BlockType}, "rename-column")
				}
			}
			return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "rename-column")
		},
	},

	"gen-column": {
		Argsn: 4,
		Doc:   "Adds a new column to table. Changes in-place and returns the new table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				switch newCol := arg1.(type) {
				case env.Word:
					switch fromCols := arg2.(type) {
					case env.Block:
						switch code := arg3.(type) {
						case env.Block:
							return GenerateColumn(ps, spr, newCol, fromCols, code)
						default:
							return evaldo.MakeArgError(ps, 4, []env.Type{env.BlockType}, "gen-column")
						}
					case env.Word:
						switch replaceBlock := arg3.(type) {
						case env.Block:
							if replaceBlock.Series.Len() != 2 {
								return evaldo.MakeBuiltinError(ps, "Replacement block must contain a regex object and replacement string.", "genadd-umn")
							}
							regexNative, ok := replaceBlock.Series.S[0].(env.Native)
							if !ok {
								return evaldo.MakeBuiltinError(ps, "First element of replacement block must be a regex object.", "genaddumn")
							}
							regex, ok := regexNative.Value.(*regexp.Regexp)
							if !ok {
								return evaldo.MakeBuiltinError(ps, "First element of replacement block must be a regex object.", "gen-column")
							}
							replaceStr, ok := replaceBlock.Series.S[1].(env.String)
							if !ok {
								return evaldo.MakeBuiltinError(ps, "Second element of replacement block must be a string.", "gen-column")
							}
							err := GenerateColumnRegexReplace(ps, &spr, newCol, fromCols, regex, replaceStr.Value)
							if err != nil {
								return err
							}
							return spr
						default:
							return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "gen-column")
						}
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "gen-column")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "gen-column")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "gen-column")
			}
		},
	},

	"update-column!": {
		Argsn: 3,
		Doc:   "Updates all cells in a column by applying a function that receives the cell value and the row.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case *env.Table:
				var colName string
				switch col := arg1.(type) {
				case env.Word:
					colName = ps.Idx.GetWord(col.Index)
				case env.String:
					colName = col.Value
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "update-column!")
				}

				colIdx := slices.Index(spr.Cols, colName)
				if colIdx < 0 {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Column '%s' not found", colName), "update-column!")
				}

				switch updater := arg2.(type) {
				case env.Function:
					for i := range spr.Rows {
						cell := env.ToRyeValue(spr.Rows[i].Values[colIdx])
						evaldo.CallFunctionArgs2(updater, ps, cell, spr.Rows[i], ps.Ctx)
						if ps.ErrorFlag {
							return ps.Res
						}
						spr.Rows[i].Values[colIdx] = ps.Res
					}
					return spr
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType}, "update-column!")
				}
			default:
				return evaldo.MakeNeedsThawedArgError(ps, "update-column!")
			}
		},
	},

	"add-column": {
		Argsn: 3,
		Doc:   "Adds a new column to table with the given data. Returns the modified table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				var colName string
				switch col := arg1.(type) {
				case env.Word:
					colName = ps.Idx.GetWord(col.Index)
				case env.String:
					colName = col.Value
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType}, "add-column")
				}

				numRows := len(spr.Rows)

				switch data := arg2.(type) {
				case env.Block:

					if data.Series.Len() != numRows {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Column data has %d values but table has %d rows", data.Series.Len(), numRows), "add-column")
					}

					spr.Cols = append(spr.Cols, colName)

					for i, row := range spr.Rows {
						row.Values = append(row.Values, data.Series.S[i])
						spr.Rows[i] = row
					}
					return spr
				case env.List:
					if len(data.Data) != numRows {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Column data has %d values but table has %d rows", len(data.Data), numRows), "add-column")
					}

					spr.Cols = append(spr.Cols, colName)

					for i, row := range spr.Rows {
						row.Values = append(row.Values, env.ToRyeValue(data.Data[i]))
						spr.Rows[i] = row
					}
					return spr
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType, env.ListType}, "add-column")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "add-column")
			}
		},
	},

	"order-by!": {
		Argsn: 3,
		Doc:   "Sorts row by given column, changes table in place.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			dir, ok := arg2.(env.Word)
			if !ok {
				return evaldo.MakeArgError(ps, 3, []env.Type{env.WordType}, "sort-by!")
			}
			var dirAsc bool
			if dir.Index == ps.Idx.IndexWord("asc") {
				dirAsc = true
			} else if dir.Index == ps.Idx.IndexWord("desc") {
				dirAsc = false
			} else {
				return evaldo.MakeBuiltinError(ps, "Direction can be just asc or desc.", "sort-by!")
			}
			switch spr := arg0.(type) {
			case env.Table:
				switch col := arg1.(type) {
				case env.String:
					if dirAsc {
						SortByColumn(ps, &spr, col.Value)
					} else {
						SortByColumnDesc(ps, &spr, col.Value)
					}
					return spr
				case env.Word:
					if dirAsc {
						SortByColumn(ps, &spr, ps.Idx.GetWord(col.Index))
					} else {
						SortByColumnDesc(ps, &spr, ps.Idx.GetWord(col.Index))
					}
					return spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "sort-by!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "sort-by!")
			}
		},
	},

	"order-by": {
		Argsn: 3,
		Doc:   "Sorts row by given column, changes table in place.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			dir, ok := arg2.(env.Word)
			if !ok {
				return evaldo.MakeArgError(ps, 3, []env.Type{env.WordType}, "sort-by!")
			}
			var dirAsc bool
			if dir.Index == ps.Idx.IndexWord("asc") {
				dirAsc = true
			} else if dir.Index == ps.Idx.IndexWord("desc") {
				dirAsc = false
			} else {
				return evaldo.MakeBuiltinError(ps, "Direction can be just asc or desc.", "sort-by!")
			}
			switch spr := arg0.(type) {
			case env.Table:
				copied := make([]env.TableRow, len(spr.Rows))
				copy(copied, spr.Rows)
				newSpr := env.NewTable(spr.Cols)
				newSpr.Rows = copied
				switch col := arg1.(type) {
				case env.String:
					if dirAsc {
						SortByColumn(ps, newSpr, col.Value)
					} else {
						SortByColumnDesc(ps, newSpr, col.Value)
					}
					return *newSpr
				case env.Word:
					if dirAsc {
						SortByColumn(ps, newSpr, ps.Idx.GetWord(col.Index))
					} else {
						SortByColumnDesc(ps, newSpr, ps.Idx.GetWord(col.Index))
					}
					return *newSpr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType}, "sort-by!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "sort-by!")
			}
		},
	},

	"add-indexes!": {
		Argsn: 2,
		Doc:   "Creates an index for all values in the provided columns. Changes in-place and returns the new table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				switch col := arg1.(type) {
				case env.Block:
					colWords := make([]env.Word, col.Series.Len())
					for c := range col.Series.S {
						switch ww := col.Series.S[c].(type) {
						case env.Word:
							colWords[c] = ww
						default:
							return evaldo.MakeError(ps, "Block of tagwords needed")
						}
					}
					err := AddIndexes(ps, &spr, colWords)
					if err != nil {
						return err
					}
					return spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "add-indexes!")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "add-indexes!")
			}
		},
	},

	"indexes?": {
		Argsn: 1,
		Doc:   "Returns the columns that are indexed in a table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			switch spr := arg0.(type) {
			case env.Table:
				res := make([]env.Object, 0)
				for col := range spr.Indexes {
					res = append(res, *env.NewString(col))
				}
				return *env.NewBlock(*env.NewTSeries(res))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "indexes?")
			}
		},
	},

	"autotype": {
		Argsn: 2,
		Doc:   "Takes a table and tries to determine and change the types of columns.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			switch spr := arg0.(type) {
			case env.Table:
				switch percent := arg1.(type) {
				case env.Decimal:
					return AutoType(ps, &spr, percent.Value)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.DecimalType}, "autotype")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "autotype")
			}
		},
	},

	"left-join": {
		Argsn: 4,
		Doc:   "Left joins two tables on the given columns.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			switch spr1 := arg0.(type) {
			case env.Table:
				switch spr2 := arg1.(type) {
				case env.Table:
					switch col1 := arg2.(type) {
					case env.Word:
						col2, ok := arg3.(env.Word)
						if !ok {
							return evaldo.MakeArgError(ps, 4, []env.Type{env.WordType}, "left-join")
						}
						return LeftJoin(ps, spr1, spr2, ps.Idx.GetWord(col1.Index), ps.Idx.GetWord(col2.Index), false)
					case env.String:
						col2, ok := arg3.(env.String)
						if !ok {
							evaldo.MakeArgError(ps, 4, []env.Type{env.StringType}, "left-join")
						}
						return LeftJoin(ps, spr1, spr2, col1.Value, col2.Value, false)
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.WordType, env.StringType}, "left-join")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.TableType}, "left-join")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "left-join")
			}
		},
	},

	"inner-join": {
		Argsn: 4,
		Doc:   "Inner joins two tables on the given columns.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			switch spr1 := arg0.(type) {
			case env.Table:
				switch spr2 := arg1.(type) {
				case env.Table:
					switch col1 := arg2.(type) {
					case env.Word:
						col2, ok := arg3.(env.Word)
						if !ok {
							return evaldo.MakeArgError(ps, 4, []env.Type{env.WordType}, "inner-join")
						}
						return LeftJoin(ps, spr1, spr2, ps.Idx.GetWord(col1.Index), ps.Idx.GetWord(col2.Index), true)
					case env.String:
						col2, ok := arg3.(env.String)
						if !ok {
							evaldo.MakeArgError(ps, 4, []env.Type{env.StringType}, "inner-join")
						}
						return LeftJoin(ps, spr1, spr2, col1.Value, col2.Value, true)
					default:
						return evaldo.MakeArgError(ps, 3, []env.Type{env.WordType, env.StringType}, "inner-join")
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.TableType}, "inner-join")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "inner-join")
			}
		},
	},

	"group-by": {
		Argsn: 3,
		Doc:   "Groups a table by the given column(s) and (optional) aggregations.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) (res env.Object) {
			switch spr := arg0.(type) {
			case env.Table:
				switch aggBlock := arg2.(type) {
				case env.Block:
					if len(aggBlock.Series.S)%2 != 0 {
						return evaldo.MakeBuiltinError(ps, "Aggregation block must contain pairs of column name and function for each aggregation.", "group-by")
					}
					aggregations := make(map[string][]string)
					for i := 0; i < len(aggBlock.Series.S); i += 2 {
						col := aggBlock.Series.S[i]
						fun, ok := aggBlock.Series.S[i+1].(env.Word)
						if !ok {
							return evaldo.MakeBuiltinError(ps, "Aggregation function must be a word", "group-by")
						}
						colStr := ""
						switch col := col.(type) {
						case env.Tagword:
							colStr = ps.Idx.GetWord(col.Index)
						case env.String:
							colStr = col.Value
						default:
							return evaldo.MakeBuiltinError(ps, "Aggregation column must be a word or string", "group-by")
						}
						funStr := ps.Idx.GetWord(fun.Index)
						aggregations[colStr] = append(aggregations[colStr], funStr)
					}
					switch col := arg1.(type) {
					case env.Word:
						return GroupBy(ps, spr, []string{ps.Idx.GetWord(col.Index)}, aggregations)
					case env.String:
						return GroupBy(ps, spr, []string{col.Value}, aggregations)
					case env.Block:
						cols := make([]string, col.Series.Len())
						for c := range col.Series.S {
							switch ww := col.Series.S[c].(type) {
							case env.String:
								cols[c] = ww.Value
							case env.Tagword:
								cols[c] = ps.Idx.GetWord(ww.Index)
							case env.Word:
								cols[c] = ps.Idx.GetWord(ww.Index)
							default:
								return evaldo.MakeBuiltinError(ps, "Block must contain only strings or words for column names", "group-by")
							}
						}
						return GroupBy(ps, spr, cols, aggregations)
					default:
						return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.StringType, env.BlockType}, "group-by")
					}
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "group-by")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "group-by")
			}
		},
	},

	"A1": {
		Argsn: 1,
		Doc:   "Accepts a Table and returns the first row first column cell.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s0 := arg0.(type) {
			case env.Table:
				r := s0.Rows[0].Values[0]
				return env.ToRyeValue(r)

			default:
				ps.ErrorFlag = true
				return env.NewError("first arg not table")
			}
		},
	},

	"B1": {
		Argsn: 1,
		Doc:   "Accepts a Table and returns the first row second column cell.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s0 := arg0.(type) {
			case env.Table:
				r := s0.Rows[0].Values[1]
				return env.ToRyeValue(r)

			default:
				ps.ErrorFlag = true
				return env.NewError("first arg not table")
			}
		},
	},

	"A2": {
		Argsn: 1,
		Doc:   "Accepts a Table and returns the second row first column cell.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s0 := arg0.(type) {
			case env.Table:
				r := s0.Rows[1].Values[0]
				return env.ToRyeValue(r)

			default:
				ps.ErrorFlag = true
				return env.NewError("first arg not table")
			}
		},
	},

	"B2": {
		Argsn: 1,
		Doc:   "Accepts a Table and returns the second row second column cell.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s0 := arg0.(type) {
			case env.Table:
				r := s0.Rows[1].Values[1]
				return env.ToRyeValue(r)

			default:
				ps.ErrorFlag = true
				return env.NewError("first arg not table")
			}
		},
	},

	"file-uri//Load\\csv": {

		Argsn: 1,
		Doc:   "Loads a .csv file to a table datatype.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch file := arg0.(type) {
			case env.Uri:

				f, err := os.Open(file.GetPath())
				if err != nil {

					return evaldo.MakeBuiltinError(ps, "Unable to read input file:"+err.Error(), "Load\\csv")
				}
				defer f.Close()

				csvReader := csv.NewReader(f)
				rows, err := csvReader.ReadAll()
				if err != nil {

					return evaldo.MakeBuiltinError(ps, "Unable to parse file as CSV: "+err.Error(), "Load\\csv")
				}
				if len(rows) == 0 {
					return evaldo.MakeBuiltinError(ps, "File is empty", "Load\\csv")
				}
				spr := env.NewTable(rows[0])

				if len(rows) > 1 {
					for _, row := range rows[1:] {
						anyRow := make([]any, len(row))
						for i, v := range row {
							anyRow[i] = *env.NewString(v)
						}
						spr.AddRow(*env.NewTableRow(anyRow, spr))
					}
				}
				return *spr
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "Load\\csv")
			}
		},
	},

	"file-uri//Load\\csv\\": {

		Argsn: 2,
		Doc:   "Loads a .csv file to a table datatype.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch file := arg0.(type) {
			case env.Uri:
				switch separator := arg1.(type) {
				case env.String:

					f, err := os.Open(file.GetPath())
					if err != nil {

						return evaldo.MakeBuiltinError(ps, "Unable to read input file:"+err.Error(), "Load\\csv")
					}
					defer f.Close()

					csvReader := csv.NewReader(f)
					if len(separator.Value) != 1 {
						return evaldo.MakeBuiltinError(ps, "Separator must be exactly 1 character long", "Load\\csv\\")
					}
					csvReader.Comma = rune(separator.Value[0])
					rows, err := csvReader.ReadAll()
					if err != nil {

						return evaldo.MakeBuiltinError(ps, "Unable to parse file as CSV: "+err.Error(), "Load\\csv")
					}
					if len(rows) == 0 {
						return evaldo.MakeBuiltinError(ps, "File is empty", "Load\\csv")
					}
					spr := env.NewTable(rows[0])

					if len(rows) > 1 {
						for _, row := range rows[1:] {
							anyRow := make([]any, len(row))
							for i, v := range row {
								anyRow[i] = *env.NewString(v)
							}
							spr.AddRow(*env.NewTableRow(anyRow, spr))
						}
					}
					return *spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "Load\\csv\\")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "Load\\csv\\")
			}
		},
	},

	"file-uri//Load\\tsv": {

		Argsn: 1,
		Doc:   "Loads a .csv file to a table datatype.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch file := arg0.(type) {
			case env.Uri:

				f, err := os.Open(file.GetPath())
				if err != nil {

					return evaldo.MakeBuiltinError(ps, "Unable to read input file:"+err.Error(), "Load\\csv")
				}
				defer f.Close()

				csvReader := csv.NewReader(f)
				csvReader.Comma = '\t'
				rows, err := csvReader.ReadAll()
				if err != nil {

					return evaldo.MakeBuiltinError(ps, "Unable to parse file as CSV: "+err.Error(), "Load\\csv")
				}
				if len(rows) == 0 {
					return evaldo.MakeBuiltinError(ps, "File is empty", "Load\\csv")
				}
				spr := env.NewTable(rows[0])

				if len(rows) > 1 {
					for _, row := range rows[1:] {
						anyRow := make([]any, len(row))
						for i, v := range row {
							anyRow[i] = *env.NewString(v)
						}
						spr.AddRow(*env.NewTableRow(anyRow, spr))
					}
				}
				return *spr
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "Load\\csv")
			}
		},
	},

	"file-uri//Save\\csv": {
		Argsn: 2,
		Doc:   "Saves a table to a .csv file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch file := arg0.(type) {
			case env.Uri:
				switch spr := arg1.(type) {
				case env.Table:

					f, err := os.Create(file.GetPath())
					if err != nil {

						return evaldo.MakeBuiltinError(ps, "Unable to create input file.", "file-uri//Save\\csv")
					}
					defer f.Close()

					cLen := len(spr.Cols)

					csvWriter := csv.NewWriter(f)

					err1 := csvWriter.Write(spr.Cols)
					if err1 != nil {
						return evaldo.MakeBuiltinError(ps, "Unable to create write header.", "file-uri//Save\\csv")
					}

					for ir, row := range spr.Rows {
						strVals := make([]string, cLen)

						for i, v := range row.Values {
							var sv string
							switch tv := v.(type) {
							case string:
								sv = tv
							case int64:
								sv = strconv.Itoa(int(tv))
							case float64:
								sv = strconv.FormatFloat(tv, 'f', -1, 64)
							case env.String:
								sv = tv.Value
							case env.Integer:
								sv = strconv.Itoa(int(tv.Value))
							case env.Decimal:
								sv = fmt.Sprintf("%f", tv.Value)
							}
							if i < cLen {
								strVals[i] = sv
							}
						}
						err := csvWriter.Write(strVals)
						if err != nil {
							return evaldo.MakeBuiltinError(ps, "Unable to write line: "+strconv.Itoa(ir), "file-uri//Save\\csv")
						}
					}
					csvWriter.Flush()
					f.Close()
					return spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.TableType}, "file-uri//Save\\csv")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Save\\csv")
			}
		},
	},

	"file-uri//Save\\tsv": {
		Argsn: 2,
		Doc:   "Saves a table to a .tsv file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch file := arg0.(type) {
			case env.Uri:
				switch spr := arg1.(type) {
				case env.Table:

					f, err := os.Create(file.GetPath())
					if err != nil {

						return evaldo.MakeBuiltinError(ps, "Unable to create input file.", "file-uri//Save\\tsv")
					}
					defer f.Close()

					cLen := len(spr.Cols)

					csvWriter := csv.NewWriter(f)
					csvWriter.Comma = '\t'
					err1 := csvWriter.Write(spr.Cols)
					if err1 != nil {
						return evaldo.MakeBuiltinError(ps, "Unable to create write header.", "file-uri//Save\\tsv")
					}

					for ir, row := range spr.Rows {
						strVals := make([]string, cLen)

						for i, v := range row.Values {
							var sv string
							switch tv := v.(type) {
							case string:
								sv = tv
							case int64:
								sv = strconv.Itoa(int(tv))
							case float64:
								sv = strconv.FormatFloat(tv, 'f', -1, 64)
							case env.String:
								sv = tv.Value
							case env.Integer:
								sv = strconv.Itoa(int(tv.Value))
							case env.Decimal:
								sv = fmt.Sprintf("%f", tv.Value)
							}
							if i < cLen {
								strVals[i] = sv
							}
						}
						err := csvWriter.Write(strVals)
						if err != nil {
							return evaldo.MakeBuiltinError(ps, "Unable to write line: "+strconv.Itoa(ir), "file-uri//Save\\tsv")
						}
					}
					csvWriter.Flush()
					f.Close()
					return spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.TableType}, "file-uri//Save\\tsv")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Save\\tsv")
			}
		},
	},

	"file-uri//Load\\xlsx": {
		Argsn: 1,
		Doc:   "Loads the first sheet in an .xlsx file to a Table.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch file := arg0.(type) {
			case env.Uri:
				f, err := excelize.OpenFile(file.GetPath())
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to open file: %s", err), "Load\\xlsx")
				}
				defer f.Close()

				sheetMap := f.GetSheetMap()
				if len(sheetMap) == 0 {
					return evaldo.MakeBuiltinError(ps, "No sheets found in file", "Load\\xlsx")
				}

				sheetName := sheetMap[1]
				rows, err := f.Rows(sheetName)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to get rows from sheet: %s", err), "Load\\xlsx")
				}
				rows.Next()
				header, err := rows.Columns()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to get columns from sheet: %s", err), "Load\\xlsx")
				}
				if len(header) == 0 {
					return evaldo.MakeBuiltinError(ps, "Header row is empty", "Load\\xlsx")
				}
				spr := env.NewTable(header)
				for rows.Next() {
					row, err := rows.Columns()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to get row: %s", err), "Load\\xlsx")
					}
					anyRow := make([]any, len(row))
					for i, v := range row {
						anyRow[i] = *env.NewString(v)
					}

					for i := len(row); i < len(spr.Cols); i++ {
						anyRow[i] = *env.NewString("")
					}
					spr.AddRow(*env.NewTableRow(anyRow, spr))
				}
				return *spr
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "Load\\xlsx")
			}
		},
	},

	"file-uri//Save\\xlsx": {
		Argsn: 2,
		Doc:   "Saves a Table to a .xlsx file.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch file := arg0.(type) {
			case env.Uri:
				switch spr := arg1.(type) {
				case env.Table:
					sheetName := "Sheet1"
					f := excelize.NewFile()
					index, err := f.NewSheet(sheetName)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to create new sheet: %s", err), "file-uri//Save\\xlsx")
					}
					err = f.SetSheetRow(sheetName, "A1", &spr.Cols)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to set header row: %s", err), "file-uri//Save\\xlsx")
					}
					for i, row := range spr.Rows {

						rowIndex := i + 2
						vals := make([]any, len(row.Values))
						for j, v := range row.Values {
							switch val := v.(type) {
							case env.String:
								vals[j] = val.Value
							case string:
								vals[j] = val
							case env.Integer:
								vals[j] = val.Value
							case int64:
								vals[j] = val
							case env.Decimal:
								vals[j] = val.Value
							case float64:
								vals[j] = val
							default:
								return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to save table: unsupported type %T", val), "file-uri//Save\\xlsx")
							}
						}
						err = f.SetSheetRow(sheetName, fmt.Sprintf("A%d", rowIndex), &vals)
						if err != nil {
							return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to set row %d: %s", rowIndex, err), "file-uri//Save\\xlsx")
						}
					}
					f.SetActiveSheet(index)
					err = f.SaveAs(file.GetPath())
					if err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Unable to save table: %s", err), "file-uri//Save\\xlsx")
					}
					return spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.TableType}, "file-uri//Save\\xlsx")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.UriType}, "file-uri//Save\\xlsx")
			}
		},
	},

	"persistent-table": {
		Argsn: 3,
		Doc:   "Creates a persistent table using BadgerDB for storage",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			cols, err := ColNames(ps, arg0, "persistent-table")
			if err != nil {
				return err
			}

			switch dbPath := arg1.(type) {
			case env.String:
				switch tableName := arg2.(type) {
				case env.String:
					pt, err := env.NewPersistentTable(cols, dbPath.Value, tableName.Value)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to create persistent table: %v", err), "persistent-table")
					}
					return pt
				default:
					return evaldo.MakeArgError(ps, 3, []env.Type{env.StringType}, "persistent-table")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "persistent-table")
			}
		},
	},

	"close-persistent-table!": {
		Argsn: 1,
		Doc:   "Closes the BadgerDB connection for a persistent table",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch pt := arg0.(type) {
			case *env.PersistentTable:
				err := pt.Close()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, fmt.Sprintf("Failed to close persistent table: %v", err), "close-persistent-table!")
				}
				return pt
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.PersistentTableType}, "close-persistent-table!")
			}
		},
	},

	"parse\\csv": {
		Argsn: 1,
		Doc:   "Parses a CSV string to a table datatype.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch csvData := arg0.(type) {
			case env.String:
				csvReader := csv.NewReader(strings.NewReader(csvData.Value))
				rows, err := csvReader.ReadAll()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to parse string as CSV: "+err.Error(), "parse\\csv")
				}
				if len(rows) == 0 {
					return evaldo.MakeBuiltinError(ps, "CSV data is empty", "parse\\csv")
				}
				spr := env.NewTable(rows[0])
				if len(rows) > 1 {
					for _, row := range rows[1:] {
						anyRow := make([]any, len(row))
						for i, v := range row {
							anyRow[i] = *env.NewString(v)
						}
						spr.AddRow(*env.NewTableRow(anyRow, spr))
					}
				}
				return *spr
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "parse\\csv")
			}
		},
	},

	"parse\\csv\\separator": {
		Argsn: 2,
		Doc:   "Parses a CSV string to a table datatype with a custom separator character.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch csvData := arg0.(type) {
			case env.String:
				switch separator := arg1.(type) {
				case env.String:
					if len(separator.Value) != 1 {
						return evaldo.MakeBuiltinError(ps, "Separator must be exactly 1 character long", "parse\\csv\\separator")
					}
					csvReader := csv.NewReader(strings.NewReader(csvData.Value))
					csvReader.Comma = rune(separator.Value[0])
					rows, err := csvReader.ReadAll()
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Unable to parse string as CSV: "+err.Error(), "parse\\csv\\separator")
					}
					if len(rows) == 0 {
						return evaldo.MakeBuiltinError(ps, "CSV data is empty", "parse\\csv\\separator")
					}
					spr := env.NewTable(rows[0])
					if len(rows) > 1 {
						for _, row := range rows[1:] {
							anyRow := make([]any, len(row))
							for i, v := range row {
								anyRow[i] = *env.NewString(v)
							}
							spr.AddRow(*env.NewTableRow(anyRow, spr))
						}
					}
					return *spr
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "parse\\csv\\separator")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "parse\\csv\\separator")
			}
		},
	},

	"parse\\tsv": {
		Argsn: 1,
		Doc:   "Parses a TSV (tab-separated values) string to a table datatype.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch tsvData := arg0.(type) {
			case env.String:
				csvReader := csv.NewReader(strings.NewReader(tsvData.Value))
				csvReader.Comma = '\t'
				rows, err := csvReader.ReadAll()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to parse string as TSV: "+err.Error(), "parse\\tsv")
				}
				if len(rows) == 0 {
					return evaldo.MakeBuiltinError(ps, "TSV data is empty", "parse\\tsv")
				}
				spr := env.NewTable(rows[0])
				if len(rows) > 1 {
					for _, row := range rows[1:] {
						anyRow := make([]any, len(row))
						for i, v := range row {
							anyRow[i] = *env.NewString(v)
						}
						spr.AddRow(*env.NewTableRow(anyRow, spr))
					}
				}
				return *spr
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "parse\\tsv")
			}
		},
	},

	"format\\csv": {
		Argsn: 1,
		Doc:   "Converts a table to a CSV string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				var buf strings.Builder
				csvWriter := csv.NewWriter(&buf)

				cLen := len(spr.Cols)

				err1 := csvWriter.Write(spr.Cols)
				if err1 != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to write header.", "format\\csv")
				}

				for ir, row := range spr.Rows {
					strVals := make([]string, cLen)

					for i, v := range row.Values {
						var sv string
						switch tv := v.(type) {
						case string:
							sv = tv
						case int64:
							sv = strconv.Itoa(int(tv))
						case float64:
							sv = strconv.FormatFloat(tv, 'f', -1, 64)
						case env.String:
							sv = tv.Value
						case env.Integer:
							sv = strconv.Itoa(int(tv.Value))
						case env.Decimal:
							sv = fmt.Sprintf("%f", tv.Value)
						}
						if i < cLen {
							strVals[i] = sv
						}
					}
					err := csvWriter.Write(strVals)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Unable to write line: "+strconv.Itoa(ir), "format\\csv")
					}
				}
				csvWriter.Flush()
				return *env.NewString(buf.String())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "format\\csv")
			}
		},
	},

	"format\\tsv": {
		Argsn: 1,
		Doc:   "Converts a table to a TSV string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				var buf strings.Builder
				csvWriter := csv.NewWriter(&buf)
				csvWriter.Comma = '\t'

				cLen := len(spr.Cols)

				err1 := csvWriter.Write(spr.Cols)
				if err1 != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to write header.", "format\\tsv")
				}

				for ir, row := range spr.Rows {
					strVals := make([]string, cLen)

					for i, v := range row.Values {
						var sv string
						switch tv := v.(type) {
						case string:
							sv = tv
						case int64:
							sv = strconv.Itoa(int(tv))
						case float64:
							sv = strconv.FormatFloat(tv, 'f', -1, 64)
						case env.String:
							sv = tv.Value
						case env.Integer:
							sv = strconv.Itoa(int(tv.Value))
						case env.Decimal:
							sv = fmt.Sprintf("%f", tv.Value)
						}
						if i < cLen {
							strVals[i] = sv
						}
					}
					err := csvWriter.Write(strVals)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Unable to write line: "+strconv.Itoa(ir), "format\\tsv")
					}
				}
				csvWriter.Flush()
				return *env.NewString(buf.String())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "format\\tsv")
			}
		},
	},

	"parse\\xlsx": {
		Argsn: 1,
		Doc:   "Parses an xlsx binary string or bytes into a table (first sheet).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var data []byte

			switch input := arg0.(type) {
			case env.String:
				data = []byte(input.Value)
			case env.Bytes:
				data = input.Value
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType, env.BytesType}, "parse\\xlsx")
			}

			tmpFile, err := os.CreateTemp("", "parse_xlsx_*.xlsx")
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Unable to create temporary file: "+err.Error(), "parse\\xlsx")
			}
			defer os.Remove(tmpFile.Name())
			defer tmpFile.Close()

			_, err = tmpFile.Write(data)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Unable to write to temporary file: "+err.Error(), "parse\\xlsx")
			}
			tmpFile.Close()

			f, err := excelize.OpenFile(tmpFile.Name())
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Unable to open xlsx data: "+err.Error(), "parse\\xlsx")
			}
			defer f.Close()

			sheetMap := f.GetSheetMap()
			if len(sheetMap) == 0 {
				return evaldo.MakeBuiltinError(ps, "No sheets found in xlsx data", "parse\\xlsx")
			}

			sheetName := sheetMap[1]
			rows, err := f.Rows(sheetName)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Unable to get rows from sheet: "+err.Error(), "parse\\xlsx")
			}
			rows.Next()
			header, err := rows.Columns()
			if err != nil {
				return evaldo.MakeBuiltinError(ps, "Unable to get columns from sheet: "+err.Error(), "parse\\xlsx")
			}
			if len(header) == 0 {
				return evaldo.MakeBuiltinError(ps, "Header row is empty", "parse\\xlsx")
			}
			spr := env.NewTable(header)
			for rows.Next() {
				row, err := rows.Columns()
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to get row: "+err.Error(), "parse\\xlsx")
				}
				anyRow := make([]any, len(header))
				for i, v := range row {
					if i < len(header) {
						anyRow[i] = *env.NewString(v)
					}
				}

				for i := len(row); i < len(header); i++ {
					anyRow[i] = *env.NewString("")
				}
				spr.AddRow(*env.NewTableRow(anyRow, spr))
			}
			return *spr
		},
	},

	"format\\xlsx": {
		Argsn: 1,
		Doc:   "Converts a table to an XLSX as bytes native value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch spr := arg0.(type) {
			case env.Table:
				sheetName := "Sheet1"
				f := excelize.NewFile()
				index, err := f.NewSheet(sheetName)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to create new sheet: "+err.Error(), "format\\xlsx")
				}
				err = f.SetSheetRow(sheetName, "A1", &spr.Cols)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to set header row: "+err.Error(), "format\\xlsx")
				}
				for i, row := range spr.Rows {

					rowIndex := i + 2
					vals := make([]any, len(row.Values))
					for j, v := range row.Values {
						switch val := v.(type) {
						case env.String:
							vals[j] = val.Value
						case string:
							vals[j] = val
						case env.Integer:
							vals[j] = val.Value
						case int64:
							vals[j] = val
						case env.Decimal:
							vals[j] = val.Value
						case float64:
							vals[j] = val
						default:
							return evaldo.MakeBuiltinError(ps, "Unable to format table: unsupported type "+fmt.Sprintf("%T", val), "format\\xlsx")
						}
					}
					err = f.SetSheetRow(sheetName, fmt.Sprintf("A%d", rowIndex), &vals)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, "Unable to set row "+strconv.Itoa(rowIndex)+": "+err.Error(), "format\\xlsx")
					}
				}
				f.SetActiveSheet(index)

				tmpFile, err := os.CreateTemp("", "format_xlsx_*.xlsx")
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to create temporary file: "+err.Error(), "format\\xlsx")
				}
				defer os.Remove(tmpFile.Name())
				defer tmpFile.Close()

				err = f.SaveAs(tmpFile.Name())
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to save xlsx data: "+err.Error(), "format\\xlsx")
				}

				data, err := os.ReadFile(tmpFile.Name())
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Unable to read xlsx data: "+err.Error(), "format\\xlsx")
				}

				return *env.NewBytes(data)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.TableType}, "format\\xlsx")
			}
		},
	},
}
View Source
var Builtins_telegrambot = map[string]*env.Builtin{

	"bot": {
		Argsn: 1,
		Doc:   "Create new telegram bot using API value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch arg := arg0.(type) {
			case env.String:
				bot, err := tgm.NewBotAPI(arg.Value)
				if err != nil {
					return evaldo.MakeBuiltinError(ps, "Error in NewBotAPI function.", "new-telegram-bot")
				}
				return *env.NewNative(ps.Idx, bot, "telegram-bot")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "new-telegram-bot")
			}
		},
	},

	"telegram-bot//on-update": {
		Argsn: 2,
		Doc:   "Get telegram update and add to Rye dictionary",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bot := arg0.(type) {
			case env.Native:
				switch code := arg1.(type) {
				case env.Block:
					u := tgm.NewUpdate(0)
					u.Timeout = 60

					updates, _ := bot.Value.(*tgm.BotAPI).GetUpdatesChan(u)
					ser := ps.Ser
					ps.Ser = code.Series

					for update := range updates {
						dict := TelegramUpdateToRyeDict(update)
						evaldo.EvalBlockInj(ps, dict, true)
						if ps.ErrorFlag {
							ps.Ser = ser
							return ps.Res
						}
						ps.Ser.Reset()
					}
					ps.Ser = ser
					return env.NewInteger(1)
				case env.Function:
					u := tgm.NewUpdate(0)
					u.Timeout = 60

					updates, _ := bot.Value.(*tgm.BotAPI).GetUpdatesChan(u)

					for update := range updates {
						dict := TelegramUpdateToRyeDict(update)
						ps.FailureFlag = false
						ps.ErrorFlag = false
						ps.ReturnFlag = false
						psTemp := env.ProgramState{}
						err := copier.Copy(&psTemp, &ps)
						if err != nil {
							fmt.Println(err.Error())

						}
						evaldo.CallFunctionArgsN(code, ps, nil, dict)
					}
					return env.NewInteger(1)

				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "telegram-bot//on-update")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "telegram-bot//on-update")
			}
		},
	},

	"telegram-message//send": {
		Argsn: 2,
		Doc:   "Send message in telegram bot.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch msg := arg0.(type) {
			case env.Native:
				switch bot := arg1.(type) {
				case env.Native:
					_, err := bot.Value.(*tgm.BotAPI).Send(msg.Value.(*tgm.MessageConfig))
					if err != nil {
						return evaldo.MakeError(ps, err.Error())
					}
					return arg0
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "telegram-message//send")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "telegram-message//send")
			}

		},
	},

	"telegram-message//parse-mode!": {
		Argsn: 2,
		Doc:   "Set the parse mode of the message",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch msg := arg0.(type) {
			case env.Native:
				switch mode := arg1.(type) {
				case env.String:
					message, _ := msg.Value.(tgm.MessageConfig)
					message.ParseMode = mode.Value
					return msg
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "telegram-message//send")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "telegram-message//send")
			}

		},
	},

	"message": {
		Argsn: 2,
		Doc:   "Create new telegram bot message.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cid := arg0.(type) {
			case env.Integer:
				switch txt := arg1.(type) {
				case env.String:
					msg := tgm.NewMessage(cid.Value, txt.Value)
					msg.ParseMode = "HTML"
					return *env.NewNative(ps.Idx, &msg, "telegram-message")
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "new-telegram-message")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "new-telegram-message")
			}
		},
	},
}
View Source
var Builtins_term = map[string]*env.Builtin{

	"clear-line": {
		Argsn: 0,
		Doc:   "Clears the current terminal line.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ClearLine()
			return *env.NewInteger(1)
		},
	},

	"cursor-up": {
		Argsn: 1,
		Doc:   "Moves the cursor up by the specified number of lines.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch lines := arg0.(type) {
			case env.Integer:
				if lines.Value > 0 {
					fmt.Printf("\033[%dA", lines.Value)
				}
				return *env.NewInteger(1)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "cursor-up")
			}
		},
	},

	"cursor-down": {
		Argsn: 1,
		Doc:   "Moves the cursor down by the specified number of lines.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch lines := arg0.(type) {
			case env.Integer:
				if lines.Value > 0 {
					fmt.Printf("\033[%dB", lines.Value)
				}
				return *env.NewInteger(1)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "cursor-down")
			}
		},
	},

	"clear-down": {
		Argsn: 0,
		Doc:   "Clears from the cursor position to the bottom of the screen.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			fmt.Print("\033[J")
			return *env.NewInteger(1)
		},
	},

	"clear-screen": {
		Argsn: 0,
		Doc:   "Clears the entire screen.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			fmt.Print("\033[2J\033[H")
			return *env.NewInteger(1)
		},
	},

	"hide-cursor": {
		Argsn: 0,
		Doc:   "Hides the terminal cursor.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			fmt.Print("\033[?25l")
			return *env.NewInteger(1)
		},
	},

	"show-cursor": {
		Argsn: 0,
		Doc:   "Shows the terminal cursor.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			fmt.Print("\033[?25h")
			return *env.NewInteger(1)
		},
	},

	"wrap": {
		Argsn: 2,
		Doc:   "Wraps a string to a specified width by inserting newlines.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			text, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "wrap")
			}
			wdth, ok := arg1.(env.Integer)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "wrap")
			}
			mkd := wrap.String(text.Value, int(wdth.Value))
			return *env.NewString(mkd)
		},
	},

	"wrap\\words": {
		Argsn: 2,
		Doc:   "Wraps a string to a specified width, preserving word boundaries.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			text, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "wrap\\words")
			}
			wdth, ok := arg1.(env.Integer)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "wrap\\words")
			}
			mkd := wordwrap.String(text.Value, int(wdth.Value))
			return *env.NewString(mkd)
		},
	},

	"indent": {
		Argsn: 2,
		Doc:   "Indents each line of a string by a specified number of spaces.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			text, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "indent")
			}
			wdth, ok := arg1.(env.Integer)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "indent")
			}
			mkd := indent.String(text.Value, uint(wdth.Value))
			return *env.NewString(mkd)
		},
	},

	"width?": {
		Argsn: 0,
		Doc:   "Returns the current width of the terminal in characters.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			fd := int(os.Stdout.Fd())
			width, _, err := goterm.GetSize(fd)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "width?")
			}
			return env.NewInteger(int64(width))
		},
	},

	"black": {
		Argsn: 0,
		Doc:   "Sets terminal text color to black.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBlack()
			return env.NewInteger(1)
		},
	},

	"red": {
		Argsn: 0,
		Doc:   "Sets terminal text color to red.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorRed()
			return env.NewInteger(1)
		},
	},

	"blue": {
		Argsn: 0,
		Doc:   "Sets terminal text color to blue.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBlue()
			return env.NewInteger(1)
		},
	},

	"green": {
		Argsn: 0,
		Doc:   "Sets terminal text color to green.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorGreen()
			return env.NewInteger(1)
		},
	},

	"yellow": {
		Argsn: 0,
		Doc:   "Sets terminal text color to yellow.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorYellow()
			return env.NewInteger(1)
		},
	},

	"magenta": {
		Argsn: 0,
		Doc:   "Sets terminal text color to magenta.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorMagenta()
			return env.NewInteger(1)
		},
	},

	"cyan": {
		Argsn: 0,
		Doc:   "Sets terminal text color to cyan.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBlue()
			return env.NewInteger(1)
		},
	},

	"white": {
		Argsn: 0,
		Doc:   "Sets terminal text color to white.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorWhite()
			return env.NewInteger(1)
		},
	},

	"str\\black": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for black text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBlack())
		},
	},

	"str\\red": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for red text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorRed())
		},
	},

	"str\\blue": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for blue text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBlue())
		},
	},

	"str\\green": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for green text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorGreen())
		},
	},

	"str\\yellow": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for yellow text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorYellow())
		},
	},

	"str\\magenta": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for magenta text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorMagenta())
		},
	},

	"str\\cyan": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for cyan text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorCyan())
		},
	},

	"str\\white": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for white text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorWhite())
		},
	},

	"br-black": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright black (gray).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrBlack()
			return env.NewInteger(1)
		},
	},

	"str\\br-black": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright black (gray) text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrBlack())
		},
	},

	"br-red": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright red.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrRed()
			return env.NewInteger(1)
		},
	},

	"br-blue": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright blue.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrBlue()
			return env.NewInteger(1)
		},
	},

	"br-green": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright green.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrGreen()
			return env.NewInteger(1)
		},
	},

	"br-yellow": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright yellow.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrYellow()
			return env.NewInteger(1)
		},
	},

	"br-magenta": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright magenta.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrMagenta()
			return env.NewInteger(1)
		},
	},

	"br-cyan": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright cyan.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrBlue()
			return env.NewInteger(1)
		},
	},

	"br-white": {
		Argsn: 0,
		Doc:   "Sets terminal text color to bright white.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBrWhite()
			return env.NewInteger(1)
		},
	},

	"bg-black": {
		Argsn: 0,
		Doc:   "Sets terminal background color to black.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgBlack()
			return env.NewInteger(1)
		},
	},

	"bg-red": {
		Argsn: 0,
		Doc:   "Sets terminal background color to red.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgRed()
			return env.NewInteger(1)
		},
	},

	"bg-blue": {
		Argsn: 0,
		Doc:   "Sets terminal background color to blue.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgBlue()
			return env.NewInteger(1)
		},
	},

	"bg-green": {
		Argsn: 0,
		Doc:   "Sets terminal background color to green.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgGreen()
			return env.NewInteger(1)
		},
	},

	"bg-yellow": {
		Argsn: 0,
		Doc:   "Sets terminal background color to yellow.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgYellow()
			return env.NewInteger(1)
		},
	},

	"bg-magenta": {
		Argsn: 0,
		Doc:   "Sets terminal background color to magenta.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgMagenta()
			return env.NewInteger(1)
		},
	},

	"bg-cyan": {
		Argsn: 0,
		Doc:   "Sets terminal background color to cyan.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgBlue()
			return env.NewInteger(1)
		},
	},

	"bg-white": {
		Argsn: 0,
		Doc:   "Sets terminal background color to white.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ColorBgWhite()
			return env.NewInteger(1)
		},
	},

	"bold": {
		Argsn: 0,
		Doc:   "Sets terminal text style to bold.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.Bold()
			return env.NewInteger(1)
		},
	},

	"underline": {
		Argsn: 0,
		Doc:   "Sets terminal text style to underlined.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.Underline()
			return env.NewInteger(1)
		},
	},

	"reset\\bold": {
		Argsn: 0,
		Doc:   "Resets terminal text bold style.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.ResetBold()
			return env.NewInteger(1)

		},
	},

	"reset": {
		Argsn: 0,
		Doc:   "Resets all terminal text styles and colors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			term.CloseProps()
			return env.NewInteger(1)
		},
	},

	"str\\reset": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string to reset all terminal text styles and colors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrCloseProps())
		},
	},

	"spin-it": {
		Argsn: 2,
		Doc:   "Takes a block of code and a message string, shows a spinner with the message while evaluating",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg1.(type) {
			case env.Block:
				switch msg := arg0.(type) {
				case env.String:

					done := make(chan bool)
					spinnerDone := make(chan bool)

					go func() {
						ser := ps.Ser
						ps.Ser = bloc.Series
						ps.BlockFile = bloc.FileName
						ps.BlockLine = bloc.Line
						evaldo.Eval(ps)
						evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "spin-it")
						ps.Ser = ser
						done <- true
					}()

					spinner := []rune{'|', '/', '-', '\\'}
					i := 0

					go func() {
						for {
							select {
							case <-done:
								fmt.Printf("\r")
								spinnerDone <- true
								return
							default:
								fmt.Printf("\r%s %c", msg.Value, spinner[i%len(spinner)])
								i++
								time.Sleep(120 * time.Millisecond)
							}
						}
					}()

					<-spinnerDone
					fmt.Println("")
					return ps.Res
				default:
					return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "spin-it")
				}
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "spin-it")
			}
		},
	},

	"pane": {
		Argsn: 2,
		Doc:   "Displays content in a bordered pane with a title header.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			title, ok1 := arg0.(env.String)
			if !ok1 {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "pane")
			}
			content, ok2 := arg1.(env.String)
			if !ok2 {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "pane")
			}

			lines := strings.Split(content.Value, "\n")

			maxContentWidth := 0
			for _, line := range lines {
				if len(line) > maxContentWidth {
					maxContentWidth = len(line)
				}
			}

			titleWidth := len(title.Value) + 4

			paneWidth := maxContentWidth + 2
			if titleWidth > paneWidth {
				paneWidth = titleWidth
			}
			if paneWidth < 10 {
				paneWidth = 10
			}

			titlePadding := paneWidth - len(title.Value) - 4
			leftPadding := titlePadding / 2
			rightPadding := titlePadding - leftPadding

			topBorder := "╭" + strings.Repeat("─", leftPadding) + "─ " + title.Value + " ─" + strings.Repeat("─", rightPadding) + "╮"
			fmt.Println(topBorder)

			for _, line := range lines {
				contentPadding := paneWidth - len(line)
				rightContentPadding := contentPadding
				fmt.Printf("│%s%s│\n", line, strings.Repeat(" ", rightContentPadding))
			}

			bottomBorder := "╰" + strings.Repeat("─", paneWidth) + "╯"
			fmt.Println(bottomBorder)

			return *env.NewInteger(1)
		},
	},
}
View Source
var Builtins_termstr = map[string]*env.Builtin{

	"black": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for black text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBlack())
		},
	},

	"red": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for red text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorRed())
		},
	},

	"blue": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for blue text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBlue())
		},
	},

	"green": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for green text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorGreen())
		},
	},

	"yellow": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for yellow text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorYellow())
		},
	},

	"magenta": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for magenta text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorMagenta())
		},
	},

	"cyan": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for cyan text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorCyan())
		},
	},

	"white": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for white text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorWhite())
		},
	},

	"br-black": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright black (gray) text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrBlack())
		},
	},

	"br-red": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright red text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrRed())
		},
	},

	"br-blue": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright blue text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrBlue())
		},
	},

	"br-green": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright green text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrGreen())
		},
	},

	"br-yellow": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright yellow text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrYellow())
		},
	},

	"br-magenta": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright magenta text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrMagenta())
		},
	},

	"br-cyan": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright cyan text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrCyan())
		},
	},

	"br-white": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bright white text color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBrWhite())
		},
	},

	"bg-black": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for black background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgBlack())
		},
	},

	"bg-red": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for red background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgRed())
		},
	},

	"bg-blue": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for blue background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgBlue())
		},
	},

	"bg-green": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for green background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgGreen())
		},
	},

	"bg-yellow": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for yellow background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgYellow())
		},
	},

	"bg-magenta": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for magenta background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgMagenta())
		},
	},

	"bg-cyan": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for cyan background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgCyan())
		},
	},

	"bg-white": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for white background color.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrColorBgWhite())
		},
	},

	"bold": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for bold text style.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrBold())
		},
	},

	"underline": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string for underlined text style.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrUnderline())
		},
	},

	"reset\\bold": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string to reset bold text style.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrResetBold())
		},
	},

	"reset": {
		Argsn: 0,
		Doc:   "Returns ANSI escape code string to reset all terminal text styles and colors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return *env.NewString(term.StrCloseProps())
		},
	},
}
View Source
var Builtins_tui = map[string]*env.Builtin{

	"text": {
		Argsn: 1,
		Doc:   "Creates a text widget (no wrapping). Returns { 'text { } content }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return tuiMakeWidget(ps, "text", *env.NewDict(nil), arg0)
		},
	},

	"text\\": {
		Argsn: 2,
		Doc:   "Creates a styled text widget. Returns { 'text { styles } content }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var styles env.Dict
			switch s := arg0.(type) {
			case env.Dict:
				styles = s
			case env.Word:

				styles = *env.NewDict(map[string]any{"_style": ps.Idx.GetWord(s.Index)})
			default:
				styles = *env.NewDict(nil)
			}
			return tuiMakeWidget(ps, "text", styles, arg1)
		},
	},

	"block": {
		Argsn: 1,
		Doc:   "Creates a text block widget that wraps. Returns { 'block { } content }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return tuiMakeWidget(ps, "block", *env.NewDict(nil), arg0)
		},
	},

	"block\\": {
		Argsn: 2,
		Doc:   "Creates a styled text block widget. Returns { 'block { styles } content }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var styles env.Dict
			switch s := arg0.(type) {
			case env.Dict:
				styles = s
			default:
				styles = *env.NewDict(nil)
			}
			return tuiMakeWidget(ps, "block", styles, arg1)
		},
	},

	"hline": {
		Argsn: 0,
		Doc:   "Creates a horizontal line widget. Returns { 'hline { } \"─\" }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return tuiMakeWidget(ps, "hline", *env.NewDict(nil), *env.NewString("─"))
		},
	},

	"hline\\char": {
		Argsn: 1,
		Doc:   "Creates a horizontal line with custom character. Returns { 'hline { } char }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return tuiMakeWidget(ps, "hline", *env.NewDict(nil), arg0)
		},
	},

	"vspace": {
		Argsn: 1,
		Doc:   "Creates a vertical spacer widget. Returns { 'vspace { } height }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return tuiMakeWidget(ps, "vspace", *env.NewDict(nil), arg0)
		},
	},

	"vbox": {
		Argsn: 1,
		Doc:   "Creates a vertical box container. Evaluates the block and collects widget results. Returns { 'vbox { } children }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch block := arg0.(type) {
			case env.Block:
				// Evaluate the block to get widget children
				// Each expression in the block should return a widget block
				var children []env.Object

				psTemp := *ps
				psTemp.Ser = block.Series
				psTemp.Ser.Reset()

				for psTemp.Ser.Pos() < psTemp.Ser.Len() {
					evaldo.EvalExpression(&psTemp, nil, false, false, false, false)
					if psTemp.ErrorFlag || psTemp.FailureFlag {
						return psTemp.Res
					}
					if psTemp.Res != nil {

						if _, ok := psTemp.Res.(env.Block); ok {
							children = append(children, psTemp.Res)
						}
					}
				}

				childrenBlock := *env.NewBlock(*env.NewTSeries(children))
				return tuiMakeWidget(ps, "vbox", *env.NewDict(nil), childrenBlock)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "vbox")
			}
		},
	},

	"vbox\\": {
		Argsn: 2,
		Doc:   "Creates a styled vertical box container. Supports background, color, padding, bold.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			styles, ok := arg0.(env.Dict)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DictType}, "vbox\\")
			}

			switch block := arg1.(type) {
			case env.Block:
				// Evaluate the block to get widget children
				var children []env.Object

				psTemp := *ps
				psTemp.Ser = block.Series
				psTemp.Ser.Reset()

				for psTemp.Ser.Pos() < psTemp.Ser.Len() {
					evaldo.EvalExpression(&psTemp, nil, false, false, false, false)
					if psTemp.ErrorFlag || psTemp.FailureFlag {
						return psTemp.Res
					}
					if psTemp.Res != nil {
						if _, ok := psTemp.Res.(env.Block); ok {
							children = append(children, psTemp.Res)
						}
					}
				}

				childrenBlock := *env.NewBlock(*env.NewTSeries(children))
				return tuiMakeWidget(ps, "vbox", styles, childrenBlock)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "vbox\\")
			}
		},
	},

	"select": {
		Argsn: 1,
		Doc:   "Creates a selection list widget. Returns { 'select { selected: 0 } items }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			styles := env.NewDict(map[string]any{"selected": *env.NewInteger(0)})
			return tuiMakeWidget(ps, "select", *styles, arg0)
		},
	},

	"select\\selected": {
		Argsn: 2,
		Doc:   "Creates a selection list with initial selection. Returns { 'select { selected: n } items }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			idx, ok := arg0.(env.Integer)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "select\\selected")
			}
			styles := env.NewDict(map[string]any{"selected": idx})
			return tuiMakeWidget(ps, "select", *styles, arg1)
		},
	},

	"tabs": {
		Argsn: 1,
		Doc:   "Creates a horizontal tabs widget. Returns { 'tabs { selected: 0 } items }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			styles := env.NewDict(map[string]any{"selected": *env.NewInteger(0)})
			return tuiMakeWidget(ps, "tabs", *styles, arg0)
		},
	},

	"tabs\\selected": {
		Argsn: 2,
		Doc:   "Creates tabs with initial selection. Returns { 'tabs { selected: n } items }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			idx, ok := arg0.(env.Integer)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "tabs\\selected")
			}
			styles := env.NewDict(map[string]any{"selected": idx})
			return tuiMakeWidget(ps, "tabs", *styles, arg1)
		},
	},

	"input": {
		Argsn: 1,
		Doc:   "Creates a managed text input widget with built-in key handling. Returns native TuiInput.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			placeholder, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "input")
			}
			inp := NewTuiInput(placeholder.Value)
			inp.ps = ps
			return *env.NewNative(ps.Idx, inp, "tui-input")
		},
	},

	"field": {
		Argsn: 1,
		Doc:   "Creates an unmanaged text field widget (pure data). Handle keys manually. Returns { 'field { } { value: '' placeholder: ... } }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			placeholder, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "field")
			}
			content := env.NewDict(map[string]any{
				"value":       *env.NewString(""),
				"placeholder": placeholder,
				"cursor":      *env.NewInteger(0),
			})
			return tuiMakeWidget(ps, "field", *env.NewDict(nil), *content)
		},
	},

	"field\\value": {
		Argsn: 2,
		Doc:   "Creates an unmanaged text field with initial value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			value, ok := arg0.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.StringType}, "field\\value")
			}
			placeholder, ok := arg1.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "field\\value")
			}
			content := env.NewDict(map[string]any{
				"value":       value,
				"placeholder": placeholder,
				"cursor":      *env.NewInteger(int64(len(value.Value))),
			})
			return tuiMakeWidget(ps, "field", *env.NewDict(nil), *content)
		},
	},

	"tui-input//On-submit": {
		Argsn: 2,
		Doc:   "Sets the callback function called when Enter is pressed. Callback receives (value).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					tinp.onSubmit = arg1
					tinp.ps = ps
					return arg0
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//On-submit")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//On-submit")
			}
		},
	},

	"tui-input//On-change": {
		Argsn: 2,
		Doc:   "Sets the callback function called when value changes. Callback receives (value).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					tinp.onChange = arg1
					tinp.ps = ps
					return arg0
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//On-change")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//On-change")
			}
		},
	},

	"tui-input//Value?": {
		Argsn: 1,
		Doc:   "Returns the current value of the input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					return *env.NewString(tinp.GetValue())
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//Value?")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//Value?")
			}
		},
	},

	"tui-input//Set-value": {
		Argsn: 2,
		Doc:   "Sets the value of the input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					if val, ok := arg1.(env.String); ok {
						tinp.SetValue(val.Value)
						return arg0
					}
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "tui-input//Set-value")
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//Set-value")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//Set-value")
			}
		},
	},

	"tui-input//Focus": {
		Argsn: 2,
		Doc:   "Sets the focus state of the input (1 = focused, 0 = not focused).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					if val, ok := arg1.(env.Integer); ok {
						tinp.focused = val.Value != 0
						return arg0
					}
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "tui-input//Focus")
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//Focus")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//Focus")
			}
		},
	},

	"tui-input//Width": {
		Argsn: 2,
		Doc:   "Sets the display width of the input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					if val, ok := arg1.(env.Integer); ok {
						tinp.width = int(val.Value)
						return arg0
					}
					return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "tui-input//Width")
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//Width")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//Width")
			}
		},
	},

	"tui-input//Handle-key": {
		Argsn: 2,
		Doc:   "Processes a key event. Returns 1 if handled, 0 if not.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					if key, ok := arg1.(env.String); ok {
						handled := tinp.HandleKey(key.Value, ps)
						if handled {
							return *env.NewInteger(1)
						}
						return *env.NewInteger(0)
					}
					return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "tui-input//Handle-key")
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//Handle-key")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//Handle-key")
			}
		},
	},

	"tui-input//Widget": {
		Argsn: 1,
		Doc:   "Returns the widget block for rendering this input.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch inp := arg0.(type) {
			case env.Native:
				if tinp, ok := inp.Value.(*TuiInput); ok {
					tinp.ps = ps
					return tinp.Render()
				}
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-input//Widget")
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-input//Widget")
			}
		},
	},

	"render": {
		Argsn: 1,
		Doc:   "Renders a widget tree to the terminal and returns number of lines.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			widget, ok := arg0.(env.Block)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "render")
			}

			width := term.GetTerminalColumns()
			if width < 20 {
				width = 80
			}

			theme := *env.NewDict(nil)
			lines := tuiRenderWidget(ps, widget, width, theme)

			for _, line := range lines {
				fmt.Println(line)
			}

			return *env.NewInteger(int64(len(lines)))
		},
	},

	"render\\theme": {
		Argsn: 2,
		Doc:   "Renders a widget tree with a theme.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			theme, ok := arg0.(env.Dict)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DictType}, "render\\theme")
			}
			widget, ok := arg1.(env.Block)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "render\\theme")
			}

			width := term.GetTerminalColumns()
			if width < 20 {
				width = 80
			}

			lines := tuiRenderWidget(ps, widget, width, theme)

			for _, line := range lines {
				fmt.Println(line)
			}

			return *env.NewInteger(int64(len(lines)))
		},
	},

	"render\\to-string": {
		Argsn: 2,
		Doc:   "Renders a widget tree to a string.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			widget, ok := arg0.(env.Block)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "render\\to-string")
			}
			width, ok := arg1.(env.Integer)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.IntegerType}, "render\\to-string")
			}

			theme := *env.NewDict(nil)
			lines := tuiRenderWidget(ps, widget, int(width.Value), theme)

			return *env.NewString(strings.Join(lines, "\n"))
		},
	},

	"app": {
		Argsn: 1,
		Doc:   "Creates a new TUI app with the given theme.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			theme, ok := arg0.(env.Dict)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.DictType}, "app")
			}
			app := NewTuiApp(theme)
			return *env.NewNative(ps.Idx, app, "tui-app")
		},
	},

	"tui-app//View": {
		Argsn: 2,
		Doc:   "Sets the view for the TUI app. Can be a widget block or a function that returns one.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//View")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//View")
			}
			app.SetView(arg1)
			return arg0
		},
	},

	"tui-app//State": {
		Argsn: 2,
		Doc:   "Sets the state for the TUI app.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//State")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//State")
			}
			state, ok := arg1.(env.Dict)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.DictType}, "tui-app//State")
			}
			app.SetState(state)
			return arg0
		},
	},

	"tui-app//State?": {
		Argsn: 1,
		Doc:   "Gets the current state of the TUI app.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//State?")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//State?")
			}
			return app.GetState()
		},
	},

	"tui-app//Update": {
		Argsn: 2,
		Doc:   "Updates the state and re-renders.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//Update")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//Update")
			}
			updates, ok := arg1.(env.Dict)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.DictType}, "tui-app//Update")
			}
			app.Update(updates)
			return arg0
		},
	},

	"tui-app//On-key": {
		Argsn: 3,
		Doc:   "Registers a handler for a specific key. Key can be 'up', 'down', 'enter', 'escape', 'q', etc.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//On-key")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//On-key")
			}
			key, ok := arg1.(env.String)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.StringType}, "tui-app//On-key")
			}
			switch arg2.(type) {
			case env.Function, env.Block:
				app.OnKey(key.Value, arg2)
				return arg0
			default:
				return evaldo.MakeArgError(ps, 3, []env.Type{env.FunctionType, env.BlockType}, "tui-app//On-key")
			}
		},
	},

	"tui-app//On-keys": {
		Argsn: 2,
		Doc:   "Registers a handler for ALL keys. Function receives (state, key). Use switch on key to handle different keys.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//On-keys")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//On-keys")
			}
			switch arg1.(type) {
			case env.Function, env.Block:
				app.OnKeys(arg1)
				return arg0
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.FunctionType, env.BlockType}, "tui-app//On-keys")
			}
		},
	},

	"tui-app//Focus": {
		Argsn: 2,
		Doc:   "Sets the focused input widget. Keys are routed to focused input first.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//Focus")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//Focus")
			}

			if i, ok := arg1.(env.Integer); ok && i.Value == 0 {
				app.mu.Lock()
				app.focusedInput = nil
				app.mu.Unlock()
				return arg0
			}

			inputNative, ok := arg1.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 2, []env.Type{env.NativeType}, "tui-app//Focus")
			}
			inp, ok := inputNative.Value.(*TuiInput)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiInput", "tui-app//Focus")
			}

			app.mu.Lock()
			app.focusedInput = inp
			inp.focused = true
			inp.ps = ps
			app.mu.Unlock()
			return arg0
		},
	},

	"tui-app//Start": {
		Argsn: 1,
		Doc:   "Starts the TUI app, entering raw mode and beginning the event loop.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//Start")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//Start")
			}
			err := app.Start(ps)
			if err != nil {
				return evaldo.MakeBuiltinError(ps, err.Error(), "tui-app//Start")
			}
			return arg0
		},
	},

	"tui-app//Stop": {
		Argsn: 1,
		Doc:   "Stops the TUI app.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//Stop")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//Stop")
			}
			app.Stop()
			return arg0
		},
	},

	"tui-app//Wait": {
		Argsn: 1,
		Doc:   "Blocks until the TUI app stops.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//Wait")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//Wait")
			}
			app.Wait()
			return arg0
		},
	},

	"tui-app//Redraw": {
		Argsn: 1,
		Doc:   "Forces a re-render of the TUI app.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//Redraw")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//Redraw")
			}

			app.mu.Lock()
			if app.ps == nil {
				app.ps = ps
			}
			app.mu.Unlock()
			app.Render()
			return arg0
		},
	},

	"tui-app//Send": {
		Argsn: 2,
		Doc:   "Sends a message into the app's event loop. Thread-safe, can be called from goroutines. The message is handled by the on-message handler.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//Send")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//Send")
			}

			select {
			case app.msgChan <- arg1:

			default:

			}
			return arg0
		},
	},

	"tui-app//On-message": {
		Argsn: 2,
		Doc:   "Registers a handler for async messages sent via Send. Function receives (state, msg). Return a dict to update state.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			native, ok := arg0.(env.Native)
			if !ok {
				return evaldo.MakeArgError(ps, 1, []env.Type{env.NativeType}, "tui-app//On-message")
			}
			app, ok := native.Value.(*TuiApp)
			if !ok {
				return evaldo.MakeBuiltinError(ps, "Expected TuiApp", "tui-app//On-message")
			}
			switch arg1.(type) {
			case env.Function:
				app.mu.Lock()
				app.msgHandler = arg1
				app.mu.Unlock()
				return arg0
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.FunctionType}, "tui-app//On-message")
			}
		},
	},

	"style": {
		Argsn: 1,
		Doc:   "Creates a style dict from a block. Example: tui-style { bold: 1 color: 'blue }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch b := arg0.(type) {
			case env.Block:

				data := make(map[string]any)
				for i := 0; i < b.Series.Len(); i += 2 {
					if i+1 >= b.Series.Len() {
						break
					}
					key := b.Series.Get(i)
					val := b.Series.Get(i + 1)

					var keyStr string
					switch k := key.(type) {
					case env.Tagword:
						keyStr = ps.Idx.GetWord(k.Index)
					case env.Word:
						keyStr = ps.Idx.GetWord(k.Index)
					case env.String:
						keyStr = k.Value
					default:
						continue
					}

					data[keyStr] = val
				}
				return *env.NewDict(data)
			case env.Dict:
				return b
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.DictType}, "style")
			}
		},
	},

	"theme": {
		Argsn: 1,
		Doc:   "Creates a theme dict. Example: tui-theme { text { color: 'blue } hline { color: 'gray } }",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch b := arg0.(type) {
			case env.Block:
				data := make(map[string]any)
				for i := 0; i < b.Series.Len(); i += 2 {
					if i+1 >= b.Series.Len() {
						break
					}
					key := b.Series.Get(i)
					val := b.Series.Get(i + 1)

					var keyStr string
					switch k := key.(type) {
					case env.Tagword:
						keyStr = ps.Idx.GetWord(k.Index)
					case env.Word:
						keyStr = ps.Idx.GetWord(k.Index)
					case env.String:
						keyStr = k.Value
					default:
						continue
					}

					switch v := val.(type) {
					case env.Block:

						styleData := make(map[string]any)
						for j := 0; j < v.Series.Len(); j += 2 {
							if j+1 >= v.Series.Len() {
								break
							}
							sk := v.Series.Get(j)
							sv := v.Series.Get(j + 1)

							var skStr string
							switch skk := sk.(type) {
							case env.Tagword:
								skStr = ps.Idx.GetWord(skk.Index)
							case env.Word:
								skStr = ps.Idx.GetWord(skk.Index)
							case env.String:
								skStr = skk.Value
							default:
								continue
							}
							styleData[skStr] = sv
						}
						data[keyStr] = *env.NewDict(styleData)
					case env.Dict:
						data[keyStr] = v
					}
				}
				return *env.NewDict(data)
			case env.Dict:
				return b
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType, env.DictType}, "theme")
			}
		},
	},
}
View Source
var Builtins_validation = map[string]*env.Builtin{

	"validate": {
		Argsn: 2,
		Doc:   "Validates and transforms data according to specified rules, returning a dictionary with converted values or an error.",
		Fn: func(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return BuiValidate(env1, arg0, arg1)
		},
	},

	"validate>ctx": {
		Argsn: 2,
		Doc:   "Validates and transforms data according to specified rules, returning a context object for easy field access.",
		Fn: func(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			obj := BuiValidate(env1, arg0, arg1)
			if env1.FailureFlag {
				return obj
			}
			switch obj1 := obj.(type) {
			case env.Dict:
				return util.Dict2Context(env1, obj1)
			default:
				return obj1
			}
		},
	},
}
View Source
var Builtins_vector = map[string]*env.Builtin{

	"vector": {
		Argsn: 1,
		Doc:   "Creates a vector from a block of numbers.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch s := arg0.(type) {
			case env.Block:
				data := ArrayFloat32FromSeries(s.Series)
				val, err := govector.AsVector(data)
				if err != nil {
					return evaldo.MakeError(ps, err.Error())
				}
				return *env.NewVector(val)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "vector")
			}
		},
	},

	"normalize": {
		Argsn: 1,
		Doc:   "Calculates the L2 norm (Euclidean length) of a vector.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Vector:
				return *env.NewDecimal(govector.Norm(val.Value, 2.0))
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "normalize")
			}
		},
	},

	"std-deviation": {
		Argsn: 1,
		Doc:   "Calculates the standard deviation of a vector's elements.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch val := arg0.(type) {
			case env.Vector:
				return *env.NewDecimal(val.Value.Sd())
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "std-deviation?")
			}
		},
	},

	"cosine-similarity": {
		Argsn: 2,
		Doc:   "Calculates the cosine similarity between two vectors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					res, err := govector.Cosine(v1.Value, v2.Value)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "cosine-similarity?")
					}
					return *env.NewDecimal(res)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "cosine-similarity?")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "cosine-similarity?")
			}
		},
	},

	"correlation": {
		Argsn: 2,
		Doc:   "Calculates the correlation coefficient between two vectors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					res, err := govector.Cor(v1.Value, v2.Value)
					if err != nil {
						return evaldo.MakeError(ps, err.Error())
					}
					return *env.NewDecimal(res)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "correlation")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "correlation")
			}
		},
	},

	"dot-product": {
		Argsn: 2,
		Doc:   "Calculates the dot product between two vectors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					res, err := govector.DotProduct(v1.Value, v2.Value)
					if err != nil {
						return evaldo.MakeError(ps, err.Error())
					}
					return *env.NewDecimal(res)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "dot-product")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "dot-product")
			}
		},
	},

	"euclidean-distance": {
		Argsn: 2,
		Doc:   "Calculates the Euclidean distance between two vectors. Useful for K-Means clustering.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					if len(v1.Value) != len(v2.Value) {
						return evaldo.MakeBuiltinError(ps, "Vectors must have the same length", "euclidean-distance")
					}
					var sum float64
					for i := 0; i < len(v1.Value); i++ {
						diff := v1.Value[i] - v2.Value[i]
						sum += diff * diff
					}
					return *env.NewDecimal(sqrtFloat64(sum))
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "euclidean-distance")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "euclidean-distance")
			}
		},
	},

	"mean-vectors": {
		Argsn: 1,
		Doc:   "Calculates the element-wise mean of multiple vectors. Useful for creating 'Master Anchors'.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch block := arg0.(type) {
			case env.Block:
				if block.Series.Len() == 0 {
					return evaldo.MakeBuiltinError(ps, "Block must contain at least one vector", "mean-vectors")
				}

				first := block.Series.Get(0)
				firstVec, ok := first.(env.Vector)
				if !ok {
					return evaldo.MakeBuiltinError(ps, "Block must contain only vectors", "mean-vectors")
				}
				vecLen := len(firstVec.Value)
				result := make(govector.Vector, vecLen)

				for i := 0; i < block.Series.Len(); i++ {
					item := block.Series.Get(i)
					vec, ok := item.(env.Vector)
					if !ok {
						return evaldo.MakeBuiltinError(ps, "Block must contain only vectors", "mean-vectors")
					}
					if len(vec.Value) != vecLen {
						return evaldo.MakeBuiltinError(ps, "All vectors must have the same length", "mean-vectors")
					}
					for j := 0; j < vecLen; j++ {
						result[j] += vec.Value[j]
					}
				}

				count := float64(block.Series.Len())
				for i := 0; i < vecLen; i++ {
					result[i] /= count
				}
				return *env.NewVector(result)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "mean-vectors")
			}
		},
	},

	"unit-vector": {
		Argsn: 1,
		Doc:   "Returns a new normalized vector (length = 1). Essential for consistent dot products and overlays.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v := arg0.(type) {
			case env.Vector:
				norm := govector.Norm(v.Value, 2.0)
				if norm == 0 {
					return evaldo.MakeBuiltinError(ps, "Cannot normalize zero vector", "Vector//unit")
				}
				result := make(govector.Vector, len(v.Value))
				for i := 0; i < len(v.Value); i++ {
					result[i] = v.Value[i] / norm
				}
				return *env.NewVector(result)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "Vector//unit")
			}
		},
	},

	"project-vector": {
		Argsn: 2,
		Doc:   "Projects vector onto another vector. Answers: 'How much of this vector is in the direction of another?'",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					if len(v1.Value) != len(v2.Value) {
						return evaldo.MakeBuiltinError(ps, "Vectors must have the same length", "Vector//project")
					}

					dotAB, err := govector.DotProduct(v1.Value, v2.Value)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "Vector//project")
					}
					dotBB, err := govector.DotProduct(v2.Value, v2.Value)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "Vector//project")
					}
					if dotBB == 0 {
						return evaldo.MakeBuiltinError(ps, "Cannot project onto zero vector", "Vector//project")
					}
					scalar := dotAB / dotBB
					result := make(govector.Vector, len(v2.Value))
					for i := 0; i < len(v2.Value); i++ {
						result[i] = v2.Value[i] * scalar
					}
					return *env.NewVector(result)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "Vector//project")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "Vector//project")
			}
		},
	},

	"reject-vector": {
		Argsn: 2,
		Doc:   "Removes projection from vector. Use this to 'subtract' a concept direction from a vector.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch v1 := arg0.(type) {
			case env.Vector:
				switch v2 := arg1.(type) {
				case env.Vector:
					if len(v1.Value) != len(v2.Value) {
						return evaldo.MakeBuiltinError(ps, "Vectors must have the same length", "Vector//reject")
					}

					dotAB, err := govector.DotProduct(v1.Value, v2.Value)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "Vector//reject")
					}
					dotBB, err := govector.DotProduct(v2.Value, v2.Value)
					if err != nil {
						return evaldo.MakeBuiltinError(ps, err.Error(), "Vector//reject")
					}
					if dotBB == 0 {

						return v1
					}
					scalar := dotAB / dotBB
					result := make(govector.Vector, len(v1.Value))
					for i := 0; i < len(v1.Value); i++ {
						result[i] = v1.Value[i] - (v2.Value[i] * scalar)
					}
					return *env.NewVector(result)
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.VectorType}, "Vector//reject")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.VectorType}, "Vector//reject")
			}
		},
	},
}
View Source
var Builtins_web = map[string]*env.Builtin{}
View Source
var ErrorCreationBuiltins = map[string]*env.Builtin{

	"fail": {
		Argsn: 1,
		Doc:   "Creates an error and sets the failure flag, but continues execution (unlike ^fail).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = true
			return evaldo.MakeRyeError(ps, arg0, nil)
		},
	},

	"^fail": {
		Argsn: 1,
		Doc:   "Creates an error and immediately returns from the current function with failure state.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = true
			ps.ReturnFlag = true
			return evaldo.MakeRyeError(ps, arg0, nil)
		},
	},

	"refail": {
		Argsn: 2,
		Doc:   "Re-raises an existing error with additional context. TODO -- duplicate of check",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch er := arg0.(type) {
			case *env.Error:
				ps.FailureFlag = true
				return evaldo.MakeRyeError(ps, arg1, er)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ErrorType}, "reraise")
			}
		},
	},

	"failure": {
		Argsn: 1,
		Doc:   "Creates an error object without setting any flags (unlike fail and ^fail).",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return evaldo.MakeRyeError(ps, arg0, nil)
		},
	},

	"empty": {
		Argsn: 0,
		Doc:   "Creates an 404 error object without setting any flags.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			return evaldo.MakeRyeError(ps, *env.NewInteger(404), nil)
		},
	},

	"failure\\wrap": {
		Argsn: 2,
		Doc:   "Creates a new error that wraps an existing error, allowing for error chaining.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch er := arg1.(type) {
			case *env.Error:
				return evaldo.MakeRyeError(ps, arg0, er)
			default:
				return evaldo.MakeArgError(ps, 2, []env.Type{env.ErrorType}, "wrap\\failure")
			}
		},
	},
}

Error Creation Functions

View Source
var ErrorHandlingBuiltins = map[string]*env.Builtin{

	"disarm": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Clears the failure flag while preserving the error object, allowing error inspection without propagation.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = false
			return arg0
		},
	},

	"check": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Checks if a value is in failure state and wraps it with a new error if so, otherwise returns the original value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if ps.FailureFlag || arg0.Type() == env.ErrorType {

				switch er := arg0.(type) {
				case *env.Error:
					if er.Status == 0 && er.Message == "" {
						er = nil
					}
					return evaldo.MakeRyeError(ps, arg1, er)
				case env.Error:

					return evaldo.MakeRyeError(ps, arg1, &er)
				}
				return env.NewError("Failure flag but value not Failure")
			}
			return arg0
		},
	},

	"^check": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Like 'check' but also sets the return flag to immediately exit the current function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if ps.FailureFlag || arg0.Type() == env.ErrorType {
				ps.ReturnFlag = true
				switch er := arg0.(type) {
				case *env.Error:
					if er.Status == 0 && er.Message == "" {
						er = nil
					}
					return evaldo.MakeRyeError(ps, arg1, er)
				case env.Error:

					return evaldo.MakeRyeError(ps, arg1, &er)
				}
				return env.NewError("Failure flag but value not Failure")
			}
			return arg0
		},
	},

	"^ensure": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Checks if a value is truthy and returns it if so, otherwise creates an error and immediately returns from the function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cond := arg0.(type) {
			case env.Object:
				if !util.IsTruthy(cond) {
					ps.FailureFlag = true
					ps.ReturnFlag = true
					return evaldo.MakeRyeError(ps, arg1, nil)
				} else {
					return arg0
				}
			}
			return arg0
		},
	},

	"ensure": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Checks if a value is truthy and returns it if so, otherwise creates an error with the failure flag set.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch cond := arg0.(type) {
			case env.Object:
				if !util.IsTruthy(cond) {
					ps.FailureFlag = true
					return evaldo.MakeRyeError(ps, arg1, nil)
				} else {
					return arg0
				}
			}
			return arg0
		},
	},

	"requires-one-of": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Validates that a value matches one of the provided options, failing with a descriptive error if not.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch optionsBlock := arg1.(type) {
			case env.Block:

				options := optionsBlock.Series.GetAll()
				for _, option := range options {

					if arg0.GetKind() == option.GetKind() && arg0.Inspect(*ps.Idx) == option.Inspect(*ps.Idx) {
						return arg0
					}
				}

				ps.FailureFlag = true

				valueStr := arg0.Inspect(*ps.Idx)

				// Build error message with options
				var errorMsg string
				if len(options) > 0 {
					optionsStr := "{ "
					for i, opt := range options {
						if i > 0 {
							optionsStr += " "
						}
						optionsStr += opt.Inspect(*ps.Idx)
					}
					optionsStr += " }"
					errorMsg = fmt.Sprintf("Value %s must be one of %s", valueStr, optionsStr)
				} else {
					errorMsg = fmt.Sprintf("Value %s does not match any valid option", valueStr)
				}

				return evaldo.MakeRyeError(ps, *env.NewString(errorMsg), nil)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "requires-one-of")
			}
		},
	},

	"^requires-one-of": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Validates that a value matches one of the provided options, failing with a descriptive error if not.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch optionsBlock := arg1.(type) {
			case env.Block:

				options := optionsBlock.Series.GetAll()
				for _, option := range options {

					if arg0.GetKind() == option.GetKind() && arg0.Inspect(*ps.Idx) == option.Inspect(*ps.Idx) {
						return arg0
					}
				}

				ps.FailureFlag = true

				valueStr := arg0.Inspect(*ps.Idx)

				// Build error message with options
				var errorMsg string
				if len(options) > 0 {
					optionsStr := "{ "
					for i, opt := range options {
						if i > 0 {
							optionsStr += " "
						}
						optionsStr += opt.Inspect(*ps.Idx)
					}
					optionsStr += " }"
					errorMsg = fmt.Sprintf("Value %s must be one of %s", valueStr, optionsStr)
				} else {
					errorMsg = fmt.Sprintf("Value %s does not match any valid option", valueStr)
				}
				ps.ReturnFlag = true
				return evaldo.MakeRyeError(ps, *env.NewString(errorMsg), nil)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "requires-one-of")
			}
		},
	},

	"ensure\\with": {
		AcceptFailure: true,
		Argsn:         3,
		Doc:           "Injects a value into a validation block and returns the value if the block is truthy, otherwise creates an error.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg1.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				evaldo.EvalBlockInj(ps, arg0, true)
				if ps.ErrorFlag {
					ps.Ser = ser
					return ps.Res
				}
				ps.Ser = ser
				if util.IsTruthy(ps.Res) {
					return arg0
				} else {
					ps.FailureFlag = true
					return evaldo.MakeRyeError(ps, arg2, nil)
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "ensure\\with")
			}
		},
	},

	"^ensure\\with": {
		AcceptFailure: true,
		Argsn:         3,
		Doc:           "Like ensure\\with but also sets the return flag to immediately exit the current function.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg1.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				evaldo.EvalBlockInj(ps, arg0, true)
				if ps.ErrorFlag {
					ps.Ser = ser
					ps.ReturnFlag = true
					return ps.Res
				}
				ps.Ser = ser
				if util.IsTruthy(ps.Res) {
					return arg0
				} else {
					ps.FailureFlag = true
					ps.ReturnFlag = true
					return evaldo.MakeRyeError(ps, arg2, nil)
				}
			default:
				ps.FailureFlag = true
				ps.ReturnFlag = true
				return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "^ensure\\with")
			}
		},
	},

	"fix": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Handles errors by executing a block if the value is in failure state, clearing the failure flag.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if ps.FailureFlag || arg0.Type() == env.ErrorType {
				ps.FailureFlag = false

				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "fix")
					if ps.ErrorFlag {
						ps.Ser = ser
						return ps.Res
					}
					ps.Ser = ser
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "fix")
				}
			} else {
				return arg0
			}
		},
	},

	"^fix": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Like 'fix' but also sets the return flag to immediately exit the current function with the handler result.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if ps.FailureFlag || arg0.Type() == env.ErrorType {
				ps.FailureFlag = false

				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "^fix")
					ps.Ser = ser
					ps.ReturnFlag = true
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "^fix")
				}
			} else {
				return arg0
			}
		},
	},

	"fix\\either": {
		AcceptFailure: true,
		Argsn:         3,
		Doc:           "Executes one of two blocks depending on whether the value is in failure state.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if ps.FailureFlag || arg0.Type() == env.ErrorType {
				ps.FailureFlag = false

				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "fix\\either")
					ps.Ser = ser
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "fix\\either")
				}
			} else {
				switch bloc := arg2.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "fix\\either")
					ps.Ser = ser
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "fix\\either")
				}
			}
		},
	},

	"fix\\else": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Executes a block if the value is not in failure state, otherwise returns the original value.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if !(ps.FailureFlag || arg0.Type() == env.ErrorType) {
				ps.FailureFlag = false

				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "fix\\else")
					ps.Ser = ser
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "fix\\else")
				}
			} else {
				return arg0
			}
		},
	},

	"fix\\continue": {
		AcceptFailure: true,
		Argsn:         3,
		Doc:           "Executes one of two blocks depending on whether the value is in failure state, like an error-handling if/else.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if ps.FailureFlag || arg0.Type() == env.ErrorType {
				ps.FailureFlag = false

				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					ps.Ser = ser
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "fix\\continue")
				}
			} else {
				switch bloc := arg2.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					ps.Ser = ser
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 3, []env.Type{env.BlockType}, "fix\\continue")
				}
			}
		},
	},

	"continue": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Executes a block only if the value is not in failure state, opposite of 'fix'.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			if !(ps.FailureFlag || arg0.Type() == env.ErrorType) {
				ps.FailureFlag = false

				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					evaldo.EvalBlockInj(ps, arg0, true)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "continue")
					ps.Ser = ser
					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "continue")
				}
			} else {
				ps.FailureFlag = false
				return arg0
			}
		},
	},

	"^fix\\match": {
		Argsn:         2,
		Doc:           "Error handling switch that matches error codes with handler blocks and sets the return flag.",
		AcceptFailure: true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = false

			switch er := arg0.(type) {
			case env.Error, *env.Error:
				switch bloc := arg1.(type) {
				case env.Block:
					var code env.Object
					any_found := false

					for i := 0; i < bloc.Series.Len(); i += 2 {
						if i > bloc.Series.Len()-2 {
							return evaldo.MakeBuiltinError(ps, "Switch block malformed.", "^fix\\match")
						}

						switch ev := bloc.Series.Get(i).(type) {
						case env.Integer:
							var status int
							if err, ok := er.(env.Error); ok {
								status = err.Status
							} else if errPtr, ok := er.(*env.Error); ok {
								status = errPtr.Status
							}

							if status == int(ev.Value) {
								any_found = true
								code = bloc.Series.Get(i + 1)
							}
						case env.Void:
							if !any_found {
								code = bloc.Series.Get(i + 1)
								any_found = true
							}
						default:
							return evaldo.MakeBuiltinError(ps, "Invalid type in block series.", "^fix\\match")
						}
					}

					switch cc := code.(type) {
					case env.Block:

						ser := ps.Ser

						ps.Ser = cc.Series

						evaldo.EvalBlockInj(ps, arg0, true)

						evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "fix\\match")

						ps.Ser = ser

						ps.ReturnFlag = true
						return ps.Res
					default:

						ps.FailureFlag = true
						return evaldo.MakeBuiltinError(ps, "Malformed switch block.", "^fix\\match")
					}
				default:

					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "^fix\\match")
				}
			default:
				return arg0
			}
		},
	},

	"try": {
		Argsn: 1,
		Doc:   "Takes a block of code and does (runs) it.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:
				ser := ps.Ser
				ps.Ser = bloc.Series
				ps.InErrHandler = true
				evaldo.Eval(ps)

				ps.InErrHandler = false
				ps.ReturnFlag = false
				ps.ErrorFlag = false
				ps.FailureFlag = false

				ps.Ser = ser
				return ps.Res
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "try")
			}
		},
	},

	"try-all": {
		Argsn: 1,
		Doc:   "Executes a block and returns a result tuple [success, result], where success is true if no error occurred.",
		Pure:  true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:

				oldSer := ps.Ser
				oldFailureFlag := ps.FailureFlag
				oldErrorFlag := ps.ErrorFlag
				ps.InErrHandler = true

				ps.Ser = bloc.Series
				evaldo.Eval(ps)
				evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "try-all")

				result := ps.Res
				success := !ps.FailureFlag && !ps.ErrorFlag
				ps.InErrHandler = false

				ps.Ser = oldSer
				ps.FailureFlag = oldFailureFlag
				ps.ErrorFlag = oldErrorFlag

				return *env.NewBlock(*env.NewTSeries([]env.Object{
					*env.NewBoolean(success),
					result,
				}))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "try-all")
			}
		},
	},

	"try\\in": {
		Argsn: 2,
		Doc:   "Takes a Context and a Block. It Does a block inside a given Context.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch ctx := arg0.(type) {
			case *env.RyeCtx:
				switch bloc := arg1.(type) {
				case env.Block:
					ser := ps.Ser
					ps.Ser = bloc.Series
					ps.InErrHandler = true
					evaldo.EvalBlockInCtxInj(ps, ctx, nil, false)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "try\\in")
					ps.InErrHandler = false
					ps.ReturnFlag = false
					ps.ErrorFlag = false
					ps.FailureFlag = false

					ps.Ser = ser
					return ps.Res
				default:
					ps.ErrorFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "try\\in")
				}
			default:
				ps.ErrorFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ContextType}, "try\\in")
			}
		},
	},

	"finally": {
		Argsn: 2,
		Doc:   "Executes a block and ensures another block is executed afterward, regardless of errors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch mainBlock := arg0.(type) {
			case env.Block:
				switch finallyBlock := arg1.(type) {
				case env.Block:

					oldSer := ps.Ser
					ps.InErrHandler = true

					ps.Ser = mainBlock.Series
					evaldo.Eval(ps)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "finally")

					result := ps.Res
					hasFailure := ps.FailureFlag
					hasError := ps.ErrorFlag

					ps.Ser = finallyBlock.Series
					ps.FailureFlag = false
					ps.ErrorFlag = false
					ps.InErrHandler = false
					evaldo.Eval(ps)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "finally")

					ps.Res = result
					ps.FailureFlag = hasFailure
					ps.ErrorFlag = hasError

					ps.Ser = oldSer

					return ps.Res
				default:
					ps.FailureFlag = true
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "finally")
				}
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "finally")
			}
		},
	},

	"retry": {
		Argsn:         2,
		Doc:           "Executes a block and retries it up to N times if it results in a failure.",
		AcceptFailure: true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch retries := arg0.(type) {
			case env.Integer:
				switch bloc := arg1.(type) {
				case env.Block:

					ser := ps.Ser

					ps.Ser = bloc.Series
					evaldo.Eval(ps)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "retry")

					if !ps.FailureFlag {
						ps.Ser = ser
						return ps.Res
					}

					result := ps.Res

					for i := int64(1); i < retries.Value; i++ {

						ps.Ser.Reset()
						ps.FailureFlag = false
						ps.ErrorFlag = false

						evaldo.Eval(ps)
						evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "retry")

						if !ps.FailureFlag {
							ps.Ser = ser
							return ps.Res
						}

						result = ps.Res
					}

					ps.Ser = ser
					ps.FailureFlag = true
					return result
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "retry")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "retry")
			}
		},
	},

	"persist": {
		Argsn:         1,
		Doc:           "Executes a block repeatedly until it succeeds (no failure), then returns the successful result. Gives up after 1000 attempts.",
		AcceptFailure: true,
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch bloc := arg0.(type) {
			case env.Block:

				ser := ps.Ser

				for attempt := 1; attempt <= 1000; attempt++ {

					ps.Ser = bloc.Series
					ps.Ser.Reset()
					ps.FailureFlag = false
					ps.ErrorFlag = false

					evaldo.Eval(ps)
					evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "persist")

					if !ps.FailureFlag {
						ps.Ser = ser
						return ps.Res
					}

				}

				ps.Ser = ser
				ps.FailureFlag = true
				return evaldo.MakeRyeError(ps, *env.NewString("Persist failed: Block did not succeed after 1000 attempts"), nil)
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.BlockType}, "persist")
			}
		},
	},

	"timeout": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Executes a block of code with a timeout, failing if execution exceeds the specified duration in milliseconds.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch ms := arg0.(type) {
			case env.Integer:
				switch bloc := arg1.(type) {
				case env.Block:

					ser := ps.Ser

					resultChan := make(chan env.Object, 1)
					doneChan := make(chan bool, 1)

					psCopy := env.NewProgramStateOLD(bloc.Series, ps.Idx)
					psCopy.Ctx = ps.Ctx
					psCopy.PCtx = ps.PCtx
					psCopy.Gen = ps.Gen

					go func() {
						evaldo.Eval(psCopy)
						evaldo.MaybeDisplayFailureOrError(ps, ps.Idx, "timeout")

						resultChan <- psCopy.Res
						doneChan <- psCopy.FailureFlag
					}()

					timeoutDuration := time.Duration(ms.Value) * time.Millisecond

					select {
					case result := <-resultChan:
						ps.FailureFlag = <-doneChan
						ps.Ser = ser
						return result

					case <-time.After(timeoutDuration):
						ps.FailureFlag = true
						ps.Ser = ser
						return evaldo.MakeRyeError(ps, *env.NewString(fmt.Sprintf("Execution timed out after %d ms", ms.Value)), nil)
					}
				default:
					return evaldo.MakeArgError(ps, 2, []env.Type{env.BlockType}, "timeout")
				}
			default:
				return evaldo.MakeArgError(ps, 1, []env.Type{env.IntegerType}, "timeout")
			}
		},
	},
}

Error Handling Functions

View Source
var ErrorInspectionBuiltins = map[string]*env.Builtin{

	"is-error": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Returns true if the value is an error, false otherwise.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = false
			switch arg0.(type) {
			case env.Error, *env.Error:
				return *env.NewBoolean(true)
			}
			return *env.NewBoolean(false)
		},
	},

	"error-kind?": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Returns the kind of an error, or void if not an error.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = false
			switch err := arg0.(type) {
			case env.Error:
				return *env.NewWord(err.Kind.Index)
			case *env.Error:
				return *env.NewWord(err.Kind.Index)
			}
			return *env.NewVoid()
		},
	},

	"is-error-of-kind": {
		AcceptFailure: true,
		Argsn:         2,
		Doc:           "Returns true if the value is an error of the specified kind, false otherwise.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = false

			// Get the kind to check
			var kindIndex int
			switch kind := arg1.(type) {
			case env.Word:
				kindIndex = kind.Index
			case env.Tagword:
				kindIndex = kind.Index
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 2, []env.Type{env.WordType, env.TagwordType}, "is-error-of-kind")
			}

			switch err := arg0.(type) {
			case env.Error:
				return *env.NewBoolean(err.Kind.Index == kindIndex)
			case *env.Error:
				return *env.NewBoolean(err.Kind.Index == kindIndex)
			}

			return *env.NewBoolean(false)
		},
	},

	"cause?": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Extracts the root cause from an error chain by traversing the Parent references.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch er := arg0.(type) {
			case env.Error:

				current := &er
				for current.Parent != nil {
					current = current.Parent
				}
				return *current
			case *env.Error:

				current := er
				for current.Parent != nil {
					current = current.Parent
				}
				return *current
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ErrorType}, "cause?")
			}
		},
	},

	"status?": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Extracts the numeric status code from an error object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch er := arg0.(type) {
			case env.Error:
				return *env.NewInteger(int64(er.Status))
			case *env.Error:
				return *env.NewInteger(int64(er.Status))
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ErrorType}, "status?")
			}
		},
	},

	"message?": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Extracts the message string from an error object.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch er := arg0.(type) {
			case env.Error:
				return *env.NewString(er.Message)
			case *env.Error:
				return *env.NewString(er.Message)
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ErrorType}, "message?")
			}
		},
	},

	"details?": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Extracts additional details from an error object as a dictionary.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			var originalMap map[string]env.Object
			switch er := arg0.(type) {
			case env.Error:
				originalMap = er.Values
			case *env.Error:
				originalMap = er.Values
			default:
				ps.FailureFlag = true
				return evaldo.MakeArgError(ps, 1, []env.Type{env.ErrorType}, "details?")
			}

			convertedMap := make(map[string]any)
			for key, value := range originalMap {
				convertedMap[key] = value
			}
			return env.NewDict(convertedMap)
		},
	},

	"has-failed": {
		AcceptFailure: true,
		Argsn:         1,
		Doc:           "Tests if a value is an error object, returning true for errors and false for non-errors.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			ps.FailureFlag = false
			switch arg0.(type) {
			case env.Error, *env.Error:
				return *env.NewBoolean(true)
			}
			return *env.NewBoolean(false)
		},
	},

	"is-failure": {
		Argsn: 1,
		Doc:   "Checks if a value is a failure/error type. Unlike has-failed, this doesn't accept failures - the value must already be disarmed.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch arg0.(type) {
			case env.Error, *env.Error:
				return *env.NewBoolean(true)
			}
			return *env.NewBoolean(false)
		},
	},

	"is-success": {
		Argsn: 1,
		Doc:   "Returns true for any value that is not a failure/error type. The opposite of is-failure.",
		Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
			switch arg0.(type) {
			case env.Error, *env.Error:
				return *env.NewBoolean(false)
			}
			return *env.NewBoolean(true)
		},
	},
}

Error Inspection Functions

View Source
var OutBuffer = "" // how does this work with multiple threads / ... in server use ... probably we would need some per environment variable, not global / global?

Functions

func AddIndexes

func AddIndexes(ps *env.ProgramState, s *env.Table, columns []env.Word) env.Object

func ArrayFloat32FromSeries

func ArrayFloat32FromSeries(block env.TSeries) []float32

func AutoType

func AutoType(ps *env.ProgramState, s *env.Table, percent float64) env.Object

func BlockToJSON

func BlockToJSON(block env.Block) string

BlockToJSON converts a Block to JSON array format.

func BlockToJSONWithIdxs

func BlockToJSONWithIdxs(block env.Block, idxs *env.Idxs) string

BlockToJSONWithIdxs converts a Block to JSON array format with Idxs for context support.

func BsonToValue_Map

func BsonToValue_Map(ps *env.ProgramState, val any, typ string, meta any, topLevel bool) env.Object

func BsonToValue_Val

func BsonToValue_Val(ps *env.ProgramState, val any, topLevel bool) env.Object

func BuiConvert

func BuiConvert(ps *env.ProgramState, arg0 env.Object, arg1 env.Object) env.Object

func BuiParseArgs

func BuiParseArgs(es *env.ProgramState, args env.Object, specBlock env.Object) env.Object

BuiParseArgs is the main builtin function for parse-args

func BuiValidate

func BuiValidate(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object) env.Object

func ColNames

func ColNames(ps *env.ProgramState, from env.Object, fnName string) ([]string, env.Object)

func ContextToJSON

func ContextToJSON(ctx *env.RyeCtx, idxs *env.Idxs) string

ContextToJSON converts a RyeCtx to JSON object format.

func Conversion_EvalBlockCtx

func Conversion_EvalBlockCtx(ps *env.ProgramState, vals *env.RyeCtx) env.Object

func Conversion_EvalBlockDict

func Conversion_EvalBlockDict(ps *env.ProgramState, vals env.Dict) env.Object

func CopyMap

func CopyMap(m map[string]any) map[string]any

func CountWhereBlock

func CountWhereBlock(ps *env.ProgramState, s *env.Table, name string, block env.Block) env.Object

func CountWhereBlockMultiCol

func CountWhereBlockMultiCol(ps *env.ProgramState, s *env.Table, cols env.Block, code env.Block) env.Object

func CountWhereBuiltin

func CountWhereBuiltin(ps *env.ProgramState, s *env.Table, name string, builtin env.Builtin) env.Object

func CountWhereFunction

func CountWhereFunction(ps *env.ProgramState, s *env.Table, name string, fn env.Function) env.Object

func DialectMath

func DialectMath(env1 *env.ProgramState, arg0 env.Object) env.Object

func DictToJSON

func DictToJSON(dict env.Dict) string

DictToJSON converts a Dict to JSON object format.

func DictToJSONWithIdxs

func DictToJSONWithIdxs(dict env.Dict, idxs *env.Idxs) string

DictToJSONWithIdxs converts a Dict to JSON object format with Idxs for context support.

func Distinct

func Distinct(ps *env.ProgramState, s *env.Table, colNames []string) env.Object

func DropColumn

func DropColumn(ps *env.ProgramState, s env.Table, name env.String) env.Object

func DropColumnBlock

func DropColumnBlock(ps *env.ProgramState, s env.Table, names env.Block) env.Object

func DropColumns

func DropColumns(ps *env.ProgramState, s env.Table, names []env.String) env.Object

Drop one or more columns from a table, returning a new table

func EmptyRM

func EmptyRM() env.Dict

EmptyRM creates an empty Dict

func EscapeJson

func EscapeJson(val string) string

func EvalBlockInPersistentCtx

func EvalBlockInPersistentCtx(ps *env.ProgramState, pctx *PersistentCtx)

EvalBlockInPersistentCtx evaluates a block within a PersistentCtx, ensuring persistence

func Eyr_CallBuiltin

func Eyr_CallBuiltin(bi env.Builtin, ps *env.ProgramState, arg0_ env.Object, toLeft bool) *env.ProgramState

func Eyr_CallBuiltinPipe

func Eyr_CallBuiltinPipe(bi env.Builtin, ps *env.ProgramState, arg0_ env.Object) *env.ProgramState

func Eyr_CallFunction

func Eyr_CallFunction(fn env.Function, es *env.ProgramState, leftVal env.Object, toLeft bool, session *env.RyeCtx) *env.ProgramState

This is separate from CallFuncitonArgsN so it can manage pulling args directly off of the eyr stack

func Eyr_EvalBlock

func Eyr_EvalBlock(ps *env.ProgramState, full bool) *env.ProgramState

func Eyr_EvalBlockInside

func Eyr_EvalBlockInside(ps *env.ProgramState, inj env.Object, injnow bool) *env.ProgramState

func Eyr_EvalExpression

func Eyr_EvalExpression(ps *env.ProgramState) *env.ProgramState

func Eyr_EvalLSetword

func Eyr_EvalLSetword(ps *env.ProgramState, word env.LSetword, leftVal env.Object, toLeft bool) *env.ProgramState

func Eyr_EvalObject

func Eyr_EvalObject(es *env.ProgramState, object env.Object, leftVal env.Object, pipeWord bool, session *env.RyeCtx, bakein bool) *env.ProgramState

func Eyr_EvalWord

func Eyr_EvalWord(ps *env.ProgramState, word env.Object, leftVal env.Object, pipeWord bool) *env.ProgramState

func FileExists

func FileExists(filePath string) int

func FillVoid

func FillVoid(ps *env.ProgramState, s *env.Table, colName string, fillValue env.Object) env.Object

func GenerateColumn

func GenerateColumn(ps *env.ProgramState, s env.Table, name env.Word, extractCols env.Block, code env.Block) env.Object

func GenerateColumnRegexReplace

func GenerateColumnRegexReplace(ps *env.ProgramState, s *env.Table, name env.Word, fromColName env.Word, re *regexp.Regexp, pattern string) env.Object

func GetNumRowsFrom

func GetNumRowsFrom(ps *env.ProgramState, data any) (int, *env.Error)

func GroupBy

func GroupBy(ps *env.ProgramState, s env.Table, cols []string, aggregations map[string][]string) env.Object

func LeftJoin

func LeftJoin(ps *env.ProgramState, s1 env.Table, s2 env.Table, col1 string, col2 string, innerJoin bool) env.Object

func ListToJSON

func ListToJSON(list env.List) string

ListToJSON converts a List to JSON array format.

func ListToJSONWithIdxs

func ListToJSONWithIdxs(list env.List, idxs *env.Idxs) string

ListToJSONWithIdxs converts a List to JSON array format with Idxs for context support.

func LoadColumnData

func LoadColumnData(ps *env.ProgramState, data any, colIdx int, numRows int, colData []env.TableRow, cols []string) *env.Error

func MakeColError

func MakeColError(ps *env.ProgramState, builtinName string, colName string, expectedRowCount int, actualRowCount int) *env.Error

func Math_EvalBlock

func Math_EvalBlock(es *env.ProgramState) []env.Object

func PopOutBuffer

func PopOutBuffer() string

func RegisterBatteries

func RegisterBatteries(ps *env.ProgramState)

RegisterBatteries registers all battery (non-base) builtins into the program state. Call this after evaldo.RegisterBuiltins to get the full standard set of Rye builtins.

func RenameColumn

func RenameColumn(ps *env.ProgramState, s *env.Table, oldName env.String, newName env.String) env.Object

Drop one or more columns from a table, returning a new table

func RyeToJSON

func RyeToJSON(res any) string

func RyeToJSONLines

func RyeToJSONLines(res any) string

func RyeToJSONWithIdxs

func RyeToJSONWithIdxs(res any, idxs *env.Idxs) string

func RyeValueToTableRow

func RyeValueToTableRow(spr *env.Table, obj env.Object) (bool, string, *env.TableRow)

func SQL_EvalBlock

func SQL_EvalBlock(es *env.ProgramState, mode int, values []any) (*env.ProgramState, []any)

SQL_EvalBlock evaluates a block of SQL expressions and builds a SQL string

func SQL_EvalExpression

func SQL_EvalExpression(es *env.ProgramState, vals []any, mode int) (*env.ProgramState, string, []any)

SQL_EvalExpression evaluates a single SQL expression and converts Rye objects to SQL syntax mode 1: SQLite (uses ? placeholders), mode 2: PostgreSQL (uses $1, $2, etc. placeholders)

func SheetFromColumns

func SheetFromColumns(ps *env.ProgramState, arg0 env.Object, arg1 env.Object) (res env.Object)

func SheetFromColumnsMapData

func SheetFromColumnsMapData(ps *env.ProgramState, cols []string, arg1 env.Object) env.Object

func SortByColumn

func SortByColumn(ps *env.ProgramState, s *env.Table, name string)

func SortByColumnDesc

func SortByColumnDesc(ps *env.ProgramState, s *env.Table, name string)

func Stck_CallBuiltin

func Stck_CallBuiltin(bi env.Builtin, ps *env.ProgramState, arg0_ env.Object, toLeft bool) *env.ProgramState

func Stck_EvalBlock

func Stck_EvalBlock(ps *env.ProgramState) *env.ProgramState

func Stck_EvalExpression

func Stck_EvalExpression(ps *env.ProgramState) *env.ProgramState

func Stck_EvalObject

func Stck_EvalObject(ps *env.ProgramState, object env.Object, leftVal env.Object, toLeft bool, ctx *env.RyeCtx) *env.ProgramState

func Stck_EvalWord

func Stck_EvalWord(ps *env.ProgramState, word env.Object, leftVal env.Object, toLeft bool) *env.ProgramState

func TableRowToJSON

func TableRowToJSON(row env.TableRow) string

TableRowToJSON converts a TableRow to JSON object format.

func TableRowToJSONWithIdxs

func TableRowToJSONWithIdxs(row env.TableRow, idxs *env.Idxs) string

TableRowToJSONWithIdxs converts a TableRow to JSON object format with Idxs for context support.

func TableRowsFromBlockOrList

func TableRowsFromBlockOrList(ps *env.ProgramState, spr *env.Table, numCols int, arg1 any) (*env.TableRow, *env.Error)

func TableToJSON

func TableToJSON(s env.Table) string

TableToJSON converts a Table to JSON array format.

func TableToJSONLines

func TableToJSONLines(s env.Table) string

func TableToJSONWithIdxs

func TableToJSONWithIdxs(s env.Table, idxs *env.Idxs) string

TableToJSONWithIdxs converts a Table to JSON array format with Idxs for context support.

func TelegramUpdateToRyeDict

func TelegramUpdateToRyeDict(update_ tgm.Update) env.Dict

func TruncateToWidth

func TruncateToWidth(s string, width int, ellipsis string) string

TruncateToWidth truncates a string to fit within the given width, preserving ANSI escape codes and optionally adding an ellipsis

func Validation_EvalBlock

func Validation_EvalBlock(es *env.ProgramState, vals env.Dict) (env.Dict, map[string]env.Object)

func Validation_EvalBlock_Context

func Validation_EvalBlock_Context(es *env.ProgramState, vals *env.RyeCtx) (*env.RyeCtx, map[string]env.Object)

func Validation_EvalBlock_List

func Validation_EvalBlock_List(es *env.ProgramState, vals env.List) (env.Object, []env.Object)

func Validation_EvalBlock_Value

func Validation_EvalBlock_Value(es *env.ProgramState, val env.Object) (env.Object, env.Object)

func ValueToBSON

func ValueToBSON(arg0 env.Object, topLevel bool) any

func VectorToJSON

func VectorToJSON(vector env.Vector) string

func VectorToJSONWithIdxs

func VectorToJSONWithIdxs(vector env.Vector, idxs *env.Idxs) string

func VisibleWidth

func VisibleWidth(s string) int

VisibleWidth returns the display width of a string, ignoring ANSI escape codes

func WhereBetween

func WhereBetween(ps *env.ProgramState, s *env.Table, name string, val1 env.Object, val2 env.Object, inclusiveMode bool) env.Object

func WhereBlock

func WhereBlock(ps *env.ProgramState, s *env.Table, name string, block env.Block) env.Object

func WhereBlockMultiCol

func WhereBlockMultiCol(ps *env.ProgramState, s *env.Table, cols env.Block, code env.Block) env.Object

func WhereBuiltin

func WhereBuiltin(ps *env.ProgramState, s *env.Table, name string, builtin env.Builtin) env.Object

func WhereContains

func WhereContains(ps *env.ProgramState, s *env.Table, name string, val string, not bool) env.Object

func WhereEquals

func WhereEquals(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object

func WhereFunction

func WhereFunction(ps *env.ProgramState, s *env.Table, name string, fn env.Function) env.Object

func WhereGreater

func WhereGreater(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object

func WhereIn

func WhereIn(ps *env.ProgramState, s *env.Table, name string, b []env.Object) env.Object

func WhereLesser

func WhereLesser(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object

func WhereMatch

func WhereMatch(ps *env.ProgramState, s *env.Table, name string, r *regexp.Regexp) env.Object

func WhereNotEquals

func WhereNotEquals(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object

func WhereNotIn

func WhereNotIn(ps *env.ProgramState, s *env.Table, name string, b []env.Object) env.Object

func WrapText

func WrapText(s string, width int) []string

WrapText wraps text to the given width, preserving ANSI codes across lines

Types

type ArgSpec

type ArgSpec struct {
	Name         string     // Name for the result (from flagword long name or setword)
	ShortFlag    string     // Short flag name (e.g., "v")
	LongFlag     string     // Long flag name (e.g., "verbose")
	IsFlag       bool       // True if it's a boolean flag (no value)
	IsPositional bool       // True if it's a positional argument
	IsRequired   bool       // True if required
	IsList       bool       // True if can be repeated (collects into list)
	IsMany       bool       // True if positional accepts many values
	ValueType    string     // "string", "integer", "decimal", "boolean", "file", "any"
	Default      env.Object // Default value
	CheckBlock   *env.Block // Optional validation block
	CheckError   string     // Error message if check fails
	Doc          string     // Documentation string
}

ArgSpec holds the specification for a single argument

type CLISpec

type CLISpec struct {
	GlobalArgs  []ArgSpec
	Subcommands map[string]*SubcommandSpec
	ProgramName string // Optional program name for help
	ProgramDoc  string // Optional program description for help
}

CLISpec holds the complete CLI specification

func CLI_ParseSpec

func CLI_ParseSpec(es *env.ProgramState, specBlock env.Block) (*CLISpec, error)

CLI_ParseSpec parses the specification block into a CLISpec

type ConversionError

type ConversionError struct {
	// contains filtered or unexported fields
}

Integer represents an integer.

type HtmlDialectNode

type HtmlDialectNode struct {
	Condition *HtmlNavigCondition
	Code      *env.Block
	SubNode   *env.Dict
	Type      int // 1 - node , 2 - code , 3 - direct_descendant (later)
}

type HtmlNavigCondition

type HtmlNavigCondition struct {
	Class string
	Id    string
}

type MarkdownDisplayItem

type MarkdownDisplayItem struct {
	Type         string   // "heading", "paragraph", "code", "list", "quote", "hr", "link"
	Content      string   // Raw content
	DisplayLines []string // Formatted lines for display
	Level        int      // For headings (1-6), or 0 for others
	Language     string   // For code blocks
}

MarkdownDisplayItem represents a selectable markdown element with its type and content

type MessageDispatcher

type MessageDispatcher struct {
	// contains filtered or unexported fields
}

MessageDispatcher provides a high-performance message routing system

func NewMessageDispatcher

func NewMessageDispatcher(bufferSize int, initialState env.Dict) *MessageDispatcher

NewMessageDispatcher creates a new message dispatcher

func (*MessageDispatcher) GetState

func (md *MessageDispatcher) GetState() env.Dict

GetState returns a copy of the current state

func (*MessageDispatcher) RegisterHandler

func (md *MessageDispatcher) RegisterHandler(msgType string, handler env.Function)

RegisterHandler registers a message handler function

func (*MessageDispatcher) Send

func (md *MessageDispatcher) Send(msg env.Object) error

Send sends a message to the dispatcher

func (*MessageDispatcher) SetState

func (md *MessageDispatcher) SetState(state env.Dict)

SetState updates the state

func (*MessageDispatcher) Start

func (md *MessageDispatcher) Start(ps *env.ProgramState, updateCallback env.Function)

Start begins processing messages in a goroutine

func (*MessageDispatcher) Stop

func (md *MessageDispatcher) Stop()

Stop stops the message processing loop

func (*MessageDispatcher) UnregisterHandler

func (md *MessageDispatcher) UnregisterHandler(msgType string)

UnregisterHandler removes a message handler

type ParsedArgs

type ParsedArgs struct {
	Values      map[string]env.Object
	Command     string   // Full command path: "remote add"
	CommandPath []string // ["remote", "add"]
	Positional  []env.Object
}

ParsedArgs holds the result of parsing

func CLI_ParseArgs

func CLI_ParseArgs(es *env.ProgramState, args env.Block, spec *CLISpec) (*ParsedArgs, map[string]env.Object)

CLI_ParseArgs parses command line arguments (as Rye values) according to the spec

type PersistentCtx

type PersistentCtx struct {
	env.RyeCtx // Minimal in-memory context for interface compatibility only

	Idxs *env.Idxs
	// contains filtered or unexported fields
}

PersistentCtx wraps a RyeCtx with a BadgerDB backend for persistence. It operates in database-first mode for ACID compliance.

func NewPersistentCtx

func NewPersistentCtx(dbPath string, ps *env.ProgramState) (*PersistentCtx, error)

NewPersistentCtx creates a new persistent context or loads an existing one.

func (*PersistentCtx) AsRyeCtx

func (pc *PersistentCtx) AsRyeCtx() *env.RyeCtx

AsRyeCtx returns the underlying RyeCtx for backward compatibility

func (*PersistentCtx) Copy

func (pc *PersistentCtx) Copy() env.Context

Copy creates a copy of the persistent context (note: copy won't be persistent)

func (*PersistentCtx) Get

func (pc *PersistentCtx) Get(word int) (env.Object, bool)

Get overrides the embedded Get method to read from database.

func (*PersistentCtx) GetDoc

func (pc *PersistentCtx) GetDoc() string

GetDoc returns the documentation string

func (*PersistentCtx) GetKindWord

func (pc *PersistentCtx) GetKindWord() env.Word

GetKindWord returns the Kind as a Word

func (*PersistentCtx) GetParent

func (pc *PersistentCtx) GetParent() env.Context

GetParent returns the parent context

func (*PersistentCtx) IsVariable

func (pc *PersistentCtx) IsVariable(word int) bool

IsVariable checks if a word is a variable by reading from database

func (*PersistentCtx) MarkAsVariable

func (pc *PersistentCtx) MarkAsVariable(word int)

MarkAsVariable marks a word as a variable in the database

func (*PersistentCtx) Mod

func (pc *PersistentCtx) Mod(word int, val env.Object) bool

Mod overrides the embedded Mod method to add ACID persistence.

func (*PersistentCtx) Set

func (pc *PersistentCtx) Set(word int, val env.Object) env.Object

Set overrides the embedded Set method to add ACID persistence.

func (*PersistentCtx) SetDoc

func (pc *PersistentCtx) SetDoc(doc string)

SetDoc sets the documentation string

func (*PersistentCtx) SetKindWord

func (pc *PersistentCtx) SetKindWord(kind env.Word)

SetKindWord sets the Kind

func (*PersistentCtx) SetNew

func (pc *PersistentCtx) SetNew(word int, val env.Object, idxs *env.Idxs) bool

SetNew overrides the embedded SetNew method to add ACID persistence.

func (*PersistentCtx) SetParent

func (pc *PersistentCtx) SetParent(parent env.Context)

SetParent sets the parent context

func (PersistentCtx) Type

func (pc PersistentCtx) Type() env.Type

func (*PersistentCtx) Unset

func (pc *PersistentCtx) Unset(word int, idxs *env.Idxs) env.Object

Unset overrides the embedded Unset method to add ACID persistence.

type PersistentCtxEvaluator

type PersistentCtxEvaluator struct {
	// contains filtered or unexported fields
}

PersistentCtxEvaluator intercepts evaluation to ensure persistence operations go through PersistentCtx

func (*PersistentCtxEvaluator) Eval

func (pce *PersistentCtxEvaluator) Eval()

evaldo.EvalBlock evaluates the current series while intercepting persistence operations

type PersistentRyeCtx

type PersistentRyeCtx struct {
	env.RyeCtx
	// contains filtered or unexported fields
}

PersistentRyeCtx is a RyeCtx with persistence methods injected

func CreatePersistentRyeCtx

func CreatePersistentRyeCtx(pctx *PersistentCtx) *PersistentRyeCtx

CreatePersistentRyeCtx creates a RyeCtx that has persistent behavior by injecting persistence functions

func (*PersistentRyeCtx) Mod

func (w *PersistentRyeCtx) Mod(word int, val env.Object) bool

Override Mod to use PersistentCtx persistence

func (*PersistentRyeCtx) Set

func (w *PersistentRyeCtx) Set(word int, val env.Object) env.Object

Override Set to use PersistentCtx persistence

func (*PersistentRyeCtx) SetNew

func (w *PersistentRyeCtx) SetNew(word int, val env.Object, idxs *env.Idxs) bool

Override SetNew to use PersistentCtx persistence

func (*PersistentRyeCtx) Unset

func (w *PersistentRyeCtx) Unset(word int, idxs *env.Idxs) env.Object

Override Unset to use PersistentCtx persistence

type RyeMutex

type RyeMutex struct {
	// contains filtered or unexported fields
}

RyeMutex wraps sync.Mutex with state tracking to prevent fatal errors on unlocking unlocked mutex

func (*RyeMutex) Lock

func (m *RyeMutex) Lock()

func (*RyeMutex) Unlock

func (m *RyeMutex) Unlock() error

type SubcommandSpec

type SubcommandSpec struct {
	Name        string
	Args        []ArgSpec
	Subcommands map[string]*SubcommandSpec // Nested subcommands
	Doc         string                     // Documentation for subcommand
}

SubcommandSpec holds the specification for a subcommand

type TuiApp

type TuiApp struct {
	// contains filtered or unexported fields
}

TuiApp represents an inline terminal app

func NewTuiApp

func NewTuiApp(theme env.Dict) *TuiApp

NewTuiApp creates a new TUI app

func (*TuiApp) GetState

func (app *TuiApp) GetState() env.Dict

GetState returns the state

func (*TuiApp) IsRunning

func (app *TuiApp) IsRunning() bool

IsRunning returns whether the app is running

func (*TuiApp) OnKey

func (app *TuiApp) OnKey(key string, handler env.Object)

OnKey registers a key handler for a specific key

func (*TuiApp) OnKeys

func (app *TuiApp) OnKeys(handler env.Object)

OnKeys registers a handler for all keys

func (*TuiApp) Render

func (app *TuiApp) Render()

Render renders the current view

func (*TuiApp) SetState

func (app *TuiApp) SetState(state env.Dict)

SetState sets the state

func (*TuiApp) SetView

func (app *TuiApp) SetView(view env.Object)

SetView sets the view (block or function)

func (*TuiApp) Start

func (app *TuiApp) Start(ps *env.ProgramState) error

Start starts the app

func (*TuiApp) Stop

func (app *TuiApp) Stop()

Stop stops the app

func (*TuiApp) Update

func (app *TuiApp) Update(updates env.Dict)

Update merges updates into state and re-renders

func (*TuiApp) Wait

func (app *TuiApp) Wait()

Wait blocks until the app stops

type TuiInput

type TuiInput struct {
	// contains filtered or unexported fields
}

TuiInput represents a text input field with cursor and selection

func NewTuiInput

func NewTuiInput(placeholder string) *TuiInput

NewTuiInput creates a new input widget

func (*TuiInput) Dump

func (inp *TuiInput) Dump(e env.Idxs) string

Dump returns a printable representation

func (*TuiInput) Equal

func (inp *TuiInput) Equal(other env.Object) bool

Equal checks equality

func (*TuiInput) GetKind

func (inp *TuiInput) GetKind() int

GetKind returns the kind string

func (*TuiInput) GetValue

func (inp *TuiInput) GetValue() string

GetValue returns the current value

func (*TuiInput) HandleKey

func (inp *TuiInput) HandleKey(key string, ps *env.ProgramState) bool

HandleKey processes a key event, returns true if handled

func (*TuiInput) Inspect

func (inp *TuiInput) Inspect(idxs env.Idxs) string

Inspect returns a string representation

func (*TuiInput) Print

func (inp *TuiInput) Print(e env.Idxs) string

Print returns printable string

func (*TuiInput) Render

func (inp *TuiInput) Render() env.Block

Render returns the widget block for this input

func (*TuiInput) SetValue

func (inp *TuiInput) SetValue(val string)

SetValue sets the input value

func (*TuiInput) Trace

func (inp *TuiInput) Trace(msg string)

Trace returns a trace representation

func (*TuiInput) Type

func (inp *TuiInput) Type() env.Type

Type returns the type name for env.Native interface

type ValidationError

type ValidationError struct {
	// contains filtered or unexported fields
}

Integer represents an integer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL