objects

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

pkg/objects/array.go

pkg/objects/builtin.go

pkg/objects/class.go

pkg/objects/float.go

pkg/objects/function.go

pkg/objects/int.go

pkg/objects/map.go

pkg/objects/methods.go

pkg/objects/module.go Module object type for runtime module representation.

pkg/objects/object.go

pkg/objects/string.go

Index

Constants

View Source
const IntCacheMax = 256

IntCacheMax is the maximum cached integer value

View Source
const IntCacheMin = -5

IntCacheMin is the minimum cached integer value

Variables

View Source
var (
	TRUE  = &Bool{Value: true}
	FALSE = &Bool{Value: false}
)

TRUE and FALSE are singleton boolean values

View Source
var Builtins = map[string]*Builtin{

	"len": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for len. got=%d, want=1", len(args))
			}

			switch arg := args[0].(type) {
			case *String:
				return &Int{Value: int64(len(arg.Value))}
			case *Array:
				return &Int{Value: int64(len(arg.Elements))}
			case *Map:
				return &Int{Value: int64(len(arg.Pairs))}
			default:
				return newError("argument to 'len' not supported, got %s", args[0].Type())
			}
		},
	},
	"print": {
		Fn: func(args ...Object) Object {
			for _, arg := range args {
				fmt.Print(arg.Inspect())
			}
			return NULL
		},
	},
	"println": {
		Fn: func(args ...Object) Object {
			for _, arg := range args {
				fmt.Print(arg.Inspect())
			}
			fmt.Println()
			return NULL
		},
	},
	"typeOf": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for typeOf. got=%d, want=1", len(args))
			}
			return &String{Value: string(args[0].Type())}
		},
	},

	"substr": {
		Fn: func(args ...Object) Object {
			if len(args) < 2 || len(args) > 3 {
				return newError("wrong number of arguments for substr. got=%d, want=2 or 3", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("first argument to 'substr' must be STRING, got %s", args[0].Type())
			}

			start, ok := args[1].(*Int)
			if !ok {
				return newError("second argument to 'substr' must be INT, got %s", args[1].Type())
			}

			strLen := int64(len(str.Value))
			end := strLen
			if len(args) == 3 {
				e, ok := args[2].(*Int)
				if !ok {
					return newError("third argument to 'substr' must be INT, got %s", args[2].Type())
				}
				end = e.Value
			}

			if start.Value < 0 || start.Value > strLen || end < start.Value || end > strLen {
				return newError("substring indices out of range")
			}

			return &String{Value: str.Value[start.Value:end]}
		},
	},
	"split": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for split. got=%d, want=2", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("first argument to 'split' must be STRING, got %s", args[0].Type())
			}

			sep, ok := args[1].(*String)
			if !ok {
				return newError("second argument to 'split' must be STRING, got %s", args[1].Type())
			}

			parts := strings.Split(str.Value, sep.Value)
			elements := make([]Object, len(parts))
			for i, part := range parts {
				elements[i] = &String{Value: part}
			}

			return &Array{Elements: elements}
		},
	},
	"join": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for join. got=%d, want=2", len(args))
			}

			arr, ok := args[0].(*Array)
			if !ok {
				return newError("first argument to 'join' must be ARRAY, got %s", args[0].Type())
			}

			sep, ok := args[1].(*String)
			if !ok {
				return newError("second argument to 'join' must be STRING, got %s", args[1].Type())
			}

			parts := make([]string, len(arr.Elements))
			for i, elem := range arr.Elements {
				if s, ok := elem.(*String); ok {
					parts[i] = s.Value
				} else {
					parts[i] = elem.Inspect()
				}
			}

			return &String{Value: strings.Join(parts, sep.Value)}
		},
	},
	"trim": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for trim. got=%d, want=1", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("argument to 'trim' must be STRING, got %s", args[0].Type())
			}

			return &String{Value: strings.TrimSpace(str.Value)}
		},
	},
	"upper": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for upper. got=%d, want=1", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("argument to 'upper' must be STRING, got %s", args[0].Type())
			}

			return &String{Value: strings.ToUpper(str.Value)}
		},
	},
	"lower": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for lower. got=%d, want=1", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("argument to 'lower' must be STRING, got %s", args[0].Type())
			}

			return &String{Value: strings.ToLower(str.Value)}
		},
	},
	"containsStr": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for contains. got=%d, want=2", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("first argument to 'contains' must be STRING, got %s", args[0].Type())
			}

			substr, ok := args[1].(*String)
			if !ok {
				return newError("second argument to 'contains' must be STRING, got %s", args[1].Type())
			}

			return &Bool{Value: strings.Contains(str.Value, substr.Value)}
		},
	},
	"replace": {
		Fn: func(args ...Object) Object {
			if len(args) != 3 {
				return newError("wrong number of arguments for replace. got=%d, want=3", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("first argument to 'replace' must be STRING, got %s", args[0].Type())
			}

			old, ok := args[1].(*String)
			if !ok {
				return newError("second argument to 'replace' must be STRING, got %s", args[1].Type())
			}

			newStr, ok := args[2].(*String)
			if !ok {
				return newError("third argument to 'replace' must be STRING, got %s", args[2].Type())
			}

			return &String{Value: strings.ReplaceAll(str.Value, old.Value, newStr.Value)}
		},
	},
	"startsWith": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for startsWith. got=%d, want=2", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("first argument to 'startsWith' must be STRING, got %s", args[0].Type())
			}

			prefix, ok := args[1].(*String)
			if !ok {
				return newError("second argument to 'startsWith' must be STRING, got %s", args[1].Type())
			}

			return &Bool{Value: strings.HasPrefix(str.Value, prefix.Value)}
		},
	},
	"endsWith": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for endsWith. got=%d, want=2", len(args))
			}

			str, ok := args[0].(*String)
			if !ok {
				return newError("first argument to 'endsWith' must be STRING, got %s", args[0].Type())
			}

			suffix, ok := args[1].(*String)
			if !ok {
				return newError("second argument to 'endsWith' must be STRING, got %s", args[1].Type())
			}

			return &Bool{Value: strings.HasSuffix(str.Value, suffix.Value)}
		},
	},

	"abs": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for abs. got=%d, want=1", len(args))
			}

			switch arg := args[0].(type) {
			case *Int:
				if arg.Value < 0 {
					return &Int{Value: -arg.Value}
				}
				return arg
			case *Float:
				if arg.Value < 0 {
					return &Float{Value: -arg.Value}
				}
				return arg
			default:
				return newError("argument to 'abs' must be INT or FLOAT, got %s", args[0].Type())
			}
		},
	},
	"floor": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for floor. got=%d, want=1", len(args))
			}

			var val float64
			switch arg := args[0].(type) {
			case *Int:
				val = float64(arg.Value)
			case *Float:
				val = arg.Value
			default:
				return newError("argument to 'floor' must be INT or FLOAT, got %s", args[0].Type())
			}

			return &Int{Value: int64(math.Floor(val))}
		},
	},
	"ceil": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for ceil. got=%d, want=1", len(args))
			}

			var val float64
			switch arg := args[0].(type) {
			case *Int:
				val = float64(arg.Value)
			case *Float:
				val = arg.Value
			default:
				return newError("argument to 'ceil' must be INT or FLOAT, got %s", args[0].Type())
			}

			return &Int{Value: int64(math.Ceil(val))}
		},
	},
	"sqrt": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for sqrt. got=%d, want=1", len(args))
			}

			var val float64
			switch arg := args[0].(type) {
			case *Int:
				val = float64(arg.Value)
			case *Float:
				val = arg.Value
			default:
				return newError("argument to 'sqrt' must be INT or FLOAT, got %s", args[0].Type())
			}
			if val < 0 {
				return newError("cannot calculate square root of negative number")
			}

			return &Float{Value: math.Sqrt(val)}
		},
	},
	"pow": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for pow. got=%d, want=2", len(args))
			}

			var base, exp float64
			switch a := args[0].(type) {
			case *Int:
				base = float64(a.Value)
			case *Float:
				base = a.Value
			default:
				return newError("first argument to 'pow' must be INT or FLOAT, got %s", args[0].Type())
			}

			switch a := args[1].(type) {
			case *Int:
				exp = float64(a.Value)
			case *Float:
				exp = a.Value
			default:
				return newError("second argument to 'pow' must be INT or FLOAT, got %s", args[1].Type())
			}

			return &Float{Value: math.Pow(base, exp)}
		},
	},
	"min": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for min. got=%d, want=2", len(args))
			}

			var a, b float64
			switch arg := args[0].(type) {
			case *Int:
				a = float64(arg.Value)
			case *Float:
				a = arg.Value
			default:
				return newError("first argument to 'min' must be INT or FLOAT, got %s", args[0].Type())
			}

			switch arg := args[1].(type) {
			case *Int:
				b = float64(arg.Value)
			case *Float:
				b = arg.Value
			default:
				return newError("second argument to 'min' must be INT or FLOAT, got %s", args[1].Type())
			}

			if a <= b {
				return args[0]
			}
			return args[1]
		},
	},
	"max": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for max. got=%d, want=2", len(args))
			}

			var a, b float64
			switch arg := args[0].(type) {
			case *Int:
				a = float64(arg.Value)
			case *Float:
				a = arg.Value
			default:
				return newError("first argument to 'max' must be INT or FLOAT, got %s", args[0].Type())
			}

			switch arg := args[1].(type) {
			case *Int:
				b = float64(arg.Value)
			case *Float:
				b = arg.Value
			default:
				return newError("second argument to 'max' must be INT or FLOAT, got %s", args[1].Type())
			}

			if a >= b {
				return args[0]
			}
			return args[1]
		},
	},

	"int": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for int. got=%d, want=1", len(args))
			}

			switch arg := args[0].(type) {
			case *Int:
				return arg
			case *Float:
				return &Int{Value: int64(arg.Value)}
			case *String:
				val, err := strconv.ParseInt(arg.Value, 10, 64)
				if err != nil {
					return newError("could not convert string to int: %s", arg.Value)
				}
				return &Int{Value: val}
			case *Bool:
				if arg.Value {
					return &Int{Value: 1}
				}
				return &Int{Value: 0}
			default:
				return newError("cannot convert %s to INT", args[0].Type())
			}
		},
	},
	"float": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for float. got=%d, want=1", len(args))
			}

			switch arg := args[0].(type) {
			case *Int:
				return &Float{Value: float64(arg.Value)}
			case *Float:
				return arg
			case *String:
				val, err := strconv.ParseFloat(arg.Value, 64)
				if err != nil {
					return newError("could not convert string to float: %s", arg.Value)
				}
				return &Float{Value: val}
			case *Bool:
				if arg.Value {
					return &Float{Value: 1.0}
				}
				return &Float{Value: 0.0}
			default:
				return newError("cannot convert %s to FLOAT", args[0].Type())
			}
		},
	},
	"string": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for string. got=%d, want=1", len(args))
			}
			return &String{Value: args[0].Inspect()}
		},
	},

	"push": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for push. got=%d, want=2", len(args))
			}

			arr, ok := args[0].(*Array)
			if !ok {
				return newError("first argument to 'push' must be ARRAY, got %s", args[0].Type())
			}
			newElements := make([]Object, len(arr.Elements)+1)
			copy(newElements, arr.Elements)
			newElements[len(arr.Elements)] = args[1]
			return &Array{Elements: newElements}
		},
	},
	"pop": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for pop. got=%d, want=1", len(args))
			}

			arr, ok := args[0].(*Array)
			if !ok {
				return newError("argument to 'pop' must be ARRAY, got %s", args[0].Type())
			}
			if len(arr.Elements) == 0 {
				return newError("cannot pop from empty array")
			}
			lastElem := arr.Elements[len(arr.Elements)-1]
			newElements := make([]Object, len(arr.Elements)-1)
			copy(newElements, arr.Elements[:len(arr.Elements)-1])
			return &Array{Elements: newElements, LastPopped: lastElem}
		},
	},
	"first": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for first. got=%d, want=1", len(args))
			}

			arr, ok := args[0].(*Array)
			if !ok {
				return newError("argument to 'first' must be ARRAY, got %s", args[0].Type())
			}
			if len(arr.Elements) == 0 {
				return NULL
			}
			return arr.Elements[0]
		},
	},
	"last": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for last. got=%d, want=1", len(args))
			}
			arr, ok := args[0].(*Array)
			if !ok {
				return newError("argument to 'last' must be ARRAY, got %s", args[0].Type())
			}
			if len(arr.Elements) == 0 {
				return NULL
			}
			return arr.Elements[len(arr.Elements)-1]
		},
	},
	"rest": {
		Fn: func(args ...Object) Object {
			if len(args) < 2 || len(args) > 3 {
				return newError("wrong number of arguments for rest. got=%d, want=2 or 3", len(args))
			}

			arr, ok := args[0].(*Array)
			if !ok {
				return newError("first argument to 'rest' must be ARRAY, got %s", args[0].Type())
			}

			start, ok := args[1].(*Int)
			if !ok {
				return newError("second argument to 'rest' must be INT, got %s", args[1].Type())
			}
			arrLen := int64(len(arr.Elements))
			end := arrLen
			if len(args) == 3 {
				e, ok := args[2].(*Int)
				if !ok {
					return newError("third argument to 'rest' must be INT, got %s", args[2].Type())
				}
				end = e.Value
			}

			if start.Value < 0 || start.Value > arrLen || end < start.Value || end > arrLen {
				return newError("slice indices out of range")
			}
			return &Array{Elements: arr.Elements[start.Value:end]}
		},
	},
	"concat": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for concat. got=%d, want=2", len(args))
			}

			arr1, ok := args[0].(*Array)
			if !ok {
				return newError("first argument to 'concat' must be ARRAY, got %s", args[0].Type())
			}
			arr2, ok := args[1].(*Array)
			if !ok {
				return newError("second argument to 'concat' must be ARRAY, got %s", args[1].Type())
			}
			newElements := make([]Object, len(arr1.Elements)+len(arr2.Elements))
			copy(newElements, arr1.Elements)
			copy(newElements[len(arr1.Elements):], arr2.Elements)
			return &Array{Elements: newElements}
		},
	},
	"indexOf": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for indexOf. got=%d, want=2", len(args))
			}

			arr, ok := args[0].(*Array)
			if !ok {
				return newError("first argument to 'indexOf' must be ARRAY, got %s", args[0].Type())
			}

			for i, elem := range arr.Elements {
				if compareObjects(elem, args[1]) {
					return &Int{Value: int64(i)}
				}
			}

			return &Int{Value: -1}
		},
	},
	"containsArr": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for containsArr. got=%d, want=2", len(args))
			}

			arr, ok := args[0].(*Array)
			if !ok {
				return newError("first argument to 'containsArr' must be ARRAY, got %s", args[0].Type())
			}

			for _, elem := range arr.Elements {
				if compareObjects(elem, args[1]) {
					return TRUE
				}
			}
			return FALSE
		},
	},

	"keys": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for keys. got=%d, want=1", len(args))
			}

			m, ok := args[0].(*Map)
			if !ok {
				return newError("argument to 'keys' must be MAP, got %s", args[0].Type())
			}
			keys := make([]Object, len(m.Pairs))
			i := 0
			for _, pair := range m.Pairs {
				keys[i] = pair.Key
				i++
			}
			return &Array{Elements: keys}
		},
	},
	"values": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for values. got=%d, want=1", len(args))
			}

			m, ok := args[0].(*Map)
			if !ok {
				return newError("argument to 'values' must be MAP, got %s", args[0].Type())
			}
			vals := make([]Object, len(m.Pairs))
			i := 0
			for _, pair := range m.Pairs {
				vals[i] = pair.Value
				i++
			}
			return &Array{Elements: vals}
		},
	},
	"hasKey": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for hasKey. got=%d, want=2", len(args))
			}

			m, ok := args[0].(*Map)
			if !ok {
				return newError("first argument to 'hasKey' must be MAP, got %s", args[0].Type())
			}
			_, exists := m.Pairs[args[1].HashKey()]
			return &Bool{Value: exists}
		},
	},
	"delete": {
		Fn: func(args ...Object) Object {
			if len(args) != 2 {
				return newError("wrong number of arguments for delete. got=%d, want=2", len(args))
			}

			m, ok := args[0].(*Map)
			if !ok {
				return newError("first argument to 'delete' must be MAP, got %s", args[0].Type())
			}
			newPairs := make(map[HashKey]MapPair, len(m.Pairs)-1)
			for k, v := range m.Pairs {
				if k != args[1].HashKey() {
					newPairs[k] = v
				}
			}
			return &Map{Pairs: newPairs}
		},
	},

	"range": {
		Fn: func(args ...Object) Object {
			if len(args) < 1 || len(args) > 2 {
				return newError("wrong number of arguments for range. got=%d, want=1 or 2", len(args))
			}
			var start, end int64
			switch len(args) {
			case 1:
				e, ok := args[0].(*Int)
				if !ok {
					return newError("argument to 'range' must be INT, got %s", args[0].Type())
				}
				start = 0
				end = e.Value
			case 2:
				s, ok := args[0].(*Int)
				if !ok {
					return newError("first argument to 'range' must be INT, got %s", args[0].Type())
				}
				e, ok := args[1].(*Int)
				if !ok {
					return newError("second argument to 'range' must be INT, got %s", args[1].Type())
				}
				start = s.Value
				end = e.Value
			}
			elements := make([]Object, 0)
			if start <= end {
				elements = make([]Object, end-start+1)
				for i := start; i <= end; i++ {
					elements[i-start] = &Int{Value: i}
				}
			} else {
				elements = make([]Object, start-end+1)
				for i := start; i >= end; i-- {
					elements[start-i] = &Int{Value: i}
				}
			}
			return &Array{Elements: elements}
		},
	},
	"sort": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for sort. got=%d, want=1", len(args))
			}
			arr, ok := args[0].(*Array)
			if !ok {
				return newError("argument to 'sort' must be ARRAY, got %s", args[0].Type())
			}
			if len(arr.Elements) == 0 {
				return arr
			}

			sorted := make([]Object, len(arr.Elements))
			copy(sorted, arr.Elements)
			for i := 0; i < len(sorted)-1; i++ {
				for j := i + 1; j < len(sorted); j++ {
					if sorted[i].Inspect() > sorted[j].Inspect() {
						sorted[i], sorted[j] = sorted[j], sorted[i]
					}
				}
			}
			return &Array{Elements: sorted}
		},
	},
	"sum": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for sum. got=%d, want=1", len(args))
			}
			arr, ok := args[0].(*Array)
			if !ok {
				return newError("argument to 'sum' must be ARRAY, got %s", args[0].Type())
			}
			if len(arr.Elements) == 0 {
				return &Int{Value: 0}
			}
			var total int64
			var hasFloat bool
			for _, elem := range arr.Elements {
				switch e := elem.(type) {
				case *Int:
					total += e.Value
				case *Float:
					total += int64(e.Value)
					hasFloat = true
				default:
					return newError("array elements must be INT or FLOAT for sum, got %s", elem.Type())
				}
			}
			if hasFloat {
				return &Float{Value: float64(total)}
			}
			return &Int{Value: total}
		},
	},
	"avg": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for avg. got=%d, want=1", len(args))
			}
			arr, ok := args[0].(*Array)
			if !ok {
				return newError("argument to 'avg' must be ARRAY, got %s", args[0].Type())
			}
			if len(arr.Elements) == 0 {
				return &Float{Value: 0}
			}
			var total float64
			for _, elem := range arr.Elements {
				switch e := elem.(type) {
				case *Int:
					total += float64(e.Value)
				case *Float:
					total += e.Value
				default:
					return newError("array elements must be INT or FLOAT for avg, got %s", elem.Type())
				}
			}
			return &Float{Value: total / float64(len(arr.Elements))}
		},
	},
	"reverse": {
		Fn: func(args ...Object) Object {
			if len(args) != 1 {
				return newError("wrong number of arguments for reverse. got=%d, want=1", len(args))
			}
			arr, ok := args[0].(*Array)
			if !ok {
				return newError("argument to 'reverse' must be ARRAY, got %s", args[0].Type())
			}
			if len(arr.Elements) == 0 {
				return arr
			}
			reversed := make([]Object, len(arr.Elements))
			for i := 0; i < len(arr.Elements); i++ {
				reversed[i] = arr.Elements[len(arr.Elements)-1-i]
			}
			return &Array{Elements: reversed}
		},
	},
}

