stdlib

package
v0.0.0-...-ce6e6e9 Latest Latest
Warning

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

Go to latest
Published: Jan 17, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const (
	RE_IGNORECASE = 2  // re.I or re.IGNORECASE
	RE_MULTILINE  = 8  // re.M or re.MULTILINE
	RE_DOTALL     = 16 // re.S or re.DOTALL
)

Flag constants matching Python's re module

View Source
const (
	JSONLibraryName        = "json"
	ReLibraryName          = "re"
	TimeLibraryName        = "time"
	DatetimeLibraryName    = "datetime"
	MathLibraryName        = "math"
	Base64LibraryName      = "base64"
	HashlibLibraryName     = "hashlib"
	RandomLibraryName      = "random"
	URLLibLibraryName      = "urllib"
	URLParseLibraryName    = "urllib.parse"
	StringLibraryName      = "string"
	UUIDLibraryName        = "uuid"
	HTMLLibraryName        = "html"
	StatisticsLibraryName  = "statistics"
	FunctoolsLibraryName   = "functools"
	TextwrapLibraryName    = "textwrap"
	PlatformLibraryName    = "platform"
	ItertoolsLibraryName   = "itertools"
	CollectionsLibraryName = "collections"
)

Library names as constants for easy reference

Variables

View Source
var (
	TRUE  = &object.Boolean{Value: true}
	FALSE = &object.Boolean{Value: false}
)

Boolean constants for datetime comparisons

View Source
var (
	DatetimeClass *object.Class
	DateClass     *object.Class
)

Forward declarations for classes (set in init)

View Source
var Base64Library = object.NewLibrary(map[string]*object.Builtin{
	"b64encode": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			str, err := args[0].AsString()
			if err != nil {
				return err
			}
			encoded := base64.StdEncoding.EncodeToString([]byte(str))
			return &object.String{Value: encoded}
		},
		HelpText: `b64encode(s) - Encode bytes-like object to Base64

Returns a Base64-encoded version of the input string.`,
	},
	"b64decode": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			str, err := args[0].AsString()
			if err != nil {
				return err
			}
			decoded, decodeErr := base64.StdEncoding.DecodeString(str)
			if decodeErr != nil {
				return errors.NewError("base64 decode error: %s", decodeErr.Error())
			}
			return &object.String{Value: string(decoded)}
		},
		HelpText: `b64decode(s) - Decode a Base64 encoded string

Returns the decoded string from a Base64-encoded input.`,
	},
}, nil, "Base64 encoding and decoding library")
View Source
var CollectionsLibrary = object.NewLibrary(map[string]*object.Builtin{
	"Counter": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			counter := createCounterInstance()

			if len(args) == 0 {
				return counter
			}
			if err := errors.MaxArgs(args, 1); err != nil {
				return err
			}

			switch arg := args[0].(type) {
			case *object.List:
				for _, elem := range arg.Elements {
					key := elem.Inspect()
					if countObj, exists := counter.Fields[key]; exists {
						if count, ok := countObj.(*object.Integer); ok {
							counter.Fields[key] = object.NewInteger(count.Value + 1)
						}
					} else {
						counter.Fields[key] = object.NewInteger(1)
					}
				}
			case *object.Tuple:
				for _, elem := range arg.Elements {
					key := elem.Inspect()
					if countObj, exists := counter.Fields[key]; exists {
						if count, ok := countObj.(*object.Integer); ok {
							counter.Fields[key] = object.NewInteger(count.Value + 1)
						}
					} else {
						counter.Fields[key] = object.NewInteger(1)
					}
				}
			case *object.String:
				for _, ch := range arg.Value {
					key := string(ch)
					if countObj, exists := counter.Fields[key]; exists {
						if count, ok := countObj.(*object.Integer); ok {
							counter.Fields[key] = object.NewInteger(count.Value + 1)
						}
					} else {
						counter.Fields[key] = object.NewInteger(1)
					}
				}
			case *object.Dict:

				for k, v := range arg.Pairs {
					if count, ok := v.Value.(*object.Integer); ok {
						counter.Fields[k] = count
					}
				}
			default:
				return errors.NewTypeError("iterable or dict", args[0].Type().String())
			}

			return counter
		},
		HelpText: `Counter([iterable]) - Count elements

Creates a Counter object that counts occurrences of elements.

Example:
  c = collections.Counter([1, 1, 2, 3, 3, 3])
  c[1] -> 2  # Count of element 1
  c[4] -> 0  # Missing elements return 0
  c.most_common() -> [(3, 3), (1, 2), (2, 1)]
  c.elements() -> [1, 1, 2, 3, 3, 3]`,
	},
	"most_common": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}
			counter, ok := args[0].(*object.Instance)
			if !ok || counter.Class != CounterClass {
				return errors.NewTypeError("Counter", args[0].Type().String())
			}

			n := len(counter.Fields)
			if len(args) == 2 {
				if nArg, ok := args[1].(*object.Integer); ok {
					n = int(nArg.Value)
				} else {
					return errors.NewTypeError("INTEGER", args[1].Type().String())
				}
			}

			// Convert to sortable slice
			type pair struct {
				key   string
				count int64
			}
			pairs := make([]pair, 0, len(counter.Fields))
			for key, countObj := range counter.Fields {
				if count, ok := countObj.(*object.Integer); ok {
					pairs = append(pairs, pair{key: key, count: count.Value})
				}
			}

			sort.Slice(pairs, func(i, j int) bool {
				return pairs[i].count > pairs[j].count
			})

			if n > len(pairs) {
				n = len(pairs)
			}
			result := make([]object.Object, n)
			for i := 0; i < n; i++ {
				key := pairs[i].key

				if intVal, err := strconv.ParseInt(key, 10, 64); err == nil {
					result[i] = &object.Tuple{Elements: []object.Object{
						object.NewInteger(intVal),
						object.NewInteger(pairs[i].count),
					}}
				} else {
					result[i] = &object.Tuple{Elements: []object.Object{
						&object.String{Value: key},
						object.NewInteger(pairs[i].count),
					}}
				}
			}
			return &object.List{Elements: result}
		},
		HelpText: `most_common(counter[, n]) - Return n most common elements

Returns a list of (element, count) tuples sorted by count.

Example:
  c = collections.Counter([1, 1, 2, 3, 3, 3])
  collections.most_common(c, 2) -> [(3, 3), (1, 2)]`,
	},

	"OrderedDict": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			od := &object.Dict{Pairs: make(map[string]object.DictPair)}

			if len(args) == 0 {
				return od
			}
			if err := errors.MaxArgs(args, 1); err != nil {
				return err
			}

			switch arg := args[0].(type) {
			case *object.List:
				for _, elem := range arg.Elements {
					tuple, ok := elem.(*object.Tuple)
					if !ok || len(tuple.Elements) != 2 {
						return errors.NewError("OrderedDict() items must be (key, value) tuples")
					}
					key := tuple.Elements[0].Inspect()
					od.Pairs[key] = object.DictPair{
						Key:   tuple.Elements[0],
						Value: tuple.Elements[1],
					}
				}
			case *object.Dict:
				for k, v := range arg.Pairs {
					od.Pairs[k] = v
				}
			default:
				return errors.NewTypeError("list of tuples or dict", args[0].Type().String())
			}
			return od
		},
		HelpText: `OrderedDict([items]) - Dict that remembers insertion order

Creates a dict that maintains insertion order.
Note: Scriptling dicts already maintain order, so this is equivalent to dict().

Example:
  od = collections.OrderedDict([("a", 1), ("b", 2)])`,
	},
	"deque": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			elements := []object.Object{}

			if len(args) >= 1 {
				switch arg := args[0].(type) {
				case *object.List:
					elements = make([]object.Object, len(arg.Elements))
					copy(elements, arg.Elements)
				case *object.Tuple:
					elements = make([]object.Object, len(arg.Elements))
					copy(elements, arg.Elements)
				case *object.String:
					for _, ch := range arg.Value {
						elements = append(elements, &object.String{Value: string(ch)})
					}
				default:
					return errors.NewTypeError("iterable", args[0].Type().String())
				}
			}

			maxlen := int64(-1)
			if len(args) >= 2 {
				if ml, ok := args[1].(*object.Integer); ok {
					maxlen = ml.Value
					if maxlen >= 0 && int64(len(elements)) > maxlen {

						elements = elements[len(elements)-int(maxlen):]
					}
				} else if args[1].Type() != object.NULL_OBJ {
					return errors.NewTypeError("INTEGER or None", args[1].Type().String())
				}
			}

			dequeList := &object.List{Elements: elements}

			return dequeList
		},
		HelpText: `deque([iterable[, maxlen]]) - Double-ended queue

Creates a double-ended queue (deque) from an iterable.
Use collections.deque_* functions for deque-specific operations.

Example:
  d = collections.deque([1, 2, 3])
  collections.deque_appendleft(d, 0)  # [0, 1, 2, 3]`,
	},
	"deque_appendleft": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			deque, ok := args[0].(*object.List)
			if !ok {
				return errors.NewTypeError("LIST (deque)", args[0].Type().String())
			}
			newElements := make([]object.Object, len(deque.Elements)+1)
			newElements[0] = args[1]
			copy(newElements[1:], deque.Elements)
			deque.Elements = newElements
			return &object.Null{}
		},
		HelpText: `deque_appendleft(deque, elem) - Add element to left side

Adds an element to the left side of the deque.

Example:
  d = collections.deque([1, 2, 3])
  collections.deque_appendleft(d, 0)  # d is now [0, 1, 2, 3]`,
	},
	"deque_popleft": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			deque, ok := args[0].(*object.List)
			if !ok {
				return errors.NewTypeError("LIST (deque)", args[0].Type().String())
			}
			if len(deque.Elements) == 0 {
				return errors.NewError("popleft from empty deque")
			}
			elem := deque.Elements[0]
			deque.Elements = deque.Elements[1:]
			return elem
		},
		HelpText: `deque_popleft(deque) - Remove and return element from left

Removes and returns the leftmost element.

Example:
  d = collections.deque([1, 2, 3])
  x = collections.deque_popleft(d)  # x=1, d=[2, 3]`,
	},
	"deque_extendleft": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			deque, ok := args[0].(*object.List)
			if !ok {
				return errors.NewTypeError("LIST (deque)", args[0].Type().String())
			}
			var elements []object.Object
			switch arg := args[1].(type) {
			case *object.List:
				elements = arg.Elements
			case *object.Tuple:
				elements = arg.Elements
			default:
				return errors.NewTypeError("iterable", args[1].Type().String())
			}

			newElements := make([]object.Object, len(elements)+len(deque.Elements))
			for i, elem := range elements {
				newElements[len(elements)-1-i] = elem
			}
			copy(newElements[len(elements):], deque.Elements)
			deque.Elements = newElements
			return &object.Null{}
		},
		HelpText: `deque_extendleft(deque, iterable) - Extend left with iterable

Extends the left side with elements from iterable (in reverse order).

Example:
  d = collections.deque([1, 2, 3])
  collections.deque_extendleft(d, [4, 5])  # d is now [5, 4, 1, 2, 3]`,
	},
	"deque_rotate": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			deque, ok := args[0].(*object.List)
			if !ok {
				return errors.NewTypeError("LIST (deque)", args[0].Type().String())
			}
			n, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			if len(deque.Elements) == 0 {
				return &object.Null{}
			}

			steps := int(n.Value) % len(deque.Elements)
			if steps < 0 {
				steps += len(deque.Elements)
			}
			if steps == 0 {
				return &object.Null{}
			}

			newElements := make([]object.Object, len(deque.Elements))
			splitPoint := len(deque.Elements) - steps
			copy(newElements, deque.Elements[splitPoint:])
			copy(newElements[steps:], deque.Elements[:splitPoint])
			deque.Elements = newElements
			return &object.Null{}
		},
		HelpText: `deque_rotate(deque, n) - Rotate deque n steps

Rotates the deque n steps to the right. If n is negative, rotates left.

Example:
  d = collections.deque([1, 2, 3, 4])
  collections.deque_rotate(d, 1)  # d is now [4, 1, 2, 3]
  collections.deque_rotate(d, -1) # d is now [1, 2, 3, 4]`,
	},
	"namedtuple": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			typename, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}

			var fieldNames []string
			switch fn := args[1].(type) {
			case *object.List:
				for _, elem := range fn.Elements {
					if s, ok := elem.(*object.String); ok {
						fieldNames = append(fieldNames, s.Value)
					} else {
						return errors.NewError("field names must be strings")
					}
				}
			case *object.Tuple:
				for _, elem := range fn.Elements {
					if s, ok := elem.(*object.String); ok {
						fieldNames = append(fieldNames, s.Value)
					} else {
						return errors.NewError("field names must be strings")
					}
				}
			case *object.String:

				fields := strings.FieldsFunc(fn.Value, func(r rune) bool {
					return r == ' ' || r == ','
				})
				for _, f := range fields {
					f = strings.TrimSpace(f)
					if f != "" {
						fieldNames = append(fieldNames, f)
					}
				}
			default:
				return errors.NewTypeError("list, tuple, or string", args[1].Type().String())
			}

			methods := make(map[string]object.Object)

			methods["__init__"] = &object.Builtin{
				Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
					if len(args) != len(fieldNames)+1 {
						return errors.NewArgumentError(len(args), len(fieldNames)+1)
					}
					nt := args[0].(*object.Instance)

					for i, name := range fieldNames {
						nt.Fields[name] = args[i+1]
					}
					nt.Fields["__typename__"] = typename

					fieldNameObjs := make([]object.Object, len(fieldNames))
					for i, name := range fieldNames {
						fieldNameObjs[i] = &object.String{Value: name}
					}
					nt.Fields["__fields__"] = &object.Tuple{Elements: fieldNameObjs}
					return &object.Null{}
				},
			}

			methods["__getitem__"] = &object.Builtin{
				Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
					if err := errors.ExactArgs(args, 2); err != nil {
						return err
					}
					nt := args[0].(*object.Instance)
					key := args[1].Inspect()

					if key == "__typename__" || key == "__fields__" {
						return &object.Null{}
					}
					if value, exists := nt.Fields[key]; exists {
						return value
					}
					return &object.Null{}
				},
				HelpText: `__getitem__(key) - Get field value (supports nt[key] syntax)`,
			}

			ntClass := &object.Class{
				Name:    typename.Value,
				Methods: methods,
			}

			return ntClass
		},
		HelpText: `namedtuple(typename, field_names) - Create a named tuple class

Creates a class for creating named tuple instances with direct attribute access.

Example:
  Point = collections.namedtuple("Point", ["x", "y"])
  p = Point(1, 2)
  p.x      # 1 (direct attribute access)
  p["y"]   # 2 (dict-style access)
  p.x()    # Also works for backward compatibility`,
	},
	"ChainMap": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			chainMap := &object.Dict{Pairs: make(map[string]object.DictPair)}

			maps := make([]object.Object, len(args))
			for i, arg := range args {
				if _, ok := arg.(*object.Dict); !ok {
					return errors.NewTypeError("DICT", arg.Type().String())
				}
				maps[i] = arg
			}

			for i := len(args) - 1; i >= 0; i-- {
				d := args[i].(*object.Dict)
				for k, v := range d.Pairs {
					chainMap.Pairs[k] = v
				}
			}

			return chainMap
		},
		HelpText: `ChainMap(*maps) - Group multiple dicts for single lookup

Creates a single dict view over multiple dicts. First dict has priority.

Example:
  d1 = {"a": 1}
  d2 = {"b": 2, "a": 10}
  cm = collections.ChainMap(d1, d2)
  cm["a"]  # 1 (from d1)
  cm["b"]  # 2 (from d2)`,
	},
}, map[string]object.Object{
	"Counter":     CounterClass,
	"DefaultDict": DefaultDictClass,
	"defaultdict": DefaultDictClass,
}, "Python-compatible collections library for specialized container datatypes")

