globals

package
v0.15.1 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2025 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package globals provides core functionality for module imports and dependency resolution in the Xel programming language. It handles both local file imports and remote package resolution, including dependency management and circular import detection.

Index

Constants

This section is empty.

Variables

View Source
var Import = values.MK_NATIVE_FN(func(args []shared.RuntimeValue, env *environment.Environment) (*shared.RuntimeValue, *errors.RuntimeError) {

	if len(args) != 1 {
		return nil, &errors.RuntimeError{
			Message: fmt.Sprintf("`import` requires exactly one argument, but received %d", len(args)),
		}
	}

	if args[0].Type != shared.String {
		return nil, &errors.RuntimeError{
			Message: fmt.Sprintf("`import` expects a string argument, but received %s (%s)",
				helpers.Stringify(args[0], false),
				shared.Stringify(args[0].Type)),
		}
	}

	libname := args[0].Value.(string)

	if loader, isNative := modules.GetNativeModuleLoader(libname); isNative {
		return loader()
	}

	libpath := fmt.Sprintf("%s.xel", libname)

	useCache := true

	modEnv := environment.NewEnvironment(xShared.XelRootEnv)

	if libname[0] == '.' {

		dirname := filepath.Dir(xShared.XelRootDebugger.CurrentFile)

		libpath = filepath.Join(dirname, libpath)
	} else {

		processRuntimeVal, err := env.LookupVar("proc")
		if err != nil {
			return nil, &errors.RuntimeError{
				Message: fmt.Sprintf("Failed to lookup process information: %v", err),
			}
		}

		if processRuntimeVal.Type != shared.Object {
			return nil, &errors.RuntimeError{
				Message: fmt.Sprintf("Expected 'proc' to be an object, but got %s (%s)",
					helpers.Stringify(*processRuntimeVal, false),
					shared.Stringify(processRuntimeVal.Type)),
			}
		}

		processObj := processRuntimeVal.Value.(map[string]*shared.RuntimeValue)
		manifestRuntimeVal, exists := processObj["manifest"]
		if !exists || manifestRuntimeVal == nil {
			return nil, &errors.RuntimeError{
				Message: "Project manifest is not available in process object",
			}
		}

		if manifestRuntimeVal.Type != shared.Object {
			return nil, &errors.RuntimeError{
				Message: fmt.Sprintf("Expected manifest to be an object, but got %s (%s)",
					helpers.Stringify(*manifestRuntimeVal, false),
					shared.Stringify(manifestRuntimeVal.Type)),
			}
		}

		manifest := manifestRuntimeVal.Value.(map[string]*shared.RuntimeValue)

		depsVal, depsExists := manifest["deps"]
		if !depsExists || depsVal.Type != shared.Object {
			return nil, &errors.RuntimeError{
				Message: "Project manifest is missing or has invalid 'dependencies' section",
			}
		}
		dependencies := depsVal.Value.(map[string]*shared.RuntimeValue)

		pkgConstraint, exists := dependencies[libname]
		if !exists {
			return nil, &errors.RuntimeError{
				Message: fmt.Sprintf("Package '%s' is not listed in the project's dependencies", libname),
			}
		}

		constraint := pkgConstraint.Value.(string)

		pkgManifestPath, pkgManifest, resolutionErr := helpers.ResolveModuleLocal(libname, constraint)
		if resolutionErr != nil {
			return nil, &errors.RuntimeError{
				Message: fmt.Sprintf("Failed to resolve package '%s' (constraint: %s): %v",
					libname, constraint, resolutionErr),
			}
		}

		manifestConverted := map[string]*shared.RuntimeValue{}

		addStringField := func(key, value string) {
			val := values.MK_STRING(value)
			manifestConverted[key] = &val
		}

		addStringField("name", pkgManifest.Name)
		addStringField("description", pkgManifest.Description)
		addStringField("version", pkgManifest.Version)
		addStringField("xel", *pkgManifest.Xel)
		addStringField("engine", *pkgManifest.Engine)
		addStringField("main", pkgManifest.Main)
		addStringField("author", pkgManifest.Author)
		addStringField("license", pkgManifest.License)

		depsMap := make(map[string]*shared.RuntimeValue, len(*pkgManifest.Deps))
		for depName, depConstraint := range *pkgManifest.Deps {
			depVal := values.MK_STRING(depConstraint)
			depsMap[depName] = &depVal
		}
		depsObj := values.MK_OBJECT(depsMap)
		manifestConverted["deps"] = &depsObj

		modifiedProc := helpers.DeepCopyObject(processRuntimeVal.Value.(map[string]*shared.RuntimeValue))

		manifestVal := values.MK_OBJECT(manifestConverted)
		modifiedProc["manifest"] = &manifestVal

		modEnv.DeclareVar("proc", values.MK_OBJECT(modifiedProc), true)

		pkgPath := filepath.Dir(pkgManifestPath)
		libpath = filepath.Join(pkgPath, pkgManifest.Main)
	}

	if resolvingImports[libpath] {
		return nil, &errors.RuntimeError{
			Message: fmt.Sprintf("Circular import detected while importing '%s'", libpath),
		}
	}

	if val, exists := importCache[libpath]; exists && useCache {
		return val, nil
	}

	resolvingImports[libpath] = true

	defer delete(resolvingImports, libpath)

	libExports, err := evaluateModule(libpath, modEnv)
	if err != nil {
		return nil, err
	}

	return libExports, nil
})

Import is the native function implementation for the `import` statement in Xel. It handles module resolution, caching, and circular dependency detection.

Supported import patterns:

  • Local file: import("./path/to/file")
  • Scoped package: import("@scope/package")
  • Regular package: import("package")

The function performs the following operations: 1. Validates the import statement syntax 2. Resolves the module path (local or remote) 3. Checks for circular dependencies 4. Returns cached module if available 5. Otherwise, loads and evaluates the module

View Source
var Len = values.MK_NATIVE_FN(func(args []shared.RuntimeValue, env *environment.Environment) (*shared.RuntimeValue, *errors.RuntimeError) {
	if len(args) != 1 {
		return nil, &errors.RuntimeError{
			Message: "len() takes exactly one argument",
		}
	}

	if args[0].Type != shared.Array && args[0].Type != shared.String {
		return nil, &errors.RuntimeError{
			Message: "len() takes an array or string as an argument",
		}
	}

	result := values.MK_NIL()

	if args[0].Type == shared.String {
		result = values.MK_NUMBER(float64(len(args[0].Value.(string))))
	} else {
		result = values.MK_NUMBER(float64(len(args[0].Value.([]shared.RuntimeValue))))
	}

	return &result, nil
})
View Source
var Print = values.MK_NATIVE_FN(func(args []shared.RuntimeValue, env *environment.Environment) (*shared.RuntimeValue, *errors.RuntimeError) {
	out := ""
	for i, arg := range args {
		out += helpers.Stringify(arg, false)

		if len(args)-1 != i {
			out += " "
		}
	}
	fmt.Printf("%s\r\n", out)
	result := values.MK_NIL()
	return &result, nil
})
View Source
var Throw = values.MK_NATIVE_FN(func(args []shared.RuntimeValue, env *environment.Environment) (*shared.RuntimeValue, *errors.RuntimeError) {
	if len(args) != 1 {
		return nil, &errors.RuntimeError{Message: "throw() takes exactly one argument"}
	}

	if args[0].Type != shared.String {
		return nil, &errors.RuntimeError{
			Message: fmt.Sprintf("throw() takes a string as an argument, but got %s", shared.Stringify(args[0].Type)),
		}
	}

	out := args[0].Value.(string)
	return nil, &errors.RuntimeError{Message: out}
})
View Source
var Typeof = values.MK_NATIVE_FN(func(args []shared.RuntimeValue, env *environment.Environment) (*shared.RuntimeValue, *errors.RuntimeError) {
	if len(args) != 1 {
		return nil, &errors.RuntimeError{
			Message: "typeof() takes exactly one argument",
		}
	}
	result := values.MK_STRING(shared.Stringify(args[0].Type))
	return &result, nil
})

Functions

func Globalize

func Globalize(env *environment.Environment)

func Proc

func Proc() shared.RuntimeValue

Types

This section is empty.

Jump to

Keyboard shortcuts

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