Builtins contains all built-in functions

View Source
var NULL = &Null{}

NULL is the singleton null value

View Source
var TypeMethods = map[ObjectType]map[string]*Builtin{
	IntType:    intMethods,
	FloatType:  floatMethods,
	StringType: stringMethods,
	ArrayType:  arrayMethods,
	MapType:    mapMethods,
	BoolType:   boolMethods,
	NullType:   nullMethods,
}

TypeMethods maps ObjectType -> methodName -> *Builtin

Functions

func IsTruthy

func IsTruthy(obj Object) bool

IsTruthy checks if an object is truthy

Types

type Array

type Array struct {
	Elements   []Object
	LastPopped Object // Used by pop() to return the popped value
}

Array represents an array value

func (*Array) HashKey

func (a *Array) HashKey() HashKey

HashKey returns the hash key for map operations

func (*Array) Inspect

func (a *Array) Inspect() string

Inspect returns the string representation

func (*Array) ToBool

func (a *Array) ToBool() *Bool

ToBool converts the array to a boolean

func (*Array) Type

func (a *Array) Type() ObjectType

Type returns the object type

func (*Array) TypeTag

func (a *Array) TypeTag() TypeTag

TypeTag returns the type tag for fast type checking

type Bool

type Bool struct {
	Value bool
}