CollectionsLibrary provides Python-like collections functions

View Source
var CounterClass = &object.Class{
	Name: "Counter",
	Methods: map[string]object.Object{
		"__init__": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

				if len(args) == 0 {
					return &object.Null{}
				}
				counter := args[0].(*object.Instance)

				if len(args) == 1 {
					return &object.Null{}
				}
				if err := errors.MaxArgs(args, 2); err != nil {
					return err
				}

				countKey := func(key string) {
					if countObj, exists := counter.Fields[key]; exists {
						if count, ok := countObj.(*object.Integer); ok {
							counter.Fields[key] = object.NewInteger(count.Value + 1)
						}
					} else {
						counter.Fields[key] = object.NewInteger(1)
					}
				}

				switch arg := args[1].(type) {
				case *object.List:
					for _, elem := range arg.Elements {
						countKey(elem.Inspect())
					}
				case *object.Tuple:
					for _, elem := range arg.Elements {
						countKey(elem.Inspect())
					}
				case *object.String:
					for _, ch := range arg.Value {
						countKey(string(ch))
					}
				case *object.Dict:

					for k, v := range arg.Pairs {
						if count, ok := v.Value.(*object.Integer); ok {
							counter.Fields[k] = count
						}
					}
				default:
					return errors.NewTypeError("iterable or dict", args[1].Type().String())
				}

				return &object.Null{}
			},
		},
		"__getitem__": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

				if err := errors.ExactArgs(args, 2); err != nil {
					return err
				}
				counter := args[0].(*object.Instance)
				key := args[1].Inspect()

				if count, ok := counter.Fields[key]; ok {
					return count
				}

				return &object.Integer{Value: 0}
			},
			HelpText: `__getitem__(key) - Get count for key (supports c[key] syntax)`,
		},
		"most_common": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

				counter := args[0].(*object.Instance)

				n := len(counter.Fields)
				if len(args) == 2 {
					if nArg, ok := args[1].(*object.Integer); ok {
						n = int(nArg.Value)
					} else {
						return errors.NewTypeError("INTEGER", args[1].Type().String())
					}
				}

				// Convert to sortable slice
				type pair struct {
					key   string
					count int64
				}
				pairs := make([]pair, 0, len(counter.Fields))
				for key, countObj := range counter.Fields {
					if count, ok := countObj.(*object.Integer); ok {
						pairs = append(pairs, pair{key: key, count: count.Value})
					}
				}

				sort.Slice(pairs, func(i, j int) bool {
					return pairs[i].count > pairs[j].count
				})

				if n > len(pairs) {
					n = len(pairs)
				}
				result := make([]object.Object, n)
				for i := 0; i < n; i++ {
					key := pairs[i].key

					if intVal, err := strconv.ParseInt(key, 10, 64); err == nil {
						result[i] = &object.Tuple{Elements: []object.Object{
							object.NewInteger(intVal),
							object.NewInteger(pairs[i].count),
						}}
					} else {
						result[i] = &object.Tuple{Elements: []object.Object{
							&object.String{Value: key},
							object.NewInteger(pairs[i].count),
						}}
					}
				}
				return &object.List{Elements: result}
			},
			HelpText: `most_common([n]) - Return n most common elements

Returns a list of (element, count) tuples sorted by count descending.
If n is omitted, returns all elements.`,
		},
		"elements": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.NoArgs(args); err != nil {
					return err
				}
				counter := args[0].(*object.Instance)

				var result []object.Object
				for key, countObj := range counter.Fields {
					if count, ok := countObj.(*object.Integer); ok {
						for i := int64(0); i < count.Value; i++ {
							result = append(result, &object.String{Value: key})
						}
					}
				}
				return &object.List{Elements: result}
			},
			HelpText: `elements() - Return iterator over elements

Returns an iterator over elements, repeating each element by its count.`,
		},
	},
}

Counter class for counting elements

View Source
var DatetimeLibrary = object.NewLibrary(
	map[string]*object.Builtin{
		"timedelta": timedeltaBuiltinNew,
		"datetime":  datetimeConstructorBuiltin,
		"date":      dateConstructorBuiltin,
	},
	nil,
	"Date and time manipulation library.",
)

DatetimeLibrary is the main datetime module

View Source
var DefaultDictClass = &object.Class{
	Name: "DefaultDict",
	Methods: map[string]object.Object{
		"__init__": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

				if err := errors.ExactArgs(args, 2); err != nil {
					return err
				}
				dd := args[0].(*object.Instance)
				factory := args[1]

				dd.Fields["__default_factory__"] = factory
				return &object.Null{}
			},
		},
		"__getitem__": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

				if err := errors.ExactArgs(args, 2); err != nil {
					return err
				}
				dd := args[0].(*object.Instance)
				key := args[1].Inspect()

				if value, exists := dd.Fields[key]; exists {
					return value
				}

				factory, hasFactory := dd.Fields["__default_factory__"]
				if !hasFactory {
					return &object.Null{}
				}

				// Create default value based on factory
				var defaultValue object.Object
				switch f := factory.(type) {
				case *object.Builtin:

					defaultValue = f.Fn(ctx, object.NewKwargs(nil))
					if object.IsError(defaultValue) {

						defaultValue = f.Fn(ctx, object.NewKwargs(nil), object.NewInteger(0))
						if object.IsError(defaultValue) {
							return defaultValue
						}
					}
				case *object.String:

					switch f.Value {
					case "int":
						defaultValue = object.NewInteger(0)
					case "float":
						defaultValue = &object.Float{Value: 0}
					case "str":
						defaultValue = &object.String{Value: ""}
					case "list":
						defaultValue = &object.List{Elements: []object.Object{}}
					case "dict":
						defaultValue = &object.Dict{Pairs: make(map[string]object.DictPair)}
					default:
						return errors.NewError("unknown default factory type: %s", f.Value)
					}
				default:
					return errors.NewError("default_factory must be a builtin function or type name")
				}

				dd.Fields[key] = defaultValue
				return defaultValue
			},
			HelpText: `__getitem__(key) - Get value with default creation (supports d[key] syntax)`,
		},
		"__setitem__": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

				if err := errors.ExactArgs(args, 3); err != nil {
					return err
				}
				dd := args[0].(*object.Instance)
				key := args[1].Inspect()
				value := args[2]

				dd.Fields[key] = value
				return &object.Null{}
			},
			HelpText: `__setitem__(key, value) - Set value (supports d[key] = value syntax)`,
		},
	},
}

DefaultDict class for dicts with default factory behavior

