Documentation
¶
Overview ¶
builtins_error_handling.go
builtins.go
builtins.go
builtins_trees.go
Index ¶
- Constants
- Variables
- func AddIndexes(ps *env.ProgramState, s *env.Table, columns []env.Word) env.Object
- func ArrayFloat32FromSeries(block env.TSeries) []float32
- func AutoType(ps *env.ProgramState, s *env.Table, percent float64) env.Object
- func BlockToJSON(block env.Block) string
- func BlockToJSONWithIdxs(block env.Block, idxs *env.Idxs) string
- func BsonToValue_Map(ps *env.ProgramState, val any, typ string, meta any, topLevel bool) env.Object
- func BsonToValue_Val(ps *env.ProgramState, val any, topLevel bool) env.Object
- func BuiConvert(ps *env.ProgramState, arg0 env.Object, arg1 env.Object) env.Object
- func BuiParseArgs(es *env.ProgramState, args env.Object, specBlock env.Object) env.Object
- func BuiValidate(env1 *env.ProgramState, arg0 env.Object, arg1 env.Object) env.Object
- func ColNames(ps *env.ProgramState, from env.Object, fnName string) ([]string, env.Object)
- func ContextToJSON(ctx *env.RyeCtx, idxs *env.Idxs) string
- func Conversion_EvalBlockCtx(ps *env.ProgramState, vals *env.RyeCtx) env.Object
- func Conversion_EvalBlockDict(ps *env.ProgramState, vals env.Dict) env.Object
- func CopyMap(m map[string]any) map[string]any
- func CountWhereBlock(ps *env.ProgramState, s *env.Table, name string, block env.Block) env.Object
- func CountWhereBlockMultiCol(ps *env.ProgramState, s *env.Table, cols env.Block, code env.Block) env.Object
- func CountWhereBuiltin(ps *env.ProgramState, s *env.Table, name string, builtin env.Builtin) env.Object
- func CountWhereFunction(ps *env.ProgramState, s *env.Table, name string, fn env.Function) env.Object
- func DialectMath(env1 *env.ProgramState, arg0 env.Object) env.Object
- func DictToJSON(dict env.Dict) string
- func DictToJSONWithIdxs(dict env.Dict, idxs *env.Idxs) string
- func Distinct(ps *env.ProgramState, s *env.Table, colNames []string) env.Object
- func DropColumn(ps *env.ProgramState, s env.Table, name env.String) env.Object
- func DropColumnBlock(ps *env.ProgramState, s env.Table, names env.Block) env.Object
- func DropColumns(ps *env.ProgramState, s env.Table, names []env.String) env.Object
- func EmptyRM() env.Dict
- func EscapeJson(val string) string
- func EvalBlockInPersistentCtx(ps *env.ProgramState, pctx *PersistentCtx)
- func Eyr_CallBuiltin(bi env.Builtin, ps *env.ProgramState, arg0_ env.Object, toLeft bool) *env.ProgramState
- func Eyr_CallBuiltinPipe(bi env.Builtin, ps *env.ProgramState, arg0_ env.Object) *env.ProgramState
- func Eyr_CallFunction(fn env.Function, es *env.ProgramState, leftVal env.Object, toLeft bool, ...) *env.ProgramState
- func Eyr_EvalBlock(ps *env.ProgramState, full bool) *env.ProgramState
- func Eyr_EvalBlockInside(ps *env.ProgramState, inj env.Object, injnow bool) *env.ProgramState
- func Eyr_EvalExpression(ps *env.ProgramState) *env.ProgramState
- func Eyr_EvalLSetword(ps *env.ProgramState, word env.LSetword, leftVal env.Object, toLeft bool) *env.ProgramState
- func Eyr_EvalObject(es *env.ProgramState, object env.Object, leftVal env.Object, pipeWord bool, ...) *env.ProgramState
- func Eyr_EvalWord(ps *env.ProgramState, word env.Object, leftVal env.Object, pipeWord bool) *env.ProgramState
- func FileExists(filePath string) int
- func FillVoid(ps *env.ProgramState, s *env.Table, colName string, fillValue env.Object) env.Object
- func GenerateColumn(ps *env.ProgramState, s env.Table, name env.Word, extractCols env.Block, ...) env.Object
- func GenerateColumnRegexReplace(ps *env.ProgramState, s *env.Table, name env.Word, fromColName env.Word, ...) env.Object
- func GetNumRowsFrom(ps *env.ProgramState, data any) (int, *env.Error)
- func GroupBy(ps *env.ProgramState, s env.Table, cols []string, ...) env.Object
- func LeftJoin(ps *env.ProgramState, s1 env.Table, s2 env.Table, col1 string, col2 string, ...) env.Object
- func ListToJSON(list env.List) string
- func ListToJSONWithIdxs(list env.List, idxs *env.Idxs) string
- func LoadColumnData(ps *env.ProgramState, data any, colIdx int, numRows int, ...) *env.Error
- func MakeColError(ps *env.ProgramState, builtinName string, colName string, expectedRowCount int, ...) *env.Error
- func Math_EvalBlock(es *env.ProgramState) []env.Object
- func PopOutBuffer() string
- func RegisterBatteries(ps *env.ProgramState)
- func RenameColumn(ps *env.ProgramState, s *env.Table, oldName env.String, newName env.String) env.Object
- func RyeToJSON(res any) string
- func RyeToJSONLines(res any) string
- func RyeToJSONWithIdxs(res any, idxs *env.Idxs) string
- func RyeValueToTableRow(spr *env.Table, obj env.Object) (bool, string, *env.TableRow)
- func SQL_EvalBlock(es *env.ProgramState, mode int, values []any) (*env.ProgramState, []any)
- func SQL_EvalExpression(es *env.ProgramState, vals []any, mode int) (*env.ProgramState, string, []any)
- func SheetFromColumns(ps *env.ProgramState, arg0 env.Object, arg1 env.Object) (res env.Object)
- func SheetFromColumnsMapData(ps *env.ProgramState, cols []string, arg1 env.Object) env.Object
- func SortByColumn(ps *env.ProgramState, s *env.Table, name string)
- func SortByColumnDesc(ps *env.ProgramState, s *env.Table, name string)
- func Stck_CallBuiltin(bi env.Builtin, ps *env.ProgramState, arg0_ env.Object, toLeft bool) *env.ProgramState
- func Stck_EvalBlock(ps *env.ProgramState) *env.ProgramState
- func Stck_EvalExpression(ps *env.ProgramState) *env.ProgramState
- func Stck_EvalObject(ps *env.ProgramState, object env.Object, leftVal env.Object, toLeft bool, ...) *env.ProgramState
- func Stck_EvalWord(ps *env.ProgramState, word env.Object, leftVal env.Object, toLeft bool) *env.ProgramState
- func TableRowToJSON(row env.TableRow) string
- func TableRowToJSONWithIdxs(row env.TableRow, idxs *env.Idxs) string
- func TableRowsFromBlockOrList(ps *env.ProgramState, spr *env.Table, numCols int, arg1 any) (*env.TableRow, *env.Error)
- func TableToJSON(s env.Table) string
- func TableToJSONLines(s env.Table) string
- func TableToJSONWithIdxs(s env.Table, idxs *env.Idxs) string
- func TelegramUpdateToRyeDict(update_ tgm.Update) env.Dict
- func TruncateToWidth(s string, width int, ellipsis string) string
- func Validation_EvalBlock(es *env.ProgramState, vals env.Dict) (env.Dict, map[string]env.Object)
- func Validation_EvalBlock_Context(es *env.ProgramState, vals *env.RyeCtx) (*env.RyeCtx, map[string]env.Object)
- func Validation_EvalBlock_List(es *env.ProgramState, vals env.List) (env.Object, []env.Object)
- func Validation_EvalBlock_Value(es *env.ProgramState, val env.Object) (env.Object, env.Object)
- func ValueToBSON(arg0 env.Object, topLevel bool) any
- func VectorToJSON(vector env.Vector) string
- func VectorToJSONWithIdxs(vector env.Vector, idxs *env.Idxs) string
- func VisibleWidth(s string) int
- func WhereBetween(ps *env.ProgramState, s *env.Table, name string, val1 env.Object, ...) env.Object
- func WhereBlock(ps *env.ProgramState, s *env.Table, name string, block env.Block) env.Object
- func WhereBlockMultiCol(ps *env.ProgramState, s *env.Table, cols env.Block, code env.Block) env.Object
- func WhereBuiltin(ps *env.ProgramState, s *env.Table, name string, builtin env.Builtin) env.Object
- func WhereContains(ps *env.ProgramState, s *env.Table, name string, val string, not bool) env.Object
- func WhereEquals(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object
- func WhereFunction(ps *env.ProgramState, s *env.Table, name string, fn env.Function) env.Object
- func WhereGreater(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object
- func WhereIn(ps *env.ProgramState, s *env.Table, name string, b []env.Object) env.Object
- func WhereLesser(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object
- func WhereMatch(ps *env.ProgramState, s *env.Table, name string, r *regexp.Regexp) env.Object
- func WhereNotEquals(ps *env.ProgramState, s *env.Table, name string, val env.Object) env.Object
- func WhereNotIn(ps *env.ProgramState, s *env.Table, name string, b []env.Object) env.Object
- func WrapText(s string, width int) []string
- type ArgSpec
- type CLISpec
- type ConversionError
- type HtmlDialectNode
- type HtmlNavigCondition
- type MarkdownDisplayItem
- type MessageDispatcher
- func (md *MessageDispatcher) GetState() env.Dict
- func (md *MessageDispatcher) RegisterHandler(msgType string, handler env.Function)
- func (md *MessageDispatcher) Send(msg env.Object) error
- func (md *MessageDispatcher) SetState(state env.Dict)
- func (md *MessageDispatcher) Start(ps *env.ProgramState, updateCallback env.Function)
- func (md *MessageDispatcher) Stop()
- func (md *MessageDispatcher) UnregisterHandler(msgType string)
- type ParsedArgs
- type PersistentCtx
- func (pc *PersistentCtx) AsRyeCtx() *env.RyeCtx
- func (pc *PersistentCtx) Copy() env.Context
- func (pc *PersistentCtx) Get(word int) (env.Object, bool)
- func (pc *PersistentCtx) GetDoc() string
- func (pc *PersistentCtx) GetKindWord() env.Word
- func (pc *PersistentCtx) GetParent() env.Context
- func (pc *PersistentCtx) IsVariable(word int) bool
- func (pc *PersistentCtx) MarkAsVariable(word int)
- func (pc *PersistentCtx) Mod(word int, val env.Object) bool
- func (pc *PersistentCtx) Set(word int, val env.Object) env.Object
- func (pc *PersistentCtx) SetDoc(doc string)
- func (pc *PersistentCtx) SetKindWord(kind env.Word)
- func (pc *PersistentCtx) SetNew(word int, val env.Object, idxs *env.Idxs) bool
- func (pc *PersistentCtx) SetParent(parent env.Context)
- func (pc PersistentCtx) Type() env.Type
- func (pc *PersistentCtx) Unset(word int, idxs *env.Idxs) env.Object
- type PersistentCtxEvaluator
- type PersistentRyeCtx
- type RyeMutex
- type SubcommandSpec
- type TuiApp
- func (app *TuiApp) GetState() env.Dict
- func (app *TuiApp) IsRunning() bool
- func (app *TuiApp) OnKey(key string, handler env.Object)
- func (app *TuiApp) OnKeys(handler env.Object)
- func (app *TuiApp) Render()
- func (app *TuiApp) SetState(state env.Dict)
- func (app *TuiApp) SetView(view env.Object)
- func (app *TuiApp) Start(ps *env.ProgramState) error
- func (app *TuiApp) Stop()
- func (app *TuiApp) Update(updates env.Dict)
- func (app *TuiApp) Wait()
- type TuiInput
- func (inp *TuiInput) Dump(e env.Idxs) string
- func (inp *TuiInput) Equal(other env.Object) bool
- func (inp *TuiInput) GetKind() int
- func (inp *TuiInput) GetValue() string
- func (inp *TuiInput) HandleKey(key string, ps *env.ProgramState) bool
- func (inp *TuiInput) Inspect(idxs env.Idxs) string
- func (inp *TuiInput) Print(e env.Idxs) string
- func (inp *TuiInput) Render() env.Block
- func (inp *TuiInput) SetValue(val string)
- func (inp *TuiInput) Trace(msg string)
- func (inp *TuiInput) Type() env.Type
- type ValidationError
Constants ¶
const MODE_PSQL = 2 // Uses $1, $2, etc. placeholders
const MODE_SQLITE = 1 // Uses ? placeholders
SQL mode constants for different database parameter styles
const TYPE_CODE int = 2
const TYPE_SUBNODE int = 1
Variables ¶
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) }, }, }
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) }, }, }
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
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") } }, }, }
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)) }), }, }
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") } }, }, }
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") } }, }, }
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") } }, }, }
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") } }, }, }
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") } }, }, }
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) }, }, }
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") } }, }, }
var Builtins_error_creation = ErrorCreationBuiltins
Export the error handling builtins for registration
var Builtins_error_handling = ErrorHandlingBuiltins
var Builtins_error_inspection = ErrorInspectionBuiltins
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") } }, }, }
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") } }, }, }
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") } }, }, }
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 }, }, }
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?") } }, }, }
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?") } }, }, }
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") } }, }, }
var Builtins_js_interop = map[string]*env.Builtin{}
JavaScript interop functions for Rye WASM
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)) }, }, }
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") }, }, }
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) }, }, }
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") } }, }, }
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") } }, }, }
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") } }, }, }
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") } }, }, }
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") } }, }, }
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
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") } }, }, }
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") } }, }, }
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") } }, }, }
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
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") } }, }, }
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") } }, }, }
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") } }, }, }
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") } }, }, }
var Builtins_ssh = map[string]*env.Builtin{}
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") } }, }, }
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 }, }, }
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?") } }, }, }
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") } }, }, }
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") } }, }, }
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) }, }, }
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()) }, }, }
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") } }, }, }
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 } }, }, }
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") } }, }, }
var Builtins_web = map[string]*env.Builtin{}
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
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
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
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 ArrayFloat32FromSeries ¶
func BlockToJSON ¶
BlockToJSON converts a Block to JSON array format.
func BlockToJSONWithIdxs ¶
BlockToJSONWithIdxs converts a Block to JSON array format with Idxs for context support.
func BsonToValue_Map ¶
func BsonToValue_Val ¶
func BuiConvert ¶
func BuiParseArgs ¶
BuiParseArgs is the main builtin function for parse-args
func BuiValidate ¶
func ContextToJSON ¶
ContextToJSON converts a RyeCtx to JSON object format.
func Conversion_EvalBlockCtx ¶
func CountWhereBlock ¶
func CountWhereBlockMultiCol ¶
func CountWhereBuiltin ¶
func CountWhereFunction ¶
func DialectMath ¶
func DictToJSON ¶
DictToJSON converts a Dict to JSON object format.
func DictToJSONWithIdxs ¶
DictToJSONWithIdxs converts a Dict to JSON object format with Idxs for context support.
func DropColumn ¶
func DropColumnBlock ¶
func DropColumns ¶
Drop one or more columns from a table, returning a new table
func EscapeJson ¶
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_EvalWord ¶
func Eyr_EvalWord(ps *env.ProgramState, word env.Object, leftVal env.Object, pipeWord bool) *env.ProgramState
func FileExists ¶
func GenerateColumn ¶
func GetNumRowsFrom ¶
func ListToJSON ¶
ListToJSON converts a List to JSON array format.
func ListToJSONWithIdxs ¶
ListToJSONWithIdxs converts a List to JSON array format with Idxs for context support.
func LoadColumnData ¶
func MakeColError ¶
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 RyeToJSONLines ¶
func RyeValueToTableRow ¶
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 SheetFromColumnsMapData ¶
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_EvalWord ¶
func Stck_EvalWord(ps *env.ProgramState, word env.Object, leftVal env.Object, toLeft bool) *env.ProgramState
func TableRowToJSON ¶
TableRowToJSON converts a TableRow to JSON object format.
func TableRowToJSONWithIdxs ¶
TableRowToJSONWithIdxs converts a TableRow to JSON object format with Idxs for context support.
func TableToJSON ¶
TableToJSON converts a Table to JSON array format.
func TableToJSONLines ¶
func TableToJSONWithIdxs ¶
TableToJSONWithIdxs converts a Table to JSON array format with Idxs for context support.
func TruncateToWidth ¶
TruncateToWidth truncates a string to fit within the given width, preserving ANSI escape codes and optionally adding an ellipsis
func Validation_EvalBlock ¶
func VectorToJSON ¶
func VisibleWidth ¶
VisibleWidth returns the display width of a string, ignoring ANSI escape codes
func WhereBetween ¶
func WhereBlock ¶
func WhereBlockMultiCol ¶
func WhereBuiltin ¶
func WhereContains ¶
func WhereEquals ¶
func WhereFunction ¶
func WhereGreater ¶
func WhereLesser ¶
func WhereMatch ¶
func WhereNotEquals ¶
func WhereNotIn ¶
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 ¶
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 HtmlNavigCondition ¶
type HtmlNavigCondition struct {
}
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) 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) SetParent ¶
func (pc *PersistentCtx) SetParent(parent env.Context)
SetParent sets the parent context
func (PersistentCtx) Type ¶
func (pc PersistentCtx) Type() env.Type
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 ¶
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
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
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
type TuiInput ¶
type TuiInput struct {
// contains filtered or unexported fields
}
TuiInput represents a text input field with cursor and selection
func NewTuiInput ¶
NewTuiInput creates a new input widget
func (*TuiInput) HandleKey ¶
func (inp *TuiInput) HandleKey(key string, ps *env.ProgramState) bool
HandleKey processes a key event, returns true if handled
type ValidationError ¶
type ValidationError struct {
// contains filtered or unexported fields
}
Integer represents an integer.
Source Files
¶
- builtins_bcrypt.go
- builtins_bson.go
- builtins_chitosocket.go
- builtins_cli.go
- builtins_cmd.go
- builtins_complex.go
- builtins_console.go
- builtins_conversion.go
- builtins_crypto.go
- builtins_echarts.go
- builtins_email.go
- builtins_encoding.go
- builtins_error_handling.go
- builtins_eyr.go
- builtins_flui.go
- builtins_flui_v2.go
- builtins_goroutines.go
- builtins_html.go
- builtins_http.go
- builtins_io.go
- builtins_js_interop_not.go
- builtins_json.go
- builtins_mail.go
- builtins_markdown.go
- builtins_match.go
- builtins_math.go
- builtins_matrix.go
- builtins_mcp.go
- builtins_mqtt.go
- builtins_msgdispatcher.go
- builtins_mysql.go
- builtins_os.go
- builtins_persistent_contexts.go
- builtins_pipes.go
- builtins_prometheus.go
- builtins_psql.go
- builtins_regexp.go
- builtins_smtpd.go
- builtins_sql.go
- builtins_sqlite.go
- builtins_ssh_not.go
- builtins_stackless.go
- builtins_structures.go
- builtins_sxml.go
- builtins_table.go
- builtins_telegrambot.go
- builtins_term.go
- builtins_termstr.go
- builtins_trees.go
- builtins_tui.go
- builtins_unique.go
- builtins_validation.go
- builtins_vector.go
- builtins_web_not.go
- register.go