Bool represents a boolean value

func (*Bool) HashKey

func (b *Bool) HashKey() HashKey

func (*Bool) Inspect

func (b *Bool) Inspect() string

func (*Bool) ToBool

func (b *Bool) ToBool() *Bool

func (*Bool) Type

func (b *Bool) Type() ObjectType

func (*Bool) TypeTag

func (b *Bool) TypeTag() TypeTag

type Builtin

type Builtin struct {
	Fn BuiltinFunction
}

Builtin represents a built-in function

func GetMethod

func GetMethod(objType ObjectType, name string) (*Builtin, bool)

GetMethod returns the builtin method for the given object type and method name

func (*Builtin) HashKey

func (b *Builtin) HashKey() HashKey

func (*Builtin) Inspect

func (b *Builtin) Inspect() string

func (*Builtin) ToBool

func (b *Builtin) ToBool() *Bool

func (*Builtin) Type

func (b *Builtin) Type() ObjectType

func (*Builtin) TypeTag

func (b *Builtin) TypeTag() TypeTag

type BuiltinFunction

type BuiltinFunction func(args ...Object) Object

BuiltinFunction is the type for built-in functions

type Class

type Class struct {
	Name       string
	SuperClass *Class
	Methods    map[string]Object // methods are CompiledFunction objects
	InitMethod Object            // constructor method
	Fields     map[string]Object // default field values
}