View Source
var FunctoolsLibrary = object.NewLibrary(map[string]*object.Builtin{
	"reduce": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return errors.NewError("reduce() requires 2 or 3 arguments")
			}

			fn, ok := args[0].(*object.Function)
			if !ok {

				if builtin, ok := args[0].(*object.Builtin); ok {
					return reduceWithBuiltin(ctx, builtin, args[1:])
				}
				return errors.NewTypeError("FUNCTION", args[0].Type().String())
			}

			list, ok := args[1].(*object.List)
			if !ok {
				return errors.NewTypeError("LIST", args[1].Type().String())
			}

			if len(list.Elements) == 0 {
				if len(args) == 3 {
					return args[2]
				}
				return errors.NewError("reduce() of empty sequence with no initial value")
			}

			// Get initial accumulator
			var accumulator object.Object
			startIdx := 0
			if len(args) == 3 {
				accumulator = args[2]
			} else {
				accumulator = list.Elements[0]
				startIdx = 1
			}

			for i := startIdx; i < len(list.Elements); i++ {

				fnEnv := object.NewEnclosedEnvironment(fn.Env)
				if len(fn.Parameters) != 2 {
					return errors.NewError("reduce function must take exactly 2 arguments")
				}
				fnEnv.Set(fn.Parameters[0].Value, accumulator)
				fnEnv.Set(fn.Parameters[1].Value, list.Elements[i])

				result := callFunction(ctx, fn, []object.Object{accumulator, list.Elements[i]}, nil)
				if result == nil {
					return errors.NewError("reduce function returned nil")
				}
				if object.IsError(result) {
					return result
				}
				accumulator = result
			}

			return accumulator
		},
		HelpText: `reduce(function, iterable[, initializer]) - Apply function cumulatively to items

Parameters:
  function    - Function taking 2 arguments (accumulator, item)
  iterable    - List of items to reduce
  initializer - Optional starting value

Returns: Reduced value

Example:
  import functools

  def add(x, y):
      return x + y

  functools.reduce(add, [1, 2, 3, 4])  # 10
  functools.reduce(add, [1, 2, 3], 10)  # 16`,
	},
	"partial": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 1 {
				return errors.NewError("partial() requires at least 1 argument")
			}

			// First arg must be a function or builtin
			var fn *object.Function
			var builtin *object.Builtin
			if f, ok := args[0].(*object.Function); ok {
				fn = f
			} else if b, ok := args[0].(*object.Builtin); ok {
				builtin = b
			} else {
				return errors.NewTypeError("FUNCTION", args[0].Type().String())
			}

			partialArgs := args[1:]
			partialKwargs := make(map[string]object.Object)
			for k, v := range kwargs.Kwargs {
				partialKwargs[k] = v
			}

			return &object.Builtin{
				Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

					allArgs := append(partialArgs, args...)
					allKwargs := make(map[string]object.Object)
					for k, v := range partialKwargs {
						allKwargs[k] = v
					}
					for k, v := range kwargs.Kwargs {
						allKwargs[k] = v
					}

					if fn != nil {
						return callFunction(ctx, fn, allArgs, allKwargs)
					} else {
						return builtin.Fn(ctx, object.NewKwargs(allKwargs), allArgs...)
					}
				},
				HelpText: "Partial function application",
			}
		},
		HelpText: `partial(func, *args, **kwargs) - Create a partial function application

Parameters:
  func - Function to partially apply
  *args - Arguments to pre-fill
  **kwargs - Keyword arguments to pre-fill

Returns: New function with pre-filled arguments

Example:
  import functools

  def add(x, y):
      return x + y

  add_five = functools.partial(add, 5)
  add_five(3)  # 8`,
	},
}, nil, "Higher-order functions and operations on callable objects")
View Source
var HTMLLibrary = object.NewLibrary(map[string]*object.Builtin{
	"escape": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			str, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}
			return &object.String{Value: html.EscapeString(str.Value)}
		},
		HelpText: `escape(s) - Escape HTML special characters

Converts &, <, >, ", and ' to HTML-safe sequences.

Parameters:
  s - String to escape

Returns: Escaped string

Example:
  import html
  safe = html.escape("<script>alert('xss')</script>")
  print(safe)  # "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;"`,
	},
	"unescape": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			str, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}

			result := html.UnescapeString(str.Value)

			result = unescapeNumericEntities(result)
			return &object.String{Value: result}
		},
		HelpText: `unescape(s) - Unescape HTML entities

Converts HTML entities back to their corresponding characters.
Handles named entities (&lt;, &gt;, &amp;, &quot;, &#39;) and
numeric entities (&#60;, &#x3c;).

Parameters:
  s - String with HTML entities to unescape

Returns: Unescaped string

Example:
  import html
  text = html.unescape("&lt;script&gt;")
  print(text)  # "<script>"`,
	},
}, nil, "HTML escaping and unescaping library")
View Source
var HashlibLibrary = object.NewLibrary(map[string]*object.Builtin{
	"sha256": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			str, err := args[0].AsString()
			if err != nil {
				return err
			}
			hash := sha256.Sum256([]byte(str))
			return &object.String{Value: hex.EncodeToString(hash[:])}
		},
		HelpText: `sha256(string) - Compute SHA-256 hash

Returns the SHA-256 hash of the input string as a hexadecimal string.`,
	},
	"sha1": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			str, err := args[0].AsString()
			if err != nil {
				return err
			}
			hash := sha1.Sum([]byte(str))
			return &object.String{Value: hex.EncodeToString(hash[:])}
		},
		HelpText: `sha1(string) - Compute SHA-1 hash

Returns the SHA-1 hash of the input string as a hexadecimal string.`,
	},
	"md5": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			str, err := args[0].AsString()
			if err != nil {
				return err
			}
			hash := md5.Sum([]byte(str))
			return &object.String{Value: hex.EncodeToString(hash[:])}
		},
		HelpText: `md5(string) - Compute MD5 hash

Returns a hexadecimal string.`,
	},
}, nil, "Cryptographic hash functions library")
View Source
var ItertoolsLibrary = object.NewLibrary(map[string]*object.Builtin{
	"chain": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			result := []object.Object{}
			for _, arg := range args {
				switch a := arg.(type) {
				case *object.List:
					result = append(result, a.Elements...)
				case *object.Tuple:
					result = append(result, a.Elements...)
				case *object.String:
					for _, ch := range a.Value {
						result = append(result, &object.String{Value: string(ch)})
					}
				default:
					return errors.NewTypeError("iterable", arg.Type().String())
				}
			}
			return &object.List{Elements: result}
		},
		HelpText: `chain(*iterables) - Chain multiple iterables together

Returns a list with elements from all iterables concatenated.

Example:
  itertools.chain([1, 2], [3, 4]) -> [1, 2, 3, 4]
  itertools.chain("ab", "cd") -> ["a", "b", "c", "d"]`,
	},
	"repeat": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}
			elem := args[0]
			times := int64(1)
			if len(args) == 2 {
				if n, ok := args[1].(*object.Integer); ok {
					times = n.Value
				} else {
					return errors.NewTypeError("INTEGER", args[1].Type().String())
				}
			}
			if times < 0 {
				times = 0
			}
			result := make([]object.Object, times)
			for i := int64(0); i < times; i++ {
				result[i] = elem
			}
			return &object.List{Elements: result}
		},
		HelpText: `repeat(elem, n) - Repeat element n times

Returns a list with the element repeated n times.

Example:
  itertools.repeat("x", 3) -> ["x", "x", "x"]
  itertools.repeat(0, 5) -> [0, 0, 0, 0, 0]`,
	},
	"cycle": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			case *object.String:
				for _, ch := range a.Value {
					elements = append(elements, &object.String{Value: string(ch)})
				}
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}
			n, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			if len(elements) == 0 || n.Value <= 0 {
				return &object.List{Elements: []object.Object{}}
			}
			result := make([]object.Object, 0, len(elements)*int(n.Value))
			for i := int64(0); i < n.Value; i++ {
				result = append(result, elements...)
			}
			return &object.List{Elements: result}
		},
		HelpText: `cycle(iterable, n) - Cycle through iterable n times

Returns a list with elements of iterable repeated n times.
Note: Unlike Python's infinite cycle, this requires specifying the count.

Example:
  itertools.cycle([1, 2, 3], 2) -> [1, 2, 3, 1, 2, 3]`,
	},
	"count": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.RangeArgs(args, 2, 3); err != nil {
				return err
			}
			start, ok := args[0].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[0].Type().String())
			}
			stop, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			step := int64(1)
			if len(args) == 3 {
				if s, ok := args[2].(*object.Integer); ok {
					step = s.Value
				} else {
					return errors.NewTypeError("INTEGER", args[2].Type().String())
				}
			}
			if step == 0 {
				return errors.NewError("step cannot be zero")
			}
			result := []object.Object{}
			if step > 0 {
				for i := start.Value; i < stop.Value; i += step {
					result = append(result, object.NewInteger(i))
				}
			} else {
				for i := start.Value; i > stop.Value; i += step {
					result = append(result, object.NewInteger(i))
				}
			}
			return &object.List{Elements: result}
		},
		HelpText: `count(start, stop[, step]) - Generate a sequence of numbers

Returns a list of numbers from start to stop (exclusive) with optional step.
Similar to range() but as an itertools function.

Example:
  itertools.count(0, 5) -> [0, 1, 2, 3, 4]
  itertools.count(0, 10, 2) -> [0, 2, 4, 6, 8]`,
	},
	"islice": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.RangeArgs(args, 2, 4); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			case *object.String:
				for _, ch := range a.Value {
					elements = append(elements, &object.String{Value: string(ch)})
				}
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			var start, stop, step int64 = 0, 0, 1
			if len(args) == 2 {

				if s, ok := args[1].(*object.Integer); ok {
					stop = s.Value
				} else {
					return errors.NewTypeError("INTEGER", args[1].Type().String())
				}
			} else {

				if s, ok := args[1].(*object.Integer); ok {
					start = s.Value
				} else {
					return errors.NewTypeError("INTEGER", args[1].Type().String())
				}
				if s, ok := args[2].(*object.Integer); ok {
					stop = s.Value
				} else {
					return errors.NewTypeError("INTEGER", args[2].Type().String())
				}
				if len(args) == 4 {
					if s, ok := args[3].(*object.Integer); ok {
						step = s.Value
					} else {
						return errors.NewTypeError("INTEGER", args[3].Type().String())
					}
				}
			}

			if step <= 0 {
				return errors.NewError("step must be positive")
			}
			if start < 0 {
				start = 0
			}
			if stop > int64(len(elements)) {
				stop = int64(len(elements))
			}

			result := []object.Object{}
			for i := start; i < stop; i += step {
				result = append(result, elements[i])
			}
			return &object.List{Elements: result}
		},
		HelpText: `islice(iterable, stop) or islice(iterable, start, stop[, step]) - Slice an iterable

Returns a list with elements from the iterable sliced by indices.

Example:
  itertools.islice([0, 1, 2, 3, 4], 3) -> [0, 1, 2]
  itertools.islice([0, 1, 2, 3, 4], 1, 4) -> [1, 2, 3]
  itertools.islice([0, 1, 2, 3, 4], 0, 5, 2) -> [0, 2, 4]`,
	},
	"takewhile": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			pred, ok := args[0].(*object.Builtin)
			if !ok {
				return errors.NewError("takewhile() predicate must be a builtin function")
			}
			var elements []object.Object
			switch a := args[1].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			default:
				return errors.NewTypeError("iterable", args[1].Type().String())
			}
			result := []object.Object{}
			for _, elem := range elements {
				res := pred.Fn(ctx, object.NewKwargs(nil), elem)
				if object.IsError(res) {
					return res
				}
				if !isTruthy(res) {
					break
				}
				result = append(result, elem)
			}
			return &object.List{Elements: result}
		},
		HelpText: `takewhile(predicate, iterable) - Take elements while predicate is true

Returns a list with elements from the start of iterable as long as predicate is true.

Example:
  itertools.takewhile(lambda x: x < 5, [1, 3, 5, 2, 4]) -> [1, 3]`,
	},
	"dropwhile": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			pred, ok := args[0].(*object.Builtin)
			if !ok {
				return errors.NewError("dropwhile() predicate must be a builtin function")
			}
			var elements []object.Object
			switch a := args[1].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			default:
				return errors.NewTypeError("iterable", args[1].Type().String())
			}
			result := []object.Object{}
			dropping := true
			for _, elem := range elements {
				if dropping {
					res := pred.Fn(ctx, object.NewKwargs(nil), elem)
					if object.IsError(res) {
						return res
					}
					if isTruthy(res) {
						continue
					}
					dropping = false
				}
				result = append(result, elem)
			}
			return &object.List{Elements: result}
		},
		HelpText: `dropwhile(predicate, iterable) - Drop elements while predicate is true

Returns a list with elements after the predicate becomes false.

Example:
  itertools.dropwhile(lambda x: x < 5, [1, 3, 5, 2, 4]) -> [5, 2, 4]`,
	},
	"zip_longest": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if len(args) < 1 {
				return &object.List{Elements: []object.Object{}}
			}

			fillvalue := object.Object(&object.Null{})
			if kwargs.Len() > 0 {
				if kwargs.Has("fillvalue") {
					fillvalue = kwargs.Get("fillvalue")
				}
			}

			iterables := make([][]object.Object, len(args))
			maxLen := 0
			for i, arg := range args {
				switch a := arg.(type) {
				case *object.List:
					iterables[i] = a.Elements
				case *object.Tuple:
					iterables[i] = a.Elements
				case *object.String:
					chars := []object.Object{}
					for _, ch := range a.Value {
						chars = append(chars, &object.String{Value: string(ch)})
					}
					iterables[i] = chars
				default:
					return errors.NewTypeError("iterable", arg.Type().String())
				}
				if len(iterables[i]) > maxLen {
					maxLen = len(iterables[i])
				}
			}

			result := []object.Object{}
			for j := 0; j < maxLen; j++ {
				tuple := make([]object.Object, len(iterables))
				for i, iter := range iterables {
					if j < len(iter) {
						tuple[i] = iter[j]
					} else {
						tuple[i] = fillvalue
					}
				}
				result = append(result, &object.Tuple{Elements: tuple})
			}
			return &object.List{Elements: result}
		},
		HelpText: `zip_longest(*iterables, fillvalue=None) - Zip iterables, filling shorter ones

Zips iterables together, using fillvalue for missing values in shorter iterables.

Example:
  itertools.zip_longest([1, 2, 3], ["a", "b"]) -> [(1, "a"), (2, "b"), (3, None)]
  itertools.zip_longest([1, 2], ["a"], fillvalue="-") -> [(1, "a"), (2, "-")]`,
	},
	"product": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if len(args) < 1 {
				return &object.List{Elements: []object.Object{&object.Tuple{Elements: []object.Object{}}}}
			}

			iterables := make([][]object.Object, len(args))
			for i, arg := range args {
				switch a := arg.(type) {
				case *object.List:
					iterables[i] = a.Elements
				case *object.Tuple:
					iterables[i] = a.Elements
				case *object.String:
					chars := []object.Object{}
					for _, ch := range a.Value {
						chars = append(chars, &object.String{Value: string(ch)})
					}
					iterables[i] = chars
				default:
					return errors.NewTypeError("iterable", arg.Type().String())
				}
			}

			for _, iter := range iterables {
				if len(iter) == 0 {
					return &object.List{Elements: []object.Object{}}
				}
			}

			result := []object.Object{}
			indices := make([]int, len(iterables))

			for {

				tuple := make([]object.Object, len(iterables))
				for i, idx := range indices {
					tuple[i] = iterables[i][idx]
				}
				result = append(result, &object.Tuple{Elements: tuple})

				carry := true
				for i := len(indices) - 1; i >= 0 && carry; i-- {
					indices[i]++
					if indices[i] >= len(iterables[i]) {
						indices[i] = 0
					} else {
						carry = false
					}
				}
				if carry {
					break
				}
			}
			return &object.List{Elements: result}
		},
		HelpText: `product(*iterables) - Cartesian product of iterables

Returns all possible combinations (tuples) of elements from input iterables.

Example:
  itertools.product([1, 2], ["a", "b"]) -> [(1, "a"), (1, "b"), (2, "a"), (2, "b")]
  itertools.product([1, 2], [3, 4]) -> [(1, 3), (1, 4), (2, 3), (2, 4)]`,
	},
	"permutations": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			case *object.String:
				for _, ch := range a.Value {
					elements = append(elements, &object.String{Value: string(ch)})
				}
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			r := len(elements)
			if len(args) == 2 {
				if rArg, ok := args[1].(*object.Integer); ok {
					r = int(rArg.Value)
				} else {
					return errors.NewTypeError("INTEGER", args[1].Type().String())
				}
			}

			if r < 0 || r > len(elements) {
				return &object.List{Elements: []object.Object{}}
			}

			result := []object.Object{}
			generatePermutations(elements, r, []object.Object{}, make([]bool, len(elements)), &result)
			return &object.List{Elements: result}
		},
		HelpText: `permutations(iterable[, r]) - Generate permutations

Returns all r-length permutations of elements from iterable.
If r is not specified, defaults to length of iterable (full permutations).

Example:
  itertools.permutations([1, 2, 3], 2) -> [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
  itertools.permutations("ab") -> [("a", "b"), ("b", "a")]`,
	},
	"combinations": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			case *object.String:
				for _, ch := range a.Value {
					elements = append(elements, &object.String{Value: string(ch)})
				}
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			rArg, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			r := int(rArg.Value)

			if r < 0 || r > len(elements) {
				return &object.List{Elements: []object.Object{}}
			}

			result := []object.Object{}
			generateCombinations(elements, r, 0, []object.Object{}, &result)
			return &object.List{Elements: result}
		},
		HelpText: `combinations(iterable, r) - Generate combinations

Returns all r-length combinations of elements from iterable (without repetition).

Example:
  itertools.combinations([1, 2, 3], 2) -> [(1, 2), (1, 3), (2, 3)]
  itertools.combinations("abc", 2) -> [("a", "b"), ("a", "c"), ("b", "c")]`,
	},
	"combinations_with_replacement": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			case *object.String:
				for _, ch := range a.Value {
					elements = append(elements, &object.String{Value: string(ch)})
				}
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			rArg, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			r := int(rArg.Value)

			if r < 0 {
				return &object.List{Elements: []object.Object{}}
			}
			if len(elements) == 0 && r > 0 {
				return &object.List{Elements: []object.Object{}}
			}

			result := []object.Object{}
			generateCombinationsWithReplacement(elements, r, 0, []object.Object{}, &result)
			return &object.List{Elements: result}
		},
		HelpText: `combinations_with_replacement(iterable, r) - Generate combinations with replacement

Returns all r-length combinations of elements from iterable (with repetition allowed).

Example:
  itertools.combinations_with_replacement([1, 2], 2) -> [(1, 1), (1, 2), (2, 2)]
  itertools.combinations_with_replacement("ab", 2) -> [("a", "a"), ("a", "b"), ("b", "b")]`,
	},
	"groupby": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			var keyFunc *object.Builtin
			if len(args) == 2 {
				var ok bool
				keyFunc, ok = args[1].(*object.Builtin)
				if !ok {
					return errors.NewError("groupby() key must be a builtin function")
				}
			}

			if len(elements) == 0 {
				return &object.List{Elements: []object.Object{}}
			}

			result := []object.Object{}
			var currentKey object.Object
			var currentGroup []object.Object

			for i, elem := range elements {
				var key object.Object
				if keyFunc != nil {
					key = keyFunc.Fn(ctx, object.NewKwargs(nil), elem)
					if object.IsError(key) {
						return key
					}
				} else {
					key = elem
				}

				if i == 0 {
					currentKey = key
					currentGroup = []object.Object{elem}
				} else if objectsEqual(key, currentKey) {
					currentGroup = append(currentGroup, elem)
				} else {

					result = append(result, &object.Tuple{Elements: []object.Object{
						currentKey,
						&object.List{Elements: currentGroup},
					}})
					currentKey = key
					currentGroup = []object.Object{elem}
				}
			}

			if len(currentGroup) > 0 {
				result = append(result, &object.Tuple{Elements: []object.Object{
					currentKey,
					&object.List{Elements: currentGroup},
				}})
			}

			return &object.List{Elements: result}
		},
		HelpText: `groupby(iterable[, key]) - Group consecutive elements

Groups consecutive elements that have the same key value.
Returns list of (key, group) tuples where group is a list.

Example:
  itertools.groupby([1, 1, 2, 2, 3]) -> [(1, [1, 1]), (2, [2, 2]), (3, [3])]
  itertools.groupby(["aa", "ab", "ba"], lambda x: x[0]) -> [("a", ["aa", "ab"]), ("b", ["ba"])]`,
	},
	"accumulate": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			if len(elements) == 0 {
				return &object.List{Elements: []object.Object{}}
			}

			var accumFunc *object.Builtin
			if len(args) == 2 {
				var ok bool
				accumFunc, ok = args[1].(*object.Builtin)
				if !ok {
					return errors.NewError("accumulate() func must be a builtin function")
				}
			}

			result := []object.Object{elements[0]}
			accumulator := elements[0]

			for i := 1; i < len(elements); i++ {
				if accumFunc != nil {
					accumulator = accumFunc.Fn(ctx, object.NewKwargs(nil), accumulator, elements[i])
					if object.IsError(accumulator) {
						return accumulator
					}
				} else {

					accumulator = addObjects(accumulator, elements[i])
					if object.IsError(accumulator) {
						return accumulator
					}
				}
				result = append(result, accumulator)
			}
			return &object.List{Elements: result}
		},
		HelpText: `accumulate(iterable[, func]) - Running totals/accumulation

Returns list of accumulated values. Default is sum, but can provide custom function.

Example:
  itertools.accumulate([1, 2, 3, 4]) -> [1, 3, 6, 10]
  itertools.accumulate([1, 2, 3], operator.mul) -> [1, 2, 6]`,
	},
	"filterfalse": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			pred, ok := args[0].(*object.Builtin)
			if !ok {
				return errors.NewError("filterfalse() predicate must be a builtin function")
			}
			var elements []object.Object
			switch a := args[1].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			default:
				return errors.NewTypeError("iterable", args[1].Type().String())
			}
			result := []object.Object{}
			for _, elem := range elements {
				res := pred.Fn(ctx, object.NewKwargs(nil), elem)
				if object.IsError(res) {
					return res
				}
				if !isTruthy(res) {
					result = append(result, elem)
				}
			}
			return &object.List{Elements: result}
		},
		HelpText: `filterfalse(predicate, iterable) - Filter elements where predicate is false

Returns elements for which the predicate returns false.

Example:
  itertools.filterfalse(lambda x: x % 2, [1, 2, 3, 4]) -> [2, 4]`,
	},
	"starmap": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			fn, ok := args[0].(*object.Builtin)
			if !ok {
				return errors.NewError("starmap() func must be a builtin function")
			}
			var elements []object.Object
			switch a := args[1].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			default:
				return errors.NewTypeError("iterable", args[1].Type().String())
			}
			result := []object.Object{}
			for _, elem := range elements {
				var fnArgs []object.Object
				switch e := elem.(type) {
				case *object.List:
					fnArgs = e.Elements
				case *object.Tuple:
					fnArgs = e.Elements
				default:
					return errors.NewError("starmap() iterable must contain sequences")
				}
				res := fn.Fn(ctx, object.NewKwargs(nil), fnArgs...)
				if object.IsError(res) {
					return res
				}
				result = append(result, res)
			}
			return &object.List{Elements: result}
		},
		HelpText: `starmap(func, iterable) - Apply function to argument tuples

Applies function using elements of each tuple as arguments.

Example:
  itertools.starmap(pow, [(2, 3), (3, 2)]) -> [8, 9]`,
	},
	"compress": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			var data []object.Object
			switch a := args[0].(type) {
			case *object.List:
				data = a.Elements
			case *object.Tuple:
				data = a.Elements
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}
			var selectors []object.Object
			switch a := args[1].(type) {
			case *object.List:
				selectors = a.Elements
			case *object.Tuple:
				selectors = a.Elements
			default:
				return errors.NewTypeError("iterable", args[1].Type().String())
			}

			result := []object.Object{}
			minLen := len(data)
			if len(selectors) < minLen {
				minLen = len(selectors)
			}
			for i := 0; i < minLen; i++ {
				if isTruthy(selectors[i]) {
					result = append(result, data[i])
				}
			}
			return &object.List{Elements: result}
		},
		HelpText: `compress(data, selectors) - Filter data based on selectors

Returns elements from data where corresponding selector is truthy.

Example:
  itertools.compress([1, 2, 3, 4], [True, False, True, False]) -> [1, 3]
  itertools.compress("abcd", [1, 0, 1, 0]) -> ["a", "c"]`,
	},
	"pairwise": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			case *object.String:
				for _, ch := range a.Value {
					elements = append(elements, &object.String{Value: string(ch)})
				}
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			if len(elements) < 2 {
				return &object.List{Elements: []object.Object{}}
			}

			result := make([]object.Object, len(elements)-1)
			for i := 0; i < len(elements)-1; i++ {
				result[i] = &object.Tuple{Elements: []object.Object{elements[i], elements[i+1]}}
			}
			return &object.List{Elements: result}
		},
		HelpText: `pairwise(iterable) - Return successive overlapping pairs

Returns consecutive pairs from the iterable.

Example:
  itertools.pairwise([1, 2, 3, 4]) -> [(1, 2), (2, 3), (3, 4)]
  itertools.pairwise("abc") -> [("a", "b"), ("b", "c")]`,
	},
	"batched": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {

			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			var elements []object.Object
			switch a := args[0].(type) {
			case *object.List:
				elements = a.Elements
			case *object.Tuple:
				elements = a.Elements
			case *object.String:
				for _, ch := range a.Value {
					elements = append(elements, &object.String{Value: string(ch)})
				}
			default:
				return errors.NewTypeError("iterable", args[0].Type().String())
			}

			n, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			if n.Value <= 0 {
				return errors.NewError("n must be positive")
			}

			batchSize := int(n.Value)
			result := []object.Object{}
			for i := 0; i < len(elements); i += batchSize {
				end := i + batchSize
				if end > len(elements) {
					end = len(elements)
				}
				batch := make([]object.Object, end-i)
				copy(batch, elements[i:end])
				result = append(result, &object.Tuple{Elements: batch})
			}
			return &object.List{Elements: result}
		},
		HelpText: `batched(iterable, n) - Batch elements into tuples of size n

Groups elements into batches of n elements each.

Example:
  itertools.batched([1, 2, 3, 4, 5], 2) -> [(1, 2), (3, 4), (5,)]
  itertools.batched("abcdef", 3) -> [("a", "b", "c"), ("d", "e", "f")]`,
	},
}, nil, "Python-compatible itertools library for iteration utilities")

