Skip to content

Releases: dev-kas/xel

Xel v0.15.1

17 Jul 12:04
Compare
Choose a tag to compare

Xel v0.15.0

15 Jul 10:32
Compare
Choose a tag to compare

Full Changelog: v0.14.0...v0.15.0

Xel v0.14.0

05 Jul 07:42
Compare
Choose a tag to compare

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

  1. A Complete Package Management Suite (xel pkg)
    The xel pkg command suite has been fully implemented, providing a comprehensive workflow for managing project dependencies.

    • pkg add <packageName>[@version] (alias install):
      • 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 the deps section.
    • pkg remove <packageName> (alias uninstall):
      • 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 and xel.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.
  2. Deterministic Installs with Lockfiles (xel.lock)
    To ensure your projects are reliable and reproducible across different machines and environments, Xel now generates and uses a xel.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.
  3. 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 via PackageRegistryURI 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.
  4. Support for Package Install Scripts (setup.xel)
    Packages can now include a setup.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.
  5. Refined Project Manifest (xel.json)
    The ProjectManifest structure has been improved to support optional fields. Fields like xel, engine, and deps 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: The xel:array module's reduce() function is now more flexible. The initialValue (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, and github.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

  1. Update to Xel v0.14.0: Download the latest binary from our GitHub Releases page.
  2. Manage your dependencies: Navigate to your project directory and start using xel pkg add, xel pkg remove, and xel 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

09 Jun 12:13
Compare
Choose a tag to compare

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

  1. 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 property key on the given object obj. If the key doesn't exist, it's added. If value is omitted, the property key is set to nil.

      • object.get(obj, key): Retrieves the value of the property key from the object obj. Returns nil if the property doesn't exist.

      • object.keys(obj): Returns an array containing all the keys (property names) of the object obj as an array of strings.

      • object.values(obj): Returns an array containing all the values of the properties in the object obj. The order corresponds to the order of keys returned by object.keys().

      • object.delete(obj, key): Removes the property key from the object obj. Returns the object. If the property didn't exist, nothing happens.

      • object.has(obj, key): Checks if the object obj has a property with the name key. Returns true if the property exists, false otherwise.

      • object.merge(obj1, obj2): Creates a new object that is a combination of obj1 and obj2. Properties in obj2 overwrite properties in obj1 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 of obj. 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 the keys array. If a key doesn't exist in obj, 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 from obj except those specified in the keys array. This is the inverse of object.pick.

      • object.entries(obj): Returns an array of arrays, 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 object obj has any properties. Returns true if it's empty, false otherwise.

      • object.equal(obj1, obj2): Performs a deep comparison of obj1 and obj2. Returns true if the objects are structurally identical (same keys and values), false otherwise.

    • Examples:

      • The example/box/main.xel script provides a fundamental introduction to the xel:object module, demonstrating core functions like creating, setting, getting, and deleting properties.
      • The example/box/extended.xel script showcases a wider range of functionality, including merge, clone, pick, omit, and other functions, and helps developers unlock the full power of Xel's object handling.

🛠️ 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 underpins object.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.
  • Preventing Infinite Loops in Object Printing (stringify.go)

    • Problem: As with other languages, the internal stringify function (used by print() 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.

Core Runtime & Architectural Changes

  • Integration of the new xel/modules/object package as a built-in native module, immediately accessible via import("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

  1. Update to Xel v0.13.0: Download the latest binary from our GitHub Releases page.
  2. 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, explore example/box/extended.xel for advanced usage patterns.
  3. 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

07 Jun 16:44
Compare
Choose a tag to compare

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

  1. Enhanced Class System Capabilities: Meaningful Member Visibility
    Building on Xel's existing class functionality, this release brings refined control and clarity to your object-oriented designs by leveraging the existing public and private keywords.

    • Leveraging public and private: While the class 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 special constructor 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)
    
  2. New Global throw() Function for Explicit Error Handling
    You can now programmatically raise runtime errors using the new global throw() function. This complements the try...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 a try...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

  1. xel:classes Module: Introspection for Your Classes!
    To provide powerful tools for working with and inspecting the class system, a new xel:classes standard library module has been introduced. This module provides functions for runtime introspection of classes and instances, leveraging the public and private distinctions.

    • Availability: Access these capabilities via import("xel:classes").
    • Key Functionality:
      • classes.instanceOf(Class, instance): Checks if a given instance is an instance of the specified Class blueprint. Returns a boolean.
      • classes.getClass(instance): Retrieves the original Class definition object from a given class instance. 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 given Class. Private methods are excluded.
      • classes.properties(Class): Returns an array of strings containing the names of all public properties defined on the given Class. 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!)
    