Class represents a class definition

func (*Class) HashKey

func (c *Class) HashKey() HashKey

func (*Class) Inspect

func (c *Class) Inspect() string

func (*Class) ToBool

func (c *Class) ToBool() *Bool

func (*Class) Type

func (c *Class) Type() ObjectType

func (*Class) TypeTag

func (c *Class) TypeTag() TypeTag

type CompiledFunction

type CompiledFunction struct {
	Instructions  []byte
	NumLocals     int
	NumParameters int
	Name          string
}

CompiledFunction represents a compiled function for the VM

func (*CompiledFunction) HashKey

func (cf *CompiledFunction) HashKey() HashKey

func (*CompiledFunction) Inspect

func (cf *CompiledFunction) Inspect() string

func (*CompiledFunction) ToBool

func (cf *CompiledFunction) ToBool() *Bool

func (*CompiledFunction) Type

func (cf *CompiledFunction) Type() ObjectType

func (*CompiledFunction) TypeTag

func (cf *CompiledFunction) TypeTag() TypeTag

type Environment

type Environment struct {
	Store map[string]Object
	Outer *Environment
}

Environment represents a variable scope

func NewEnclosedEnvironment

func NewEnclosedEnvironment(outer *Environment) *Environment

NewEnclosedEnvironment creates a new environment with an outer scope

