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 pkg
command 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.json
file, adding the new package and its resolved version to thedeps
section.
- 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.json
andxel.lock
, or to completely uninstall it from your global~/.xel/modules
cache (using the--global
flag).
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.lock
file.- 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.lock
file is present,xel pkg add
will 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 rockets
and Xel will query the registry (configurable viaPackageRegistryURI
in~/.xel/config.json
) for the package. - Secure & Verified: Packages downloaded from the registry are delivered as
.tar.gz
tarballs. 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.xel
script to perform complex installation or build steps.- Purpose: This is ideal for packages that need to compile native components using the
xel:native
FFI, set up configuration files, or perform other post-download tasks. - Execution: Xel automatically detects and runs
setup.xel
after a package is successfully downloaded and extracted. - Security: This powerful feature is enabled by default but can be disabled by setting
AllowInstallScripts: false
in your global~/.xel/config.json
.
- Purpose: This is ideal for packages that need to compile native components using the
-
Refined Project Manifest (
xel.json
)
TheProjectManifest
structure has been improved to support optional fields. Fields likexel
,engine
, anddeps
will 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:array
module'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.com/urfave/cli/v2
have 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 rockets
Upgrade 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
pkg
command 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:object
Module: 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 propertykey
on the given objectobj
. If the key doesn't exist, it's added. Ifvalue
is omitted, the propertykey
is set tonil
. -
object.get(obj, key)
: Retrieves the value of the propertykey
from the objectobj
. Returnsnil
if the property doesn't exist. -
object.keys(obj)
: Returns anarray
containing all the keys (property names) of the objectobj
as anarray
of strings. -
object.values(obj)
: Returns anarray
containing 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 propertykey
from the objectobj
. Returns the object. If the property didn't exist, nothing happens. -
object.has(obj, key)
: Checks if the objectobj
has a property with the namekey
. Returnstrue
if the property exists,false
otherwise. -
object.merge(obj1, obj2)
: Creates a new object that is a combination ofobj1
andobj2
. Properties inobj2
overwrite properties inobj1
if 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 thekeys
array. 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 fromobj
except those specified in thekeys
array. This is the inverse ofobject.pick
. -
object.entries(obj)
: Returns anarray
ofarray
s, 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 objectobj
has any properties. Returnstrue
if it's empty,false
otherwise. -
object.equal(obj1, obj2)
: Performs a deep comparison ofobj1
andobj2
. Returnstrue
if the objects are structurally identical (same keys and values),false
otherwise.
-
-
Examples:
- The
example/box/main.xel
script provides a fundamental introduction to thexel:object
module, demonstrating core functions like creating, setting, getting, and deleting properties. - The
example/box/extended.xel
script 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
equalRuntimeValues
function, 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
stringify
function (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
stringify
function. When a circular reference is encountered,stringify
will 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/object
package 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:object
Module:- Add
const object = import("xel:object")
to your scripts. - Start with the
example/box/main.xel
script to understand core functionalities. Then, exploreexample/box/extended.xel
for 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 existingclass
functionality, this release brings refined control and clarity to your object-oriented designs by leveraging the existingpublic
andprivate
keywords.- Leveraging
public
andprivate
: While theclass
keyword 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 specialconstructor
method 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...catch
mechanism 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...catch
block.
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:classes
Module: Introspection for Your Classes!
To provide powerful tools for working with and inspecting the class system, a newxel:classes
standard library module has been introduced. This module provides functions for runtime introspection of classes and instances, leveraging thepublic
andprivate
distinctions.- Availability: Access these capabilities via
import("xel:classes")
. - Key Functionality:
classes.instanceOf(Class, instance)
: Checks if a giveninstance
is an instance of the specifiedClass
blueprint. Returns a boolean.classes.getClass(instance)
: Retrieves the originalClass
definition 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 thethrow
function. - Cleaner Runtime Error Output
The formatting of runtime error messages has been streamlined, now usingPrintln
instead ofPrintf
. This results in a cleaner, more direct error display, improving readability during debugging.
Core Runtime & Architectural Changes
- Integration of the new
xel/modules/classes
package into the Xel runtime, makingxel:classes
a built-in native module. - Registration of the new global
throw
function. - 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
/private
distinctions leveraged by introspection) and the newxel:classes
module have been thoroughly tested, with example usage demonstrated in the newexample/blueprint/main.xel
script. - 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.message
property.
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
class
keyword. - Explicitly use
public
andprivate
to define the intended access levels for your members.
- Continue defining classes with the
- Explore the
xel:classes
Module:- 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.xel
script provides a comprehensive demonstration of the enhanced class system and thexel:classes
module 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:os
module 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
path
and 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
content
to the file atpath
. If the file does not exist, it's created. If it exists, its content is overwritten. - Note: Xel's
stringify
helper is used to convert thecontent
to 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
srcPath
todestPath
. - If
srcPath
is a directory, it will recursively copy all its contents. - Throws an error if
destPath
already 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
srcPath
todestPath
. This is implemented as a copy followed by a remove. - Throws an error if
destPath
already 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
array
of 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
. Returnstrue
if it exists,false
otherwise. - Example:
if (os.exists("config.json")) { print("Config found!") }
- Checks if a file or directory exists at
os.stat(path: string)
:- Returns an
object
containing 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)true
if it's a directory,false
if 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
string
representing 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
string
indicating 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
string
indicating the CPU architecture Xel is running on (e.g.,"amd64"
,"arm64"
). - Example:
print("Architecture:", os.arch)
- A constant
os.tempdir
:- A constant
string
representing 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
object
containing 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
object
containing: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:native
Module (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
.so
file on Linux,.dylib
on macOS, or.dll
on 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. argumentsArray
is 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
FFReturn
struct (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:native
module 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/native
Package: 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=1
is 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-release
job downloads all platform artifacts and attaches them to the GitHub Release. - Updated to use newer versions of
actions/checkout
andactions/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:native
module 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:native
module 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.xel
and 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.message
property contains the core error message and no longer includes the "Runtime Error: " prefix automatically. - Action: Update your
catch
blocks.// 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:threads
Module:- 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 executefunction
withargs
. Returns aThread
object. Manages a limited pool of worker goroutines.Thread
Object 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 afterjoin
orwaitForAll
).
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:threads
module 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:threads
are responsible for managing shared state access to prevent race conditions. VirtLang-Go does not yet expose script-level mutexes/channels. - Debugging Threads: The
xel debug
command primarily focuses on the main execution thread. Debugging individual spawned threads might have limitations.
Upgrade Notes
- This release introduces the
xel:threads
module 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...catch
blocks. - 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:threads
module 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!