ItertoolsLibrary provides Python-like itertools functions

View Source
var JSONLibrary = object.NewLibrary(map[string]*object.Builtin{
	"loads": {
		Fn: jsonLoads,
		HelpText: `loads(json_string) - Parse JSON string

Parses a JSON string and returns the corresponding Scriptling object.`,
	},
	"dumps": {
		Fn: jsonDumps,
		HelpText: `dumps(obj, indent="") - Serialize object to JSON string

Converts a Scriptling object to its JSON string representation.
Optional indent parameter for pretty-printing.`,
	},
	"parse": {
		Fn: jsonLoads,
		HelpText: `parse(json_string) - Parse JSON string (alias for loads)

Parses a JSON string and returns the corresponding Scriptling object.`,
	},
	"stringify": {
		Fn: jsonDumps,
		HelpText: `stringify(obj, indent="") - Serialize object to JSON string (alias for dumps)

Converts a Scriptling object to its JSON string representation.
Optional indent parameter for pretty-printing.`,
	},
}, nil, "JSON encoding and decoding library")
View Source
var MatchClass = &object.Class{
	Name: "Match",
	Methods: map[string]object.Object{
		"group": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if len(args) > 2 {
					return errors.NewError("group() takes at most 1 argument (%d given)", len(args))
				}
				match := args[0].(*object.Instance)
				groups := match.Fields["groups"].(*object.List).Elements
				groupNum := 0
				if len(args) == 2 {
					if args[1].Type() != object.INTEGER_OBJ {
						return errors.NewTypeError("INTEGER", args[1].Type().String())
					}
					val, _ := args[1].AsInt()
					groupNum = int(val)
				}
				if groupNum < 0 || groupNum >= len(groups) {
					return errors.NewError("no such group: %d", groupNum)
				}
				return groups[groupNum]
			},
			HelpText: `group(n=0) - Return the nth matched group (0 = full match)`,
		},
		"groups": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.ExactArgs(args, 1); err != nil {
					return err
				}
				match := args[0].(*object.Instance)
				groups := match.Fields["groups"].(*object.List).Elements
				if len(groups) <= 1 {
					return &object.Tuple{Elements: []object.Object{}}
				}
				elements := make([]object.Object, len(groups)-1)
				for i := 1; i < len(groups); i++ {
					elements[i-1] = groups[i]
				}
				return &object.Tuple{Elements: elements}
			},
			HelpText: `groups() - Return tuple of all matched groups (excluding group 0)`,
		},
		"start": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if len(args) > 2 {
					return errors.NewError("start() takes at most 1 argument (%d given)", len(args))
				}
				match := args[0].(*object.Instance)
				groupNum := 0
				if len(args) == 2 {
					if args[1].Type() != object.INTEGER_OBJ {
						return errors.NewTypeError("INTEGER", args[1].Type().String())
					}
					val, _ := args[1].AsInt()
					groupNum = int(val)
				}
				if groupNum != 0 {
					return errors.NewError("start() only supports group 0")
				}
				return match.Fields["start"]
			},
			HelpText: `start(n=0) - Return start position of nth group`,
		},
		"end": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if len(args) > 2 {
					return errors.NewError("end() takes at most 1 argument (%d given)", len(args))
				}
				match := args[0].(*object.Instance)
				groupNum := 0
				if len(args) == 2 {
					if args[1].Type() != object.INTEGER_OBJ {
						return errors.NewTypeError("INTEGER", args[1].Type().String())
					}
					val, _ := args[1].AsInt()
					groupNum = int(val)
				}
				if groupNum != 0 {
					return errors.NewError("end() only supports group 0")
				}
				return match.Fields["end"]
			},
			HelpText: `end(n=0) - Return end position of nth group`,
		},
		"span": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if len(args) > 2 {
					return errors.NewError("span() takes at most 1 argument (%d given)", len(args))
				}
				match := args[0].(*object.Instance)
				groupNum := 0
				if len(args) == 2 {
					if args[1].Type() != object.INTEGER_OBJ {
						return errors.NewTypeError("INTEGER", args[1].Type().String())
					}
					val, _ := args[1].AsInt()
					groupNum = int(val)
				}
				if groupNum != 0 {
					return errors.NewError("span() only supports group 0")
				}
				return &object.Tuple{Elements: []object.Object{
					match.Fields["start"],
					match.Fields["end"],
				}}
			},
			HelpText: `span(n=0) - Return (start, end) tuple for nth group`,
		},
	},
}

Match class definition

View Source
var MathLibrary = object.NewLibrary(map[string]*object.Builtin{
	"sqrt": {
		Fn: oneFloatFunc(math.Sqrt),
		HelpText: `sqrt(x) - Return the square root of x

x must be a non-negative number (integer or float).
Returns a float.`,
	},
	"pow": {
		Fn: twoFloatFunc(math.Pow),
		HelpText: `pow(base, exp) - Return base raised to the power exp

base and exp can be integers or floats.
Returns a float.`,
	},
	"fabs": {
		Fn: oneFloatFunc(math.Abs),
		HelpText: `fabs(x) - Return the absolute value of x as a float

x can be an integer or float.
Always returns a float.`,
	},
	"floor": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			switch arg := args[0].(type) {
			case *object.Integer:
				return arg
			case *object.Float:
				return &object.Integer{Value: int64(math.Floor(arg.Value))}
			default:
				return errors.NewTypeError("INTEGER or FLOAT", arg.Type().String())
			}
		},
		HelpText: `floor(x) - Return the floor of x

x can be an integer or float.
Returns the largest integer less than or equal to x.`,
	},
	"ceil": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			switch arg := args[0].(type) {
			case *object.Integer:
				return arg
			case *object.Float:
				return &object.Integer{Value: int64(math.Ceil(arg.Value))}
			default:
				return errors.NewTypeError("INTEGER or FLOAT", arg.Type().String())
			}
		},
		HelpText: `ceil(x) - Return the ceiling of x

x can be an integer or float.
Returns the smallest integer greater than or equal to x.`,
	},

	"sin": {
		Fn: oneFloatFunc(math.Sin),
		HelpText: `sin(x) - Return the sine of x (radians)

x can be an integer or float in radians.
Returns a float.`,
	},
	"cos": {
		Fn: oneFloatFunc(math.Cos),
		HelpText: `cos(x) - Return the cosine of x (radians)

x can be an integer or float in radians.
Returns a float.`,
	},
	"tan": {
		Fn: oneFloatFunc(math.Tan),
		HelpText: `tan(x) - Return the tangent of x (radians)

x can be an integer or float in radians.
Returns a float.`,
	},
	"log": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			x, err := args[0].AsFloat()
			if err != nil {
				return errors.NewTypeError("INTEGER or FLOAT", args[0].Type().String())
			}
			if x <= 0 {
				return errors.NewError("log: domain error")
			}
			return &object.Float{Value: math.Log(x)}
		},
		HelpText: `log(x) - Return the natural logarithm of x

x must be positive (integer or float).
Returns a float.`,
	},
	"exp": {
		Fn: oneFloatFunc(math.Exp),
		HelpText: `exp(x) - Return e raised to the power x

x can be an integer or float.
Returns a float.`,
	},
	"degrees": {
		Fn: oneFloatFunc(func(x float64) float64 { return x * 180.0 / math.Pi }),
		HelpText: `degrees(x) - Convert radians to degrees

x can be an integer or float in radians.
Returns a float in degrees.`,
	},
	"radians": {
		Fn: oneFloatFunc(func(x float64) float64 { return x * math.Pi / 180.0 }),
		HelpText: `radians(x) - Convert degrees to radians

x can be an integer or float in degrees.
Returns a float in radians.`,
	},
	"fmod": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			x, err := args[0].AsFloat()
			if err != nil {
				return errors.NewTypeError("INTEGER or FLOAT", args[0].Type().String())
			}
			y, err := args[1].AsFloat()
			if err != nil {
				return errors.NewTypeError("INTEGER or FLOAT", args[1].Type().String())
			}
			if y == 0 {
				return errors.NewError("fmod: division by zero")
			}
			return &object.Float{Value: math.Mod(x, y)}
		},
		HelpText: `fmod(x, y) - Return the floating-point remainder of x/y

x and y can be integers or floats.
y must not be zero. Returns a float.`,
	},
	"gcd": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			a, err := args[0].AsInt()
			if err != nil {
				return errors.NewTypeError("INTEGER", args[0].Type().String())
			}
			b, err := args[1].AsInt()
			if err != nil {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			return &object.Integer{Value: gcd(a, b)}
		},
		HelpText: `gcd(a, b) - Return the greatest common divisor of a and b

a and b must be integers.
Returns an integer.`,
	},
	"factorial": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			n, err := args[0].AsInt()
			if err != nil {
				return errors.NewTypeError("INTEGER", args[0].Type().String())
			}
			if n < 0 {
				return errors.NewError("factorial: negative number")
			}
			if n > 20 {
				return errors.NewError("factorial: result too large")
			}
			result := int64(1)
			for i := int64(2); i <= n; i++ {
				result *= i
			}
			return &object.Integer{Value: result}
		},
		HelpText: `factorial(n) - Return n!

n must be a non-negative integer <= 20.
Returns an integer.`,
	},
	"isnan": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			switch arg := args[0].(type) {
			case *object.Integer:
				return &object.Boolean{Value: false}
			case *object.Float:
				return &object.Boolean{Value: math.IsNaN(arg.Value)}
			default:
				return errors.NewTypeError("INTEGER or FLOAT", arg.Type().String())
			}
		},
		HelpText: `isnan(x) - Check if x is NaN (Not a Number)

Returns True if x is NaN, False otherwise.`,
	},
	"isinf": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			switch arg := args[0].(type) {
			case *object.Integer:
				return &object.Boolean{Value: false}
			case *object.Float:
				return &object.Boolean{Value: math.IsInf(arg.Value, 0)}
			default:
				return errors.NewTypeError("INTEGER or FLOAT", arg.Type().String())
			}
		},
		HelpText: `isinf(x) - Check if x is infinite

Returns True if x is positive or negative infinity.`,
	},
	"isfinite": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			switch arg := args[0].(type) {
			case *object.Integer:
				return &object.Boolean{Value: true}
			case *object.Float:
				return &object.Boolean{Value: !math.IsNaN(arg.Value) && !math.IsInf(arg.Value, 0)}
			default:
				return errors.NewTypeError("INTEGER or FLOAT", arg.Type().String())
			}
		},
		HelpText: `isfinite(x) - Check if x is finite

Returns True if x is neither NaN nor infinite.`,
	},
	"copysign": {
		Fn: twoFloatFunc(math.Copysign),
		HelpText: `copysign(x, y) - Return x with the sign of y

Returns a float with magnitude of x and sign of y.`,
	},
	"trunc": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			switch arg := args[0].(type) {
			case *object.Integer:
				return arg
			case *object.Float:
				return &object.Integer{Value: int64(math.Trunc(arg.Value))}
			default:
				return errors.NewTypeError("INTEGER or FLOAT", arg.Type().String())
			}
		},
		HelpText: `trunc(x) - Truncate x to the nearest integer toward zero

Returns an integer.`,
	},
	"log10": {
		Fn: oneFloatFunc(math.Log10),
		HelpText: `log10(x) - Return the base-10 logarithm of x


x must be positive. Returns a float.`,
	},
	"log2": {
		Fn: oneFloatFunc(math.Log2),
		HelpText: `log2(x) - Return the base-2 logarithm of x

x must be positive. Returns a float.`,
	},
	"hypot": {
		Fn: twoFloatFunc(math.Hypot),
		HelpText: `hypot(x, y) - Return the Euclidean distance sqrt(x*x + y*y)

Returns a float.`,
	},
	"asin": {
		Fn: oneFloatFunc(math.Asin),
		HelpText: `asin(x) - Return the arc sine of x in radians

x must be in the range [-1, 1]. Returns a float.`,
	},
	"acos": {
		Fn: oneFloatFunc(math.Acos),
		HelpText: `acos(x) - Return the arc cosine of x in radians

x must be in the range [-1, 1]. Returns a float.`,
	},
	"atan": {
		Fn: oneFloatFunc(math.Atan),
		HelpText: `atan(x) - Return the arc tangent of x in radians

Returns a float in the range [-pi/2, pi/2].`,
	},
	"atan2": {
		Fn: twoFloatFunc(math.Atan2),
		HelpText: `atan2(y, x) - Return the arc tangent of y/x in radians

Correctly handles the quadrant of the result.
Returns a float in the range [-pi, pi].`,
	},
}, map[string]object.Object{
	"pi":  &object.Float{Value: math.Pi},
	"e":   &object.Float{Value: math.E},
	"inf": &object.Float{Value: math.Inf(1)},
	"nan": &object.Float{Value: math.NaN()},
}, "Mathematical functions library")
View Source
var ParseResultClass = &object.Class{
	Name: "ParseResult",
	Methods: map[string]object.Object{
		"geturl": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.ExactArgs(args, 1); err != nil {
					return err
				}
				result := args[0].(*object.Instance)

				scheme, _ := result.Fields["scheme"].(*object.String)
				netloc, _ := result.Fields["netloc"].(*object.String)
				path, _ := result.Fields["path"].(*object.String)
				query, _ := result.Fields["query"].(*object.String)
				fragment, _ := result.Fields["fragment"].(*object.String)

				url := scheme.Value + "://"
				if netloc.Value != "" {
					url += netloc.Value
				}
				url += path.Value
				if query.Value != "" {
					url += "?" + query.Value
				}
				if fragment.Value != "" {
					url += "#" + fragment.Value
				}

				return &object.String{Value: url}
			},
			HelpText: `geturl() - Reconstruct URL from parsed components`,
		},
	},
}