func NewEnvironment

func NewEnvironment() *Environment

NewEnvironment creates a new environment

func (*Environment) Get

func (e *Environment) Get(name string) (Object, bool)

Get retrieves a variable from the environment

func (*Environment) Set

func (e *Environment) Set(name string, val Object) Object

Set sets a variable in the environment

type Error

type Error struct {
	Message string
}

Error represents a runtime error

func (*Error) HashKey

func (e *Error) HashKey() HashKey

func (*Error) Inspect

func (e *Error) Inspect() string

func (*Error) ToBool

func (e *Error) ToBool() *Bool

func (*Error) Type

func (e *Error) Type() ObjectType

func (*Error) TypeTag

func (e *Error) TypeTag() TypeTag

type Float

type Float struct {
	Value float64
}

Float represents a floating-point value

func (*Float) HashKey

func (f *Float) HashKey() HashKey

HashKey returns the hash key for map operations

func (*Float) Inspect

func (f *Float) Inspect() string

Inspect returns the string representation

func (*Float) ToBool

func (f *Float) ToBool() *Bool

ToBool converts the float to a boolean

func (*Float) Type

func (f *Float) Type() ObjectType

Type returns the object type

func (*Float) TypeTag

func (f *Float) TypeTag() TypeTag

TypeTag returns the type tag for fast type checking

type Function

type Function struct {
	Parameters []*Identifier
	Body       interface{} // Will be *ast.BlockStatement, using interface{} to avoid import cycle
	Env        *Environment
	Name       string // Optional: for named functions
}

Function represents a user-defined function

func (*Function) HashKey

func (f *Function) HashKey() HashKey

func (*Function) Inspect

func (f *Function) Inspect() string

func (*Function) ToBool

func (f *Function) ToBool() *Bool

func (*Function) Type

func (f *Function) Type() ObjectType

func (*Function) TypeTag

func (f *Function) TypeTag() TypeTag

type HashKey

type HashKey struct {
	Type  ObjectType
	Value uint64
}

HashKey is used for map keys

type Identifier

type Identifier struct {
	Value string
}

Identifier represents an identifier (used in function parameters)

func (*Identifier) String

func (i *Identifier) String() string

type Instance

type Instance struct {
	Class  *Class
	Fields map[string]Object
}

Instance represents an instance of a class

func (*Instance) HashKey

func (i *Instance) HashKey() HashKey

func (*Instance) Inspect

func (i *Instance) Inspect() string

func (*Instance) ToBool

func (i *Instance) ToBool() *Bool

func (*Instance) Type

func (i *Instance) Type() ObjectType

func (*Instance) TypeTag

func (i *Instance) TypeTag() TypeTag

type Int

type Int struct {
	Value int64
}

Int represents an integer value

func NewInt

func NewInt(val int64) *Int

NewInt creates a new Int object, using cache for small values

func (*Int) HashKey

func (i *Int) HashKey() HashKey

HashKey returns the hash key for map operations

func (*Int) Inspect

func (i *Int) Inspect() string

Inspect returns the string representation

func (*Int) ToBool

func (i *Int) ToBool() *Bool

ToBool converts the integer to a boolean

func (*Int) Type

func (i *Int) Type() ObjectType

Type returns the object type

func (*Int) TypeTag

func (i *Int) TypeTag() TypeTag

TypeTag returns the type tag for fast type checking

type Map

type Map struct {
	Pairs map[HashKey]MapPair
}

Map represents a map value

func (*Map) HashKey

func (m *Map) HashKey() HashKey

HashKey returns the hash key for map operations

func (*Map) Inspect

func (m *Map) Inspect() string

Inspect returns the string representation

func (*Map) ToBool

func (m *Map) ToBool() *Bool

ToBool converts the map to a boolean

func (*Map) Type

func (m *Map) Type() ObjectType

Type returns the object type

func (*Map) TypeTag

func (m *Map) TypeTag() TypeTag

TypeTag returns the type tag for fast type checking

type MapPair

type MapPair struct {
	Key   Object
	Value Object
}

MapPair represents a key-value pair in a map

type Module

type Module struct {
	// Name is the module's identifier (typically the file path)
	Name string

	// Exports maps exported symbol names to their values
	Exports map[string]Object

	// Globals holds the module's global variables state.
	// This is needed so exported functions can access module-level variables.
	Globals []Object
}

Module represents a loaded module with its exported symbols. Modules are created when a source file is imported and compiled, and they hold all exported values accessible to importers.

func (*Module) HashKey

func (m *Module) HashKey() HashKey

HashKey returns a hash key for the module. Modules are not hashable in a meaningful way, so we return a constant.

func (*Module) Inspect

func (m *Module) Inspect() string

Inspect returns a string representation of the module.

func (*Module) ToBool

func (m *Module) ToBool() *Bool

ToBool converts the module to a boolean (always true).

func (*Module) Type

func (m *Module) Type() ObjectType

Type returns the object type.

func (*Module) TypeTag

func (m *Module) TypeTag() TypeTag

TypeTag returns the type tag for fast type checking.

type Null

type Null struct{}

Null represents the null value

func (*Null) HashKey

func (n *Null) HashKey() HashKey

func (*Null) Inspect

func (n *Null) Inspect() string

func (*Null) ToBool

func (n *Null) ToBool() *Bool

func (*Null) Type

func (n *Null) Type() ObjectType

func (*Null) TypeTag

func (n *Null) TypeTag() TypeTag

type Object

type Object interface {
	Type() ObjectType
	TypeTag() TypeTag // Fast type check without string comparison
	Inspect() string
	ToBool() *Bool
	HashKey() HashKey
}

Object is the base interface for all values in Xxlang

type ObjectType

type ObjectType string

ObjectType represents the type of an object

const (
	NullType     ObjectType = "NULL"
	IntType      ObjectType = "INT"
	FloatType    ObjectType = "FLOAT"
	StringType   ObjectType = "STRING"
	BoolType     ObjectType = "BOOL"
	ArrayType    ObjectType = "ARRAY"
	MapType      ObjectType = "MAP"
	FunctionType ObjectType = "FUNCTION"
	BuiltinType  ObjectType = "BUILTIN"
	BytesType    ObjectType = "BYTES"
	ClassType    ObjectType = "CLASS"
	InstanceType ObjectType = "INSTANCE"
	ErrorType    ObjectType = "ERROR"
	ReturnType   ObjectType = "RETURN"
	ClosureType  ObjectType = "CLOSURE"
	ModuleType   ObjectType = "MODULE"
)

Object types

const CompiledFunctionType ObjectType = "COMPILED_FUNCTION"

CompiledFunctionType is the type for compiled functions

type Return

type Return struct {
	Value Object
}

Return represents a return value (used internally)

func (*Return) HashKey

func (r *Return) HashKey() HashKey

func (*Return) Inspect

func (r *Return) Inspect() string

func (*Return) ToBool

func (r *Return) ToBool() *Bool

func (*Return) Type

func (r *Return) Type() ObjectType

func (*Return) TypeTag

func (r *Return) TypeTag() TypeTag

type String

type String struct {
	Value string
}

String represents a string value

func InternBatch

func InternBatch(strings []string) []*String

InternBatch pre-interns a batch of strings

func InternString

func InternString(val string) *String

Intern returns a cached *String for the given value This reduces allocations for frequently used strings

func (*String) HashKey

func (s *String) HashKey() HashKey

HashKey returns the hash key for map operations

func (*String) Inspect

func (s *String) Inspect() string

Inspect returns the string representation

func (*String) ToBool

func (s *String) ToBool() *Bool

ToBool converts the string to a boolean

func (*String) Type

func (s *String) Type() ObjectType

Type returns the object type

func (*String) TypeTag

func (s *String) TypeTag() TypeTag

TypeTag returns the type tag for fast type checking

type TypeTag

type TypeTag uint8

TypeTag is a fast integer type identifier for hot path checks

const (
	TagNull TypeTag = iota
	TagInt
	TagFloat
	TagString
	TagBool
	TagArray
	TagMap
	TagFunction
	TagBuiltin
	TagBytes
	TagClass
	TagInstance
	TagError
	TagReturn
	TagClosure
	TagModule
	TagUnknown
)

Type tags for fast type checking (must match ObjectType order)

const TagCompiledFunction TypeTag = TagClosure // Use same tag as Closure

TagCompiledFunction is the type tag for compiled functions

Jump to

Keyboard shortcuts

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