🛠️ 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 the throw function.
  • Cleaner Runtime Error Output
    The formatting of runtime error messages has been streamlined, now using Println instead of Printf. 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, making xel: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 new xel:classes module have been thoroughly tested, with example usage demonstrated in the new example/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: The throw() 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 the e.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

  1. Update to Xel v0.12.0: Download the latest binary for your operating system and architecture from our GitHub Releases page.
  2. Utilize Enhanced Class Features:
    • Continue defining classes with the class keyword.
    • Explicitly use public and private to define the intended access levels for your members.
  3. Explore the xel:classes Module:
    • Add const classes = import("xel:classes") to your scripts.
    • Use classes.instanceOf(), classes.getClass(), classes.methods(), and classes.properties() for powerful introspection and dynamic class interaction, focusing on a class's public API.
  4. Implement Robust Error Handling: Utilize throw("Your custom error message") within your functions for explicit error signaling.
  5. Check out the example: The example/blueprint/main.xel script provides a comprehensive demonstration of the enhanced class system and the xel: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...

Read more

Xel v0.11.0

07 Jun 09:24
Compare
Choose a tag to compare

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")
    • os.write(path: string, content: string | number | boolean | object | array | nil):
      • Writes the given content to the file at path. 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 the content to a string before writing.
      • Example: os.write("new_file.txt", "Hello from Xel!") or os.write("data.json", { key: "value", num: 123 })
    • os.copy(srcPath: string, destPath: string):
      • Copies the file or directory from srcPath to destPath.
      • 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")
    • os.move(srcPath: string, destPath: string):
      • Moves (renames) a file or directory from srcPath to destPath. 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")
    • os.remove(path: string):
      • Deletes the file or empty directory at path.
      • For non-empty directories, os.remove() will fail. Future enhancements may include os.removeall() for recursive deletion.
      • Example: os.remove("temp_file.tmp")
    • 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")
    • os.list(path: string):
      • Returns an array of strings, where each string is the name of a file or directory within the specified path.
      • Does not return full paths, only names.
      • Example: const files = os.list(".") // List files in current directory
    • os.exists(path: string):
      • Checks if a file or directory exists at path. Returns true if it exists, false otherwise.
      • Example: if (os.exists("config.json")) { print("Config found!") }
    • os.stat(path: string):
      • Returns an object containing detailed information (metadata) about the file or directory at path.
      • 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)
  • 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)
  • 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"))
    • 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!") }
    • os.arch:
      • A constant string indicating the CPU architecture Xel is running on (e.g., "amd64", "arm64").
      • Example: print("Architecture:", os.arch)
    • 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")
    • 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)
  • Process Execution:

    • os.exec(program: string, args: array):
      • Executes an external program (e.g., "ls", "grep", "cmd.exe") with the specified args (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)

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...
Read more

Xel v0.10.1

06 Jun 07:05
Compare
Choose a tag to compare

Full Changelog: v0.10.0...v0.10.1

Xel v0.10.0

05 Jun 22:02
Compare
Choose a tag to compare

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

  1. 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") 
        
      • 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!"
          
        • 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 the xel:native module to call Rust functions from Xel.
  2. 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 of void* pointers, where each pointer points to the actual argument data.
      • arg_types: An array of const 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 standard free(), which might not be correct for all allocation schemes, potentially leading to memory leaks if the library uses custom allocators.
    • Type Marshalling:
      • Xel Number -> C double
      • Xel String -> C const char* (UTF-8 encoded)
      • Xel Boolean -> C char (1 for true, 0 for false)
      • Xel Nil -> C void* (NULL)
      • Return types are similarly mapped.

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.
  • 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 and actions/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 in example/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

  1. Update to Xel v0.10.0.
  2. 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()
      
  3. 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

04 Jun 20:30
Compare
Choose a tag to compare

Full Changelog: v0.9.0...v0.9.1

Xel v0.9.0

04 Jun 19:29
Compare
Choose a tag to compare

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.

⚠️ Important: Breaking Changes & Migration Notes from VirtLang-Go v4.0.0

This Xel release incorporates VirtLang-Go v4.0.0, which includes some breaking changes. Please review these carefully:

  1. 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.
  2. Greater-Than-Or-Equal Operator:
    • The operator is now correctly >=. If you used => (which was an internal AST error), update your code to >=.
  3. 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) 
      }
      
  4. 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

  1. 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 execute function with args. Returns a Thread object. Manages a limited pool of worker goroutines.
      • Thread Object API (returned by spawn):
        • 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 after join or waitForAll).
      • 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/.
  2. 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 in try...catch blocks.
  • To use threading, import("xel:threads").

Getting Started

  1. Update to Xel v0.9.0.
  2. Review the migration notes for adapting existing scripts to VirtLang-Go v4.0.0.
  3. Explore the new xel:threads module and the examples in example/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!