ParseResult class for URL parsing results

View Source
var PlatformLibrary = object.NewLibrary(map[string]*object.Builtin{
	"python_version": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}

			return &object.String{Value: build.Version}
		},
		HelpText: `python_version() - Returns the Python version

Returns the Python version (Scriptling version for compatibility).`,
	},
	"system": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}

			switch runtime.GOOS {
			case "darwin":
				return &object.String{Value: "Darwin"}
			case "linux":
				return &object.String{Value: "Linux"}
			case "windows":
				return &object.String{Value: "Windows"}
			case "freebsd":
				return &object.String{Value: "FreeBSD"}
			default:
				return &object.String{Value: runtime.GOOS}
			}
		},
		HelpText: `system() - Returns the system/OS name

Returns 'Darwin', 'Linux', 'Windows', etc.`,
	},
	"architecture": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}

			arch := "64bit"
			if runtime.GOARCH == "386" || runtime.GOARCH == "arm" {
				arch = "32bit"
			}

			return &object.List{Elements: []object.Object{&object.String{Value: arch}, &object.String{Value: ""}}}
		},
		HelpText: `architecture() - Returns the architecture

Returns a list like ['64bit', ''] indicating bits and linkage.`,
	},
	"machine": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			return &object.String{Value: runtime.GOARCH}
		},
		HelpText: `machine() - Returns the machine type (architecture)

Returns 'amd64', 'arm64', 'arm', etc.`,
	},
	"platform": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}

			return &object.String{Value: runtime.GOOS + "-" + runtime.GOARCH}
		},
		HelpText: `platform() - Returns a string identifying the platform

Returns a string like 'darwin-amd64', 'linux-amd64', etc.`,
	},
	"scriptling_version": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			return &object.String{Value: build.Version}
		},
		HelpText: `scriptling_version() - Returns Scriptling version string

Returns the current version of Scriptling.`,
	},
	"processor": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			return &object.String{Value: runtime.GOARCH}
		},
		HelpText: `processor() - Returns the processor name

Returns the processor name, often same as machine.`,
	},
	"node": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			if hostname, err := os.Hostname(); err == nil {
				return &object.String{Value: hostname}
			}
			return &object.String{Value: ""}
		},
		HelpText: `node() - Returns the network name (hostname)

Returns the computer's network name.`,
	},
	"release": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}

			return &object.String{Value: build.Version}
		},
		HelpText: `release() - Returns the system release

Returns the system release (Scriptling version for compatibility).`,
	},
	"version": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}

			return &object.String{Value: build.Version}
		},
		HelpText: `version() - Returns the system version

Returns the system version (Scriptling version for compatibility).`,
	},
	"uname": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}

			pairs := make(map[string]object.DictPair)

			// Get system name (capitalized, matching system() function)
			var systemName string
			switch runtime.GOOS {
			case "darwin":
				systemName = "Darwin"
			case "linux":
				systemName = "Linux"
			case "windows":
				systemName = "Windows"
			case "freebsd":
				systemName = "FreeBSD"
			default:
				systemName = runtime.GOOS
			}

			pairs["system"] = object.DictPair{Key: &object.String{Value: "system"}, Value: &object.String{Value: systemName}}
			pairs["machine"] = object.DictPair{Key: &object.String{Value: "machine"}, Value: &object.String{Value: runtime.GOARCH}}
			pairs["processor"] = object.DictPair{Key: &object.String{Value: "processor"}, Value: &object.String{Value: runtime.GOARCH}}

			node := ""
			if hostname, err := os.Hostname(); err == nil {
				node = hostname
			}
			pairs["node"] = object.DictPair{Key: &object.String{Value: "node"}, Value: &object.String{Value: node}}

			pairs["release"] = object.DictPair{Key: &object.String{Value: "release"}, Value: &object.String{Value: build.Version}}
			pairs["version"] = object.DictPair{Key: &object.String{Value: "version"}, Value: &object.String{Value: build.Version}}

			return &object.Dict{Pairs: pairs}
		},
		HelpText: `uname() - Returns system information

Returns a dict with keys: system, node, release, version, machine, processor`,
	},
}, nil, "Access to underlying platform's identifying data")

PlatformLibrary provides system/platform information (Python's platform module)

View Source
var RandomLibrary = object.NewLibrary(map[string]*object.Builtin{
	"seed": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.MaxArgs(args, 1); err != nil {
				return err
			}
			var seedVal int64
			if len(args) == 0 {
				seedVal = time.Now().UnixNano()
			} else {
				switch arg := args[0].(type) {
				case *object.Integer:
					seedVal = arg.Value
				case *object.Float:
					seedVal = int64(arg.Value)
				default:
					return errors.NewTypeError("INTEGER or FLOAT", args[0].Type().String())
				}
			}
			rng = rand.New(rand.NewSource(seedVal))
			return &object.Null{}
		},
		HelpText: `seed([a]) - Initialize the random number generator

If a is omitted, current time is used. Otherwise, a is used as the seed.`,
	},
	"randint": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			var min, max int64
			switch arg := args[0].(type) {
			case *object.Integer:
				min = arg.Value
			default:
				return errors.NewTypeError("INTEGER", args[0].Type().String())
			}
			switch arg := args[1].(type) {
			case *object.Integer:
				max = arg.Value
			default:
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			if min > max {
				return errors.NewError("randint() min must be <= max")
			}
			val := min + rng.Int63n(max-min+1)
			return &object.Integer{Value: val}
		},
		HelpText: `randint(min, max) - Return random integer

Returns a random integer N such that min <= N <= max.`,
	},
	"random": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			return &object.Float{Value: rng.Float64()}
		},
		HelpText: `random() - Return random float

Returns a random float in the range [0.0, 1.0).`,
	},
	"choice": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			if str, ok := args[0].(*object.String); ok {
				if len(str.Value) == 0 {
					return errors.NewError("choice() string cannot be empty")
				}
				idx := rng.Intn(len(str.Value))
				return &object.String{Value: string(str.Value[idx])}
			}
			if list, ok := args[0].(*object.List); ok {
				if len(list.Elements) == 0 {
					return errors.NewError("choice() list cannot be empty")
				}
				idx := rng.Intn(len(list.Elements))
				return list.Elements[idx]
			}
			return errors.NewTypeError("LIST or STRING", args[0].Type().String())
		},
		HelpText: `choice(seq) - Return random element from sequence

Returns a randomly selected element from the given list or string.`,
	},
	"shuffle": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			if list, ok := args[0].(*object.List); ok {
				n := len(list.Elements)
				for i := n - 1; i > 0; i-- {
					j := rng.Intn(i + 1)
					list.Elements[i], list.Elements[j] = list.Elements[j], list.Elements[i]
				}
				return &object.Null{}
			}
			return errors.NewTypeError("LIST", args[0].Type().String())
		},
		HelpText: `shuffle(list) - Shuffle list in place

Randomly shuffles the elements of the list in place using the Fisher-Yates algorithm. Returns None.`,
	},
	"uniform": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			var a, b float64
			switch arg := args[0].(type) {
			case *object.Integer:
				a = float64(arg.Value)
			case *object.Float:
				a = arg.Value
			default:
				return errors.NewTypeError("INTEGER or FLOAT", args[0].Type().String())
			}
			switch arg := args[1].(type) {
			case *object.Integer:
				b = float64(arg.Value)
			case *object.Float:
				b = arg.Value
			default:
				return errors.NewTypeError("INTEGER or FLOAT", args[1].Type().String())
			}

			val := a + rng.Float64()*(b-a)
			return &object.Float{Value: val}
		},
		HelpText: `uniform(a, b) - Return random float N such that a <= N <= b

Returns a random floating-point number N such that a <= N <= b.`,
	},
	"sample": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}
			list, err := args[0].AsList()
			if err != nil {
				return err
			}
			k, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			n := len(list)
			if k.Value < 0 || k.Value > int64(n) {
				return errors.NewError("sample larger than population or is negative")
			}

			indices := make([]int, n)
			for i := range indices {
				indices[i] = i
			}

			for i := 0; i < int(k.Value); i++ {
				j := i + rng.Intn(n-i)
				indices[i], indices[j] = indices[j], indices[i]
			}

			result := make([]object.Object, k.Value)
			for i := 0; i < int(k.Value); i++ {
				result[i] = list[indices[i]]
			}
			return &object.List{Elements: result}
		},
		HelpText: `sample(population, k) - Return k unique random elements from population

Returns a k length list of unique elements chosen from the population sequence.
Used for random sampling without replacement.`,
	},
	"randrange": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 3 {
				return errors.NewError("randrange() takes 1 to 3 arguments (%d given)", len(args))
			}
			var start, stop, step int64
			step = 1
			switch len(args) {
			case 1:

				start = 0
				if i, ok := args[0].(*object.Integer); ok {
					stop = i.Value
				} else {
					return errors.NewTypeError("INTEGER", args[0].Type().String())
				}
			case 2:

				if i, ok := args[0].(*object.Integer); ok {
					start = i.Value
				} else {
					return errors.NewTypeError("INTEGER", args[0].Type().String())
				}
				if i, ok := args[1].(*object.Integer); ok {
					stop = i.Value
				} else {
					return errors.NewTypeError("INTEGER", args[1].Type().String())
				}
			case 3:

				if i, ok := args[0].(*object.Integer); ok {
					start = i.Value
				} else {
					return errors.NewTypeError("INTEGER", args[0].Type().String())
				}
				if i, ok := args[1].(*object.Integer); ok {
					stop = i.Value
				} else {
					return errors.NewTypeError("INTEGER", args[1].Type().String())
				}
				if i, ok := args[2].(*object.Integer); ok {
					step = i.Value
				} else {
					return errors.NewTypeError("INTEGER", args[2].Type().String())
				}
			}
			if step == 0 {
				return errors.NewError("randrange() step argument must not be zero")
			}
			var n int64
			if step > 0 {
				n = (stop - start + step - 1) / step
			} else {
				n = (start - stop - step - 1) / (-step)
			}
			if n <= 0 {
				return errors.NewError("randrange() empty range")
			}
			return &object.Integer{Value: start + step*rng.Int63n(n)}
		},
		HelpText: `randrange(stop) or randrange(start, stop[, step]) - Return random integer from range

Returns a randomly selected element from range(start, stop, step).
Like randint, but doesn't include the endpoint.`,
	},
	"gauss": {
		Fn: gaussianRandom,
		HelpText: `gauss(mu, sigma) - Return random number from Gaussian distribution

mu is the mean, sigma is the standard deviation.`,
	},
	"normalvariate": {
		Fn: gaussianRandom,
		HelpText: `normalvariate(mu, sigma) - Return random number from normal distribution

mu is the mean, sigma is the standard deviation.
Same as gauss() but provided for compatibility.`,
	},
	"expovariate": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			var lambd float64
			switch arg := args[0].(type) {
			case *object.Integer:
				lambd = float64(arg.Value)
			case *object.Float:
				lambd = arg.Value
			default:
				return errors.NewTypeError("INTEGER or FLOAT", args[0].Type().String())
			}
			if lambd == 0 {
				return errors.NewError("expovariate() lambda must not be zero")
			}

			val := -math.Log(1.0-rng.Float64()) / lambd
			return &object.Float{Value: val}
		},
		HelpText: `expovariate(lambd) - Return random number from exponential distribution

lambd is 1.0 divided by the desired mean.`,
	},
}, nil, "Random number generation library")
View Source
var ReLibrary = object.NewLibrary(map[string]*object.Builtin{
	"match": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return errors.NewError("match() takes 2 or 3 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ || args[1].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", "mixed types")
			}
			pattern, _ := args[0].AsString()
			text, _ := args[1].AsString()

			flags, err := getFlags(args, 2)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			re, err := GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			match := re.FindStringSubmatchIndex(text)
			if match == nil || match[0] != 0 {
				return &object.Null{}
			}

			groups := make([]string, 0)
			for i := 0; i < len(match); i += 2 {
				if match[i] >= 0 && match[i+1] >= 0 {
					groups = append(groups, text[match[i]:match[i+1]])
				} else {
					groups = append(groups, "")
				}
			}

			return createMatchInstance(groups, match[0], match[1])
		},
		HelpText: `match(pattern, string, flags=0) - Match pattern at start of string

Returns a Match object if the pattern matches at the beginning, or None if no match.
Use match.group(0) for the full match, match.group(1) for the first group, etc.

Methods on Match object:
  group(n=0)  - Return the nth matched group (0 = full match)
  groups()    - Return tuple of all matched groups (excluding group 0)
  start(n=0)  - Return start position of nth group
  end(n=0)    - Return end position of nth group
  span(n=0)   - Return (start, end) tuple for nth group

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
	"search": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return errors.NewError("search() takes 2 or 3 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ || args[1].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", "mixed types")
			}
			pattern, _ := args[0].AsString()
			text, _ := args[1].AsString()

			flags, err := getFlags(args, 2)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			re, err := GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			match := re.FindStringSubmatchIndex(text)
			if match == nil {
				return &object.Null{}
			}

			groups := make([]string, 0)
			for i := 0; i < len(match); i += 2 {
				if match[i] >= 0 && match[i+1] >= 0 {
					groups = append(groups, text[match[i]:match[i+1]])
				} else {
					groups = append(groups, "")
				}
			}

			return createMatchInstance(groups, match[0], match[1])
		},
		HelpText: `search(pattern, string, flags=0) - Search for pattern anywhere in string

Returns a Match object for the first match, or None if no match found.
Use match.group(0) for the full match, match.group(1) for the first group, etc.

Methods on Match object:
  group(n=0)  - Return the nth matched group (0 = full match)
  groups()    - Return tuple of all matched groups (excluding group 0)
  start(n=0)  - Return start position of nth group
  end(n=0)    - Return end position of nth group
  span(n=0)   - Return (start, end) tuple for nth group

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
	"findall": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return errors.NewError("findall() takes 2 or 3 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ || args[1].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", "mixed types")
			}
			pattern, _ := args[0].AsString()
			text, _ := args[1].AsString()

			flags, err := getFlags(args, 2)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			re, err := GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			matches := re.FindAllStringSubmatch(text, -1)
			elements := make([]object.Object, len(matches))
			numGroups := re.NumSubexp()
			for i, match := range matches {
				if numGroups == 0 {
					elements[i] = &object.String{Value: match[0]}
				} else if numGroups == 1 {
					elements[i] = &object.String{Value: match[1]}
				} else {
					groupElements := make([]object.Object, numGroups)
					for j := 1; j <= numGroups; j++ {
						groupElements[j-1] = &object.String{Value: match[j]}
					}
					elements[i] = &object.Tuple{Elements: groupElements}
				}
			}
			return &object.List{Elements: elements}
		},
		HelpText: `findall(pattern, string, flags=0) - Find all matches

Returns a list of all substrings that match the regex pattern.
If the pattern contains capturing groups, returns a list of tuples containing the groups.
If there is one capturing group, returns a list of strings for that group.
If there are no capturing groups, returns a list of strings for the full matches.

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
	"finditer": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return errors.NewError("finditer() takes 2 or 3 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ || args[1].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", "mixed types")
			}
			pattern, _ := args[0].AsString()
			text, _ := args[1].AsString()

			flags, err := getFlags(args, 2)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			re, err := GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			allMatches := re.FindAllStringSubmatchIndex(text, -1)
			elements := make([]object.Object, len(allMatches))
			for i, match := range allMatches {

				groups := make([]string, 0)
				for j := 0; j < len(match); j += 2 {
					if match[j] >= 0 && match[j+1] >= 0 {
						groups = append(groups, text[match[j]:match[j+1]])
					} else {
						groups = append(groups, "")
					}
				}
				elements[i] = createMatchInstance(groups, match[0], match[1])
			}
			return &object.List{Elements: elements}
		},
		HelpText: `finditer(pattern, string, flags=0) - Find all matches as Match objects

Returns a list of Match objects for all matches of the regex pattern in the string.

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
	"sub": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 3 || len(args) > 5 {
				return errors.NewError("sub() takes 3 to 5 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ || args[1].Type() != object.STRING_OBJ || args[2].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", "mixed types")
			}
			pattern, _ := args[0].AsString()
			replacement, _ := args[1].AsString()
			text, _ := args[2].AsString()

			count := -1
			if len(args) > 3 {
				if args[3].Type() != object.INTEGER_OBJ {
					return errors.NewError("count must be an integer")
				}
				val, _ := args[3].AsInt()
				count = int(val)
			}

			flags, err := getFlags(args, 4)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			re, err := GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			var result string
			if count == 0 {
				result = text
			} else if count < 0 {
				result = re.ReplaceAllString(text, replacement)
			} else {

				replaced := 0
				result = re.ReplaceAllStringFunc(text, func(match string) string {
					if replaced < count {
						replaced++
						return re.ReplaceAllString(match, replacement)
					}
					return match
				})
			}
			return &object.String{Value: result}
		},
		HelpText: `sub(pattern, repl, string, count=0, flags=0) - Replace matches

Replaces occurrences of the regex pattern in the string with the replacement.
If count is 0 (default), all occurrences are replaced.
If count > 0, only the first count occurrences are replaced.

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
	"split": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 4 {
				return errors.NewError("split() takes 2 to 4 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ || args[1].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", "mixed types")
			}
			pattern, _ := args[0].AsString()
			text, _ := args[1].AsString()

			maxsplit := -1
			if len(args) > 2 {
				if args[2].Type() != object.INTEGER_OBJ {
					return errors.NewError("maxsplit must be an integer")
				}
				val, _ := args[2].AsInt()
				maxsplit = int(val)
				if maxsplit == 0 {
					maxsplit = -1
				}
			}

			flags, err := getFlags(args, 3)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			re, err := GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			parts := re.Split(text, maxsplit)
			elements := make([]object.Object, len(parts))
			for i, part := range parts {
				elements[i] = &object.String{Value: part}
			}
			return &object.List{Elements: elements}
		},
		HelpText: `split(pattern, string, maxsplit=0, flags=0) - Split string by pattern

Splits the string by occurrences of the regex pattern and returns a list of substrings.
If maxsplit is 0 (default), all occurrences are split.
If maxsplit > 0, at most maxsplit splits are done.

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
	"compile": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 1 || len(args) > 2 {
				return errors.NewError("compile() takes 1 or 2 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}
			pattern, _ := args[0].AsString()

			flags, err := getFlags(args, 1)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			_, err = GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			return createRegexInstance(pattern, flags)
		},
		HelpText: `compile(pattern, flags=0) - Compile regex pattern

Validates and caches a regex pattern for later use. Returns the pattern if valid.

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
	"escape": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			if args[0].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}
			text, _ := args[0].AsString()

			escaped := regexp.QuoteMeta(text)
			return &object.String{Value: escaped}
		},
		HelpText: `escape(pattern) - Escape special regex characters

Returns a string with all special regex characters escaped.`,
	},
	"fullmatch": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 || len(args) > 3 {
				return errors.NewError("fullmatch() takes 2 or 3 arguments (%d given)", len(args))
			}
			if args[0].Type() != object.STRING_OBJ || args[1].Type() != object.STRING_OBJ {
				return errors.NewTypeError("STRING", "mixed types")
			}
			pattern, _ := args[0].AsString()
			text, _ := args[1].AsString()

			flags, err := getFlags(args, 2)
			if err != nil {
				return errors.NewError("%s", err.Error())
			}
			pattern = applyFlags(pattern, flags)

			re, err := GetCompiledRegex(pattern)
			if err != nil {
				return errors.NewError("regex compile error: %s", err.Error())
			}

			match := re.FindStringSubmatchIndex(text)
			if match == nil || match[0] != 0 || match[1] != len(text) {
				return &object.Null{}
			}

			groups := make([]string, 0)
			for i := 0; i < len(match); i += 2 {
				if match[i] >= 0 && match[i+1] >= 0 {
					groups = append(groups, text[match[i]:match[i+1]])
				} else {
					groups = append(groups, "")
				}
			}

			return createMatchInstance(groups, match[0], match[1])
		},
		HelpText: `fullmatch(pattern, string, flags=0) - Match entire string

Returns a Match object if the regex pattern matches the entire string, or None if no match.

Flags:
  re.IGNORECASE or re.I - Case-insensitive matching
  re.MULTILINE or re.M  - ^ and $ match at line boundaries
  re.DOTALL or re.S     - . matches newlines`,
	},
}, map[string]object.Object{

	"IGNORECASE": &object.Integer{Value: RE_IGNORECASE},
	"I":          &object.Integer{Value: RE_IGNORECASE},
	"MULTILINE":  &object.Integer{Value: RE_MULTILINE},
	"M":          &object.Integer{Value: RE_MULTILINE},
	"DOTALL":     &object.Integer{Value: RE_DOTALL},
	"S":          &object.Integer{Value: RE_DOTALL},
}, "Regular expression library")
View Source
var RegexClass = &object.Class{
	Name: "Regex",
	Methods: map[string]object.Object{
		"match": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.ExactArgs(args, 2); err != nil {
					return err
				}
				if args[1].Type() != object.STRING_OBJ {
					return errors.NewTypeError("STRING", args[1].Type().String())
				}
				regex := args[0].(*object.Instance)
				pattern := regex.Fields["pattern"].(*object.String).Value
				text, _ := args[1].AsString()

				re, err := GetCompiledRegex(pattern)
				if err != nil {
					return errors.NewError("regex compile error: %s", err.Error())
				}

				match := re.FindStringSubmatchIndex(text)
				if match == nil || match[0] != 0 {
					return &object.Null{}
				}

				groups := make([]string, 0)
				for i := 0; i < len(match); i += 2 {
					if match[i] >= 0 && match[i+1] >= 0 {
						groups = append(groups, text[match[i]:match[i+1]])
					} else {
						groups = append(groups, "")
					}
				}

				return createMatchInstance(groups, match[0], match[1])
			},
			HelpText: `match(string) - Match pattern at start of string

Returns a Match object if the pattern matches at the beginning, or None if no match.`,
		},
		"search": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.ExactArgs(args, 2); err != nil {
					return err
				}
				if args[1].Type() != object.STRING_OBJ {
					return errors.NewTypeError("STRING", args[1].Type().String())
				}
				regex := args[0].(*object.Instance)
				pattern := regex.Fields["pattern"].(*object.String).Value
				text, _ := args[1].AsString()

				re, err := GetCompiledRegex(pattern)
				if err != nil {
					return errors.NewError("regex compile error: %s", err.Error())
				}

				match := re.FindStringSubmatchIndex(text)
				if match == nil {
					return &object.Null{}
				}

				groups := make([]string, 0)
				for i := 0; i < len(match); i += 2 {
					if match[i] >= 0 && match[i+1] >= 0 {
						groups = append(groups, text[match[i]:match[i+1]])
					} else {
						groups = append(groups, "")
					}
				}

				return createMatchInstance(groups, match[0], match[1])
			},
			HelpText: `search(string) - Search for pattern anywhere in string

Returns a Match object for the first match, or None if no match found.`,
		},
		"findall": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.ExactArgs(args, 2); err != nil {
					return err
				}
				if args[1].Type() != object.STRING_OBJ {
					return errors.NewTypeError("STRING", args[1].Type().String())
				}
				regex := args[0].(*object.Instance)
				pattern := regex.Fields["pattern"].(*object.String).Value
				text, _ := args[1].AsString()

				re, err := GetCompiledRegex(pattern)
				if err != nil {
					return errors.NewError("regex compile error: %s", err.Error())
				}

				matches := re.FindAllStringSubmatch(text, -1)
				elements := make([]object.Object, len(matches))
				numGroups := re.NumSubexp()
				for i, match := range matches {
					if numGroups == 0 {
						elements[i] = &object.String{Value: match[0]}
					} else if numGroups == 1 {
						elements[i] = &object.String{Value: match[1]}
					} else {
						groupElements := make([]object.Object, numGroups)
						for j := 1; j <= numGroups; j++ {
							groupElements[j-1] = &object.String{Value: match[j]}
						}
						elements[i] = &object.Tuple{Elements: groupElements}
					}
				}
				return &object.List{Elements: elements}
			},
			HelpText: `findall(string) - Find all matches

Returns a list of all substrings that match the regex pattern.
If the pattern contains capturing groups, returns a list of tuples containing the groups.
If there is one capturing group, returns a list of strings for that group.
If there are no capturing groups, returns a list of strings for the full matches.`,
		},
		"finditer": &object.Builtin{
			Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
				if err := errors.ExactArgs(args, 2); err != nil {
					return err
				}
				if args[1].Type() != object.STRING_OBJ {
					return errors.NewTypeError("STRING", args[1].Type().String())
				}
				regex := args[0].(*object.Instance)
				pattern := regex.Fields["pattern"].(*object.String).Value
				text, _ := args[1].AsString()

				re, err := GetCompiledRegex(pattern)
				if err != nil {
					return errors.NewError("regex compile error: %s", err.Error())
				}

				allMatches := re.FindAllStringSubmatchIndex(text, -1)
				elements := make([]object.Object, len(allMatches))
				for i, match := range allMatches {

					groups := make([]string, 0)
					for j := 0; j < len(match); j += 2 {
						if match[j] >= 0 && match[j+1] >= 0 {
							groups = append(groups, text[match[j]:match[j+1]])
						} else {
							groups = append(groups, "")
						}
					}
					elements[i] = createMatchInstance(groups, match[0], match[1])
				}
				return &object.List{Elements: elements}
			},
			HelpText: `finditer(string) - Find all matches as Match objects

Returns a list of Match objects for all matches of the regex pattern in the string.`,
		},
	},
}

Regex class definition

View Source
var StatisticsLibrary = object.NewLibrary(map[string]*object.Builtin{
	"mean": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) == 0 {
				return errors.NewError("mean requires at least one data point")
			}
			sum := 0.0
			for _, v := range values {
				sum += v
			}
			return &object.Float{Value: sum / float64(len(values))}
		},
		HelpText: `mean(data) - Return the arithmetic mean of data

Parameters:
  data - List of numbers

Returns: Float

Example:
  import statistics
  statistics.mean([1, 2, 3, 4, 5])  # 3.0`,
	},
	"fmean": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) == 0 {
				return errors.NewError("fmean requires at least one data point")
			}
			sum := 0.0
			for _, v := range values {
				sum += v
			}
			return &object.Float{Value: sum / float64(len(values))}
		},
		HelpText: `fmean(data) - Return the arithmetic mean of data (faster float version)

Parameters:
  data - List of numbers

Returns: Float

Example:
  import statistics
  statistics.fmean([1.0, 2.0, 3.0])  # 2.0`,
	},
	"geometric_mean": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) == 0 {
				return errors.NewError("geometric_mean requires at least one data point")
			}

			logSum := 0.0
			for _, v := range values {
				if v <= 0 {
					return errors.NewError("geometric_mean requires positive numbers")
				}
				logSum += math.Log(v)
			}
			return &object.Float{Value: math.Exp(logSum / float64(len(values)))}
		},
		HelpText: `geometric_mean(data) - Return the geometric mean of data

Parameters:
  data - List of positive numbers

Returns: Float

Example:
  import statistics
  statistics.geometric_mean([1, 2, 4])  # 2.0`,
	},
	"harmonic_mean": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) == 0 {
				return errors.NewError("harmonic_mean requires at least one data point")
			}
			reciprocalSum := 0.0
			for _, v := range values {
				if v <= 0 {
					return errors.NewError("harmonic_mean requires positive numbers")
				}
				reciprocalSum += 1.0 / v
			}
			return &object.Float{Value: float64(len(values)) / reciprocalSum}
		},
		HelpText: `harmonic_mean(data) - Return the harmonic mean of data

Parameters:
  data - List of positive numbers

Returns: Float

Example:
  import statistics
  statistics.harmonic_mean([1, 2, 4])  # ~1.714`,
	},
	"median": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) == 0 {
				return errors.NewError("median requires at least one data point")
			}
			sorted := make([]float64, len(values))
			copy(sorted, values)
			sort.Float64s(sorted)
			n := len(sorted)
			if n%2 == 0 {
				return &object.Float{Value: (sorted[n/2-1] + sorted[n/2]) / 2}
			}
			return &object.Float{Value: sorted[n/2]}
		},
		HelpText: `median(data) - Return the median (middle value) of data

Parameters:
  data - List of numbers

Returns: Float

Example:
  import statistics
  statistics.median([1, 3, 5])  # 3.0
  statistics.median([1, 3, 5, 7])  # 4.0`,
	},
	"mode": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			list, ok := args[0].(*object.List)
			if !ok {
				return errors.NewTypeError("LIST", args[0].Type().String())
			}
			if len(list.Elements) == 0 {
				return errors.NewError("mode requires at least one data point")
			}

			counts := make(map[string]int)
			elements := make(map[string]object.Object)
			for _, elem := range list.Elements {
				key := elem.Inspect()
				counts[key]++
				elements[key] = elem
			}

			maxCount := 0
			var modeKey string
			for key, count := range counts {
				if count > maxCount {
					maxCount = count
					modeKey = key
				}
			}
			return elements[modeKey]
		},
		HelpText: `mode(data) - Return the most common value in data

Parameters:
  data - List of values

Returns: Most frequent value (same type as input elements)

Example:
  import statistics
  statistics.mode([1, 1, 2, 3])  # 1
  statistics.mode(["a", "b", "a"])  # "a"`,
	},
	"stdev": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) < 2 {
				return errors.NewError("stdev requires at least two data points")
			}
			variance := sampleVariance(values)
			return &object.Float{Value: math.Sqrt(variance)}
		},
		HelpText: `stdev(data) - Return the sample standard deviation of data

Parameters:
  data - List of numbers (at least 2)

Returns: Float

Example:
  import statistics
  statistics.stdev([1, 2, 3, 4, 5])  # ~1.58`,
	},
	"pstdev": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) < 1 {
				return errors.NewError("pstdev requires at least one data point")
			}
			variance := populationVariance(values)
			return &object.Float{Value: math.Sqrt(variance)}
		},
		HelpText: `pstdev(data) - Return the population standard deviation of data

Parameters:
  data - List of numbers

Returns: Float

Example:
  import statistics
  statistics.pstdev([1, 2, 3, 4, 5])  # ~1.41`,
	},
	"variance": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) < 2 {
				return errors.NewError("variance requires at least two data points")
			}
			return &object.Float{Value: sampleVariance(values)}
		},
		HelpText: `variance(data) - Return the sample variance of data

Parameters:
  data - List of numbers (at least 2)

Returns: Float

Example:
  import statistics
  statistics.variance([1, 2, 3, 4, 5])  # 2.5`,
	},
	"pvariance": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			values, err := extractNumbers(args[0])
			if err != nil {
				return err
			}
			if len(values) < 1 {
				return errors.NewError("pvariance requires at least one data point")
			}
			return &object.Float{Value: populationVariance(values)}
		},
		HelpText: `pvariance(data) - Return the population variance of data

Parameters:
  data - List of numbers

Returns: Float

Example:
  import statistics
  statistics.pvariance([1, 2, 3, 4, 5])  # 2.0`,
	},
}, nil, "Statistical functions library")
View Source
var StringLibrary = object.NewLibrary(
	nil,
	map[string]object.Object{
		"ascii_letters":   &object.String{Value: asciiLetters},
		"ascii_lowercase": &object.String{Value: asciiLowercase},
		"ascii_uppercase": &object.String{Value: asciiUppercase},
		"digits":          &object.String{Value: digits},
		"hexdigits":       &object.String{Value: hexdigits},
		"octdigits":       &object.String{Value: octdigits},
		"punctuation":     &object.String{Value: punctuation},
		"whitespace":      &object.String{Value: whitespace},
		"printable":       &object.String{Value: printable},
	},
	"String constants for character classification",
)
View Source
var TextwrapLibrary = object.NewLibrary(map[string]*object.Builtin{
	"wrap": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			width, _ := kwargs.GetInt("width", 70)
			widthInt := int(width)

			if len(args) < 1 {
				return errors.NewError("wrap() requires at least 1 argument")
			}

			text, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}

			if len(args) >= 2 {
				if intVal, ok := args[1].(*object.Integer); ok {
					widthInt = int(intVal.Value)
				}
			}

			lines := wrapText(text.Value, widthInt)
			elements := make([]object.Object, len(lines))
			for i, line := range lines {
				elements[i] = &object.String{Value: line}
			}
			return &object.List{Elements: elements}
		},
		HelpText: `wrap(text, width=70) - Wrap a single paragraph of text

Parameters:
  text  - Text to wrap
  width - Maximum line width (default 70)

Returns: List of lines

Example:
  import textwrap
  lines = textwrap.wrap("Hello world, this is a long line", 10)`,
	},

	"fill": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			width, _ := kwargs.GetInt("width", 70)
			widthInt := int(width)

			if len(args) < 1 {
				return errors.NewError("fill() requires at least 1 argument")
			}

			text, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}

			if len(args) >= 2 {
				if intVal, ok := args[1].(*object.Integer); ok {
					widthInt = int(intVal.Value)
				}
			}

			lines := wrapText(text.Value, widthInt)
			return &object.String{Value: strings.Join(lines, "\n")}
		},
		HelpText: `fill(text, width=70) - Wrap text and return a single string

Parameters:
  text  - Text to wrap
  width - Maximum line width (default 70)

Returns: Wrapped text as single string with newlines

Example:
  import textwrap
  result = textwrap.fill("Hello world, this is a long line", 10)`,
	},

	"dedent": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) != 1 {
				return errors.NewError("dedent() requires exactly 1 argument")
			}

			text, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}

			return &object.String{Value: dedentText(text.Value)}
		},
		HelpText: `dedent(text) - Remove common leading whitespace from all lines

Parameters:
  text - Text to dedent

Returns: Dedented text

Example:
  import textwrap
  text = """
      Hello
      World
  """
  result = textwrap.dedent(text)  # Lines start at column 0`,
	},

	"indent": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if len(args) < 2 {
				return errors.NewError("indent() requires at least 2 arguments")
			}

			text, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}

			prefix, ok := args[1].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[1].Type().String())
			}

			lines := strings.Split(text.Value, "\n")
			result := make([]string, len(lines))
			for i, line := range lines {

				if len(strings.TrimSpace(line)) > 0 {
					result[i] = prefix.Value + line
				} else {
					result[i] = line
				}
			}
			return &object.String{Value: strings.Join(result, "\n")}
		},
		HelpText: `indent(text, prefix) - Add prefix to non-empty lines

Parameters:
  text   - Text to indent
  prefix - String to add to beginning of each line

Returns: Indented text

Example:
  import textwrap
  result = textwrap.indent("Hello\nWorld", "  ")  # "  Hello\n  World"`,
	},

	"shorten": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			placeholder, _ := kwargs.GetString("placeholder", "[...]")

			if len(args) < 2 {
				return errors.NewError("shorten() requires at least 2 arguments")
			}

			text, ok := args[0].(*object.String)
			if !ok {
				return errors.NewTypeError("STRING", args[0].Type().String())
			}

			widthObj, ok := args[1].(*object.Integer)
			if !ok {
				return errors.NewTypeError("INTEGER", args[1].Type().String())
			}
			width := int(widthObj.Value)

			collapsed := collapseWhitespace(text.Value)
			if len(collapsed) <= width {
				return &object.String{Value: collapsed}
			}

			if width <= len(placeholder) {
				return &object.String{Value: placeholder[:width]}
			}

			maxLen := width - len(placeholder)
			truncated := collapsed[:maxLen]

			lastSpace := strings.LastIndex(truncated, " ")
			if lastSpace > 0 {
				truncated = truncated[:lastSpace]
			}

			return &object.String{Value: strings.TrimSpace(truncated) + placeholder}
		},
		HelpText: `shorten(text, width, placeholder="[...]") - Truncate text to fit width

Parameters:
  text        - Text to shorten
  width       - Maximum width including placeholder
  placeholder - String to indicate truncation (default "[...]")

Returns: Shortened text

Example:
  import textwrap
  result = textwrap.shorten("Hello World!", 10)  # "Hello[...]"`,
	},
}, nil, "Text wrapping and filling utilities")
View Source
var TimeLibrary = object.NewLibrary(map[string]*object.Builtin{
	"time": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			return &object.Float{Value: float64(time.Now().UnixNano()) / 1e9}
		},
		HelpText: `time() - Return current time in seconds

Returns the current time as a floating point number of seconds since the Unix epoch.`,
	},
	"perf_counter": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			return &object.Float{Value: time.Since(startTime).Seconds()}
		},
		HelpText: `perf_counter() - Return performance counter

Returns the value of a performance counter in fractional seconds.`,
	},
	"sleep": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}
			seconds, err := args[0].AsFloat()
			if err != nil {
				return errors.ParameterError("seconds", err)
			}

			timer := time.NewTimer(time.Duration(seconds * float64(time.Second)))
			defer timer.Stop()

			select {
			case <-ctx.Done():
				if ctx.Err() == context.DeadlineExceeded {
					return errors.NewTimeoutError()
				}
				return errors.NewCancelledError()
			case <-timer.C:
				return &object.Null{}
			}
		},
		HelpText: `sleep(seconds) - Sleep for specified seconds

Suspends execution for the given number of seconds.`,
	},
	"localtime": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			var t time.Time
			if len(args) == 0 {
				t = time.Now()
			} else if len(args) == 1 {

				if ts, err := args[0].AsFloat(); err == nil {
					t = time.Unix(int64(ts), 0)
				} else if instance, ok := args[0].(*object.Instance); ok {

					if dt, err := GetTimeFromObject(instance); err == nil {
						t = dt
					} else {
						return errors.NewTypeError("INTEGER, FLOAT, or datetime instance", args[0].Type().String())
					}
				} else {
					return errors.NewTypeError("INTEGER, FLOAT, or datetime instance", args[0].Type().String())
				}
			} else {
				if err := errors.MaxArgs(args, 1); err != nil {
					return err
				}
			}

			return timeToTuple(t, false)
		},
		HelpText: `localtime([timestamp_or_datetime]) - Convert to local time tuple

Returns a time tuple in local time. If timestamp/datetime is omitted, uses current time.`,
	},
	"gmtime": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			var t time.Time
			if len(args) == 0 {
				t = time.Now()
			} else if len(args) == 1 {

				if ts, err := args[0].AsFloat(); err == nil {
					t = time.Unix(int64(ts), 0)
				} else if instance, ok := args[0].(*object.Instance); ok {

					if dt, err := GetTimeFromObject(instance); err == nil {
						t = dt
					} else {
						return errors.NewTypeError("INTEGER, FLOAT, or datetime instance", args[0].Type().String())
					}
				} else {
					return errors.NewTypeError("INTEGER, FLOAT, or datetime instance", args[0].Type().String())
				}
			} else {
				if err := errors.MaxArgs(args, 1); err != nil {
					return err
				}
			}

			return timeToTuple(t, true)
		},
		HelpText: `gmtime([timestamp_or_datetime]) - Convert to UTC time tuple

Returns a time tuple in UTC. If timestamp/datetime is omitted, uses current time.`,
	},
	"mktime": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}

			tuple, err := args[0].AsList()
			if err != nil {
				return err
			}

			if len(tuple) != 9 {
				return errors.NewError("time tuple must have exactly 9 elements")
			}

			year, _ := tuple[0].AsInt()
			month, _ := tuple[1].AsInt()
			day, _ := tuple[2].AsInt()
			hour, _ := tuple[3].AsInt()
			minute, _ := tuple[4].AsInt()
			second, _ := tuple[5].AsInt()

			t := time.Date(int(year), time.Month(month), int(day), int(hour), int(minute), int(second), 0, time.Local)
			return &object.Float{Value: float64(t.Unix())}
		},
		HelpText: `mktime(tuple) - Convert time tuple to timestamp

Converts a time tuple (9 elements) to a Unix timestamp.`,
	},
	"strftime": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}

			format, err := args[0].AsString()
			if err != nil {
				return err
			}

			var t time.Time
			if len(args) == 1 {
				t = time.Now()
			} else {
				tuple, err := args[1].AsList()
				if err != nil {
					return err
				}
				if len(tuple) != 9 {
					return errors.NewError("time tuple must have exactly 9 elements")
				}

				year, _ := tuple[0].AsInt()
				month, _ := tuple[1].AsInt()
				day, _ := tuple[2].AsInt()
				hour, _ := tuple[3].AsInt()
				minute, _ := tuple[4].AsInt()
				second, _ := tuple[5].AsInt()

				t = time.Date(int(year), time.Month(month), int(day), int(hour), int(minute), int(second), 0, time.Local)
			}

			return &object.String{Value: t.Format(pythonToGoFormat(format))}
		},
		HelpText: `strftime(format[, tuple]) - Format time as string

Formats a time according to the given format string. If tuple is omitted, uses current time.`,
	},
	"strptime": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			format, err := args[1].AsString()
			if err != nil {
				return err
			}

			t, parseErr := time.Parse(pythonToGoFormat(format), str)
			if parseErr != nil {
				return errors.NewError("strptime() parse error: %s", parseErr.Error())
			}

			return timeToTuple(t, false)
		},
		HelpText: `strptime(string, format) - Parse time from string

Parses a time string according to the given format and returns a time tuple.`,
	},
	"asctime": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			var t time.Time
			if len(args) == 0 {
				t = time.Now()
			} else if len(args) == 1 {
				tuple, err := args[0].AsList()
				if err != nil {
					return err
				}
				if len(tuple) != 9 {
					return errors.NewError("time tuple must have exactly 9 elements")
				}

				year, _ := tuple[0].AsInt()
				month, _ := tuple[1].AsInt()
				day, _ := tuple[2].AsInt()
				hour, _ := tuple[3].AsInt()
				minute, _ := tuple[4].AsInt()
				second, _ := tuple[5].AsInt()

				t = time.Date(int(year), time.Month(month), int(day), int(hour), int(minute), int(second), 0, time.Local)
			} else {
				if err := errors.MaxArgs(args, 1); err != nil {
					return err
				}
			}

			return &object.String{Value: t.Format("Mon Jan 2 15:04:05 2006")}
		},
		HelpText: `asctime([tuple]) - Convert time tuple to string

Converts a time tuple to a string in the format 'Mon Jan 2 15:04:05 2006'. If tuple is omitted, uses current time.`,
	},
	"ctime": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			var t time.Time
			if len(args) == 0 {
				t = time.Now()
			} else if len(args) == 1 {
				timestamp, err := args[0].AsFloat()
				if err != nil {
					return errors.ParameterError("timestamp", err)
				}
				t = time.Unix(int64(timestamp), 0)
			} else {
				if err := errors.MaxArgs(args, 1); err != nil {
					return err
				}
			}

			return &object.String{Value: t.Format("Mon Jan 2 15:04:05 2006")}
		},
		HelpText: `ctime([timestamp]) - Convert timestamp to string

Converts a Unix timestamp to a string in the format 'Mon Jan 2 15:04:05 2006'. If timestamp is omitted, uses current time.`,
	},
}, nil, "Time-related functions library")
View Source
var URLLibLibrary = object.NewLibraryWithSubs(
	nil,
	nil,
	map[string]*object.Library{
		"parse": URLParseLibrary,
	},
	"URL handling modules",
)

URLLibrary is the parent urllib module with parse as a sub-library

View Source
var URLParseLibrary = object.NewLibrary(map[string]*object.Builtin{
	"quote": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			safe := ""
			if len(args) == 2 {
				safe, err = args[1].AsString()
				if err != nil {
					return err
				}
			}

			encoded := urlQuote(str, safe)
			return &object.String{Value: encoded}
		},
		HelpText: `quote(string, safe='') - URL encode string

Returns a URL-encoded version of the string. Characters in 'safe' are not encoded.`,
	},
	"quote_plus": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			safe := ""
			if len(args) == 2 {
				safe, err = args[1].AsString()
				if err != nil {
					return err
				}
			}

			encoded := urlQuote(str, safe)
			encoded = strings.ReplaceAll(encoded, "%20", "+")
			return &object.String{Value: encoded}
		},
		HelpText: `quote_plus(string, safe='') - URL encode string with + for spaces

Like quote(), but also replaces spaces with plus signs.`,
	},
	"unquote": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			decoded, urlErr := url.PathUnescape(str)
			if urlErr != nil {
				return errors.NewError("unquote() invalid URL encoding")
			}
			return &object.String{Value: decoded}
		},
		HelpText: `unquote(string) - URL decode string

Returns a URL-decoded version of the string.`,
	},
	"unquote_plus": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			str = strings.ReplaceAll(str, "+", " ")
			decoded, urlErr := url.PathUnescape(str)
			if urlErr != nil {
				return errors.NewError("unquote_plus() invalid URL encoding")
			}
			return &object.String{Value: decoded}
		},
		HelpText: `unquote_plus(string) - URL decode string with + as spaces

Like unquote(), but also replaces plus signs with spaces.`,
	},
	"urlparse": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			u, urlErr := url.Parse(str)
			if urlErr != nil {
				return errors.NewError("urlparse() invalid URL")
			}

			netloc := u.Host
			if u.User != nil {
				if pwd, hasPwd := u.User.Password(); hasPwd {
					netloc = u.User.Username() + ":" + pwd + "@" + u.Host
				} else {
					netloc = u.User.Username() + "@" + u.Host
				}
			}

			return createParseResultInstance(u.Scheme, netloc, u.Path, "", u.RawQuery, u.Fragment)
		},
		HelpText: `urlparse(urlstring) - Parse URL into components

Returns a ParseResult object with URL components: scheme, netloc, path, params, query, fragment.
Access components as attributes: result.scheme, result.netloc, etc. Use result.geturl() to reconstruct URL.`,
	},
	"urlunparse": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}

			switch arg := args[0].(type) {
			case *object.Instance:

				if arg.Class == ParseResultClass {
					u := &url.URL{}
					if value, ok := arg.Fields["scheme"]; ok {
						if str, err := value.AsString(); err == nil {
							u.Scheme = str
						}
					}
					if value, ok := arg.Fields["netloc"]; ok {
						if str, err := value.AsString(); err == nil {
							u.Host = str
						}
					}
					if value, ok := arg.Fields["path"]; ok {
						if str, err := value.AsString(); err == nil {
							u.Path = str
						}
					}
					if value, ok := arg.Fields["query"]; ok {
						if str, err := value.AsString(); err == nil {
							u.RawQuery = str
						}
					}
					if value, ok := arg.Fields["fragment"]; ok {
						if str, err := value.AsString(); err == nil {
							u.Fragment = str
						}
					}
					return &object.String{Value: u.String()}
				}
				return errors.NewTypeError("DICT, LIST, TUPLE, or ParseResult", args[0].Type().String())

			case *object.Dict:
				u := &url.URL{}
				if value, ok := arg.Pairs["scheme"]; ok {
					if str, err := value.Value.AsString(); err == nil {
						u.Scheme = str
					}
				}
				if value, ok := arg.Pairs["netloc"]; ok {
					if str, err := value.Value.AsString(); err == nil {
						u.Host = str
					}
				}
				if value, ok := arg.Pairs["path"]; ok {
					if str, err := value.Value.AsString(); err == nil {
						u.Path = str
					}
				}
				if value, ok := arg.Pairs["query"]; ok {
					if str, err := value.Value.AsString(); err == nil {
						u.RawQuery = str
					}
				}
				if value, ok := arg.Pairs["fragment"]; ok {
					if str, err := value.Value.AsString(); err == nil {
						u.Fragment = str
					}
				}
				return &object.String{Value: u.String()}

			case *object.List:
				if len(arg.Elements) != 6 {
					return errors.NewError("urlunparse() requires exactly 6 elements")
				}
				components := make([]string, 6)
				for i, elem := range arg.Elements {
					str, err := elem.AsString()
					if err != nil {
						return err
					}
					components[i] = str
				}
				u := &url.URL{
					Scheme:   components[0],
					Host:     components[1],
					Path:     components[2],
					RawQuery: components[4],
					Fragment: components[5],
				}
				return &object.String{Value: u.String()}

			case *object.Tuple:
				if len(arg.Elements) != 6 {
					return errors.NewError("urlunparse() requires exactly 6 elements")
				}
				components := make([]string, 6)
				for i, elem := range arg.Elements {
					str, err := elem.AsString()
					if err != nil {
						return err
					}
					components[i] = str
				}
				u := &url.URL{
					Scheme:   components[0],
					Host:     components[1],
					Path:     components[2],
					RawQuery: components[4],
					Fragment: components[5],
				}
				return &object.String{Value: u.String()}

			default:
				return errors.NewTypeError("DICT, LIST, TUPLE, or ParseResult", args[0].Type().String())
			}
		},
		HelpText: `urlunparse(components) - Construct URL from components

Constructs a URL string from a 6-tuple or dict of URL components.`,
	},
	"urljoin": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 2); err != nil {
				return err
			}

			base, err := args[0].AsString()
			if err != nil {
				return err
			}

			ref, err := args[1].AsString()
			if err != nil {
				return err
			}

			baseURL, urlErr := url.Parse(base)
			if urlErr != nil {
				return errors.NewError("urljoin() invalid base URL")
			}

			refURL, urlErr := url.Parse(ref)
			if urlErr != nil {
				return errors.NewError("urljoin() invalid reference URL")
			}

			joined := baseURL.ResolveReference(refURL)
			return &object.String{Value: joined.String()}
		},
		HelpText: `urljoin(base, url) - Join base URL with reference

Joins a base URL with a reference URL, resolving relative references.`,
	},
	"urlsplit": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			u, urlErr := url.Parse(str)
			if urlErr != nil {
				return errors.NewError("urlsplit() invalid URL")
			}

			netloc := u.Host
			if u.User != nil {
				if pwd, hasPwd := u.User.Password(); hasPwd {
					netloc = u.User.Username() + ":" + pwd + "@" + u.Host
				} else {
					netloc = u.User.Username() + "@" + u.Host
				}
			}

			elements := []object.Object{
				&object.String{Value: u.Scheme},
				&object.String{Value: netloc},
				&object.String{Value: u.Path},
				&object.String{Value: u.RawQuery},
				&object.String{Value: u.Fragment},
			}

			return &object.List{Elements: elements}
		},
		HelpText: `urlsplit(urlstring) - Split URL into components

Returns a 5-tuple: (scheme, netloc, path, query, fragment).`,
	},
	"urlunsplit": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 1); err != nil {
				return err
			}

			elements, err := args[0].AsList()
			if err != nil {
				return errors.ParameterError("elements", err)
			}

			if len(elements) != 5 {
				return errors.NewError("urlunsplit() requires exactly 5 elements")
			}

			components := make([]string, 5)
			for i, elem := range elements {
				str, err := elem.AsString()
				if err != nil {
					return err
				}
				components[i] = str
			}

			u := &url.URL{
				Scheme:   components[0],
				Host:     components[1],
				Path:     components[2],
				RawQuery: components[3],
				Fragment: components[4],
			}

			return &object.String{Value: u.String()}
		},
		HelpText: `urlunsplit(components) - Construct URL from component tuple

Constructs a URL string from a 5-tuple of URL components.`,
	},
	"parse_qs": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			values, urlErr := url.ParseQuery(str)
			if urlErr != nil {
				return errors.NewError("parse_qs() invalid query string")
			}

			pairs := make(map[string]object.DictPair)
			for key, vals := range values {
				elements := make([]object.Object, len(vals))
				for i, val := range vals {
					elements[i] = &object.String{Value: val}
				}
				pairs[key] = object.DictPair{
					Key:   &object.String{Value: key},
					Value: &object.List{Elements: elements},
				}
			}

			return &object.Dict{Pairs: pairs}
		},
		HelpText: `parse_qs(qs, keep_blank_values=False) - Parse query string

Parses a URL query string and returns a dictionary where values are lists.`,
	},
	"parse_qsl": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}

			str, err := args[0].AsString()
			if err != nil {
				return err
			}

			values, urlErr := url.ParseQuery(str)
			if urlErr != nil {
				return errors.NewError("parse_qsl() invalid query string")
			}

			// Convert to list of (key, value) tuples
			var result []object.Object
			for key, vals := range values {
				for _, val := range vals {
					tuple := &object.Tuple{
						Elements: []object.Object{
							&object.String{Value: key},
							&object.String{Value: val},
						},
					}
					result = append(result, tuple)
				}
			}

			return &object.List{Elements: result}
		},
		HelpText: `parse_qsl(qs, keep_blank_values=False) - Parse query string as list

Parses a URL query string and returns a list of (key, value) tuples.`,
	},
	"urlencode": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.RangeArgs(args, 1, 2); err != nil {
				return err
			}

			values := make(url.Values)

			switch arg := args[0].(type) {
			case *object.Dict:
				for key, pair := range arg.Pairs {
					switch val := pair.Value.(type) {
					case *object.String:
						values[key] = []string{val.Value}
					case *object.List:
						strVals := make([]string, len(val.Elements))
						for i, elem := range val.Elements {
							if str, err := elem.AsString(); err == nil {
								strVals[i] = str
							}
						}
						values[key] = strVals
					}
				}
			case *object.List:

				for _, elem := range arg.Elements {
					if tuple, ok := elem.(*object.Tuple); ok && len(tuple.Elements) == 2 {
						if key, err := tuple.Elements[0].AsString(); err == nil {
							if val, err := tuple.Elements[1].AsString(); err == nil {
								values.Add(key, val)
							}
						}
					}
				}
			default:
				return errors.NewTypeError("DICT or LIST", args[0].Type().String())
			}

			return &object.String{Value: values.Encode()}
		},
		HelpText: `urlencode(query, doseq=False) - Encode dictionary as query string

Encodes a dictionary or list of tuples into a URL query string.`,
	},
}, nil, "URL parsing and manipulation (urllib.parse compatible)")

URLParseLibrary implements Python's urllib.parse module

View Source
var UUIDLibrary = object.NewLibrary(map[string]*object.Builtin{
	"uuid1": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			id, err := uuid.NewUUID()
			if err != nil {
				return errors.NewError("failed to generate UUID v1: %s", err.Error())
			}
			return &object.String{Value: id.String()}
		},
		HelpText: `uuid1() - Generate a UUID version 1 (time-based)

Returns a UUID based on current time and MAC address.
Format: xxxxxxxx-xxxx-1xxx-yxxx-xxxxxxxxxxxx

Example:
  import uuid
  id = uuid.uuid1()
  print(id)  # e.g., "f47ac10b-58cc-1e4c-a26f-e3fc32165abc"`,
	},
	"uuid4": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			return &object.String{Value: uuid.New().String()}
		},
		HelpText: `uuid4() - Generate a UUID version 4 (random)

Returns a randomly generated UUID.
Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx

Example:
  import uuid
  id = uuid.uuid4()
  print(id)  # e.g., "550e8400-e29b-41d4-a716-446655440000"`,
	},
	"uuid7": {
		Fn: func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
			if err := errors.ExactArgs(args, 0); err != nil {
				return err
			}
			id, err := uuid.NewV7()
			if err != nil {
				return errors.NewError("failed to generate UUID v7: %s", err.Error())
			}
			return &object.String{Value: id.String()}
		},
		HelpText: `uuid7() - Generate a UUID version 7 (Unix timestamp-based, sortable)

Returns a UUID based on Unix timestamp in milliseconds.
UUIDs generated in sequence will sort in chronological order.
Format: xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx

Example:
  import uuid
  id = uuid.uuid7()
  print(id)  # e.g., "018f6b1c-4e5d-7abc-8def-0123456789ab"`,
	},
}, nil, "UUID generation library")

Functions

func GetCompiledRegex

func GetCompiledRegex(pattern string) (*regexp.Regexp, error)

GetCompiledRegex retrieves a compiled regex from cache or compiles and caches it

func GetTimeFromObject

func GetTimeFromObject(obj object.Object) (time.Time, object.Object)

GetTimeFromObject extracts time.Time from a datetime/date instance

func PythonToGoDateFormat

func PythonToGoDateFormat(pyFormat string) string

PythonToGoDateFormat converts Python datetime format codes to Go format

func RegisterAll

func RegisterAll(p interface{ RegisterLibrary(string, *object.Library) })

RegisterAll registers all standard libraries

func SetFunctionCaller

func SetFunctionCaller(caller func(ctx context.Context, fn *object.Function, args []object.Object, keywords map[string]object.Object) object.Object)

SetFunctionCaller allows the evaluator to register its function caller

Types

This section is empty.

Jump to

Keyboard shortcuts

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