Skip to content

Releases: rufflang/ruff

0.10.0

18 Feb 21:25

Choose a tag to compare

Added

  • Optional Static Typing Design Package (Exploratory, v0.10.0):

    • Added consolidated design document at docs/OPTIONAL_TYPING_DESIGN.md covering:
      • annotation surface proposal for function signatures, variable declarations, and generic collection forms
      • optional runtime type-check mode contract and deterministic type-error shape targets
      • typed-JIT optimization boundaries, explicit non-goals, migration/compatibility posture, and open decisions
  • Native Bulk SSG Rendering Builtin (P0 Optimization step):

    • Added ssg_render_pages(source_pages) native function for high-volume static page wrapping
    • Returns a dictionary with:
      • pages: rendered HTML page array
      • checksum: aggregate output checksum for benchmark equivalence checks
    • Updated benchmarks/cross-language/bench_ssg.ruff to use native bulk rendering before async_write_files(...)
    • Added comprehensive validation tests in src/interpreter/native_functions/strings.rs for:
      • valid page rendering + checksum behavior
      • non-array input errors
      • non-string page element errors
      • invalid argument count errors
    • Measured Ruff-only bench-ssg --profile-async impact (10,000 files, local run):
      • Before native rendering: 33,107.557 ms (302.05 files/sec)
      • After native rendering: 23,178.914 ms (431.43 files/sec)
      • Improvement: ~29.99% faster total build time in this benchmark path
  • Bulk Async File I/O Builtins for SSG-Scale Workloads (P0 Optimization step):

    • Added async_read_files(paths, concurrency_limit?) for bounded concurrent multi-file reads
    • Added async_write_files(paths, contents, concurrency_limit?) for bounded concurrent multi-file writes
    • Added comprehensive native-function coverage for:
      • ordered multi-file read behavior
      • full multi-file write + output verification
      • input validation (path/content element types, array length mismatch, invalid concurrency limits)
      • propagated I/O error behavior for missing files
    • Updated benchmarks/cross-language/bench_ssg.ruff to use bulk async APIs instead of per-file promise arrays
    • Measured impact on ruff bench-ssg (10,000 files, local run):
      • Before: 57,685.809 ms (173.35 files/sec)
      • After: 51,713.739 ms (193.37 files/sec)
      • Improvement: ~10.35% faster Ruff build time in this benchmark path
  • Spawn Parent-Binding Snapshot Capture (P0 shared-state milestone):

    • spawn { ... } now receives a transferable snapshot of parent bindings at spawn time

    • Spawned workers can reference parent-defined scalar/collection values (for example shared-store keys)

    • Preserves non-blocking spawn semantics while keeping parent scope write-back isolated

    • Added comprehensive integration tests covering:

      • scalar capture visibility inside spawned workers
      • parent-defined shared-key usage from spawned workers
      • no write-back of spawned local mutations into parent scope
    • Example usage:

            counter_key := "jobs_counter"
      

      shared_set(counter_key, 0)

      for i in range(0, 12) {
      spawn {
      shared_add_int(counter_key, 1)
      }
      }

  • Thread-Safe Shared Value Operations for Spawn Concurrency (P0 Phase 1 completion):

    • Added process-wide thread-safe shared value builtins:

      • shared_set(key, value)
      • shared_get(key)
      • shared_has(key)
      • shared_delete(key)
      • shared_add_int(key, delta)
    • Shared values are synchronized with Arc<Mutex<...>> storage so updates are safe across spawned interpreters

    • Enables practical cross-thread coordination despite spawn using isolated environments

    • Added comprehensive integration tests for:

      • shared value lifecycle (set/get/has/delete)
      • atomic-style integer accumulation with validation error paths
      • spawn workers updating a shared counter across isolated interpreters
    • Example usage:

            shared_set("counter", 0)
      

      for i in range(0, 20) {
      spawn {
      shared_add_int("counter", 1)
      }
      }

  • 10K+ Concurrency Scalability Testing (Phase 3 Completion):

    • Added comprehensive scalability test example (examples/test_scalability_10k.ruff)

    • Tests parallel_map, promise_all, and par_each with 10,000 concurrent operations

    • All scalability tests complete successfully in <3 seconds

    • Added three integration tests to test suite:

      • test_parallel_map_scalability_10k: 10K items with parallel_map
      • test_promise_all_scalability: 10K items across 10 promises with promise_all
      • test_par_each_scalability: 10K items with par_each
    • Completes Phase 3 roadmap item: "Test scalability with 10K+ concurrent operations"

    • Example usage:

            items := range(0, 10000)
      

      result_promise := parallel_map(items, func(x) { return x * x }, 100)
      results := await result_promise

      Processes 10,000 items in <1 second

  • Async SSG Bottleneck Profiling (P0 Optimization step):

    • Added --profile-async flag to ruff bench-ssg for per-stage timing breakdown output
    • bench-ssg now reports read-stage and render/write-stage timings when benchmark scripts emit profiling metrics
    • Added bottleneck summary output (largest stage + profiled-time share)
    • Extended SSG benchmark artifacts to emit stage metrics:
      • Ruff script emits RUFF_SSG_READ_MS and RUFF_SSG_RENDER_WRITE_MS
      • Python baseline emits PYTHON_SSG_READ_MS and PYTHON_SSG_RENDER_WRITE_MS
    • Added comprehensive parser/profile tests in src/benchmarks/ssg.rs for optional metric parsing and bottleneck-stage calculations
  • Promise Creation/Resolution Overhead Optimization (P0 Optimization step):

    • Optimized parallel_map(...) mixed-result path to avoid creating synthetic oneshot-backed promises for immediate mapper values
    • parallel_map(...) now:
      • preserves immediate results directly in preallocated output slots
      • awaits only real promise receivers with bounded in-task concurrency
      • resolves immediately when all mapper outputs are non-promise values
    • Reduced allocation/churn in Promise.all(...) hot path by preallocating receiver/future vectors and reusing a single debug flag check
    • Added integration coverage for mixed immediate/promise mapper behavior and immediate-only fast path
  • Cached Await Reuse for Frequently-Awaited Operations (P0 Optimization step):

    • Added cache-aware promise aggregation in Promise.all(...) and parallel_map(...)
    • Already-polled promises now resolve from cached results without re-consuming oneshot receivers
    • Aggregation paths now persist resolved/rejected outcomes back into each source promise cache to accelerate repeated awaits
    • Added integration coverage for:
      • reusing a previously awaited promise in promise_all([p, p], ...)
      • reusing a cached promise returned by a parallel_map(...) mapper
  • Cross-Language Async SSG Benchmark Harness (P0 Option 1 validation):

    • Added ruff bench-ssg command to execute a reproducible 10,000-file async SSG workload in Ruff
    • Added optional Python baseline comparison via ruff bench-ssg --compare-python
    • Added benchmark artifacts:
      • benchmarks/cross-language/bench_ssg.ruff
      • benchmarks/cross-language/bench_ssg.py
    • Added benchmark parser/validator module at src/benchmarks/ssg.rs with checksum + file-count equivalence checks
    • Added comprehensive unit tests for metric parsing and speedup calculations
    • Latest baseline run (ruff bench-ssg --compare-python):
      • Ruff: 73,392.770 ms (136.25 files/sec)
      • Python: 4,390.775 ms (2,277.50 files/sec)
      • Relative speed: Ruff 0.06x vs Python baseline
  • Async VM Cooperative Scheduler (P0 Option 1 step):

    • Added scheduler APIs in src/vm.rs for managing multiple suspended VM contexts:
      • run_scheduler_round()
      • run_scheduler_until_complete(max_rounds)
      • pending_execution_context_count()
    • Added VmSchedulerRoundResult with per-round completion and pending counts
    • resume_execution_context(context_id) now removes completed contexts automatically to prevent stale context accumulation
    • Added comprehensive VM tests for:
      • scheduler completion cleanup semantics
      • multi-context scheduler completion
      • pending-round reporting for unready promises
      • scheduler round-budget exhaustion and validation errors
  • Cooperative Await Yield/Resume Execution (P0 Option 1 step):

    • Added cooperative VM execution APIs in src/vm.rs:
      • execute_until_suspend(chunk)
      • resume_execution_context(context_id)
    • Added VmExecutionResult to report cooperative execution state (Completed vs Suspended)
    • OpCode::Await now supports non-blocking cooperative polling via try_recv() and suspends execution contexts instead of blocking when cooperative mode is enabled
    • Suspended await contexts now preserve state by rewinding IP to re-run Await on resume and snapshotting the active context
    • Added VM tests covering:
      • suspension/resume flow for pending async await
      • cooperative completion flow with no suspension
  • Async VM Execution Context Switching Foundation (P0 Option 1 step):

    • Added stable VM context IDs via VmContextId
    • Added VM context lifecycle APIs in src/vm.rs:
      • `create_executi...
Read more

0.9.0

12 Feb 20:07

Choose a tag to compare

Added

  • Hash Map Loop Fusion Optimization (2026-02-12):

    • Added fused bytecode opcodes for canonical int-key map loops:
      • SumIntMapUntilLocalInPlace for sum := sum + map[i] read loops
      • FillIntMapWithDoubleUntilLocalInPlace for map[i] := i * 2 write loops
    • Added compiler pattern matching/lowering for both loop forms
    • Added VM execution handlers for both fused opcodes
    • Added targeted VM tests for fused sum loop success and missing-key error paths
    • Verified cross-language benchmark improvement:
      • Ruff hash map benchmark: 0.56078 ms
      • Python hash map benchmark: 33.25 ms
  • JIT Stability Regression Fix (2026-02-12):

    • Fixed Cranelift block sealing regressions in JIT compile paths
    • Restored full test-suite stability (cargo test all passing)
    • Revalidated cross-language benchmarks after the fix
  • String Concatenation Optimization + Stability Validation (2026-02-12):

    • Added dedicated bytecode append opcodes for constant string/char in-place updates
    • Added compiler lowering for x := x + "literal" and loop fusion for canonical concat loops
    • Added VM handlers for in-place append and fused append-until-local execution
    • Added JIT helper wiring for append in-place paths and translator opcode support
    • Fixed regressions and warning sources uncovered during optimization work
    • Validated with green cargo test --release and updated cross-language benchmark run
  • Phase 7: Function-Level JIT Implementation (v0.9.0) - IN PROGRESS:

    • Step 11: Loop Back-Edge Fix (2026-01-30):

      • Fixed JIT compilation of loops with backward jumps (JumpBack opcode)
      • Added analyze_loop_headers() to pre-detect backward jump targets
      • Added stack_effect() to calculate stack depth changes per opcode
      • Added loop_header_pcs HashSet to track loop headers
      • Loop headers are now created with proper Cranelift block parameters
      • Loop headers are sealed AFTER back-edges are processed (late sealing)
      • JumpBack now correctly passes stack values as block arguments
      • Added comprehensive test test_compile_simple_loop for validation
      • All JIT tests (31) passing with loop support
      • Note: Loops in top-level scripts still run interpreted (only functions JIT-compile)
    • Step 12 Partial: Direct JIT Recursion (2026-01-30):

      • Added CompiledFnWithArg type for functions that take args directly
      • Added CompiledFnInfo struct tracking standard + direct-arg variants
      • Implemented function_has_self_recursion() for bytecode analysis
      • Implemented compile_function_with_direct_arg() Cranelift compilation
      • Implemented translate_direct_arg_instruction() for direct-arg mode
      • Updated interpreter to prefer direct-arg variant for 1-int-arg calls
      • Self-recursion detection correctly identifies recursive patterns
      • Infrastructure complete but performance optimization needs debugging
      • Note: Direct-arg functions being called but not achieving expected speedup
    • Step 10 Partial: Fast Argument Passing (2026-01-29):

      • Implemented fast argument passing via VMContext.argN fields
      • Added arg0-arg3 and arg_count fields to VMContext struct
      • Added jit_get_arg() runtime helper for parameter access
      • JIT now reads parameters from VMContext.argN (≤4 integer args)
      • Eliminated var_names HashMap clone on recursive calls
      • Skipped HashMap population for simple integer functions
      • Performance improved from ~1.03s to ~0.81s for fib(25) (~20% faster)
      • Note: Still 29x slower than Python (~28ms) due to call overhead
      • Architecture limitation: Each JIT call goes through FFI boundary
      • Future work needed: True direct JIT-to-JIT recursion requires changing function signature to pass args directly in Cranelift
    • Step 9 Complete: Inline Caching for Function Calls (2026-01-28):

      • Implemented inline caching to accelerate repeated function calls
      • Added CallSiteId struct to uniquely identify call sites by (chunk_id, ip)
      • Added InlineCacheEntry struct with cached function pointer and var_names
      • Call sites now cache:
        • JIT-compiled function pointer (no HashMap lookup after first call)
        • Pre-computed var_names HashMap (avoids rebuilding on every call)
        • Guard validation via function name comparison
      • Eliminated var_names HashMap clone in inline cache fast path
      • Added hit/miss counters for profiling and debugging
      • Added comprehensive test suite (tests/jit_inline_cache.ruff):
        • Test 1: Simple function called 200 times (cache warm-up)
        • Test 2: Recursive Fibonacci with inline cache
        • Test 3: Nested function calls (multiple call sites)
        • Test 4: Different functions (guard validation)
        • Test 5: Function with local variables
        • Test 6: Higher-order function pattern (pre-JIT)
        • Test 7: Deep call chain (4 levels)
        • Test 8: Zero-parameter function
      • All 198 unit tests passing
      • Phase 7 now 90% complete (Steps 1-9 of 10)
      • Note: Discovered JIT limitation with higher-order functions (functions as arguments)
      • Next: Step 10 - Value Unboxing
    • Step 8 Complete: Return Value Optimization (2026-01-28):

      • Implemented fast return value path that bypasses VM stack operations
      • Added return_value and has_return_value fields to VMContext struct
      • Added jit_set_return_int() runtime helper for optimized integer returns
      • Modified Return opcode translation to use fast path when available
      • Updated VM to check has_return_value before reading from stack
      • Fallback to stack-based returns for non-integer types preserved
      • Added comprehensive test: test_return_value_optimization
      • Optimization reduces overhead for integer returns by:
        • Eliminating stack push/pop operations for return values
        • Avoiding Value::Int boxing at the JIT/VM boundary
        • Direct memory access to VMContext.return_value field
      • All 198 unit tests passing
      • Phase 7 now 80% complete (Steps 1-8 of 10)
      • Next: Step 9 - Iterative Fibonacci & Full Benchmarks
    • Step 7 Complete: Register-Based Locals (2026-01-28):

      • Implemented register-based locals optimization for JIT-compiled functions
      • Added local_slots HashMap to BytecodeTranslator for stack slot mapping
      • Implemented allocate_local_slots() to pre-allocate Cranelift stack slots
      • Implemented allocate_parameter_slots() for function parameters
      • Implemented initialize_parameter_slots() to copy params from HashMap to slots
      • LoadVar/StoreVar now use fast stack slots for local variables
      • Fall back to runtime calls for globals and function references
      • Added comprehensive test suite (tests/jit_register_locals.ruff)
      • All 198 unit tests passing
      • Local variables now use direct memory access instead of:
        • C function calls for every variable access
        • HashMap lookups at runtime
      • Phase 7 now 70% complete (Steps 1-7 of 10)
      • Next: Step 8 - Inline Caching for function calls
    • Step 5 Complete: Testing & Validation (2026-01-28):

      • Created comprehensive test suite for JIT function calls
      • Test nested function calls (2-4 levels deep): All passing
      • Test iterative fibonacci: Correct results for fib(0) to fib(20)
      • Test recursive fibonacci: Faster than Python for fib(20) (101ms vs 168ms)
      • Test edge cases: 0 params, 5+ params, local variables, recursion
      • Added test files: test_nested_simple.ruff, test_fib_simple.ruff, test_fib_rec_simple.ruff, test_edges_simple.ruff
      • All 198 unit tests still passing
      • Verified JIT compilation triggers correctly after 100 calls
      • Confirmed correct stack and locals handling in nested calls
      • Phase 7 now 50% complete (Steps 1-5 of 10)
      • Next: Step 6 - Recursive Function Optimization
      • Performance validation shows JIT is working as designed!
    • Step 4 Complete: Argument Passing Optimization (2026-01-28):

      • Implemented jit_push_int runtime helper for return value handling
      • Implemented call_function_from_jit in VM for function execution from JIT
      • Added proper locals binding with parameter name → value mapping
      • Added var_names HashMap for variable name resolution via hashing
      • LoadVar/StoreVar now work correctly in JIT-compiled functions
      • Functions can now call other functions with full argument passing
      • Return values properly pushed to VM stack as Value::Int
      • Test examples working: identity(x), add(a,b), nested calls
      • All 79 tests still passing
      • Major milestone: JIT functions are now truly functional!
      • Next: Step 5 - Testing & Validation
    • Step 3 Complete: Call Opcode JIT Support (2026-01-28):

      • Added jit_call_function runtime helper for function calls from JIT code
      • Added Call opcode translation in BytecodeTranslator::translate_instruction
      • Updated is_supported_opcode to include OpCode::Call
      • Added call_func field and setter to BytecodeTranslator
      • Declared jit_call_function symbol in JitCompiler::new
      • Functions containing Call opcodes can now be JIT-compiled!
      • Runtime execution is placeholder (Step 4 will implement actual execution)
      • All 79 tests...
Read more

0.8.0

26 Jan 18:08

Choose a tag to compare

Added

  • Async/Await ⚡ - Full asynchronous programming support with Promise-based concurrency (P1 feature - COMPLETE):
    • Async Functions: Declare functions with async func syntax
    • Await Expression: Pause execution with await promise_value until Promise resolves
    • Promise Type: New built-in type for representing asynchronous operations
    • Thread-Based Runtime: Async functions execute in separate threads for true concurrency
    • Channel Communication: Promises use mpsc channels for thread-safe result passing
    • Thread-Safe Architecture: Complete Arc<Mutex<>> refactor replacing Rc<RefCell<>> throughout codebase
    • Features:
      • Async function declarations create Promises automatically
      • Await expressions properly block and retrieve results
      • Error handling with try/except in async contexts
      • Compatible with existing concurrency (spawn blocks, channels)
      • Generator compatibility maintained
    • Examples:
      # Async function declaration
      async func fetch_data(id) {
          let result := simulate_api_call(id)
          return result
      }
      
      # Await the result
      let promise := fetch_data(42)
      let data := await promise
      print("Data: ${data}")
      
      # Concurrent execution
      let p1 := process_file("file1.txt")
      let p2 := process_file("file2.txt")
      let p3 := process_file("file3.txt")
      
      # Wait for all to complete
      let r1 := await p1
      let r2 := await p2
      let r3 := await p3
      
    • Architecture Changes:
      • Migrated entire environment handling from Rc<RefCell<>> to Arc<Mutex<>> for Send trait compliance
      • Updated Value::Function, Value::AsyncFunction, Value::Generator to use Arc<Mutex>
      • All .borrow()/.borrow_mut() calls replaced with .lock().unwrap()
      • Proper mutex scope management to prevent deadlocks
    • See examples/async_*.ruff for comprehensive usage examples
    • See notes/2026-01-26_async-await-complete.md for full implementation details

Fixed

  • Generator Loop Execution 🔧 - Critical fix for yields inside loop statements:
    • Fixed PC (program counter) tracking to support yields inside loops
    • Previous implementation advanced PC before statement execution, causing loops with yields to execute only once
    • Now PC only advances when statement completes without yielding
    • Enables fibonacci(), counter(), and range() generator patterns with loops
    • All ROADMAP examples now work correctly

Added

  • Iterators & Iterator Methods 🔄 - Lazy evaluation and functional iteration patterns (P1 feature - COMPLETE):

    • Iterator Methods for arrays:
      • .filter(predicate) - Filter elements based on a predicate function, returns iterator
      • .map(transformer) - Transform each element with a function, returns iterator
      • .take(n) - Limit iteration to first n elements, returns iterator
      • .collect() - Consume iterator and collect into an array
    • Method Chaining: Combine multiple iterator operations for data processing pipelines
    • Lazy Evaluation: Operations are only executed when .collect() is called, not when chained
    • Generator Functions ✅ - Full implementation of func* and yield:
      • func* name() { yield value } - Generator function syntax
      • yield expression - Suspend execution and yield a value
      • Generator instances maintain state between yields (PC, environment)
      • Generators work seamlessly with for-in loops
      • Infinite generators supported (with manual break)
      • Examples:
        # Fibonacci generator
        func* fibonacci() {
            let a := 0
            let b := 1
            loop {
                yield a
                let temp := a
                a := b
                b := temp + b
            }
        }
        
        # Get first 10 fibonacci numbers
        count := 0
        for n in fibonacci() {
            print(n)
            count := count + 1
            if count >= 10 {
                break
            }
        }
        
        # Simple counter generator
        func* count_to(max) {
            let i := 0
            loop {
                if i >= max {
                    break
                }
                yield i
                i := i + 1
            }
        }
        
        for num in count_to(5) {
            print(num)  # Prints 0, 1, 2, 3, 4
        }
        
    • Syntax: array.filter(func).map(func).take(n).collect()
    • Examples:
      # Filter even numbers and double them
      numbers := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      result := numbers
          .filter(func(n) { return n % 2 == 0 })
          .map(func(n) { return n * 2 })
          .collect()
      # Result: [4, 8, 12, 16, 20]
      
      # Process scores: filter passing, curve, take top 5
      scores := [45, 67, 89, 23, 91, 56, 78, 34, 92, 88]
      top_curved := scores
          .filter(func(s) { return s >= 60 })
          .map(func(s) { return s + 5 })
          .take(5)
          .collect()
      
    • Comprehensive Example: examples/iterators_comprehensive.ruff with 8 different usage patterns
    • Performance: Memory efficient - intermediate arrays not created during chaining, generators don't compute values until requested
    • Test Coverage: 6 comprehensive generator tests covering basic yield, state preservation, parameters, early break, and fibonacci sequence
  • Crypto Module 🔐 - Advanced encryption and digital signature support (P1 feature):

    • AES-256-GCM Symmetric Encryption:
      • aes_encrypt(plaintext, key) - Encrypt string with AES-256-GCM, returns base64-encoded ciphertext
      • aes_decrypt(ciphertext, key) - Decrypt AES-256-GCM ciphertext, returns plaintext string
      • aes_encrypt_bytes(data, key) - Encrypt arbitrary bytes with AES-256-GCM
      • aes_decrypt_bytes(ciphertext, key) - Decrypt bytes encrypted with AES-256-GCM
      • Automatic key derivation via SHA-256 (supports any password length)
      • Random nonce generation per encryption (ensures unique ciphertext)
      • Authentication tag for integrity verification (GCM mode)
    • RSA Asymmetric Encryption:
      • rsa_generate_keypair(bits) - Generate RSA keypair (2048 or 4096 bits), returns dict with "public" and "private" PEM-encoded keys
      • rsa_encrypt(plaintext, public_key_pem) - Encrypt with RSA public key using OAEP padding
      • rsa_decrypt(ciphertext, private_key_pem) - Decrypt with RSA private key
      • Non-deterministic encryption (random padding for each encryption)
      • Supports up to 190 bytes plaintext (2048-bit key) or 446 bytes (4096-bit key)
    • RSA Digital Signatures:
      • rsa_sign(message, private_key_pem) - Sign message with RSA private key, returns base64 signature
      • rsa_verify(message, signature, public_key_pem) - Verify signature with RSA public key, returns boolean
      • PKCS#1 v1.5 signature scheme with SHA-256 hashing
      • Provides authentication, integrity, and non-repudiation
    • Security Features:
      • Industry-standard cryptographic primitives (AES-GCM, RSA-OAEP, PKCS#1 v1.5)
      • Proper error handling for invalid keys, corrupted data, and wrong passwords
      • PEM format for key storage and exchange
      • Hybrid encryption support (combine RSA + AES for large messages)
    • Examples:
      • examples/crypto_aes_example.ruff - File encryption with AES-256-GCM
      • examples/crypto_rsa_example.ruff - Secure messaging with RSA (Alice-Bob scenario)
    • Test Suite: tests/stdlib_crypto_test.ruff with 30 comprehensive tests covering encryption, decryption, signing, verification, error handling, and edge cases
    • Use Cases: Secure file storage, encrypted communications, password protection, data integrity verification, digital signatures, hybrid encryption systems
  • Built-in Testing Framework 🧪 - Comprehensive testing support with assertion functions (P2 feature):

    • Test Syntax: test "name" { ... }, test_setup { ... }, test_teardown { ... }, test_group "name" { ... }
    • Assertion Functions:
      • assert_equal(actual, expected) - Compare values for equality (Int, Float, Str, Bool, Null, Array, Dict)
      • assert_true(value) - Assert boolean is true
      • assert_false(value) - Assert boolean is false
      • assert_contains(collection, item) - Assert array/string/dict contains element
    • Test Runner: ruff test-run <file> command to execute tests with colored output
      • Runs setup before each test, teardown after each test
      • Isolated test environments (fresh interpreter per test)
      • Pass/fail/error tracking with timing information
      • Verbose mode (--verbose) for detailed test output
    • Test Organization:
      • Global setup/teardown for test suite initialization/cleanup
      • Test groups for logical organization
      • Descriptive test names as strings
    • Examples: examples/testing_demo.ruff with 27 comprehensive test cases
    • Test Suite: tests/testing_framework.ruff with 25 assertion tests
  • VM Native Function Integration 🚀 - Complete built-in function support in bytecode VM (P1 feature):

    • All 180+ Native Functions: VM now has access to every interpreter built-in function
    • Zero Code Duplication: VM delegates native function calls to interpreter implementation
    • Architecture:
      • VM contains Interpreter instance for native function execution
      • call_native_function_impl method handles pre-evaluated Value arguments
      • Automatic registration of all built-in function names via get_builtin_names()
    • Categories Supported:
      • Math (abs, sqrt, pow, sin, cos, tan, floor, ceil, round, min, max, etc.)
      • String (len, to_upper, to_lower, trim, split, join, replace, etc.)
      • Array (push, pop, map, filter, reduce, sort, reverse, etc.)
      • Dict (keys, values, ...
Read more

0.7.0

25 Jan 16:37

Choose a tag to compare

Added

  • Range Function 🔢 - Generate number sequences for loops and iteration (P2 feature):

    • range(stop) - Generate [0, 1, 2, ..., stop-1]
    • range(start, stop) - Generate [start, start+1, ..., stop-1]
    • range(start, stop, step) - Generate with custom step size
    • Supports negative steps for descending sequences
    • Returns empty array for invalid ranges
    • Example: range(5)[0, 1, 2, 3, 4]
    • Example: range(2, 7)[2, 3, 4, 5, 6]
    • Example: range(10, 0, 0 - 2)[10, 8, 6, 4, 2]
  • Format String 📝 - sprintf-style string formatting (P2 feature):

    • format(template, ...args) - Format strings with placeholders:
      • %s - String placeholder (converts any value to string)
      • %d - Integer placeholder (converts numbers to integers)
      • %f - Float placeholder (converts numbers to floats)
      • %% - Escaped percent sign
    • Supports variadic arguments
    • Returns formatted string
    • Example: format("Hello %s!", "World")"Hello World!"
    • Example: format("%s is %d years old", "Alice", 25)"Alice is 25 years old"
    • Example: format("Success rate: %d%%", 95)"Success rate: 95%"
  • Extended Math Functions 🧮 - Additional mathematical operations (P2 feature):

    • log(x) - Natural logarithm (base e)
    • exp(x) - Exponential function (e^x)
    • All 13 math functions now available: abs(), sqrt(), pow(), floor(), ceil(), round(), min(), max(), sin(), cos(), tan(), log(), exp()
  • String Methods 📚 - Comprehensive string manipulation (P2 feature):

    • Case conversion:
      • upper(str) / to_upper(str) - Convert to uppercase
      • lower(str) / to_lower(str) - Convert to lowercase
      • capitalize(str) - Capitalize first character
    • Trimming:
      • trim(str) - Remove whitespace from both ends
      • trim_start(str) - Remove leading whitespace
      • trim_end(str) - Remove trailing whitespace
    • Character operations:
      • char_at(str, index) - Get character at index
      • count_chars(str) - Count characters (not bytes)
    • Validation:
      • is_empty(str) - Check if string is empty
    • Search (existing, now documented):
      • contains(str, substr) - Check if contains substring
      • starts_with(str, prefix) - Check prefix
      • ends_with(str, suffix) - Check suffix
      • index_of(str, substr) - Find first occurrence index
    • Manipulation (existing, now documented):
      • replace(str, old, new) / replace_str(str, old, new) - Replace occurrences
      • split(str, delimiter) - Split into array
      • join(array, separator) - Join array into string
      • substring(str, start, end) - Extract substring
      • repeat(str, count) - Repeat string n times
  • Array Mutation Methods 🔧 - Essential array operations (P2 feature):

    • push(arr, item) / append(arr, item) - Add item to end
    • pop(arr) - Remove and return last item (returns [modified_array, popped_item])
    • insert(arr, index, item) - Insert item at specific index
    • remove(arr, item) - Remove first occurrence of item
    • remove_at(arr, index) - Remove item at index (returns [modified_array, removed_item])
    • clear(arr) - Return empty array
    • Polymorphic functions (work with both strings and arrays):
      • contains(arr, item) - Check if array contains item (also works with strings)
      • index_of(arr, item) - Find index of item (also works with strings)
    • Existing (now documented):
      • concat(arr1, arr2) - Concatenate two arrays
      • slice(arr, start, end) - Extract sub-array
  • Dict/Map Methods 🗺️ - Essential dictionary operations (P2 feature):

    • items(dict) - Get array of [key, value] pairs
    • get(dict, key, default?) - Get value with optional default if key not found
    • merge(dict1, dict2) - Merge two dictionaries (dict2 overwrites dict1)
    • Polymorphic functions:
      • clear(dict) - Return empty dict (also works with arrays)
      • remove(dict, key) - Remove key-value pair (returns [modified_dict, removed_value], also works with arrays)
    • Existing (now documented):
      • keys(dict) - Get all keys as array
      • values(dict) - Get all values as array
      • has_key(dict, key) - Check if key exists
  • Assert & Debug Functions 🐛 - Runtime assertions and debug output for testing and troubleshooting (P2 feature):

    • assert(condition, message?) - Runtime assertion with optional custom error message:
      • Returns true if condition is truthy (non-zero numbers, non-null values, true boolean)
      • Returns error value with message if condition is falsy (0, null, false)
      • Falsy values: false, 0 (Int), null
      • Truthy values: true, non-zero numbers, strings, arrays, objects
      • Optional message parameter provides context for failed assertions
      • Use in guard clauses and input validation
      • Example: assert(x > 0, "x must be positive") → returns true or error
    • debug(...args) - Print debug output with detailed type information:
      • Accepts variadic arguments (any number of values)
      • Prints values with full type information for inspection
      • Shows detailed structure for arrays, dicts, and nested objects
      • Prefixed with [DEBUG] for easy filtering in logs
      • Returns null (useful for debugging without affecting program flow)
      • Example: debug("User", user_id, "logged in") → prints [DEBUG] String("User") Int(123) String("logged in")
    • Type Integration: Added type introspection functions (is_int, is_float, is_string, etc.) to type checker
    • Variadic Support: Fixed type checker to support variadic functions like debug()
    • Comprehensive Testing: 10 new integration tests covering:
      • Successful assertions with various data types
      • Failed assertions with default and custom messages
      • Truthy/falsy value handling
      • Assertions in functions and guard clauses
      • Debug output for simple and complex values
      • Debug with multiple arguments
    • Example File: examples/assert_debug_demo.ruff with 10 practical use cases
    • Example:
      # Basic assertions
      assert(age >= 0, "Age cannot be negative")
      assert(len(items) > 0, "List cannot be empty")
      
      # Guard functions
      func divide(a, b) {
          if b == 0 {
              return assert(false, "Division by zero not allowed")
          }
          return a / b
      }
      
      # Debug output
      debug("Processing user:", user_id, "at", timestamp)
      # Prints: [DEBUG] String("Processing user:") Int(12345) String("at") Int(1706140800)
      
      # Debug complex structures
      data := {"users": [{"name": "Alice", "age": 30}], "count": 1}
      debug("Data:", data)
      # Prints: [DEBUG] String("Data:") Dict{users: Array[Dict{name: String("Alice"), age: Int(30)}], count: Int(1)}
      
      # Input validation
      func validate_age(age) {
          check := assert(age >= 0, "Age cannot be negative")
          if type(check) == "error" {
              return check
          }
          return "Valid age: " + to_string(age)
      }
      
  • Array Utilities 🔢 - Essential array manipulation and analysis functions (P1 feature):

    • sort(array) - Sort array in ascending order:
      • Works with numbers (Int and Float) and strings
      • Returns new sorted array (original unchanged)
      • Mixed Int/Float arrays sorted numerically
      • Example: sort([3, 1, 4, 1, 5])[1, 1, 3, 4, 5]
    • reverse(array) - Reverse array order:
      • Returns new array with elements in reverse order
      • Example: reverse([1, 2, 3])[3, 2, 1]
    • unique(array) - Remove duplicate elements:
      • Preserves order of first occurrence
      • Works with any value types
      • Example: unique([1, 2, 1, 3, 2])[1, 2, 3]
    • sum(array) - Calculate sum of numeric elements:
      • Returns Int if all elements are Int, Float if any Float present
      • Skips non-numeric values
      • Empty array returns 0
      • Example: sum([1, 2, 3, 4, 5])15
    • any(array, predicate) - Check if any element satisfies condition:
      • Returns true if predicate returns truthy for any element
      • Returns false for empty array
      • Example: any([1, 2, 3], func(x) { return x > 2 })true
    • all(array, predicate) - Check if all elements satisfy condition:
      • Returns true if predicate returns truthy for all elements
      • Returns true for empty array (vacuous truth)
      • Example: all([1, 2, 3], func(x) { return x > 0 })true
    • Comprehensive Testing: 18 new tests covering all functions, edge cases, and chaining
    • Example:
      scores := [85, 92, 78, 92, 88, 95, 78, 90]
      
      # Sort and get unique values
      unique_scores := sort(unique(scores))  # [78, 85, 88, 90, 92, 95]
      
      # Calculate statistics
      total := sum(scores)           # 698
      average := total / len(scores) # 87.25
      
      # Check conditions
      has_excellent := any(scores, func(s) { return s >= 90 })  # true
      all_passing := all(scores, func(s) { return s >= 60 })    # true
      
      # Chain operations
      top_scores := reverse(sort(unique(scores)))  # [95, 92, 90, 88, 85, 78]
      
  • File Operations 📁 - Essential file manipulation functions for common operations (P1 feature):

    • file_size(path) - Get file size in bytes:
      • Returns integer byte count (e.g., file_size("document.pdf")1024000)
      • Useful for checking file sizes before reading or for progress tracking
    • delete_file(path) - Remove a file:
      • Deletes the specified file from the filesystem
      • Returns true on success, error on failure
    • rename_file(old_path, new_path) - Rename or move a file:
      • Renames file from old_path to new_path
      • ...
Read more

0.6.0

25 Jan 02:08

Choose a tag to compare

Added

  • Database Transactions 🎉:

    • db_begin(db) - Start a database transaction
    • db_commit(db) - Commit transaction changes
    • db_rollback(db) - Rollback transaction on error
    • db_last_insert_id(db) - Get auto-generated ID from last INSERT
    • Ensures atomic operations across multiple SQL statements
    • Full support for SQLite, PostgreSQL, and MySQL
    • Automatic transaction cleanup on interpreter shutdown (prevents hangs)
    • Example: Money transfers, e-commerce order processing, inventory management
    • See examples/database_transactions.ruff for working examples
    • See tests/test_transactions_working.ruff for comprehensive tests
  • Connection Pooling 🎉:

    • db_pool(db_type, connection_string, config) - Create connection pool
    • db_pool_acquire(pool) - Acquire connection from pool (blocks if all in use)
    • db_pool_release(pool, conn) - Release connection back to pool
    • db_pool_stats(pool) - Get pool statistics (available, in_use, total, max)
    • db_pool_close(pool) - Close entire pool and all connections
    • Configuration options:
      • min_connections - Minimum pool size (reserved for future use)
      • max_connections - Maximum concurrent connections
      • connection_timeout - Seconds to wait for available connection
    • Thread-safe lazy connection creation
    • Supports all three database backends: SQLite, PostgreSQL, MySQL
    • Critical for production apps with high traffic and concurrent users
    • See examples/database_pooling.ruff for working examples
    • See tests/test_connection_pooling.ruff for comprehensive tests

Fixed

  • Fixed critical bug where SQLite connections would hang on exit if in active transaction
  • Added Interpreter::cleanup() method to rollback active transactions before drop

Added (Previous)

  • Unified Database API:
    • Multi-Backend Support:

      • Unified db_connect(db_type, connection_string) API that works across different databases
      • Database type parameter: "sqlite" ✅, "postgres" ✅, "mysql" (coming soon)
      • Same db_execute() and db_query() functions work with any database backend
      • Seamless migration path between database types without code changes
    • SQLite Support ✅:

      • db_connect("sqlite", "path/to/database.db") - Connect to SQLite database
      • db_execute(db, sql, params) - Execute INSERT, UPDATE, DELETE, CREATE statements
      • db_query(db, sql, params) - Query data and return array of dictionaries
      • Parameter binding with ? placeholders: ["Alice", 30]
      • Full support for NULL values, integers, floats, text, and blobs
    • PostgreSQL Support ✅:

      • db_connect("postgres", "host=localhost dbname=myapp user=admin password=secret")
      • db_connect("postgresql", ...) - Both "postgres" and "postgresql" accepted
      • db_execute(db, sql, params) - Execute SQL with $1, $2, $3 parameter syntax
      • db_query(db, sql, params) - Query with full type support
      • Parameter binding: ["Alice", 30] mapped to $1, $2 in SQL
      • Supports: SERIAL, INTEGER, BIGINT, REAL, DOUBLE PRECISION, TEXT, BOOLEAN, NULL
      • Compatible with PostgreSQL 9.6+ features
    • MySQL Support ✅:

      • db_connect("mysql", "mysql://user:pass@localhost:3306/myapp")
      • Asynchronous driver (mysql_async) with transparent blocking interface
      • Parameter binding with ? placeholders (MySQL style)
      • Full CRUD support: CREATE, INSERT, SELECT, UPDATE, DELETE
      • Supports: INT, AUTO_INCREMENT, VARCHAR, BOOLEAN, TIMESTAMP, NULL
      • Compatible with MySQL 5.7+ and MariaDB 10.2+
    • Common Database Functions:

      • db_close(db) - Close database connection (works for all database types)
      • Full parameter binding support prevents SQL injection
      • Automatic type conversion between Ruff and database types
      • Proper NULL value handling across all databases
    • Transaction Support (Planned):

      • db_begin(db) - Begin transaction
      • db_commit(db) - Commit transaction
      • db_rollback(db) - Rollback transaction
      • Stub implementations show helpful messages
    • Connection Pooling (Planned):

      • db_pool(db_type, connection_string, options) - Create connection pool
      • For high-traffic applications
      • Infrastructure designed, implementation planned for future release
    • Use Cases:

      • 🍽️ Restaurant menu management (SQLite for local, PostgreSQL for cloud)
      • 📝 Blog platforms with PostgreSQL
      • 💬 Forums and community sites
      • 🛒 E-commerce applications
      • 📊 Analytics dashboards
      • 🏢 Business management tools
    • Examples:

            # SQLite with unified API
      

      db := db_connect("sqlite", "myapp.db")
      db_execute(db, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", [])
      db_execute(db, "INSERT INTO users (name) VALUES (?)", ["Alice"])
      users := db_query(db, "SELECT * FROM users WHERE id > ?", [100])

      PostgreSQL with same API!

      db := db_connect("postgres", "host=localhost dbname=myapp user=admin password=secret")
      db_execute(db, "CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)", [])
      db_execute(db, "INSERT INTO users (name) VALUES ($1)", ["Alice"])
      users := db_query(db, "SELECT * FROM users WHERE id > $1", [100])

      MySQL with same API!

      db := db_connect("mysql", "mysql://root@localhost:3306/myapp")
      db_execute(db, "CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))", [])
      db_execute(db, "INSERT INTO users (name) VALUES (?)", ["Alice"])
      users := db_query(db, "SELECT * FROM users WHERE id > ?", [100])

      Same Ruff code works across all databases!

      for user in users {
      print(user["name"])
      }
      db_close(db)

    • See examples/database_unified.ruff for comprehensive SQLite examples

    • See examples/database_postgres.ruff for comprehensive PostgreSQL examples

    • See examples/database_mysql.ruff for comprehensive MySQL examples

    • Breaking change: Old db_connect(path) syntax replaced with db_connect("sqlite", path)

    • Migration: Add "sqlite" as first argument to existing db_connect() calls

Fixed

  • Function Scope Handling:

    • Fixed variable shadowing in functions - functions now properly use call-time environment
    • Fixed outer variable modification from within functions
    • Regular function definitions no longer capture environment (only closures do)
    • All 117 tests now pass (fixed 5 previously failing scope tests)
  • Concurrency & Parallelism (v0.6.0):

    • spawn Statement:

      • spawn { code } - Execute code block in a background thread
      • Non-blocking execution for fire-and-forget tasks
      • Each spawn runs in isolation with its own environment
      • Perfect for background processing and long-running operations
    • Parallel HTTP Requests:

      • parallel_http(urls_array) - Make multiple HTTP GET requests concurrently
      • Returns array of response dicts in same order as input URLs
      • Each response contains status (number) and body (string) fields
      • 3x faster than sequential requests when fetching from 3+ endpoints
      • Critical for AI tools comparing multiple model providers (OpenAI, Claude, DeepSeek)
      • Ideal for batch processing and data pipelines
    • Channels for Thread Communication:

      • channel() - Create thread-safe communication channel
      • chan.send(value) - Send value to channel (non-blocking)
      • chan.receive() - Receive value from channel (returns null if empty)
      • FIFO ordering (first in, first out)
      • Perfect for producer-consumer patterns
      • Enables coordination between spawned tasks and main thread
    • Use Cases:

      • AI Model Comparison: Query GPT-4, Claude, and DeepSeek simultaneously for 3x speedup
      • Batch Content Generation: Process 100+ prompts across multiple providers in parallel
      • Background Processing: File processing, log analysis, data transformation without blocking
      • Web Scraping: Fetch multiple pages concurrently
      • API Aggregation: Combine data from multiple services in real-time
    • Examples:

            # Parallel HTTP requests
      

      urls := ["https://api1.com", "https://api2.com", "https://api3.com"]
      results := parallel_http(urls) # All 3 requests happen simultaneously

      Background tasks with spawn

      spawn {
      print("Processing in background...")
      process_large_file()
      }
      print("Main thread continues immediately")

      Thread communication with channels

      chan := channel()

      spawn {
      result := expensive_computation()
      chan.send(result)
      }

      value := chan.receive() # Get result from background thread

    • See examples/concurrency_parallel_http.ruff for parallel HTTP demo

    • See examples/concurrency_spawn.ruff for spawn examples

    • See examples/concurrency_channels.ruff for channel communication patterns

    • See examples/projects/ai_model_comparison.ruff for real-world AI tool example

  • Image Processing (v0.6.0):

    • Image Loading:
      • load_image(path) - Load images from files (JPEG, PNG, WebP, GIF, BMP)
      • Error handling for missing or invalid image files
      • Automatic format detection from f...
Read more

0.5.0

23 Jan 18:01

Choose a tag to compare

Added

  • HTTP Server & Networking: Full-featured HTTP client and server capabilities

    • HTTP Client Functions:

      • http_get(url) - Send GET requests and receive responses
      • http_post(url, body) - Send POST requests with JSON body
      • http_put(url, body) - Send PUT requests with JSON body
      • http_delete(url) - Send DELETE requests
      • Returns Result<dict, string> with status code and response body
    • HTTP Server Creation:

      • http_server(port) - Create HTTP server on specified port
      • server.route(method, path, handler) - Register route handlers
      • server.listen() - Start server and handle incoming requests
    • Request/Response Objects:

      • http_response(status, body) - Create HTTP response with status code and text body
      • json_response(status, data) - Create HTTP response with JSON body
      • Request object includes: method, path, body fields
    • Features:

      • Method-based routing (GET, POST, PUT, DELETE, etc.)
      • Path-based routing with exact matching
      • JSON request/response handling
      • Automatic request body parsing
      • Error handling with proper status codes
    • Example applications:

      • examples/http_server_simple.ruff - Basic hello world server
      • examples/http_rest_api.ruff - Full REST API with in-memory data
      • examples/http_client.ruff - HTTP client usage examples
      • examples/http_webhook.ruff - Webhook receiver implementation
    • Example:

            let server = http_server(8080);
      

      server.route("GET", "/hello", func(request) {
      return http_response(200, "Hello, World!");
      });

      server.route("POST", "/data", func(request) {
      return json_response(200, {"received": request.body});
      });

      server.listen(); // Start serving requests

  • SQLite Database Support: Built-in SQLite database functions for persistent data storage

    • db_connect(path) - Connect to a SQLite database file (creates if not exists)
    • db_execute(db, sql, params) - Execute INSERT, UPDATE, DELETE, CREATE statements
    • db_query(db, sql, params) - Execute SELECT queries, returns array of dicts
    • db_close(db) - Close database connection
    • Parameters use ? placeholders: db_execute(db, "INSERT INTO t (a, b) VALUES (?, ?)", [val1, val2])
    • Query results are arrays of dicts with column names as keys
    • Thread-safe with Arc<Mutex<Connection>> wrapper
  • HTTP redirect_response(): New function for creating HTTP 302 redirect responses

    • redirect_response(url) - Returns HTTP response with Location header
    • Used for URL shorteners and OAuth flows
  • Dynamic route path parameters: HTTP server routes now support parameterized paths like /:code

    • New match_route_pattern() function extracts path parameters from URLs
    • Request object now includes a params dict with extracted path values
    • Example: server.route("GET", "/:code", func(request) { code := request.params["code"] })
    • Exact routes take priority over parameterized routes (e.g., /health matches before /:code)
  • Interactive REPL (Read-Eval-Print Loop): Full-featured interactive shell for Ruff

    • Launch with ruff repl - Start interactive mode for quick experimentation and learning

    • Multi-line input support - Automatically detects incomplete statements (unclosed braces, brackets, parentheses)

      • Type opening brace { and continue on next line with ....> prompt
      • Close brace } to execute the complete statement
      • Works for functions, loops, conditionals, and any multi-line construct
    • Command history - Navigate previous commands with up/down arrow keys

    • Line editing - Full readline support with cursor movement and editing

    • Special commands:

      • :help or :h - Display help information
      • :quit or :q - Exit the REPL (or use Ctrl+D)
      • :clear or :c - Clear the screen
      • :vars or :v - Show defined variables
      • :reset or :r - Reset environment to clean state
      • Ctrl+C - Interrupt current input
    • Persistent state - Variables and functions remain defined across inputs

    • Pretty-printed output - Colored, formatted display of values

      • Numbers: => 42
      • Strings: => "Hello, World"
      • Booleans: => true
      • Arrays: => [1, 2, 3, 4]
      • Dictionaries: => {"name": "Alice", "age": 30}
      • Functions: => <function(x, y)>
      • Structs: => Point { x: 3, y: 4 }
    • Expression evaluation - Any expression automatically prints its result

    • Error handling - Errors display clearly without crashing the REPL

    • Example session:

            ruff> let x := 42
      

      ruff> x + 10
      => 52
      ruff> func greet(name) {
      ....> print("Hello, " + name)
      ....> }
      ruff> greet("World")
      Hello, World
      => 0
      ruff> let nums := [1, 2, 3, 4, 5]
      ruff> nums
      => [1, 2, 3, 4, 5]
      ruff> :quit
      Goodbye!

    • See tests/test_repl_*.txt for comprehensive examples

Changed

  • URL Shortener example: Updated to use SQLite database for secure URL storage
    • URLs no longer exposed via public /list JSON endpoint
    • Stats endpoint now requires POST with code in body
    • New /count endpoint shows total URLs without exposing data
    • Database file: urls.db in working directory

Fixed

  • Critical: Logical AND (&&) and OR (||) operators not working: The && and || operators were completely broken - they always returned false regardless of operands.

    • Lexer: Added tokenization for | and & characters to produce || and && tokens
    • Parser: Added parse_or() and parse_and() functions with proper operator precedence (|| lowest, then &&, then comparisons)
    • Interpreter: Added && and || cases to the Bool/Bool match arm
    • Also added != operator support for Bool and String comparisons
    • This fixes URL validation in url_shortener.ruff which uses starts_with(url, "http://") || starts_with(url, "https://")
    • Example: true || false now correctly returns true (previously returned false)
  • URL shortener /list endpoint: Changed from for code in keys(urls) to for code in urls

    • The keys() function inside closures causes hangs
    • Direct dict iteration works correctly and iterates over keys
  • Critical: Function cleanup hang bug: Fixed stack overflow that occurred when functions containing loops were cleaned up during program shutdown. Functions can now safely contain loops, nested control structures, and complex logic without hanging.

    • Introduced LeakyFunctionBody wrapper type using ManuallyDrop to prevent deep recursion during Rust's automatic drop
    • Function bodies are intentionally leaked at program shutdown (OS reclaims all memory anyway)
    • Updated url_shortener.ruff example to use proper random code generation with loops
    • Added comprehensive tests in tests/test_function_drop_fix.ruff
  • HTTP functions type checking warnings: Fixed "Undefined function" warnings for HTTP functions in the type checker.

    • Registered all HTTP client functions: http_get, http_post, http_put, http_delete
    • Registered all HTTP server functions: http_server, http_response, json_response
    • HTTP examples now run without type checking warnings
    • Added test file tests/test_http_type_checking.ruff

0.4.0

23 Jan 12:54

Choose a tag to compare

Ruff v0.4.0 - Operator Overloading & Advanced Struct Features

We're excited to announce Ruff v0.4.0, a major release featuring comprehensive operator overloading, explicit self parameters for methods, and enhanced error handling!

🎯 Highlights

✨ Unary Operator Overloading

Structs can now define custom behavior for unary operators:

  • op_neg for unary minus (-value)
  • op_not for logical not (!value)
struct Vector {
    x: float,
    y: float,
    
    fn op_neg(self) {
        return Vector { x: -self.x, y: -self.y };
    }
}

let v = Vector { x: 3.0, y: 4.0 };
let neg_v = -v;  // Vector { x: -3.0, y: -4.0 }

Perfect for:

  • Vector and matrix operations
  • Complex number arithmetic
  • Custom boolean logic
  • Flag toggling

🔧 Explicit self Parameter

Methods can now use an explicit self parameter for method composition and builder patterns:

struct Calculator {
    base: float,
    
    fn add(self, x) {
        return self.base + x;
    }
    
    fn chain(self, x) {
        return self.add(x) * 2.0;  // Call other methods!
    }
}

Enable fluent interfaces:

result := Builder { x: 0.0, y: 0.0 }
    .set_x(10.0)
    .set_y(20.0);

Fully backward compatible - existing code without self continues to work!

⚡ Binary Operator Overloading

Complete support for custom operator behavior:

Arithmetic: op_add (+), op_sub (-), op_mul (*), op_div (/), op_mod (%)
Comparison: op_eq (==), op_ne (!=), op_lt (<), op_gt (>), op_lte (<=), op_gte (>=)

struct Vector {
    x: float,
    y: float,
    
    fn op_add(self, other) {
        return Vector { 
            x: self.x + other.x, 
            y: self.y + other.y 
        };
    }
}

v1 := Vector { x: 1.0, y: 2.0 };
v2 := Vector { x: 3.0, y: 4.0 };
v3 := v1 + v2;  // Vector { x: 4.0, y: 6.0 }

🛡️ Enhanced Error Handling

Error Properties: Access detailed error information

  • err.message - Error message string
  • err.stack - Call stack trace array
  • err.line - Line number (when available)

Custom Error Types: Define domain-specific errors

struct ValidationError {
    field: string,
    message: string
}

throw(ValidationError {
    field: "email",
    message: "Email is required"
})

Error Chaining: Preserve error context

try {
    risky_operation()
} except original_err {
    throw(DatabaseError {
        message: "Failed to process",
        cause: original_err.message
    })
}

📚 Standard Library Enhancements

Math & Random:

  • random() - Float between 0.0 and 1.0
  • random_int(min, max) - Random integer in range
  • random_choice(array) - Random array element

Date/Time:

  • now() - Current timestamp
  • format_date(timestamp, format) - Custom date formatting
  • parse_date(string, format) - Parse date strings

String & Array:

  • join(array, separator) - Join array elements
  • split(string, separator) - Split string into array
  • trim(string) - Remove whitespace
  • contains(haystack, needle) - Search strings/arrays
  • And many more!

📦 Installation

git clone https://github.com/rufflang/ruff.git
cd ruff
cargo build --release
./target/release/ruff run your_script.ruff

📝 Examples

Check out these comprehensive examples:

  • examples/unary_operators.ruff - Vector negation, complex numbers, boolean flags
  • examples/operator_overloading.ruff - Complete operator overloading showcase
  • examples/struct_self_methods.ruff - Builder patterns and method composition
  • examples/error_handling_enhanced.ruff - Advanced error handling patterns

🔗 Resources

🙏 Acknowledgments

Thank you to everyone who has contributed feedback and ideas for this release!


Full Changelog: https://github.com/rufflang/ruff/blob/main/CHANGELOG.md#040---2026-01-23

0.3.0

23 Jan 05:18

Choose a tag to compare

Added

  • JSON Support: Native JSON parsing and serialization functions
  • Doc Comments: Documentation comments for code documentation
  • Enhanced Comment Support: All comment types work together seamlessly
  • Array Higher-Order Functions: Functional programming operations on arrays for data transformation and processing
  • Anonymous Function Expressions: Support for inline function definitions in expression contexts
  • Enhanced String Functions: Six new string manipulation functions for common string operations
  • String Interpolation: Embed expressions directly in strings with ${} syntax
  • Parenthesized Expression Grouping: Parser now supports (expr) for grouping expressions
  • Loop Control Statements: Full support for while loops, break, and continue
  • Modulo Operator: Added % operator for modulo arithmetic
  • Not-Equal Operator: Added != comparison operator
  • Boolean Type as First-Class Value: Booleans are now proper runtime values
  • File I/O Functions: Complete filesystem operations support
  • User Input Functions: Added interactive I/O capabilities
  • Lexical Scoping: Implemented proper lexical scoping with environment stack
  • Scope Management: Environment now uses Vec scope stack
  • Comprehensive Tests: 12 new integration tests for scoping
  • Example File: examples/scoping.ruff demonstrates all scoping features

Fixed

  • Assignment Operator: Fixed := to update existing variables instead of always creating new
  • Function Call Cleanup: Fixed return_value not being cleared after function calls

Changed

  • Environment Architecture: Replaced single HashMap with Vec scope stack

0.2.0

22 Jan 15:36

Choose a tag to compare

Added

  • Field Assignment: Full support for mutating struct fields with := operator
    • Direct field mutation: person.age := 26
    • Nested field mutation: todos[0].done := true
    • Works with array indexing and dictionary keys
  • Truthy/Falsy Evaluation: If conditions now properly handle boolean values and collections
    • Boolean identifiers (true/false) work in conditionals
    • Strings: "true" → truthy, "false" → falsy, empty → falsy
    • Arrays: empty → falsy, non-empty → truthy
    • Dictionaries: empty → falsy, non-empty → truthy
  • Test Suite: Added 10 comprehensive integration tests covering:
    • Field assignment for structs and arrays
    • Boolean conditions and truthy values
    • Array and dict operations
    • String concatenation
    • For-in loops
    • Variable assignment behavior
    • Struct field access
  • Example Projects: Two demonstration projects showcasing language features
    • Todo Manager: struct mutation, arrays, control flow
    • Contact Manager: dictionaries, string functions, error handling
  • Clean Build: Zero compiler warnings - all infrastructure code properly annotated

Fixed

  • Variable Assignment: := operator now consistently creates or updates variables
    • Previously would fail if variable didn't exist in certain contexts
    • Now always inserts/updates in environment
  • Boolean Handling: Fixed if statements not recognizing boolean struct fields
    • Was only checking numeric values for truthiness
    • Now properly evaluates boolean identifiers and other types
  • Pattern Matching: Corrected struct pattern matching syntax in field assignment
    • Changed from incorrect Value::Struct(ref mut fields)
    • To correct Value::Struct { name: _, fields }

Changed

  • Documentation: Clarified that example projects are demonstrations, not interactive applications
  • Build Output: Added --quiet flag recommendation for clean execution output
  • README: Updated with clearer feature descriptions and usage examples

Known Limitations (Documented)

  • No lexical scoping - uses single global environment
  • Variable shadowing in blocks doesn't update outer scope (design limitation)
  • Booleans stored as string identifiers internally (architectural choice)
  • No user input function yet (input() planned for future release)

Technical Details

  • Total tests: 14 (up from 4)
  • Compiler warnings: 0 (down from 14)
  • Lines of test code added: ~200
  • Files modified: interpreter.rs, ast.rs, errors.rs, builtins.rs, module.rs

0.1.0

21 Jan 23:05

Choose a tag to compare

  • First stable release