modules

package
v0.1.8 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2025 License: GPL-3.0 Imports: 13 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SocketTypeTCP  = "tcp"
	SocketTypeUDP  = "udp"
	SocketTypeWeb  = "web"
	SocketTypeUnix = "unix"
)

Socket types

Variables

View Source
var FileBuiltins = map[string]*object.Builtin{
	"fileOpen": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "fileOpen requires 1-2 arguments: path, [mode]"}
			}

			pathStr, ok := extractStringFile(args[0])
			if !ok {
				return &object.Error{Message: "fileOpen: path must be a string"}
			}

			mode := "r"
			if len(args) == 2 {
				modeStr, ok := extractStringFile(args[1])
				if !ok {
					return &object.Error{Message: "fileOpen: mode must be a string"}
				}
				mode = modeStr
			}

			var file *os.File
			var err error

			switch mode {
			case "r":
				file, err = os.Open(pathStr)
			case "w":
				file, err = os.Create(pathStr)
			case "a":
				file, err = os.OpenFile(pathStr, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
			case "r+":
				file, err = os.OpenFile(pathStr, os.O_RDWR, 0644)
			case "w+":
				file, err = os.OpenFile(pathStr, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
			case "a+":
				file, err = os.OpenFile(pathStr, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
			default:
				return &object.Error{Message: "fileOpen: unsupported mode '" + mode + "'. Use r, w, a, r+, w+, a+"}
			}

			if err != nil {
				return &object.Error{Message: "failed to open file '" + pathStr + "': " + err.Error()}
			}

			handleID := storeFileHandle(file)
			return &object.Integer{Value: handleID}
		},
	},

	"fileReadHandle": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "fileReadHandle requires 1-2 arguments: handleID, [size]"}
			}

			handleID, ok := extractIntFile(args[0])
			if !ok {
				return &object.Error{Message: "fileReadHandle: handleID must be an integer"}
			}

			file, exists := getFileHandle(handleID)
			if !exists {
				return &object.Error{Message: "fileReadHandle: invalid file handle"}
			}

			// Conditional size parameter
			var data []byte
			var err error

			if len(args) == 2 {
				size, ok := extractIntFile(args[1])
				if !ok {
					return &object.Error{Message: "fileReadHandle: size must be an integer"}
				}
				if size <= 0 {

					data, err = io.ReadAll(file)
				} else {

					data = make([]byte, size)
					n, readErr := file.Read(data)
					if readErr != nil && readErr != io.EOF {
						err = readErr
					} else {
						data = data[:n]
					}
				}
			} else {

				data, err = io.ReadAll(file)
			}

			if err != nil {
				return &object.Error{Message: "failed to read from file: " + err.Error()}
			}

			return &object.String{Value: string(data)}
		},
	},

	"fileWriteHandle": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "fileWriteHandle requires 2 arguments: handleID, content"}
			}

			handleID, ok := extractIntFile(args[0])
			if !ok {
				return &object.Error{Message: "fileWriteHandle: handleID must be an integer"}
			}

			contentStr, ok := extractStringFile(args[1])
			if !ok {
				return &object.Error{Message: "fileWriteHandle: content must be a string"}
			}

			file, exists := getFileHandle(handleID)
			if !exists {
				return &object.Error{Message: "fileWriteHandle: invalid file handle"}
			}

			n, err := file.WriteString(contentStr)
			if err != nil {
				return &object.Error{Message: "failed to write to file: " + err.Error()}
			}

			return &object.Integer{Value: int64(n)}
		},
	},

	"fileClose": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fileClose requires 1 argument: handleID"}
			}

			handleID, ok := extractIntFile(args[0])
			if !ok {
				return &object.Error{Message: "fileClose: handleID must be an integer"}
			}

			file, exists := getFileHandle(handleID)
			if !exists {
				return &object.Error{Message: "fileClose: invalid file handle"}
			}

			err := file.Close()
			removeFileHandle(handleID)

			if err != nil {
				return &object.Error{Message: "failed to close file: " + err.Error()}
			}

			return &object.None{}
		},
	},

	"fileSeek": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return &object.Error{Message: "fileSeek requires 2-3 arguments: handleID, offset, [whence]"}
			}

			handleID, ok := extractIntFile(args[0])
			if !ok {
				return &object.Error{Message: "fileSeek: handleID must be an integer"}
			}

			offset, ok := extractIntFile(args[1])
			if !ok {
				return &object.Error{Message: "fileSeek: offset must be an integer"}
			}

			whence := int(io.SeekStart)
			if len(args) == 3 {
				whenceVal, ok := extractIntFile(args[2])
				if !ok {
					return &object.Error{Message: "fileSeek: whence must be an integer"}
				}
				whence = int(whenceVal)
			}

			file, exists := getFileHandle(handleID)
			if !exists {
				return &object.Error{Message: "fileSeek: invalid file handle"}
			}

			newPos, err := file.Seek(offset, whence)
			if err != nil {
				return &object.Error{Message: "failed to seek in file: " + err.Error()}
			}

			return &object.Integer{Value: newPos}
		},
	},

	"fileTell": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fileTell requires 1 argument: handleID"}
			}

			handleID, ok := extractIntFile(args[0])
			if !ok {
				return &object.Error{Message: "fileTell: handleID must be an integer"}
			}

			file, exists := getFileHandle(handleID)
			if !exists {
				return &object.Error{Message: "fileTell: invalid file handle"}
			}

			pos, err := file.Seek(0, io.SeekCurrent)
			if err != nil {
				return &object.Error{Message: "failed to get file position: " + err.Error()}
			}

			return &object.Integer{Value: pos}
		},
	},

	"fileFlush": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fileFlush requires 1 argument: handleID"}
			}

			handleID, ok := extractIntFile(args[0])
			if !ok {
				return &object.Error{Message: "fileFlush: handleID must be an integer"}
			}

			file, exists := getFileHandle(handleID)
			if !exists {
				return &object.Error{Message: "fileFlush: invalid file handle"}
			}

			err := file.Sync()
			if err != nil {
				return &object.Error{Message: "failed to flush file: " + err.Error()}
			}

			return &object.None{}
		},
	},

	"fileReadPath": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fileReadPath requires 1 argument: path"}
			}
			pathStr, ok := extractStringFile(args[0])
			if !ok {
				return &object.Error{Message: "fileReadPath: path must be a string"}
			}
			data, err := os.ReadFile(pathStr)
			if err != nil {
				return &object.Error{Message: "failed to read file '" + pathStr + "': " + err.Error()}
			}
			return &object.String{Value: string(data)}
		},
	},

	"fileWritePath": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "fileWritePath requires 2 arguments: path, content"}
			}
			pathStr, ok1 := extractStringFile(args[0])
			contentStr, ok2 := extractStringFile(args[1])
			if !ok1 || !ok2 {
				return &object.Error{Message: "fileWritePath: path/content must be strings"}
			}
			err := os.WriteFile(pathStr, []byte(contentStr), 0644)
			if err != nil {
				return &object.Error{Message: "failed to write file '" + pathStr + "': " + err.Error()}
			}
			return &object.None{}
		},
	},

	"fileAppendPath": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "fileAppendPath requires 2 arguments: path, content"}
			}
			pathStr, ok1 := extractStringFile(args[0])
			contentStr, ok2 := extractStringFile(args[1])
			if !ok1 || !ok2 {
				return &object.Error{Message: "fileAppendPath: path/content must be strings"}
			}
			f, err := os.OpenFile(pathStr, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
			if err != nil {
				return &object.Error{Message: "failed to open file '" + pathStr + "' for append: " + err.Error()}
			}
			defer f.Close()
			_, err = f.WriteString(contentStr)
			if err != nil {
				return &object.Error{Message: "failed to append to file '" + pathStr + "': " + err.Error()}
			}
			return &object.None{}
		},
	},

	"fileExists": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fileExists requires 1 argument: path"}
			}
			pathStr, ok := extractStringFile(args[0])
			if !ok {
				return &object.Error{Message: "fileExists: path must be a string, got " + string(args[0].Type()) + " with value: " + args[0].Inspect()}
			}
			stat, err := os.Stat(pathStr)
			if err != nil {
				if os.IsNotExist(err) {
					return &object.Boolean{Value: false}
				}
				return &object.Error{Message: "error checking fileExists for '" + pathStr + "': " + err.Error()}
			}

			fileType := "file"
			if stat.IsDir() {
				fileType = "directory"
			}
			_ = fileType
			return &object.Boolean{Value: true}
		},
	},

	"fileRead": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fileRead requires 1 argument: path"}
			}
			pathStr, ok := extractStringFile(args[0])
			if !ok {
				return &object.Error{Message: "fileRead: path must be a string"}
			}
			data, err := os.ReadFile(pathStr)
			if err != nil {
				return &object.Error{Message: "failed to read file '" + pathStr + "': " + err.Error()}
			}
			return &object.String{Value: string(data)}
		},
	},

	"fileWrite": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "fileWrite requires 2 arguments: path, content"}
			}
			pathStr, ok1 := extractStringFile(args[0])
			contentStr, ok2 := extractStringFile(args[1])
			if !ok1 || !ok2 {
				return &object.Error{Message: "fileWrite: path/content must be strings"}
			}
			err := os.WriteFile(pathStr, []byte(contentStr), 0644)
			if err != nil {
				return &object.Error{Message: "failed to write file '" + pathStr + "': " + err.Error()}
			}
			return &object.None{}
		},
	},

	"fileAppend": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "fileAppend requires 2 arguments: path, content"}
			}
			pathStr, ok1 := extractStringFile(args[0])
			contentStr, ok2 := extractStringFile(args[1])
			if !ok1 || !ok2 {
				return &object.Error{Message: "fileAppend: path/content must be strings"}
			}
			f, err := os.OpenFile(pathStr, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
			if err != nil {
				return &object.Error{Message: "failed to open file '" + pathStr + "' for append: " + err.Error()}
			}
			defer f.Close()
			_, err = f.WriteString(contentStr)
			if err != nil {
				return &object.Error{Message: "failed to append to file '" + pathStr + "': " + err.Error()}
			}
			return &object.None{}
		},
	},
}
View Source
var HttpModule = map[string]*object.Builtin{
	"httpGet": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "httpGet expects 1 or 2 arguments: httpGet(url, [headers])"}
			}

			urlObj, ok := args[0].(*object.String)
			if !ok {
				if instance, ok := args[0].(*object.Instance); ok {
					if value, ok := instance.Env.Get("value"); ok {
						if str, ok := value.(*object.String); ok {
							urlObj = str
						} else {
							return &object.Error{Message: "httpGet expects URL as string"}
						}
					} else {
						return &object.Error{Message: "httpGet expects URL as string"}
					}
				} else {
					return &object.Error{Message: "httpGet expects URL as string"}
				}
			}

			client := &http.Client{
				Timeout: 30 * time.Second,
			}

			req, err := http.NewRequest("GET", urlObj.Value, nil)
			if err != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to create request: %v", err)}
			}

			if len(args) == 2 {
				if err := setHeaders(req, args[1]); err != nil {
					return err
				}
			}

			resp, err := client.Do(req)
			if err != nil {
				return &object.Error{Message: fmt.Sprintf("Request failed: %v", err)}
			}
			defer resp.Body.Close()

			body, err := io.ReadAll(resp.Body)
			if err != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to read response: %v", err)}
			}

			result := &object.Hash{
				Pairs: make(map[object.HashKey]object.HashPair),
			}

			statusKey := &object.String{Value: "status"}
			result.Pairs[statusKey.HashKey()] = object.HashPair{
				Key:   statusKey,
				Value: &object.Integer{Value: int64(resp.StatusCode)},
			}

			bodyKey := &object.String{Value: "body"}
			result.Pairs[bodyKey.HashKey()] = object.HashPair{
				Key:   bodyKey,
				Value: &object.String{Value: string(body)},
			}

			headersKey := &object.String{Value: "headers"}
			result.Pairs[headersKey.HashKey()] = object.HashPair{
				Key:   headersKey,
				Value: headersToHash(resp.Header),
			}

			return result
		},
	},
	"httpPost": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return &object.Error{Message: "httpPost expects 2 or 3 arguments: httpPost(url, body, [headers])"}
			}

			urlObj, err := extractString(args[0], "URL")
			if err != nil {
				return err
			}

			bodyStr, err := extractString(args[1], "body")
			if err != nil {
				return err
			}

			client := &http.Client{
				Timeout: 30 * time.Second,
			}

			req, reqErr := http.NewRequest("POST", urlObj, strings.NewReader(bodyStr))
			if reqErr != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to create request: %v", reqErr)}
			}

			req.Header.Set("Content-Type", "application/json")

			if len(args) == 3 {
				if err := setHeaders(req, args[2]); err != nil {
					return err
				}
			}

			resp, respErr := client.Do(req)
			if respErr != nil {
				return &object.Error{Message: fmt.Sprintf("Request failed: %v", respErr)}
			}
			defer resp.Body.Close()

			return buildResponse(resp)
		},
	},
	"httpPut": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return &object.Error{Message: "httpPut expects 2 or 3 arguments: httpPut(url, body, [headers])"}
			}

			urlObj, err := extractString(args[0], "URL")
			if err != nil {
				return err
			}

			bodyStr, err := extractString(args[1], "body")
			if err != nil {
				return err
			}

			client := &http.Client{
				Timeout: 30 * time.Second,
			}

			req, reqErr := http.NewRequest("PUT", urlObj, strings.NewReader(bodyStr))
			if reqErr != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to create request: %v", reqErr)}
			}

			req.Header.Set("Content-Type", "application/json")

			if len(args) == 3 {
				if err := setHeaders(req, args[2]); err != nil {
					return err
				}
			}

			resp, respErr := client.Do(req)
			if respErr != nil {
				return &object.Error{Message: fmt.Sprintf("Request failed: %v", respErr)}
			}
			defer resp.Body.Close()

			return buildResponse(resp)
		},
	},
	"httpDelete": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "httpDelete expects 1 or 2 arguments: httpDelete(url, [headers])"}
			}

			urlObj, err := extractString(args[0], "URL")
			if err != nil {
				return err
			}

			client := &http.Client{
				Timeout: 30 * time.Second,
			}

			req, reqErr := http.NewRequest("DELETE", urlObj, nil)
			if reqErr != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to create request: %v", reqErr)}
			}

			if len(args) == 2 {
				if err := setHeaders(req, args[1]); err != nil {
					return err
				}
			}

			resp, respErr := client.Do(req)
			if respErr != nil {
				return &object.Error{Message: fmt.Sprintf("Request failed: %v", respErr)}
			}
			defer resp.Body.Close()

			return buildResponse(resp)
		},
	},
	"httpHead": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "httpHead expects 1 or 2 arguments: httpHead(url, [headers])"}
			}

			urlObj, err := extractString(args[0], "URL")
			if err != nil {
				return err
			}

			client := &http.Client{
				Timeout: 30 * time.Second,
			}

			req, reqErr := http.NewRequest("HEAD", urlObj, nil)
			if reqErr != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to create request: %v", reqErr)}
			}

			if len(args) == 2 {
				if err := setHeaders(req, args[1]); err != nil {
					return err
				}
			}

			resp, respErr := client.Do(req)
			if respErr != nil {
				return &object.Error{Message: fmt.Sprintf("Request failed: %v", respErr)}
			}
			defer resp.Body.Close()

			result := &object.Hash{
				Pairs: make(map[object.HashKey]object.HashPair),
			}

			statusKey := &object.String{Value: "status"}
			result.Pairs[statusKey.HashKey()] = object.HashPair{
				Key:   statusKey,
				Value: &object.Integer{Value: int64(resp.StatusCode)},
			}

			headersKey := &object.String{Value: "headers"}
			result.Pairs[headersKey.HashKey()] = object.HashPair{
				Key:   headersKey,
				Value: headersToHash(resp.Header),
			}

			return result
		},
	},
	"httpRequest": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "httpRequest expects 1 argument: httpRequest(options)"}
			}

			options, ok := args[0].(*object.Hash)
			if !ok {
				return &object.Error{Message: "httpRequest expects options as hash"}
			}

			method, err := getHashString(options, "method")
			if err != nil {
				method = "GET"
			}

			url, err := getHashString(options, "url")
			if err != nil {
				return &object.Error{Message: "httpRequest requires 'url' in options"}
			}

			var bodyReader io.Reader
			if body, err := getHashString(options, "body"); err == nil {
				bodyReader = strings.NewReader(body)
			}

			timeout := 30
			if timeoutVal, err := getHashInt(options, "timeout"); err == nil {
				timeout = int(timeoutVal)
			}

			client := &http.Client{
				Timeout: time.Duration(timeout) * time.Second,
			}

			req, reqErr := http.NewRequest(method, url, bodyReader)
			if reqErr != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to create request: %v", reqErr)}
			}

			if headers, err := getHashValue(options, "headers"); err == nil {
				if err := setHeaders(req, headers); err != nil {
					return err
				}
			}

			resp, respErr := client.Do(req)
			if respErr != nil {
				return &object.Error{Message: fmt.Sprintf("Request failed: %v", respErr)}
			}
			defer resp.Body.Close()

			return buildResponse(resp)
		},
	},
	"httpParseJSON": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "httpParseJSON expects 1 argument: httpParseJSON(jsonString)"}
			}

			jsonStr, err := extractString(args[0], "JSON string")
			if err != nil {
				return err
			}

			var result interface{}
			if err := json.Unmarshal([]byte(jsonStr), &result); err != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to parse JSON: %v", err)}
			}

			return jsonToObject(result)
		},
	},
	"httpStringifyJSON": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "httpStringifyJSON expects 1 argument: httpStringifyJSON(object)"}
			}

			data := objectToInterface(args[0])
			jsonBytes, err := json.Marshal(data)
			if err != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to stringify JSON: %v", err)}
			}

			return &object.String{Value: string(jsonBytes)}
		},
	},
	"httpBuildQuery": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "httpBuildQuery expects 1 argument: httpBuildQuery(params)"}
			}

			params, ok := args[0].(*object.Hash)
			if !ok {
				return &object.Error{Message: "httpBuildQuery expects params as hash"}
			}

			var queryParts []string
			for _, pair := range params.Pairs {
				key := pair.Key.Inspect()
				value := pair.Value.Inspect()
				queryParts = append(queryParts, fmt.Sprintf("%s=%s", key, value))
			}

			return &object.String{Value: strings.Join(queryParts, "&")}
		},
	},

	"http_parse_request": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "http_parse_request requires 1 argument: request_data"}
			}

			requestData, err := extractString(args[0], "request_data")
			if err != nil {
				return err
			}

			return parseHTTPRequest(requestData)
		},
	},

	"http_response": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return &object.Error{Message: "http_response requires 2-3 arguments: status_code, body, [headers]"}
			}

			statusCode, ok := args[0].(*object.Integer)
			if !ok {
				return &object.Error{Message: "http_response: status_code must be an integer"}
			}

			body, err := extractString(args[1], "body")
			if err != nil {
				return err
			}

			headers := make(map[string]string)
			if len(args) == 3 {
				if headerHash, ok := args[2].(*object.Hash); ok {
					for _, pair := range headerHash.Pairs {
						key := pair.Key.Inspect()
						value := pair.Value.Inspect()
						headers[key] = value
					}
				}
			}

			return buildHTTPResponse(int(statusCode.Value), body, headers)
		},
	},

	"serve_static_file": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "serve_static_file requires 1 argument: file_path"}
			}

			filePath, err := extractString(args[0], "file_path")
			if err != nil {
				return err
			}

			return serveStaticFile(filePath)
		},
	},

	"list_directory": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "list_directory requires 1 argument: directory_path"}
			}

			dirPath, err := extractString(args[0], "directory_path")
			if err != nil {
				return err
			}

			return listDirectory(dirPath)
		},
	},
}
View Source
var OSBuiltins = map[string]*object.Builtin{
	"osRunCommand": {
		Fn: func(args ...object.Object) object.Object {
			var command string
			var cmdArgs []string
			var capture bool

			if len(args) < 1 {
				return &object.Error{Message: "osRunCommand requires at least 1 argument (command)"}
			}

			command, ok := extractStringOS(args[0])
			if !ok {
				errMsg := "osRunCommand command must be a STRING, got=" + string(args[0].Type())
				if inst, isInst := args[0].(*object.Instance); isInst {
					if inst.Grimoire != nil {
						errMsg += " (grimoire: " + inst.Grimoire.Name + ")"
					}
					errMsg += " with inspect: " + args[0].Inspect()
				}
				return &object.Error{Message: errMsg}
			}

			if len(args) > 1 {
				arrArg, isArr := args[1].(*object.Array)
				if isArr {
					for _, elem := range arrArg.Elements {
						elemStr, ok := extractStringOS(elem)
						if !ok {
							return &object.Error{Message: "osRunCommand arg array must contain only STRINGs"}
						}
						cmdArgs = append(cmdArgs, elemStr)
					}
				}
			}

			if len(args) > 2 {
				capture, ok = extractBoolOS(args[2])
				if !ok {
					return &object.Error{Message: "osRunCommand third arg must be BOOLEAN for captureOutput"}
				}
			}

			cmd := exec.Command(command, cmdArgs...)
			var outputBytes []byte
			var err error
			if capture {
				outputBytes, err = cmd.CombinedOutput()
			} else {
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
				err = cmd.Run()
			}

			if err != nil {
				return &object.Error{Message: "error running command '" + command + "': " + err.Error()}
			}

			if capture {
				return &object.String{Value: string(outputBytes)}
			}
			return &object.None{}
		},
	},

	"osGetEnv": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "osGetEnv requires 1 argument: key"}
			}
			keyStr, ok := extractStringOS(args[0])
			if !ok {
				return &object.Error{Message: "osGetEnv argument must be STRING, got=" + string(args[0].Type())}
			}
			val := os.Getenv(keyStr)
			return &object.String{Value: val}
		},
	},

	"osSetEnv": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "osSetEnv requires 2 arguments: key, value"}
			}
			key, okKey := extractStringOS(args[0])
			val, okVal := extractStringOS(args[1])
			if !okKey || !okVal {
				return &object.Error{Message: "osSetEnv arguments must be STRINGS, got types: " + string(args[0].Type()) + " and " + string(args[1].Type())}
			}
			err := os.Setenv(key, val)
			if err != nil {
				return &object.Error{Message: "failed to set env var: " + err.Error()}
			}
			return &object.None{}
		},
	},

	"osGetCwd": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 0 {
				return &object.Error{Message: "osGetCwd takes no arguments"}
			}
			dir, err := os.Getwd()
			if err != nil {
				return &object.Error{Message: "failed to get current directory: " + err.Error()}
			}
			return &object.String{Value: dir}
		},
	},

	"osChdir": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "osChdir requires 1 argument: directory path"}
			}
			dirPath, ok := extractStringOS(args[0])
			if !ok {
				return &object.Error{Message: "osChdir argument must be STRING"}
			}
			err := os.Chdir(dirPath)
			if err != nil {
				return &object.Error{Message: "failed to chdir to '" + dirPath + "': " + err.Error()}
			}
			return &object.None{}
		},
	},

	"osSleep": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "osSleep requires 1 argument: seconds (INT or FLOAT)"}
			}

			if intVal, ok := extractIntOS(args[0]); ok {
				time.Sleep(time.Duration(intVal) * time.Second)
			} else if floatVal, ok := extractFloatOS(args[0]); ok {
				nanos := int64(floatVal * 1_000_000_000)
				time.Sleep(time.Duration(nanos))
			} else {
				return &object.Error{Message: "osSleep argument must be INTEGER or FLOAT, got " + string(args[0].Type())}
			}

			return &object.None{}
		},
	},

	"osListDir": {
		Fn: func(args ...object.Object) object.Object {
			var dir string
			if len(args) == 0 {
				dir = "."
			} else if len(args) == 1 {
				dirStr, ok := extractStringOS(args[0])
				if !ok {
					return &object.Error{Message: "osListDir argument must be STRING, got=" + string(args[0].Type()) + " with value: " + args[0].Inspect()}
				}
				dir = dirStr
			} else {
				return &object.Error{Message: "osListDir requires 0 or 1 arguments"}
			}

			entries, err := os.ReadDir(dir)
			if err != nil {
				return &object.Error{Message: "failed to read directory '" + dir + "': " + err.Error()}
			}

			var results []object.Object
			for _, e := range entries {
				results = append(results, &object.String{Value: e.Name()})
			}
			return &object.Array{Elements: results}
		},
	},

	"osRemove": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "osRemove requires 1 argument: path"}
			}
			pathStr, ok := extractStringOS(args[0])
			if !ok {
				return &object.Error{Message: "osRemove argument must be STRING"}
			}
			err := os.Remove(pathStr)
			if err != nil {
				return &object.Error{Message: "failed to remove '" + pathStr + "': " + err.Error()}
			}
			return &object.None{}
		},
	},

	"osMkdir": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "osMkdir requires 1 or 2 arguments: path, [perm int]"}
			}
			pathStr, ok := extractStringOS(args[0])
			if !ok {
				return &object.Error{Message: "osMkdir path must be STRING, got=" + string(args[0].Type())}
			}
			perm := os.FileMode(0755)
			if len(args) == 2 {
				permVal, ok := extractIntOS(args[1])
				if !ok {
					return &object.Error{Message: "osMkdir second arg must be an INTEGER for permissions"}
				}
				perm = os.FileMode(permVal)
			}
			err := os.Mkdir(pathStr, perm)
			if err != nil {
				return &object.Error{Message: "failed to create directory '" + pathStr + "': " + err.Error()}
			}
			return &object.None{}
		},
	},

	"osExpandEnv": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "osExpandEnv requires 1 argument: string"}
			}
			strArg, ok := extractStringOS(args[0])
			if !ok {
				return &object.Error{Message: "osExpandEnv argument must be STRING, got " + string(args[0].Type())}
			}
			expanded := os.ExpandEnv(strArg)
			return &object.String{Value: expanded}
		},
	},
}
View Source
var SocketsModule = map[string]*object.Builtin{
	"new_socket": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 {
				return &object.Error{Message: "new_socket requires at least 1 argument: type, [protocol], [port/address], [timeout]"}
			}

			socketType, ok := extractSocketString(args[0])
			if !ok {
				return &object.Error{Message: "new_socket: type must be a string"}
			}

			protocol := "tcp"
			if len(args) > 1 {
				if p, ok := extractSocketString(args[1]); ok {
					protocol = p
				}
			}

			address := "localhost:8080"
			if len(args) > 2 {
				if addr, ok := extractSocketString(args[2]); ok {
					address = addr
				}
			}

			timeout := 30 * time.Second
			if len(args) > 3 {
				if t, ok := extractSocketInt(args[3]); ok {
					if t < 0 {

						timeout = 30 * time.Second
					} else {
						timeout = time.Duration(t) * time.Second
					}
				}
			}

			switch strings.ToLower(socketType) {
			case "tcp":
				return createTCPSocket(protocol, address, timeout)
			case "udp":
				return createUDPSocket(address, timeout)
			case "web", "http":
				return createWebSocket(address, timeout)
			case "unix":
				return createUnixSocket(address, timeout)
			default:
				return &object.Error{Message: fmt.Sprintf("unsupported socket type: %s", socketType)}
			}
		},
	},

	"client": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 2 {
				return &object.Error{Message: "client requires at least 2 arguments: type, address, [timeout]"}
			}

			socketType, ok := extractSocketString(args[0])
			if !ok {
				return &object.Error{Message: "client: type must be a string"}
			}

			address, ok := extractSocketString(args[1])
			if !ok {
				return &object.Error{Message: "client: address must be a string"}
			}

			timeout := 30 * time.Second
			if len(args) > 2 {
				if t, ok := extractSocketInt(args[2]); ok {
					timeout = time.Duration(t) * time.Second
				}
			}

			switch strings.ToLower(socketType) {
			case "tcp":
				return connectTCPClient(address, timeout)
			case "udp":
				return connectUDPClient(address, timeout)
			case "unix":
				return connectUnixClient(address, timeout)
			default:
				return &object.Error{Message: fmt.Sprintf("unsupported client type: %s", socketType)}
			}
		},
	},

	"server": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 2 {
				return &object.Error{Message: "server requires at least 2 arguments: type, port/address, [timeout]"}
			}

			socketType, ok := extractSocketString(args[0])
			if !ok {
				return &object.Error{Message: "server: type must be a string"}
			}

			address, ok := extractSocketString(args[1])
			if !ok {
				return &object.Error{Message: "server: address must be a string"}
			}

			timeout := 30 * time.Second
			if len(args) > 2 {
				if t, ok := extractSocketInt(args[2]); ok {
					timeout = time.Duration(t) * time.Second
				}
			}

			switch strings.ToLower(socketType) {
			case "tcp":
				return startTCPServer(address, timeout)
			case "udp":
				return startUDPServer(address, timeout)
			case "web", "http":
				return startWebServer(address, timeout)
			case "unix":
				return startUnixServer(address, timeout)
			default:
				return &object.Error{Message: fmt.Sprintf("unsupported server type: %s", socketType)}
			}
		},
	},

	"socket_send": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "socket_send requires 2 arguments: handleID, data"}
			}

			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_send: handleID must be an integer"}
			}

			data, ok := extractSocketString(args[1])
			if !ok {
				return &object.Error{Message: "socket_send: data must be a string"}
			}

			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_send: invalid socket handle"}
			}

			return sendData(socket, data)
		},
	},

	"socket_receive": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "socket_receive requires 1-2 arguments: handleID, [bufferSize]"}
			}

			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_receive: handleID must be an integer"}
			}

			bufferSize := int64(1024)
			if len(args) > 1 {
				if size, ok := extractSocketInt(args[1]); ok {
					bufferSize = size
				}
			}

			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_receive: invalid socket handle"}
			}

			return receiveData(socket, bufferSize)
		},
	},

	"socket_close": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "socket_close requires 1 argument: handleID"}
			}

			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_close: handleID must be an integer"}
			}

			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_close: invalid socket handle"}
			}

			err := closeSocket(socket)
			removeSocketHandle(handleID)

			if err != nil {
				return &object.Error{Message: fmt.Sprintf("failed to close socket: %v", err)}
			}

			return &object.None{}
		},
	},

	"socket_listen": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "socket_listen requires 1 argument: handleID"}
			}

			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_listen: handleID must be an integer"}
			}

			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_listen: invalid socket handle"}
			}

			return listenForConnections(socket)
		},
	},

	"socket_accept": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "socket_accept requires 1 argument: handleID"}
			}

			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_accept: handleID must be an integer"}
			}

			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_accept: invalid socket handle"}
			}

			return acceptConnection(socket)
		},
	},

	"socket_set_timeout": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "socket_set_timeout requires 2 arguments: handleID, timeoutSeconds"}
			}

			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_set_timeout: handleID must be an integer"}
			}

			timeoutSecs, ok := extractSocketInt(args[1])
			if !ok {
				return &object.Error{Message: "socket_set_timeout: timeoutSeconds must be an integer"}
			}

			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_set_timeout: invalid socket handle"}
			}

			return setSocketTimeout(socket, time.Duration(timeoutSecs)*time.Second)
		},
	},

	"socket_get_info": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "socket_get_info requires 1 argument: handleID"}
			}

			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_get_info: handleID must be an integer"}
			}

			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_get_info: invalid socket handle"}
			}

			return getSocketInfo(socket)
		},
	},

	"socket_send_to": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 3 {
				return &object.Error{Message: "socket_send_to requires 3 arguments: handleID, data, targetAddress"}
			}
			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_send_to: handleID must be an integer"}
			}
			data, ok := extractSocketString(args[1])
			if !ok {
				return &object.Error{Message: "socket_send_to: data must be a string"}
			}
			targetAddress, ok := extractSocketString(args[2])
			if !ok {
				return &object.Error{Message: "socket_send_to: targetAddress must be a string"}
			}
			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_send_to: invalid socket handle"}
			}
			return sendDataTo(socket, data, targetAddress)
		},
	},

	"socket_receive_from": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "socket_receive_from requires 2 arguments: handleID, bufferSize"}
			}
			handleID, ok := extractSocketInt(args[0])
			if !ok {
				return &object.Error{Message: "socket_receive_from: handleID must be an integer"}
			}
			bufferSize, ok := extractSocketInt(args[1])
			if !ok {
				return &object.Error{Message: "socket_receive_from: bufferSize must be an integer"}
			}
			socket, exists := getSocketHandle(handleID)
			if !exists {
				return &object.Error{Message: "socket_receive_from: invalid socket handle"}
			}
			return receiveDataFrom(socket, bufferSize)
		},
	},
}
View Source
var TimeModule = map[string]*object.Builtin{

	"now": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 0 {
				return &object.Error{Message: "now() takes no arguments"}
			}
			return &object.Time{Value: time.Now()}
		},
	},

	"timeNow": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 0 {
				return &object.Error{Message: "timeNow takes no arguments"}
			}
			return &object.Integer{Value: time.Now().Unix()}
		},
	},

	"timeNowNano": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 0 {
				return &object.Error{Message: "timeNowNano takes no arguments"}
			}
			return &object.Integer{Value: time.Now().UnixNano()}
		},
	},

	"timeSleep": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "timeSleep requires 1 argument: seconds (INT or FLOAT)"}
			}

			if intVal, ok := getIntegerValue(args[0]); ok {
				if intVal < 0 {
					return &object.Error{Message: "timeSleep duration cannot be negative"}
				}
				time.Sleep(time.Duration(intVal) * time.Second)
				return &object.None{}
			}

			if floatVal, ok := getFloatValue(args[0]); ok {
				if floatVal < 0 {
					return &object.Error{Message: "timeSleep duration cannot be negative"}
				}
				nanos := int64(floatVal * 1_000_000_000)
				time.Sleep(time.Duration(nanos))
				return &object.None{}
			}

			if durVal, ok := args[0].(*object.Duration); ok {
				if durVal.Value < 0 {
					return &object.Error{Message: "timeSleep duration cannot be negative"}
				}
				time.Sleep(durVal.Value)
				return &object.None{}
			}

			return &object.Error{Message: "timeSleep argument must be INTEGER, FLOAT, or DURATION, got " + string(args[0].Type())}
		},
	},

	"parseTime": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 && len(args) != 2 {
				return &object.Error{Message: "parseTime() takes 1 or 2 arguments (timeString, [format])"}
			}

			timeStr, ok := args[0].(*object.String)
			if !ok {
				return &object.Error{Message: "First argument must be a STRING"}
			}

			format := time.RFC3339
			if len(args) == 2 {
				formatStr, ok := args[1].(*object.String)
				if !ok {
					return &object.Error{Message: "Second argument must be a STRING"}
				}
				format = formatStr.Value
			}

			parsedTime, err := time.Parse(format, timeStr.Value)
			if err != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to parse time: %s", err)}
			}

			return &object.Time{Value: parsedTime}
		},
	},

	"timeParse": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "timeParse requires 2 arguments: format, timeString"}
			}

			format, ok1 := args[0].(*object.String)
			timeStr, ok2 := args[1].(*object.String)
			if !ok1 || !ok2 {
				return &object.Error{Message: "timeParse arguments must be STRINGs"}
			}

			t, err := time.Parse(format.Value, timeStr.Value)
			if err != nil {
				return &object.Error{Message: "timeParse failed: " + err.Error()}
			}

			return &object.Integer{Value: t.Unix()}
		},
	},

	"formatTime": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "formatTime() requires exactly 2 arguments"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "First argument must be of type TIME"}
			}

			formatStr, ok := args[1].(*object.String)
			if !ok {
				return &object.Error{Message: "Second argument must be a STRING"}
			}

			formatted := timeObj.Value.Format(formatStr.Value)
			return &object.String{Value: formatted}
		},
	},

	"timeFormat": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return &object.Error{Message: "timeFormat requires 1 or 2 arguments: timestamp, [format]"}
			}

			timestamp, ok := getIntegerValue(args[0])
			if !ok {
				return &object.Error{Message: "timeFormat first argument must be INTEGER timestamp"}
			}

			format := "2006-01-02 15:04:05"
			if len(args) == 2 {
				formatArg, ok := args[1].(*object.String)
				if !ok {
					return &object.Error{Message: "timeFormat second argument must be STRING format"}
				}
				format = formatArg.Value
			}

			t := time.Unix(timestamp, 0)
			formatted := t.Format(format)
			return &object.String{Value: formatted}
		},
	},

	"timeSince": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "timeSince() requires exactly 1 argument"}
			}

			if t, ok := args[0].(*object.Time); ok {
				elapsed := time.Since(t.Value)
				return &object.Duration{Value: elapsed}
			}

			if timestamp, ok := getIntegerValue(args[0]); ok {
				elapsed := time.Since(time.Unix(timestamp, 0))
				return &object.Duration{Value: elapsed}
			}

			return &object.Error{Message: "Argument must be of type TIME or INTEGER (Unix timestamp)"}
		},
	},

	"timeUntil": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "timeUntil() requires exactly 1 argument"}
			}

			if t, ok := args[0].(*object.Time); ok {
				until := time.Until(t.Value)
				return &object.Duration{Value: until}
			}

			if timestamp, ok := getIntegerValue(args[0]); ok {
				until := time.Until(time.Unix(timestamp, 0))
				return &object.Duration{Value: until}
			}

			return &object.Error{Message: "Argument must be of type TIME or INTEGER (Unix timestamp)"}
		},
	},

	"addDuration": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "addDuration() requires exactly 2 arguments"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "First argument must be of type TIME"}
			}

			durObj, ok := args[1].(*object.Duration)
			if !ok {
				return &object.Error{Message: "Second argument must be of type DURATION"}
			}

			newTime := timeObj.Value.Add(durObj.Value)
			return &object.Time{Value: newTime}
		},
	},

	"timeAddDuration": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "timeAddDuration requires 2 arguments: timestamp, seconds"}
			}

			timestamp, ok1 := getIntegerValue(args[0])
			duration, ok2 := getIntegerValue(args[1])
			if !ok1 || !ok2 {
				return &object.Error{Message: "timeAddDuration arguments must be INTEGERs"}
			}

			t := time.Unix(timestamp, 0)
			newTime := t.Add(time.Duration(duration) * time.Second)
			return &object.Integer{Value: newTime.Unix()}
		},
	},

	"timeDiff": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "timeDiff requires 2 arguments"}
			}

			if t1, ok1 := args[0].(*object.Time); ok1 {
				if t2, ok2 := args[1].(*object.Time); ok2 {
					diff := t1.Value.Sub(t2.Value)
					return &object.Duration{Value: diff}
				}
				return &object.Error{Message: "Both arguments must be of the same type"}
			}

			if val1, ok1 := getIntegerValue(args[0]); ok1 {
				if val2, ok2 := getIntegerValue(args[1]); ok2 {
					diff := val1 - val2
					return &object.Integer{Value: diff}
				}
				return &object.Error{Message: "Both arguments must be of the same type"}
			}

			return &object.Error{Message: "Arguments must be INTEGERs or TIMEs"}
		},
	},

	"timeDate": {
		Fn: func(args ...object.Object) object.Object {
			var t time.Time
			if len(args) == 0 {
				t = time.Now()
			} else if len(args) == 1 {

				if timeObj, ok := args[0].(*object.Time); ok {
					t = timeObj.Value
				} else if intVal, ok := getIntegerValue(args[0]); ok {

					t = time.Unix(intVal, 0)
				} else {
					return &object.Error{Message: "timeDate argument must be INTEGER timestamp or TIME"}
				}
			} else {
				return &object.Error{Message: "timeDate requires 0 or 1 arguments"}
			}

			year, month, day := t.Date()
			elements := []object.Object{
				&object.Integer{Value: int64(year)},
				&object.Integer{Value: int64(month)},
				&object.Integer{Value: int64(day)},
			}
			return &object.Array{Elements: elements}
		},
	},

	"seconds": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "seconds() requires exactly 1 argument"}
			}

			if intVal, ok := getIntegerValue(args[0]); ok {
				return &object.Duration{Value: time.Duration(intVal) * time.Second}
			}

			if floatVal, ok := getFloatValue(args[0]); ok {
				nanos := int64(floatVal * float64(time.Second))
				return &object.Duration{Value: time.Duration(nanos)}
			}

			return &object.Error{Message: "Argument must be an INTEGER or FLOAT"}
		},
	},

	"minutes": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "minutes() requires exactly 1 argument"}
			}

			if intVal, ok := getIntegerValue(args[0]); ok {
				return &object.Duration{Value: time.Duration(intVal) * time.Minute}
			}

			if floatVal, ok := getFloatValue(args[0]); ok {
				nanos := int64(floatVal * float64(time.Minute))
				return &object.Duration{Value: time.Duration(nanos)}
			}

			return &object.Error{Message: "Argument must be an INTEGER or FLOAT"}
		},
	},

	"hours": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "hours() requires exactly 1 argument"}
			}

			if intVal, ok := getIntegerValue(args[0]); ok {
				return &object.Duration{Value: time.Duration(intVal) * time.Hour}
			}

			if floatVal, ok := getFloatValue(args[0]); ok {
				nanos := int64(floatVal * float64(time.Hour))
				return &object.Duration{Value: time.Duration(nanos)}
			}

			return &object.Error{Message: "Argument must be an INTEGER or FLOAT"}
		},
	},

	"milliseconds": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "milliseconds() requires exactly 1 argument"}
			}

			if intVal, ok := getIntegerValue(args[0]); ok {
				return &object.Duration{Value: time.Duration(intVal) * time.Millisecond}
			}

			if floatVal, ok := getFloatValue(args[0]); ok {
				nanos := int64(floatVal * float64(time.Millisecond))
				return &object.Duration{Value: time.Duration(nanos)}
			}

			return &object.Error{Message: "Argument must be an INTEGER or FLOAT"}
		},
	},

	"durationToSeconds": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "durationToSeconds() requires exactly 1 argument"}
			}

			durObj, ok := args[0].(*object.Duration)
			if !ok {
				return &object.Error{Message: "Argument must be of type DURATION"}
			}

			return &object.Float{Value: durObj.Value.Seconds()}
		},
	},

	"durationToMinutes": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "durationToMinutes() requires exactly 1 argument"}
			}

			durObj, ok := args[0].(*object.Duration)
			if !ok {
				return &object.Error{Message: "Argument must be of type DURATION"}
			}

			return &object.Float{Value: durObj.Value.Minutes()}
		},
	},

	"durationToHours": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "durationToHours() requires exactly 1 argument"}
			}

			durObj, ok := args[0].(*object.Duration)
			if !ok {
				return &object.Error{Message: "Argument must be of type DURATION"}
			}

			return &object.Float{Value: durObj.Value.Hours()}
		},
	},

	"durationToMilliseconds": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "durationToMilliseconds() requires exactly 1 argument"}
			}

			durObj, ok := args[0].(*object.Duration)
			if !ok {
				return &object.Error{Message: "Argument must be of type DURATION"}
			}

			return &object.Integer{Value: durObj.Value.Milliseconds()}
		},
	},

	"timeBefore": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "timeBefore() requires exactly 2 arguments"}
			}

			time1, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "First argument must be of type TIME"}
			}

			time2, ok := args[1].(*object.Time)
			if !ok {
				return &object.Error{Message: "Second argument must be of type TIME"}
			}

			return &object.Boolean{Value: time1.Value.Before(time2.Value)}
		},
	},

	"timeAfter": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "timeAfter() requires exactly 2 arguments"}
			}

			time1, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "First argument must be of type TIME"}
			}

			time2, ok := args[1].(*object.Time)
			if !ok {
				return &object.Error{Message: "Second argument must be of type TIME"}
			}

			return &object.Boolean{Value: time1.Value.After(time2.Value)}
		},
	},

	"timeEqual": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "timeEqual() requires exactly 2 arguments"}
			}

			time1, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "First argument must be of type TIME"}
			}

			time2, ok := args[1].(*object.Time)
			if !ok {
				return &object.Error{Message: "Second argument must be of type TIME"}
			}

			return &object.Boolean{Value: time1.Value.Equal(time2.Value)}
		},
	},

	"year": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "year() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: int64(timeObj.Value.Year())}
		},
	},

	"month": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "month() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: int64(timeObj.Value.Month())}
		},
	},

	"day": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "day() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: int64(timeObj.Value.Day())}
		},
	},

	"weekday": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "weekday() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: int64(timeObj.Value.Weekday())}
		},
	},

	"hour": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "hour() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: int64(timeObj.Value.Hour())}
		},
	},

	"minute": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "minute() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: int64(timeObj.Value.Minute())}
		},
	},

	"second": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "second() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: int64(timeObj.Value.Second())}
		},
	},

	"unix": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "unix() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: timeObj.Value.Unix()}
		},
	},

	"unixNano": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "unixNano() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Integer{Value: timeObj.Value.UnixNano()}
		},
	},

	"fromUnix": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fromUnix() requires exactly 1 argument"}
			}

			timestamp, ok := getIntegerValue(args[0])
			if !ok {
				return &object.Error{Message: "Argument must be an INTEGER"}
			}

			return &object.Time{Value: time.Unix(timestamp, 0)}
		},
	},

	"fromUnixNano": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "fromUnixNano() requires exactly 1 argument"}
			}

			timestamp, ok := getIntegerValue(args[0])
			if !ok {
				return &object.Error{Message: "Argument must be an INTEGER"}
			}

			return &object.Time{Value: time.Unix(0, timestamp)}
		},
	},

	"inLocation": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 2 {
				return &object.Error{Message: "inLocation() requires exactly 2 arguments"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "First argument must be of type TIME"}
			}

			locStr, ok := args[1].(*object.String)
			if !ok {
				return &object.Error{Message: "Second argument must be a STRING"}
			}

			loc, err := time.LoadLocation(locStr.Value)
			if err != nil {
				return &object.Error{Message: fmt.Sprintf("Failed to load location: %s", err)}
			}

			return &object.Time{Value: timeObj.Value.In(loc)}
		},
	},

	"utc": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "utc() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Time{Value: timeObj.Value.UTC()}
		},
	},

	"local": {
		Fn: func(args ...object.Object) object.Object {
			if len(args) != 1 {
				return &object.Error{Message: "local() requires exactly 1 argument"}
			}

			timeObj, ok := args[0].(*object.Time)
			if !ok {
				return &object.Error{Message: "Argument must be of type TIME"}
			}

			return &object.Time{Value: timeObj.Value.Local()}
		},
	},
}

Functions

This section is empty.

Types

type TCPListener added in v0.1.8

type TCPListener struct {
	Listener net.Listener
	Type     string
	Address  string
	Timeout  time.Duration
}

type TCPSocket added in v0.1.8

type TCPSocket struct {
	Conn    net.Conn
	Type    string
	Address string
	Timeout time.Duration
}

Socket wrapper types

type UDPSocket added in v0.1.8

type UDPSocket struct {
	Conn    *net.UDPConn
	Type    string
	Address string
	Timeout time.Duration
}

type UnixSocket added in v0.1.8

type UnixSocket struct {
	Conn    net.Conn
	Type    string
	Address string
	Timeout time.Duration
}

type WebSocket added in v0.1.8

type WebSocket struct {
	Server  *http.Server
	Mux     *http.ServeMux
	Type    string
	Address string
	Timeout time.Duration
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL