Releases: dev-kas/xel
Xel v0.15.1
Full Changelog: v0.15.0...v0.15.1
Xel v0.15.0
Full Changelog: v0.14.0...v0.15.0
Xel v0.14.0
Xel v0.14.0 Release Notes: A Full-Featured Package Manager with Registry Support, Lockfiles, and Install Scripts!
We are thrilled to announce the release of Xel v0.14.0, a monumental update that transforms Xel into a true, professional-grade development ecosystem. This release delivers a complete, robust, and full-featured package management system, building upon the foundational work of previous versions to provide a seamless and powerful developer experience.
While v0.6.0 introduced the initial xel pkg command, v0.14.0 realizes the full vision. With support for an official package registry, deterministic installs via lockfiles (xel.lock), recursive dependency resolution, package install scripts (setup.xel), and a complete command suite (add, remove, list), managing Xel projects has never been easier or more reliable.
🚀 Major Features & Enhancements
-
A Complete Package Management Suite (
xel pkg)
Thexel pkgcommand suite has been fully implemented, providing a comprehensive workflow for managing project dependencies.pkg add <packageName>[@version](aliasinstall):- Registry & Git Support: Installs packages from the official Xel package registry by name, or directly from
git+URLs. - Recursive Dependency Resolution: When you add a package, Xel now automatically downloads and installs all of its dependencies, ensuring a complete and working environment.
- Manifest Integration: Automatically updates your project's
xel.jsonfile, adding the new package and its resolved version to thedepssection.
- Registry & Git Support: Installs packages from the official Xel package registry by name, or directly from
pkg remove <packageName>(aliasuninstall):- Safely removes a package from your project.
- Local & Global Scopes: Intelligently determines whether to remove a package from just the local project's
xel.jsonandxel.lock, or to completely uninstall it from your global~/.xel/modulescache (using the--globalflag).
pkg list:- Instantly view all packages installed in the current project, listing their names and exact versions as defined in your
xel.json.
- Instantly view all packages installed in the current project, listing their names and exact versions as defined in your
-
Deterministic Installs with Lockfiles (
xel.lock)
To ensure your projects are reliable and reproducible across different machines and environments, Xel now generates and uses axel.lockfile.- Reproducible Builds: The lockfile records the exact version, resolved download URL, and integrity hash (
sha256) for every installed package and its dependencies. - Installation Speed: When a
xel.lockfile is present,xel pkg addwill use it to download the exact, pre-verified versions of packages, bypassing version resolution and speeding up subsequent installs.
- Reproducible Builds: The lockfile records the exact version, resolved download URL, and integrity hash (
-
Official Package Registry Integration
Xel can now fetch packages from a central package registry, making it incredibly simple to discover and use community libraries.- Seamless Downloads: Simply run
xel pkg add rocketsand Xel will query the registry (configurable viaPackageRegistryURIin~/.xel/config.json) for the package. - Secure & Verified: Packages downloaded from the registry are delivered as
.tar.gztarballs. Xel verifies the integrity of every download using a secure hash (e.g.,sha256) provided by the registry, protecting against corrupted or tampered packages.
- Seamless Downloads: Simply run
-
Support for Package Install Scripts (
setup.xel)
Packages can now include asetup.xelscript to perform complex installation or build steps.- Purpose: This is ideal for packages that need to compile native components using the
xel:nativeFFI, set up configuration files, or perform other post-download tasks. - Execution: Xel automatically detects and runs
setup.xelafter a package is successfully downloaded and extracted. - Security: This powerful feature is enabled by default but can be disabled by setting
AllowInstallScripts: falsein your global~/.xel/config.json.
- Purpose: This is ideal for packages that need to compile native components using the
-
Refined Project Manifest (
xel.json)
TheProjectManifeststructure has been improved to support optional fields. Fields likexel,engine, anddepswill now be omitted from the JSON file if they are not present, leading to cleaner and more minimal manifest files for simple packages.
🛠️ Improvements & Fixes
array.reduce()Enhancement: Thexel:arraymodule'sreduce()function is now more flexible. TheinitialValue(accumulator) argument is now optional. If omitted,reduce()will use the first element of the array as the initial value, matching the behavior of modern JavaScript.- Dependency Updates: Core dependencies including
github.com/Masterminds/semver/v3,github.com/dev-kas/virtlang-go/v4, andgithub.qkg1.top/urfave/cli/v2have been updated to their latest versions, bringing bug fixes and stability improvements.
Example Workflow
# Start a new Xel project
$ xel init
# Add a package from the registry
$ xel pkg add rockets@^1.0.0
> Package `rockets@1.2.5` installed
# xel.json is updated, and xel.lock is created!
# See what's installed in your project
$ xel pkg list
> Installed Packages in my-project@0.1.0:
> --------------------
> - rockets@1.2.5
# Remove the package from the project
$ xel pkg remove rockets
> Package `rockets` removed from project manifest.
# Or, uninstall it from the global cache entirely
# $ xel pkg remove --global rocketsUpgrade Notes
- This is a minor version increment that introduces a massive suite of new package management features.
- No breaking changes are expected for existing Xel scripts. Your existing projects will seamlessly benefit from the new package manager.
- Update your Xel binary to access the new
pkgcommand functionalities.
Getting Started
- Update to Xel v0.14.0: Download the latest binary from our GitHub Releases page.
- Manage your dependencies: Navigate to your project directory and start using
xel pkg add,xel pkg remove, andxel pkg list.
Acknowledgements
A huge thank you to @dev-kas for the incredible effort in designing and implementing this comprehensive package management system. This is a transformative release that solidifies Xel as a serious and capable scripting platform.
Xel v0.14.0 elevates the developer experience to new heights, providing the tools you need to build, share, and manage complex applications with confidence. We are incredibly excited to see the ecosystem of libraries and tools you'll create! Happy scripting
Xel v0.13.0
Xel Runtime v0.13.0 Release Notes: Introducing the xel:object Module for Powerful Object Manipulation and Enhanced Core Stability!
We are excited to announce the release of Xel v0.13.0! This release marks a significant step forward in Xel's data manipulation capabilities with the introduction of the brand new xel:object module. This module empowers you to dynamically create, manipulate, and query objects, a fundamental data structure, directly within your Xel scripts.
Before v0.13.0, while Xel supported creating object literals (e.g., { hello: "world" }), there was no way to directly manipulate these objects using built-in functions. The xel:object module fills this critical gap, significantly enhancing the flexibility and expressiveness of the language.
Building on previous feature modules such as xel:time in v0.8.0, xel:threads in v0.9.0, xel:native in v0.10.0, and on OOP support via v0.12.0's integrated class system, this release represents the next evolution in Xel's core capabilities.
Beyond the new xel:object module, this release incorporates essential bug fixes addressing object comparison and string representation, greatly improving the stability and reliability of Xel.
🚀 Major Features & Enhancements
-
New Native
xel:objectModule: Empowering Dynamic Object Manipulation!-
Purpose: Provides a comprehensive suite of functions for creating, modifying, and querying object literals.
-
Availability: Access these capabilities via
import("xel:object"). -
Functions:
-
object.create([initialObject]): Creates a new, empty object. Optionally, you can initialize it with properties from an existing object. -
object.set(obj, key, value): Sets the value of the propertykeyon the given objectobj. If the key doesn't exist, it's added. Ifvalueis omitted, the propertykeyis set tonil. -
object.get(obj, key): Retrieves the value of the propertykeyfrom the objectobj. Returnsnilif the property doesn't exist. -
object.keys(obj): Returns anarraycontaining all the keys (property names) of the objectobjas anarrayof strings. -
object.values(obj): Returns anarraycontaining all the values of the properties in the objectobj. The order corresponds to the order of keys returned byobject.keys(). -
object.delete(obj, key): Removes the propertykeyfrom the objectobj. Returns the object. If the property didn't exist, nothing happens. -
object.has(obj, key): Checks if the objectobjhas a property with the namekey. Returnstrueif the property exists,falseotherwise. -
object.merge(obj1, obj2): Creates a new object that is a combination ofobj1andobj2. Properties inobj2overwrite properties inobj1if they have the same key. The result is a merged object, not a modification to the original. -
object.clone(obj): Creates a new object that is a shallow copy ofobj. Changes to properties in the cloned object will not affect the original. This ensures that data is copied, not simply referenced. -
object.pick(obj, keys): Creates a new object containing only the properties specified in thekeysarray. If a key doesn't exist inobj, it's simply omitted from the result. This is useful for creating subsets of object properties. -
object.omit(obj, keys): Creates a new object containing all properties fromobjexcept those specified in thekeysarray. This is the inverse ofobject.pick. -
object.entries(obj): Returns anarrayofarrays, where each inner array represents a key-value pair. The first element of each inner array is the key (a string), and the second element is the corresponding value. This is useful for iterating over object properties. -
object.isEmpty(obj): Checks if the objectobjhas any properties. Returnstrueif it's empty,falseotherwise. -
object.equal(obj1, obj2): Performs a deep comparison ofobj1andobj2. Returnstrueif the objects are structurally identical (same keys and values),falseotherwise.
-
-
Examples:
- The
example/box/main.xelscript provides a fundamental introduction to thexel:objectmodule, demonstrating core functions like creating, setting, getting, and deleting properties. - The
example/box/extended.xelscript showcases a wider range of functionality, includingmerge,clone,pick,omit, and other functions, and helps developers unlock the full power of Xel's object handling.
- The
-
🛠️ Improvements & Fixes
-
Critical Fix: Accurate Object Comparison (
equalRuntimeValues.go)- Problem: Previous versions of Xel had a bug in the
equal()function, which caused incorrect comparisons of objects, especially when they contained nested objects. - Solution: The internal
equalRuntimeValuesfunction, which underpinsobject.equal(), has been completely rewritten to recursively compare object properties, ensuring accurate deep comparisons. - Impact: The
object.equal()function is now reliable for comparing objects, even with complex nested structures. - Recommendation: We highly recommend upgrading to this version to avoid potential errors in object comparisons.
- Problem: Previous versions of Xel had a bug in the
-
Preventing Infinite Loops in Object Printing (
stringify.go)- Problem: As with other languages, the internal
stringifyfunction (used byprint()and other functions that convert values to strings) could enter an infinite recursion loop when attempting to print objects with circular references (where an object contains a reference to itself, directly or indirectly). - Solution: We've implemented cycle detection in the
stringifyfunction. When a circular reference is encountered,stringifywill now output a "[Circular *n: path]" message indicating the circular dependency's origin instead of crashing the runtime. The depth is also limited to prevent stack overflows, displaying "[Maximum depth exceeded]" if reached. - Impact: Xel can now gracefully handle objects with circular references without crashing.
- Problem: As with other languages, the internal
Core Runtime & Architectural Changes
- Integration of the new
xel/modules/objectpackage as a built-in native module, immediately accessible viaimport("xel:object").
Upgrade Notes
- This release includes a major new module (
xel:object) and crucial bug fixes. - No breaking changes are expected for existing scripts. However, please review object comparisons if you are using the
object.equal()function, as the behavior is now significantly more accurate.
Getting Started
- Update to Xel v0.13.0: Download the latest binary from our GitHub Releases page.
- Explore the
xel:objectModule:- Add
const object = import("xel:object")to your scripts. - Start with the
example/box/main.xelscript to understand core functionalities. Then, exploreexample/box/extended.xelfor advanced usage patterns.
- Add
- Review Object Comparisons: If your existing scripts use the
equal()function, ensure that they are working correctly with the improved comparison logic.
Acknowledgements
A huge thank you to @dev-kas for the continued dedication to improving Xel, especially for the development of the xel:object module and the critical bug fixes in this release!
Xel v0.13.0 empowers you with powerful object manipulation capabilities and delivers enhanced core stability. We are incredibly excited to see the innovative solutions you'll build with these new tools! Happy scripting!
Xel v0.12.0
Xel Runtime v0.12.0 Release Notes: Deeper Class Introspection & Enhanced Error Handling!
We are absolutely thrilled to announce the release of Xel v0.12.0! This version takes a significant step forward by empowering your Xel applications with deeper control and introspection over Object-Oriented Programming (OOP) constructs, building upon the existing class system.
Following our recent advancements in system control (xel:os in v0.11.0), parallelism (xel:threads in v0.9.0), and native integration (xel:native in v0.10.0), Xel v0.12.0 enhances your ability to write more organized, reusable, and maintainable code by providing robust tools to interact with classes and their instances. This release also introduces a new global error throw() function and refines existing global variables for greater accuracy.
🚀 Major Features & Enhancements
-
Enhanced Class System Capabilities: Meaningful Member Visibility
Building on Xel's existingclassfunctionality, this release brings refined control and clarity to your object-oriented designs by leveraging the existingpublicandprivatekeywords.- Leveraging
publicandprivate: While theclasskeyword and basic member visibility syntax have been present, this release introduces tools that distinguish and leverage these modifiers. This means you can now write code that introspects and interacts specifically with a class's public interface, making the distinction between public and private members more meaningful for library authors and developers. - Refined
constructor()Method: The specialconstructormethod continues to be the entry point for initializing new instances of a class, ensuring proper setup of object state. - Benefits: These enhancements solidify Xel's OOP capabilities by providing new ways to analyze and interact with classes, promoting encapsulation by convention and making it easier to manage application state and build more robust and maintainable class-based architectures.
class Person { public name private age // Age is only accessible inside this class definition public constructor(name_param, age_param) { name = name_param age = age_param } public greet() { print(strings.format("Hello, my name is %v and I'm %v years old.", name, age)) } public haveBirthday() { age = age + 1 print(strings.format("Happy Birthday! %v is now %v.", name, age)) } // This method can access 'age' as it's within the same class definition public getAge() { return age } } const jedi = Person("Jedi", 30) jedi.greet() jedi.haveBirthday() print(jedi.name) // "Jedi" (public) // Attempting to access 'jedi.age' directly will not work, // hence the new xel:classes.properties() will not show it, // reinforcing the 'private' convention. print(jedi.getAge()) // 31 (accessible via public method) - Leveraging
-
New Global
throw()Function for Explicit Error Handling
You can now programmatically raise runtime errors using the new globalthrow()function. This complements thetry...catchmechanism introduced with VirtLang-Go v4.0.0 (in Xel v0.9.0) and is essential for implementing robust validation and error signaling within your applications.throw(message: string): Takes a single string argument, which becomes the error message. The script execution will immediately halt unless caught by atry...catchblock.
fn validateInput(value) { if (typeof(value) != "string" || len(value) == 0) { throw("Input must be a non-empty string!") } print("Input is valid:", value) } try { validateInput(123) } catch e { print("Caught validation error:", e.message) // Caught validation error: Input must be a non-empty string! }
📦 New Standard Library Module
-
xel:classesModule: Introspection for Your Classes!
To provide powerful tools for working with and inspecting the class system, a newxel:classesstandard library module has been introduced. This module provides functions for runtime introspection of classes and instances, leveraging thepublicandprivatedistinctions.- Availability: Access these capabilities via
import("xel:classes"). - Key Functionality:
classes.instanceOf(Class, instance): Checks if a giveninstanceis an instance of the specifiedClassblueprint. Returns a boolean.classes.getClass(instance): Retrieves the originalClassdefinition object from a given classinstance. This allows you to create new instances of the same class from an existing object, or inspect its definition.classes.methods(Class): Returns an array of strings containing the names of all public methods defined on the givenClass. Private methods are excluded.classes.properties(Class): Returns an array of strings containing the names of all public properties defined on the givenClass. Private properties are excluded.
- Benefits: These functions enable powerful reflection capabilities, dynamic programming patterns, and are crucial for building meta-programming tools or frameworks within Xel by allowing you to inspect the intended public interface of classes.
const classes = import("xel:classes") // ... (Person class definition from above) ... const jedi = Person("Jedi", 30) print(classes.instanceOf(Person, jedi)) // true const PersonClass = classes.getClass(jedi) // Get the 'Person' class definition from the 'jedi' instance const thanos = PersonClass("Thanos", 1000) // Create a new 'Person' instance using the retrieved class thanos.greet() // Hello, my name is Thanos and I'm 1000 years old. print(classes.methods(PersonClass)) // ["greet", "haveBirthday", "getAge"] print(classes.properties(PersonClass)) // ["name"] (only public properties, 'age' is not listed here!) - Availability: Access these capabilities via
🛠️ Improvements & Fixes
- Accurate
__dirname__and__filename__Global Variables
The global variables__dirname__and__filename__have been significantly improved. They now precisely reflect the directory and full path, respectively, of the currently executing Xel script file, rather than the program's current working directory or an empty string. This ensures more reliable path resolution, especially for imported modules or when scripts are executed from different locations. This fix was identified and implemented during the development of thethrowfunction. - Cleaner Runtime Error Output
The formatting of runtime error messages has been streamlined, now usingPrintlninstead ofPrintf. This results in a cleaner, more direct error display, improving readability during debugging.
Core Runtime & Architectural Changes
- Integration of the new
xel/modules/classespackage into the Xel runtime, makingxel:classesa built-in native module. - Registration of the new global
throwfunction. - Internal adjustments for handling
__dirname__and__filename__based on the active script context, making them accurately reflect the current file's location.
Testing
- The enhanced class system (specifically the
public/privatedistinctions leveraged by introspection) and the newxel:classesmodule have been thoroughly tested, with example usage demonstrated in the newexample/blueprint/main.xelscript. - The
throw()function has been verified for correct error propagation. - The improved
__dirname__and__filename__behavior has been confirmed across various execution scenarios.
Known Issues and Limitations
throw()Argument: Thethrow()function currently accepts only a single string argument for the error message. Custom error objects or multi-argument error details are not yet supported natively beyond thee.messageproperty.
Upgrade Notes
- This is a minor version increment, introducing powerful enhancements to the existing class system and a new global function (
throw). - No breaking changes are expected for existing Xel scripts. The improved accuracy of
__dirname__and__filename__is generally beneficial and not expected to cause issues. - To leverage the enhanced class system and the
throw()function, simply update your Xel runtime binary.
Getting Started
- Update to Xel v0.12.0: Download the latest binary for your operating system and architecture from our GitHub Releases page.
- Utilize Enhanced Class Features:
- Continue defining classes with the
classkeyword. - Explicitly use
publicandprivateto define the intended access levels for your members.
- Continue defining classes with the
- Explore the
xel:classesModule:- Add
const classes = import("xel:classes")to your scripts. - Use
classes.instanceOf(),classes.getClass(),classes.methods(), andclasses.properties()for powerful introspection and dynamic class interaction, focusing on a class's public API.
- Add
- Implement Robust Error Handling: Utilize
throw("Your custom error message")within your functions for explicit error signaling. - Check out the example: The
example/blueprint/main.xelscript provides a comprehensive demonstration of the enhanced class system and thexel:classesmodule in action.
Acknowledgements
A huge thank you, as always, to @dev-kas for spearheading this transformative release, bringing robust Object-Oriented Programming control a...
Xel v0.11.0
Xel v0.11.0 Release Notes: System Control at Your Fingertips with the xel:os Module!
We are absolutely thrilled to announce the release of Xel v0.11.0! This version is a monumental step forward, empowering your Xel scripts with direct, robust, and platform-agnostic interaction with the underlying operating system. Get ready to seamlessly manage files, directories, environmental variables, and even execute external commands, all from within your favorite scripting language.
Building on the foundation laid by previous releases, such as the introduction of the xel:time module in v0.8.0 for temporal control and the groundbreaking xel:native FFI in v0.10.0 for direct native library interaction, v0.11.0 completes a crucial piece of the system-level scripting puzzle. You can now build even more powerful and integrated applications with Xel!
Major Features & Enhancements
🚀 Introducing the xel:os Standard Library Module: Your Gateway to System Interaction!
This is the star of v0.11.0! The new xel:os module provides a comprehensive and intuitive API for all your operating system needs. Forget about cumbersome workarounds; xel:os brings core system capabilities directly into your Xel scripts.
- Availability: To harness this power, simply
import("xel:os")at the top of your script. - Purpose: The
xel:osmodule abstracts away OS-specific complexities, offering a consistent interface for common system tasks, making your scripts more portable and powerful.
Key Functionalities & Extensive Documentation:
-
File System Operations:
os.read(path: string):- Reads the entire content of the file located at
pathand returns it as a string. - Example:
const content = os.read("my_file.txt")
- Reads the entire content of the file located at
os.write(path: string, content: string | number | boolean | object | array | nil):- Writes the given
contentto the file atpath. If the file does not exist, it's created. If it exists, its content is overwritten. - Note: Xel's
stringifyhelper is used to convert thecontentto a string before writing. - Example:
os.write("new_file.txt", "Hello from Xel!")oros.write("data.json", { key: "value", num: 123 })
- Writes the given
os.copy(srcPath: string, destPath: string):- Copies the file or directory from
srcPathtodestPath. - If
srcPathis a directory, it will recursively copy all its contents. - Throws an error if
destPathalready exists. - Example:
os.copy("template.xel", "new_script.xel")
- Copies the file or directory from
os.move(srcPath: string, destPath: string):- Moves (renames) a file or directory from
srcPathtodestPath. This is implemented as a copy followed by a remove. - Throws an error if
destPathalready exists. - Example:
os.move("old_name.log", "archive/current_log.log")
- Moves (renames) a file or directory from
os.remove(path: string):- Deletes the file or empty directory at
path. - For non-empty directories,
os.remove()will fail. Future enhancements may includeos.removeall()for recursive deletion. - Example:
os.remove("temp_file.tmp")
- Deletes the file or empty directory at
os.mkdir(path: string):- Creates a new directory at
path. - If the directory already exists, it will not throw an error (idempotent).
- Example:
os.mkdir("logs/daily")
- Creates a new directory at
os.list(path: string):- Returns an
arrayof strings, where each string is the name of a file or directory within the specifiedpath. - Does not return full paths, only names.
- Example:
const files = os.list(".") // List files in current directory
- Returns an
os.exists(path: string):- Checks if a file or directory exists at
path. Returnstrueif it exists,falseotherwise. - Example:
if (os.exists("config.json")) { print("Config found!") }
- Checks if a file or directory exists at
os.stat(path: string):- Returns an
objectcontaining detailed information (metadata) about the file or directory atpath. - The returned object includes:
name: (string) The base name of the file or directory.size: (number) The size of the file in bytes.perm: (string) The file's permission bits (e.g., "-rw-r--r--").modTime: (number) The last modification time in milliseconds since the Unix Epoch.isDir: (boolean)trueif it's a directory,falseif it's a file.
- Example:
const stats = os.stat("main.xel"); print("Size:", stats.size, "Is Dir:", stats.isDir)
- Returns an
-
Path Utilities:
os.cwd():- Returns the current working directory of the Xel process as a string.
- Example:
print("Your current location:", os.cwd())
os.join(parts: string...):- Joins multiple path segments into a single, clean path, using the appropriate OS-specific path separator.
- Handles absolute paths correctly (e.g.,
os.join("/home", "user", "file.txt")->/home/user/file.txt). - Example:
const fullPath = os.join("my_app", "data", "users.json")
os.sep:- A constant
stringrepresenting the operating system's path separator (e.g.,/on Unix-like systems,\on Windows). - Example:
print("Path separator:", os.sep)
- A constant
-
System Information & Environment:
os.get(envVarName: string):- Retrieves the value of the environment variable named
envVarName. Returns an empty string if the variable is not set. - Example:
print("Your username:", os.get("USER") || os.get("USERNAME"))
- Retrieves the value of the environment variable named
os.platform:- A constant
stringindicating the operating system platform Xel is running on (e.g.,"linux","darwin","windows"). - Example:
if (os.platform == "windows") { print("Running on Windows!") }
- A constant
os.arch:- A constant
stringindicating the CPU architecture Xel is running on (e.g.,"amd64","arm64"). - Example:
print("Architecture:", os.arch)
- A constant
os.tempdir:- A constant
stringrepresenting the system's default temporary directory path. - Example:
os.write(os.join(os.tempdir, "xel_temp.txt"), "Temporary data")
- A constant
os.user():- Returns an
objectcontaining detailed information about the current user. - The returned object includes:
name: (string) The user's full name or login name.uid: (string) The user's user ID.gid: (string) The user's primary group ID.home: (string) The user's home directory path.shell: (string) The user's login shell (derived from environment if available).
- Example:
const user = os.user(); print("Home Directory:", user.home)
- Returns an
-
Process Execution:
os.exec(program: string, args: array):- Executes an external
program(e.g., "ls", "grep", "cmd.exe") with the specifiedargs(an array of strings). - Waits for the program to complete and returns an
objectcontaining:stdout: (string) The standard output of the executed program.stderr: (string) The standard error of the executed program.code: (number) The exit code of the executed program.
- Example:
const result = os.exec("git", ["status"]); print("Git Status:\n", result.stdout)
- Executes an external
Comprehensive xel:os Example (from example/system/main.xel):
This script demonstrates a wide array of xel:os functionalities in action:
const os = import("xel:os")
const time = import("xel:time") // time module also useful for system interaction
print("--- Current System Info ---")
print("CWD:", os.cwd())
print("Hello,", os.get("USER") || os.get("USERNAME")) // Get user from env var
print("Running on", os.platform, "(" + os.arch + ")")
print("Temp Directory:", os.tempdir)
const currentUser = os.user()
print("User Home:", currentUser.home, "UID:", currentUser.uid)
print("")
print("--- File & Directory Operations ---")
// List directory contents
print("Files in parent directory:", os.list("../"))
print("Does 'main.xel' exist?", os.exists("../system/main.xel"))
// Write, Read, Remove a file
const testFilePath = "../system/test_xel_file.txt"
print("Writing to:", testFilePath)
os.write(testFilePath, "This is a test file created by Xel at " + time.format(time.now()))
print("Content of", testFilePath + ":", os.read(testFilePath))
print("Removing:", testFilePath)
os.remove(testFilePath)
print("Does", testFilePath, "still exist?", os.exists(testFilePath))
// Create and remove a directory
const testDirPath = "../system/test_xel_dir"
print("Creating directory:", testDirPath)
os.mkdir(testDirPath)
print("Does", testDirPath, "exist?", os.exists(testDirPath))
print("Removing directory:", testDirPath)
os.remove(testDirPath) // Only works if empty
print("Does", testDirPath, "still exist?", os.exists(testDirPath))
// Copy and Move operations
const srcFile = "../system/main.xel"
const copyFile = "../system/main_copy.xel"
const movedFile = "../system/main_moved.xel"
print("Copying", srcFile, "to", copyFile)
os.copy(srcFile, copyFile)
print("Does", copyFile, "exist?", os.exists(copyFile), "(Should be true)")
print("Are contents identical?", os.read(copyFile) == os.read(srcFile), "(Should be true)")
print("Moving", copyFile, "to", movedFile)
os.move(copyFile, movedFile)
print("Does", movedFile, "exist?", os.exists(movedFile), "(Should be true)")
print("Does", copyFile, "still exist?", os.exists(copyFile), "(Should be false)")
// Stat a file
print("Stats for", movedFile + ":", os.stat(movedFile))
print("Removing moved fi...
Xel v0.10.1
Full Changelog: v0.10.0...v0.10.1
Xel v0.10.0
Xel v0.10.0 Release Notes: Unleash Native Power with the xel:native FFI Module!
We are beyond thrilled to announce the release of Xel v0.10.0! This is a landmark version that revolutionizes Xel's capabilities by introducing the xel:native module, a powerful Foreign Function Interface (FFI) that allows your Xel scripts to load and interact with native shared libraries (.so, .dll, .dylib) written in languages like C, C++, Rust, and more.
This opens up endless possibilities for extending Xel's functionality, leveraging high-performance native code, and integrating with existing system libraries. Get ready to bridge the gap between Xel's scripting ease and the raw power of native execution!
🚀 Major Features & Enhancements
-
New Native
xel:nativeModule (Foreign Function Interface):- Availability: Access this powerful new capability via
import("xel:native"). - Purpose: Enables Xel scripts to load dynamic/shared libraries and call functions within them, passing data between Xel and native code.
- Key Functionality:
native.load(libraryPath):- Loads a native shared library from the given
libraryPath(string). - Returns a library object if successful, or an error if the library cannot be loaded.
- The library path should point to a
.sofile on Linux,.dylibon macOS, or.dllon Windows.
const native = import("xel:native") // On Linux/macOS const myLib = native.load("./path/to/my_library.so") // On Windows // const myLib = native.load("./path/to/my_library.dll")- Loads a native shared library from the given
- Library Object Methods: The object returned by
native.load()has the following methods:myLib.call(functionName, argumentsArray):- Calls a function named
functionName(string) within the loaded native library. argumentsArrayis a Xel array containing the arguments to pass to the native function.- Argument Marshalling: Xel values (Number, String, Boolean, Nil) are automatically marshalled to corresponding C types (double, char*, char, void*) for the native function.
- Return Value Marshalling: The native function is expected to return a special
FFReturnstruct (defined in C, see FFI details below). Xel unmarshalls this back into a Xel RuntimeValue (Number, String, Boolean, or Nil).
const result = myLib.call("native_add_function", [5, 10]) // result will be 15 (if native_add_function returns a number) const greeting = myLib.call("get_greeting", ["Xel"]) // greeting might be "Hello, Xel!"- Calls a function named
myLib.unload():- Unloads the native library, freeing its resources. It's good practice to call this when you're done with a library, especially for long-running applications.
myLib.unload()
- Example Usage: A new example script
example/foreigner/main.xel(along with example Rust code) demonstrates how to use thexel:nativemodule to call Rust functions from Xel.
- Availability: Access this powerful new capability via
-
FFI Technical Details (for Native Library Authors):
- C ABI: Native functions intended to be called from Xel must be exposed via a C-compatible ABI (e.g., using
extern "C"in C++ or#[no_mangle] pub extern "C"in Rust). - Function Signature: Native functions must adhere to the following C signature:
typedef enum { TYPE_VOID, TYPE_INT, TYPE_FLOAT, TYPE_LONG, TYPE_DOUBLE, TYPE_STRING, TYPE_BOOL } Type; typedef struct { void* ret_val; Type ret_type; } FFReturn; FFReturn your_function_name(void** args, const char** arg_types, int arg_count);
args: An array ofvoid*pointers, where each pointer points to the actual argument data.arg_types: An array ofconst char*strings describing the type of each argument (e.g., "string", "float", "bool", "void" for nil).arg_count: The number of arguments passed.
- Memory Management:
- Native functions returning data (especially strings or complex types that allocate memory) must also provide a corresponding
free_<type>function (e.g.,free_string(void* ptr),free_float(void* ptr)). - Xel will attempt to call this
free_<type>function after unmarshalling the return value. If not found, Xel will use standardfree(), which might not be correct for all allocation schemes, potentially leading to memory leaks if the library uses custom allocators.
- Native functions returning data (especially strings or complex types that allocate memory) must also provide a corresponding
- Type Marshalling:
- Xel
Number-> Cdouble - Xel
String-> Cconst char*(UTF-8 encoded) - Xel
Boolean-> Cchar(1 for true, 0 for false) - Xel
Nil-> Cvoid*(NULL) - Return types are similarly mapped.
- Xel
- C ABI: Native functions intended to be called from Xel must be exposed via a C-compatible ABI (e.g., using
Core Runtime & Build System Enhancements
- New
modules/nativePackage: Contains the CGo code (ffi.c,ffi.h) and Go wrapper (ffi.go,load.go,main.go) implementing the FFI bridge. - Makefile Updates:
- Build targets are now more granular (e.g.,
build-linux-amd64,build-darwin-arm64). CGO_ENABLED=1is explicitly set for builds to enable CGo for the FFI.- Cross-compilation setups for Linux (aarch64) and Windows (amd64) now include installing necessary GCC cross-compilers.
- Build targets are now more granular (e.g.,
- GitHub Actions Workflow (
.github/workflows/release.yml):- Complete Overhaul: The release workflow is now significantly more robust and comprehensive.
- Matrix-like Builds: Separate jobs for Linux (amd64, arm64), Windows (amd64), and macOS (amd64, arm64).
- Version Extraction: Smarter version extraction from tags or Makefile.
- Artifact Upload/Download: Each platform build uploads its binary as an artifact.
- Release Creation: A dedicated
create-releasejob downloads all platform artifacts and attaches them to the GitHub Release. - Updated to use newer versions of
actions/checkoutandactions/setup-go.
- VirtLang-Go Engine Update: Xel v0.10.0 is now built with VirtLang-Go v4.0.0. This engine version includes critical enhancements such as full string escape sequence support and robust comparison operators, which benefit the entire Xel ecosystem.
Testing
- The new
xel:nativemodule has been tested by calling example Rust functions that perform addition and string concatenation, as shown inexample/foreigner/main.xel. - The FFI marshalling for basic types (numbers, strings, booleans, nil) has been verified.
Known Issues and Limitations
- FFI Type Support: The initial FFI implementation primarily supports basic C types (integers/floats via
double, C strings, booleans). Passing complex structures, Xel objects, or arrays directly to/from native functions is not yet supported and would require more sophisticated marshalling/serialization. - Memory Management Responsibility: While Xel attempts to call
free_<type>functions, ultimate responsibility for memory management of data allocated by the native library and passed to Xel (or vice-versa for complex types in the future) lies with the native library author. - Error Handling: Errors originating from within the native function calls are surfaced as Xel runtime errors, but detailed error codes or messages from the native side might require specific marshalling.
- Windows ARM64: The build workflow does not currently produce a Windows ARM64 binary.
Upgrade Notes
- This is a MAJOR version update due to the introduction of the FFI and the upgrade to VirtLang-Go v4.0.0, which has its own breaking changes (primarily related to string escape sequences and the
>=operator). - Action Required for VirtLang-Go v3.x users: If you are upgrading Xel and were using VirtLang-Go v3.x features directly or had scripts sensitive to string literal interpretation, review the VirtLang-Go v4.0.0 release notes for details on string escapes and the
>=operator. - The new
xel:nativemodule offers powerful new capabilities but should be used with an understanding of FFI complexities, especially around memory management and type systems.
Getting Started
- Update to Xel v0.10.0.
- To use the FFI:
- Create a shared library (
.so,.dll,.dylib) in C, C++, Rust, etc., exposing functions with the C ABI signature detailed above. - In your Xel script:
const native = import("xel:native") const myLib = native.load("path/to/your/library") const result = myLib.call("your_native_function_name", [arg1, arg2]) print("Native call result:", result) myLib.unload()
- Create a shared library (
- Explore the
example/foreigner/main.xeland the accompanying example Rust code for a practical demonstration.
Acknowledgements
A monumental thank you to @dev-kas for architecting and implementing this incredibly powerful Foreign Function Interface for Xel! This is a transformative feature that significantly expands Xel's horizons. Also, thanks for the extensive CI/CD pipeline enhancements!
Xel v0.10.0 is a true powerhouse release! The ability to integrate with native code via the xel:native FFI module, combined with a more robust build and release pipeline, solidifies Xel's position as a versatile and serious scripting environment. We are immensely excited to see the innovative ways the community will leverage these new capabilities!
Xel v0.9.1
Full Changelog: v0.9.0...v0.9.1
Xel v0.9.0
Xel Runtime v0.9.0 Release Notes: Parallelism with xel:threads, VirtLang v4 Engine, and Refined Error Handling!
Get ready for a paradigm shift in your Xel scripting! We are incredibly excited to unleash Xel v0.9.0, a groundbreaking release that introduces true parallelism to the Xel runtime via the new native xel:threads module. This version also upgrades the core engine to VirtLang-Go v4.0.0, bringing a host of language enhancements including full string escape sequence support, robust comparison operators, and important changes to error handling in try...catch blocks.
With xel:threads, you can now design and execute concurrent tasks, unlock significant performance gains, and build more responsive Xel applications. The VirtLang-Go v4 engine integration ensures your scripts benefit from the latest language features and correctness improvements.
This Xel release incorporates VirtLang-Go v4.0.0, which includes some breaking changes. Please review these carefully:
- String Literal Escape Sequences:
- Strings like
"literal\\n"(which previously might have been interpreted as a literal backslash then 'n') will now be unescaped to a literal backslash followed by a newline character. - Action: To represent a literal backslash, you must now use
\\\\. Review string literals in your scripts.
- Strings like
- Greater-Than-Or-Equal Operator:
- The operator is now correctly
>=. If you used=>(which was an internal AST error), update your code to>=.
- The operator is now correctly
- Error Variable in
try...catch:- The variable captured in
catch (e)(e.g.,e) is now an error object, not a simple string. - To access the error message, use
e.message. - The
e.messageproperty contains the core error message and no longer includes the "Runtime Error: " prefix automatically. - Action: Update your
catchblocks.// Old Xel code // try { ... } catch e { print(e) } // Might have printed "Runtime Error: Some issue" // try { ... } catch e { let msg = strings.replace(e, "Runtime Error: ", ""); print(msg) } // New Xel code: try { riskyOperation() } catch e { print("Caught error message:", e.message) // e.g., "Some issue" // If you need the old prefix for some reason: // print("Runtime Error: " + e.message) }
- The variable captured in
- Comparison Operator Behavior & Function Argument Arity: Refer to VirtLang-Go v4.0.0 release notes for details on more robust comparisons and flexible function argument handling. Most scripts will benefit, but review code with unusual comparisons or strict arity expectations.
🚀 Major Features & Enhancements in Xel v0.9.0
-
New Native
xel:threadsModule:- Unlock Parallelism: Write truly concurrent Xel scripts by spawning functions to run in parallel.
- Availability:
import("xel:threads") - Core Functionality:
threads.spawn(function, ...args): Spawns a new thread to executefunctionwithargs. Returns aThreadobject. Manages a limited pool of worker goroutines.ThreadObject API (returned byspawn):thread.id: (Number) Unique thread identifier.thread.join(): (Function) Waits for completion, returns result or propagates error.thread.kill(): (Function) Attempts to cancel thread execution.thread.status(): (Function) Returns status ("RUNNING","FINISHED","KILLED").thread.time(): (Function) Execution duration in ms (after completion/kill).thread.getResult(): (Function) Retrieves the stored result (use afterjoinorwaitForAll).
threads.waitForAll(): Blocks until all spawned threads complete.threads.killAll(): Attempts to kill all active spawned threads.
- Example Usage:
const threads = import("xel:threads") const time = import("xel:time") fn workerTask(id, durationMs) { print("Worker", id, "started, will run for", durationMs, "ms") time.sleep(durationMs) print("Worker", id, "finished.") return strings.format("Worker %v done!", id) } const worker1 = threads.spawn(workerTask, 1, 1000) const worker2 = threads.spawn(workerTask, 2, 500) print("Spawned workers. Waiting...") threads.waitForAll() print("All workers finished.") print("W1:", worker1.getResult(), "Status:", worker1.status(), "Time:", worker1.time()) print("W2:", worker2.getResult(), "Status:", worker2.status(), "Time:", worker2.time()) - See examples in
example/parallelism/.
-
Upgraded to VirtLang-Go v4.0.0 Engine:
- Xel now runs on the latest VirtLang-Go engine, bringing all its enhancements (detailed in the "Breaking Changes" section above and VirtLang-Go v4.0.0 release notes) to your Xel scripts.
Core Runtime & Architectural Changes
- Updated VirtLang-Go Dependency: All internal Xel components now use
virtlang-go/v4. - Native String Function Refinements: Functions within Xel's native modules (e.g.,
xel:strings,xel:array) are updated to align with VirtLang-Go v4.0.0's string semantics (operating on unescaped string values directly). - Environment Handling: Internal adjustments for compatibility with VirtLang-Go v4's environment structure.
Testing
- The new
xel:threadsmodule has been tested with various concurrency scenarios. - The underlying VirtLang-Go v4.0.0 engine includes its own extensive test suite.
Known Issues and Limitations
- Thread Cancellation:
thread.kill()is cooperative; long-running VirtLang loops in a thread might not terminate immediately unless designed to be cancellable. - Shared State Management: Developers using
xel:threadsare responsible for managing shared state access to prevent race conditions. VirtLang-Go does not yet expose script-level mutexes/channels. - Debugging Threads: The
xel debugcommand primarily focuses on the main execution thread. Debugging individual spawned threads might have limitations.
Upgrade Notes
- This release introduces the
xel:threadsmodule and upgrades the core engine to VirtLang-Go v4.0.0. - Action Required for Xel Scripts: Carefully review the "Important: Breaking Changes & Migration Notes" section above, especially regarding string escapes, the
>=operator, and how error objects are handled intry...catchblocks. - To use threading,
import("xel:threads").
Getting Started
- Update to Xel v0.9.0.
- Review the migration notes for adapting existing scripts to VirtLang-Go v4.0.0.
- Explore the new
xel:threadsmodule and the examples inexample/parallelism/.
Acknowledgements
A massive thank you to @dev-kas for this transformative Xel release, bringing powerful parallelism capabilities and integrating the latest VirtLang-Go v4.0.0 engine!