Commit Graph

322 Commits

Author SHA1 Message Date
Brummel 3676eb51e5 Rename pipe-buffered to pipe-series
The `pipe-buffered` function has been renamed to `pipe-series` to better
reflect its functionality. This change involves updating the function
name in the example file `examples/data_stream_pipe_buffered.myc` and
across the Rust source code in `src/ast/rtl/streams.rs`. Additionally,
test cases and documentation have been updated accordingly.
2026-03-30 14:16:04 +02:00
Brummel 24d36a08a6 Refactor 'again' type check to use unify
This change replaces a manual type check for the `again` function with a
call to the generic `unify` function. This improves consistency and
leverages existing type-checking logic.

A new test case `test_again_type_mismatch` has been added to
specifically verify that type mismatches in `again` calls are caught at
compile time, preventing potential infinite loops.
2026-03-30 11:50:08 +02:00
Brummel c403c80f5b Refine type error reporting for readability
The `display_compact` method on `StaticType` has been enhanced to
provide more concise representations of types within error messages.
This change aims to improve the clarity of type-related diagnostics
generated by the compiler.
2026-03-30 11:45:31 +02:00
Brummel 8aa2a67b5b Introduce StaticType::Variadic for variadic parameters
This commit introduces `StaticType::Variadic` to represent variadic
parameter types in function signatures. This allows for more precise
type checking of functions that accept a variable number of arguments,
such as arithmetic operators.

Previously, variadic functions were handled using `StaticType::Any`,
which was too permissive and could lead to runtime errors. The new
`Variadic` type enforces that all arguments must conform to a specified
inner type.

Changes include:

- Adding `StaticType::Variadic` to `src/ast/types.rs`.
- Updating the type checker to handle `Variadic` types correctly when
  unifying with tuples or single arguments.
- Modifying built-in functions like arithmetic operators to use
  `Variadic` for their parameter types.
- Improving error messages for function call mismatches to be more
  specific.
- Adding a new test case to ensure arithmetic type mismatches are caught
  at compile time.
- A new example `data_stream_pipe_buffered.myc` is added.
- The `HMA.myc` example now has a `Skip: output` directive.
2026-03-30 11:36:26 +02:00
Brummel f1621ed1ac Update data_stream_print.myc 2026-03-30 10:54:48 +02:00
Brummel 6d24c5b64c Add pipe-buffered function
Implements `pipe-buffered`, a new primitive that allows accumulating
values from multiple input streams into internal series buffers before
executing a user-provided lambda. This is useful for implementing
lookback logic and ensuring that the lambda only executes when
sufficient data is available in all input streams.

The function takes a `lookback` integer, input streams, and a lambda.
The lambda receives `Series` objects for each input, allowing indexed
access to past values. The `pipe-buffered` function manages the
buffering and fill-gate logic.
2026-03-30 10:54:32 +02:00
Brummel 141ae36ede Refactor: Create typed series factory function
Introduces `create_typed_series` to centralize series creation logic.
This function dispatches on `StaticType` to select the appropriate
`SeriesStorage` implementation,
improving code reuse and maintainability within the series RTL.

The `SeriesHook` compiler hook is updated to use this new factory
function.
Additionally, new tests have been added to `rtl/streams.rs` and
`tests/pipeline.rs`
to specifically cover the behavior of `pipe-buffered`, focusing on its
fill gate
mechanism and multi-input handling.
2026-03-30 10:38:28 +02:00
Brummel 6628941a50 Create propa.myc 2026-03-30 10:31:51 +02:00
Brummel 0ef5faed91 Remove unused Propa example
The `Propa.myc` example was not being used and has been removed to clean
up the examples directory.
2026-03-30 10:31:45 +02:00
Brummel 9b13546609 feat: Add pipe parameter validation and fix VM call frame
Adds a check within the `PipeHook` to ensure the number of input streams
provided to a `pipe` operation matches the number of parameters expected
by the associated lambda function. This prevents runtime errors and
provides a clearer compile-time diagnostic.

Additionally, this commit corrects the order in which a `CallFrame` is
pushed onto the VM's frame stack. By pushing the frame earlier, it
ensures that slow-path `unpack` operations have access to a valid frame,
preventing "No call frame" errors.
2026-03-30 09:43:58 +02:00
Brummel e82d48d1cb Refactor data streams to support time windows
This commit introduces time windowing functionality to the M1 and tick
data streams.

Key changes:

- **`DataServer::stream_m1_windowed` and
  `DataServer::stream_tick_windowed`**: New methods added to
  `DataServer` to allow streaming data within a specified `from_ms` and
  `to_ms` range.
- **`SymbolChunkIter` modifications**: The `SymbolChunkIter` struct now
  includes `from_ms`, `to_ms`, and `exhausted` fields to manage time
  window filtering.
- **`filter_chunk` helper function**: A new utility function to
  efficiently filter individual data chunks based on the time window.
  This function also handles early termination when `to_ms` is exceeded.
- **`HasTimestamp` trait**: Introduced to provide a common interface for
  accessing timestamps across different record types (`M1Parsed`,
  `TickParsed`), enabling generic filtering.
- **`filter_files` method**: Added to `DataServer` to pre-filter file
  keys based on the time window before creating iterators. This
  optimizes file loading by skipping files that fall entirely outside
  the desired range.
- **`create-m1-stream` and `create-tick-stream`**: The native functions
  in `data_streams.rs` are updated to accept optional `DateTime`
  arguments for `from` and `to` timestamps. They now also handle unknown
  symbols by returning `Value::Void` and return an empty stream if the
  time window results in no data.
- **Documentation**: Updated doc comments for the stream creation
  functions to reflect the new time windowing capabilities and to
  clarify behavior for unknown symbols and empty time windows.

These changes significantly enhance the flexibility of data streaming,
allowing users to query specific time ranges of M1 and tick data more
efficiently.
2026-03-29 22:03:33 +02:00
Brummel 1f68371920 Add symbol-based cache eviction
Introduces a reference counting mechanism for symbols within the
`FileCache`. When a `SymbolChunkIter` is created, it increments the
reference count for its symbol. When the iterator is dropped, the
reference count is decremented. If a symbol's reference count drops to
zero, all cached data associated with that symbol is evicted from the
cache, freeing up memory. This prevents stale data from being held
indefinitely when no active iterators are using it.
2026-03-29 21:40:30 +02:00
Brummel c32cc0f49c Refactor FileCache to use Condvar for efficient waits
The `FileCache` now uses `std::sync::Condvar` to signal when files have
finished loading. This replaces the previous spin-wait mechanism,
significantly improving efficiency by allowing waiting threads to sleep
until explicitly woken up.

The `wait_for_load` method now blocks on the `Condvar`, and the
`insert_m1` and `insert_tick` methods call `notify_all` after updating
the cache and removing the loading guard. This ensures that all waiting
threads are woken up and can re-check the cache.

Additionally, `ensure_m1_loaded` and `ensure_tick_loaded` in
`DataServer` have been simplified to directly call `wait_for_load` when
another thread is already loading the file, removing the redundant
synchronous loading logic.
Refactor FileCache to use Condvar
2026-03-29 20:47:49 +02:00
Brummel 38f657076b feat: Add data server for market data loading
This commit introduces a new data server module (`src/ast/data_server`)
designed for high-performance, thread-safe loading and caching of market
data.

Key components:
- `DataServer`: Manages symbol indexing and delegates loading/caching.
- `SymbolIndex`: Scans the data directory and maintains a sorted index
  of data files per symbol.
- `FileCache`: Implements a thread-safe cache using `RwLock` and a
  loading guard to prevent duplicate work.
- `loader`: Handles ZIP decompression and binary record parsing from
  `.bin` files.
- `records`: Defines raw and parsed data structures for M1 and tick
  data.
- `SymbolChunkIter`: Provides an iterator over pre-parsed data chunks,
  prefetching subsequent files.

This architecture allows multiple VM threads to access market data
concurrently without redundant I/O, mirroring the strategy used in the
original Delphi `TDataServer`.
2026-03-29 20:28:55 +02:00
Brummel 1f3fb40bcc Update record type computation
This commit refactors the way record types are computed within the
optimizer. Previously, the optimizer would often reuse the existing
`NodeMetrics` for records, which could lead to stale or polymorphic
types.

The changes introduce a new function, `compute_record_type`, which
explicitly recalculates the `StaticType` for a `Record` node based on
the concrete types of its child fields. This ensures that after
optimizations like inlining and folding, record types are as concrete as
possible, eliminating unresolved `TypeVars`.

Additionally, the `folder.rs` module is updated to recompute the
`RecordLayout` when creating constant record values, further improving
type accuracy. Two new tests are added to verify that inlined records,
including those with multiple fields, correctly result in concrete
types.
2026-03-29 18:59:38 +02:00
Brummel 6c8e2df45c Refactor: Improve type propagation in optimizer
Refactor the `updated_metrics` function to `refreshed_metrics`. This
function now clones the `NodeMetrics` if the new type is identical to
the original, avoiding unnecessary allocations.

Also, adjust the `Block` and `Lambda` node kinds to correctly propagate
concrete types after inlining, especially when dealing with polymorphic
functions. This ensures that the return types of blocks and lambdas
reflect the actual computed types rather than stale type variables.

This change improves type inference accuracy and prepares for more
advanced optimizations by ensuring type information is correctly
propagated through the AST.
2026-03-29 18:50:05 +02:00
Brummel 03862d50c6 Add tuple type recomputation after inlining
Introduce helper functions to recompute the `StaticType` of a tuple node
based on its children's types. This ensures that after inlining, tuples
within the AST have concrete types, rather than unresolved type
variables, even when derived from polymorphic functions.

Also adds tests to verify this behavior for both homogeneous and
heterogeneous tuples.
2026-03-29 18:44:48 +02:00
Brummel 0e806b9e5d feat: Add compact AST dump
Introduce a new `dump_ast_compact` function for the environment and
Dumper. This function provides a simplified, human-readable
representation of the AST, focusing on inferred types and purity markers
instead of detailed debug information.

This change adds:
- A `compact` flag to the `Dumper` struct.
- The `dump_compact` method to the `Dumper`.
- The `dump_ast_compact` method to the `Environment`.
- A new `dump_ast_compact` command-line argument for the `ast` binary.
- A new MCP server endpoint `dump_ast_compact`.
- A `CompactMetadata` trait to abstract over different metadata types
  for compact display.
- Updates to documentation and CLI help messages.
2026-03-29 18:28:10 +02:00
Brummel 10a7fcb576 Refactor: Replace Object with StreamStorage for streams
The `Object` trait is too generic and has been causing confusion. This
commit introduces `StreamStorage` as a dedicated trait for reactive
stream types.

This change involves:

- Renaming `Object` to `StreamStorage` in relevant places.
- Updating the `Value::Object` enum variant to `Value::Stream`.
- Modifying how streams are handled in the compiler, VM, and tests to
  use the new `StreamStorage` trait.
- Adjusting example scripts and tests to reflect the change in type
  representation.
- The `StreamNode` struct now explicitly holds its `element_type`.
2026-03-29 18:01:46 +02:00
Brummel a665e2c1a5 Refactor call hooks to use trait objects
This commit refactors the call hook mechanism in the compiler. Instead
of using function pointer types (`PostCallHook`, `FinalizeHook`) and a
struct to hold them (`CallHooks`), it introduces a trait
`RtlCompilerHook` with default implementations for `post_call` and
`finalize`.

This change aligns with Rust's idiomatic way of handling extension
points and allows for more flexible and extensible compiler behavior.
The `TypeChecker` now holds a map of `Rc<dyn RtlCompilerHook>`, enabling
different RTL functions to register their specific compiler hooks. The
`SeriesHook` and `PushHook` structs are introduced to demonstrate this
new pattern.
2026-03-29 14:52:58 +02:00
Brummel 916460ab03 Remove IndexElementFn and series_element_type
The `IndexElementFn` trait and its associated `series_element_type`
function have been removed. The `TypeChecker` now directly inspects the
`StaticType::Series` variant to extract the element type when
propagating index constraints. This simplifies the type-checking logic
by removing an unnecessary layer of indirection and adhering to the
project rule of keeping the AST simple and pushing complexity into the
system.
2026-03-29 14:00:48 +02:00
Brummel 0292ead7a5 Refactor InferenceAccess for call hooks
The `TypeInferenceAccess` and `TypeSlotAccess` traits have been
consolidated into a single `InferenceAccess` trait. This simplifies the
call hook interface by providing a unified way to access type inference
operations and scope slot types.

A new struct, `CheckerInferenceAccess`, is introduced to provide a
concrete implementation of `InferenceAccess` for the `TypeChecker`. This
struct wraps both the `TypeChecker` and the `TypeContext`, allowing call
hooks to interact with both without needing to know their specific
types. This avoids potential circular dependencies between modules.

The `get_slot_type` method has been moved to the new `InferenceAccess`
trait. This method is crucial for call hooks that need to recover the
original `TypeVar` ID after substitutions have occurred, particularly in
the `push_post_call` function for series.
2026-03-29 13:55:32 +02:00
Brummel 93a85cd15c Add IndexElementFn for series type probing
Introduce `IndexElementFn` as a type alias for a function that maps a
`StaticType` to an optional `StaticType` representing its element type.
This allows the `TypeChecker` to determine the element type of indexable
types like `Series` without needing to be aware of their specific
implementations.

The `series_element_type` function is created and registered with the
`TypeChecker` to handle `Series` types. This design centralizes
type-specific logic for indexable types, making the `TypeChecker` more
generic and extensible for future indexable types such as `Stream`.
2026-03-29 13:20:49 +02:00
Brummel 9c434fb49d Fix: Unify TypeVars when indexing generic parameters twice
When a generic function indexes the same TypeVar parameter multiple
times,
all resulting TypeVars must share a single element type. This change
ensures
that subsequent indexing operations unify their fresh TypeVar with an
existing
one if the parameter has already been indexed, preventing incorrect type
inference and false negatives.

A new test, `test_let_poly_multi_index_all_results_typed`, is added to
verify this behavior.
2026-03-28 23:03:38 +01:00
Brummel 84abbd9721 Add Forall type for polymorphism
Introduce `StaticType::Forall` to represent universally quantified
types. This enables Hindley-Milner's let-polymorphism, allowing
functions to be generalized and reused with different concrete types.

- **Generalization at `def`:** Function values are now generalized using
  `self.generalize` when they are defined, wrapping their type in
  `Forall`. This occurs at `def` boundaries.
- **Instantiation at use:** Function types are instantiated with fresh
  type variables at each call site using `self.instantiate`. This
  ensures that different uses of the same polymorphic function do not
  interfere with each other's type inference.
- **Value restriction:** Only function-typed definitions are
  generalized. Mutable state like series and scalars remain monomorphic
  to prevent unexpected behavior.
- **Type context awareness:** The `generalize` function considers the
  current type context to avoid quantifying type variables that are
  still in use elsewhere.
  Feat: Add Forall type for polymorphism

Introduces the `Forall` type to support polymorphic functions and enable
let-polymorphism.

- `Forall(vars, body)`: Represents a universally quantified type where
  `vars` are the type variables bound by this quantification, and `body`
  is the type itself.
- `TypeChecker::generalize`: Wraps a type in `Forall` when a `def`
  boundary is encountered for function-typed values. This ensures that
  each use site of a polymorphic function gets its own instantiation.
- `TypeChecker::instantiate`: Replaces the type variables within a
  `Forall` type with fresh ones. This is performed at each call site of
  a polymorphic function.
- Updates `TypeChecker::unify` and `TypeChecker::apply_subst` to
  correctly handle `Forall` types, ensuring that bound variables within
  a `Forall` are not affected by global substitutions and that `Forall`
  types are instantiated before unification.
- Adds a new example script `examples/Propa.myc` to demonstrate basic
  usage.
- Includes a regression test
  `test_let_poly_non_series_callable_no_false_positive` to ensure that
  passing non-series callables to generic functions does not lead to
  type errors.
- Introduces `TypeChecker::bind_var` to handle lazy propagation of
  index-call constraints, crucial for correctly typing series lookups
  like `(s 0)`.
2026-03-28 22:49:44 +01:00
Brummel bf12755905 Add HM Let-Polymorphism tests
This commit introduces a new test suite for HM Let-Polymorphism.
These tests verify that user-defined generic functions work correctly
across multiple series element types without type conflicts. This is
crucial for ensuring that the type inference system can handle
polymorphic functions properly, especially when they are applied to
different types. The tests cover scenarios like generic accessors,
runtime correctness with different series types, record series, and
higher-order functions. They also include a test for the value
restriction to ensure that series bindings are not generalized, which
would lead to incorrect type errors.
2026-03-28 21:40:35 +01:00
Brummel 8efd12add6 Add call hooks for series and push
Introduces `CallHooks` to enable extensions to the type inference and
AST finalization process. This allows for more dynamic and configurable
behavior without hardcoding symbol names in the compiler core.

Specifically, this commit adds:

- **`series_post_call`**: A hook for the `(series n)` function. It
  ensures that the return type is a fresh `TypeVar` when the element
  type is `Any`, allowing for proper type inference from subsequent
  `push` calls.
- **`series_finalize`**: A hook for `(series n)` that rewrites the AST
  node. It replaces the generic `series` call with a pre-configured
  factory closure that allocates the correct series storage type (e.g.,
  `ScalarSeries<f64>` for floats, `RecordSeries` for records). This
  avoids runtime dispatch and relies on type information captured during
  compilation.
- **`push_post_call`**: A hook for the `(push series val)` function. It
  unifies the series element `TypeVar` with the pushed value's type. It
  also handles numeric and record field promotion and updates the
  `TypeVar` binding if a promotion occurs.
2026-03-28 21:13:26 +01:00
Brummel 6cab8f649b Introduce numeric and record widening
This commit introduces implicit numeric widening from Int to Float and a
corresponding record promotion mechanism.

When pushing values into a series, if the series' element type is a
TypeVar,
and the pushed value is of a different numeric type (e.g., Int and
Float),
the TypeVar will be unified with the wider type (Float). This ensures
that
operations on series elements handle type differences gracefully.

The record promotion handles cases where two records are involved, and
their
fields have compatible types, either identical or through numeric
widening.
This allows for more flexible type inference in complex structures.
2026-03-28 14:52:24 +01:00
Brummel 350b7b49b6 Fix: Apply substitutions to upvalue types
When an identifier is used as an upvalue within a nested scope (e.g., a
`while` loop), the type checker needs to apply the global substitution
map to resolve `TypeVar`s that might have been determined in outer
scopes. This ensures that the correct type is used even if
`ctx.set_type` couldn't propagate the change directly through the
upvalue address.

This fix also includes a regression test to specifically cover this
scenario with series and closures.
2026-03-28 14:22:25 +01:00
Brummel 9c85fb605b Update series definition to infer schema
The `series` function no longer requires an explicit schema. The element
type is now inferred at compile time from subsequent `push` calls using
Hindley-Milner type inference. This simplifies series creation and
aligns with the project's goal of making the untyped AST simple while
the system handles complexity.
2026-03-28 14:05:20 +01:00
Brummel d7d1aef8ed Refactor type checker for series and overloads
Introduce `unify_matched_overload` to handle type variable propagation
for overloaded functions. This ensures that when an overload is chosen,
its concrete parameter types are unified with the actual argument types.
This is crucial for resolving type variables nested within closures
called through overloaded functions.

Additionally, this commit:
- Allows `series` to infer schema type from `push` calls, simplifying
  its signature.
- Adds a fallback to `ValueSeries` in `rtl::series` if schema injection
  fails.
- Updates `StaticType::TypeVar` to return `Any` when accessed,
  simplifying field access logic.
- Adjusts tests to reflect the simplified `series` signature.
2026-03-28 14:03:48 +01:00
Brummel d2cba2d55d Refactor: Simplify series creation and infer element type
The `series` constructor now only accepts the `lookback` limit. The
element type is inferred by the type checker and implicitly added as a
schema argument during compilation. This simplifies the API and
centralizes type inference.

This change also includes:
- Updates to example scripts (`HMA.myc`, `sma.myc`, `soa_series.myc`) to
  reflect the new `series` signature.
- Modifications to the `TypeChecker` to handle the inferred schema
  injection.
- An addition of a regression test for type inference through nested
  closures with `series`.
- Removal of `#[allow(dead_code)]` from several `TypeChecker` methods as
  they are now used.
- Update to `rtl/prelude.myc` macro `cache`.
- Update to `rtl/series/mod.rs` to reflect new signature.
- Update to `ast/types.rs` to allow `series` to be indexed with an
  integer to retrieve its element type.
2026-03-28 13:47:15 +01:00
Brummel e595e747d4 Add type inference infrastructure
Introduces a `TypeChecker` struct with logic for Hindley-Milner type
inference.
This includes:
- `var_counter` for generating unique type variable IDs.
- `subst` for the global substitution map.
- `fresh_var` to create new type variables.
- `apply_subst` to resolve type variables recursively.
- `occurs` to check for cycles during unification.
- `unify` to merge types and extend the substitution.

The `StaticType` enum is extended with a `TypeVar(u32)` variant to
represent unresolved type variables.
The `Display` and `is_assignable_from` implementations for `StaticType`
are updated to handle `TypeVar`.
2026-03-28 13:08:15 +01:00
Brummel 982d2239b6 Refactor GlobalStore to use separate RTL and user value stores
The `GlobalStore` was refactored to clearly distinguish between
immutable RTL values and mutable user-defined global slots.

The `Environment` struct now holds:
- `rtl_values`: An immutable `Rc<[Value]>` for pre-defined RTL values.
- `user_values`: An `Rc<RefCell<Vec<Value>>>` for user-defined mutable
  globals.

The `GlobalStore` struct now takes both `rtl` and `user` as parameters
and uses `rtl_len` to determine which store to access. This change
separates concerns and better reflects the immutability of RTL values
after the bootstrap phase, aligning with the project's concurrency
rules.

Documentation in `docs/Analysis_Environment.md` was updated to reflect
these structural changes.
2026-03-28 00:02:34 +01:00
Brummel 0e8cd0832f Refactor global variable access in VM and optimizer
Replaces `Rc<RefCell<Vec<Value>>>` with a new `GlobalStore` struct for
accessing global variables. This provides a more structured way to
manage global values and allows for future optimizations like sharing
immutable RTL portions across environments. The `GlobalStore` also
includes an `rtl_len` field to distinguish between RTL and user global
slots, enabling debug-time checks for writes to immutable RTL slots.
2026-03-27 23:40:42 +01:00
Brummel 893d9936ed Introduce Rtl struct and from_rtl constructor
This commit refactors the `Environment` struct to better manage the Rust
Runtime Library (RTL) bootstrap state.

A new `Rtl` struct is introduced to hold a frozen snapshot of the
initial RTL state, including scopes, types, purity, values, and
documentation. This snapshot is created once after `rtl::register()`
completes.

The `Environment::new()` constructor is updated to perform a two-phase
bootstrap: first, it registers RTL functions, and then it freezes the
scope 0 and captures the RTL state into the new `Rtl` struct.

A new constructor, `Environment::from_rtl()`, is added. This allows
creating independent execution environments that all share the same
underlying RTL state. This is crucial for isolation between different
execution contexts, as user definitions and loaded modules will not leak
between environments created from the same `Rtl` snapshot.

The `Environment::list_bindings` and `Environment::list_rtl_docs`
methods are updated to use the `rtl` field for accessing the RTL scope
and documentation, reinforcing the concept of a shared, immutable RTL
state.

A new test, `test_environments_from_shared_rtl_are_independent`, is
added to verify that environments created from the same `Rtl` snapshot
are indeed independent and do not leak user-defined bindings.
2026-03-27 22:49:03 +01:00
Brummel b6dcdbde8d Refactor instantiate to return Closure
The `instantiate` method in `Environment` has been refactored to return
`Result<Rc<Closure>, String>` instead of `Rc<NativeFunction>`. This
change separates the creation of a `Closure` from its execution,
allowing the caller to manage the `VM` lifecycle and choose the
appropriate execution strategy (e.g., single run vs. repeated benchmark
iterations).

The `NativeFunction` type is now exclusively used for true Rust
intrinsics. The benchmark runner has also been updated to reuse a single
`VM` across iterations, improving performance by avoiding repeated VM
allocations.
2026-03-27 22:04:20 +01:00
Brummel 3d0ea094b0 Fix: Dump AST ignores parse errors
The `dump_ast` method previously bypassed the `compile` method, which
meant it would silently ignore parsing errors. This commit ensures that
`dump_ast` now delegates to `compile` and correctly propagates any
parsing errors. This aligns the behavior of `dump_ast` with other
compilation steps and provides better feedback to the user.
Fix: Dump AST ignores parse errors

The `dump_ast` method now delegates to `compile(source).into_result()?`
to properly handle and report parse errors, ensuring consistency with
the compilation process.
2026-03-27 21:36:01 +01:00
Brummel 1736602b0d Create Analysis_Environment.md 2026-03-27 21:16:19 +01:00
Brummel ddea07666d Monomorphize function templates by re-type-checking
Re-type-checks function templates with concrete argument types to
produce specialized TypedNodes for monomorphization. This process
leverages the `check_node_as_bound` method, which is generic enough to
handle different binding phases, allowing for fresh type inference from
the call site.
2026-03-27 21:16:13 +01:00
Brummel 1379ab366a Refactor module loading to improve clarity
The module loading logic has been refactored to enhance readability and
maintainability. Key changes include:

*   **Path Handling**: Simplified path construction using `join` for
    better clarity and consistency.
*   **Error Reporting**: Improved error messages during parsing by
    utilizing `parser.diagnostics.format_errors()`.
*   **Module Loading Logic**:
    *   The `loaded_modules` set now uses `insert()` to both add new
        modules and efficiently check for duplicates, returning `false`
        if the module was already loaded.
    *   The recursive call to `collect_dependencies` is now placed
        before processing the current file's AST, ensuring a topological
        order of dependency loading.
*   **Helper Function Scope**: `extract_use_directives` is now a static
    method as it doesn't depend on the `ModuleLoader` instance.
2026-03-27 16:16:45 +01:00
Brummel 1f0208af95 Add module loader and related tests
Introduce `ModuleLoader` to handle `#use` directives and dependency
resolution. This involves adding `tempfile` dependency, modifying
`Cargo.toml` and `Cargo.lock`, creating a new `module_loader.rs` file,
and updating `environment.rs` to use the new module.

Also, add comprehensive tests for `Diagnostics::format_errors`,
`CompilationResult`, and the new `ModuleLoader` functionality. These
tests cover various scenarios including empty diagnostics, multiple
errors, error formatting, compilation success/failure, and complex
dependency loading with topological ordering and search path resolution.
2026-03-27 15:08:28 +01:00
Brummel 636f5a1814 Extract RTL documentation types
Move `RtlDocEntry`, `RtlRegistration`, and `PipelineGenerator` to a new
`docs` module within `src/ast/rtl/` and re-export them. This improves
organization and modularity of the RTL component.
2026-03-27 14:54:36 +01:00
Brummel 4f05562e0c Introduce CompilationResult struct
This commit introduces the `CompilationResult` struct to encapsulate the
outcome of a compilation pass. It holds either a successfully compiled
`TypedNode` or a `Diagnostics` object containing errors. Helper methods
for creating success or error results and for converting to a `Result`
are also included. This improves error handling and clarity in the
compilation process.
2026-03-27 13:25:12 +01:00
Brummel 9b7c0b68a4 Refactor global slot allocation
Introduce `allocate_slot` helper function to centralize the logic for
allocating new global slots. This improves code clarity and reduces
duplication by consolidating common operations like updating scopes,
types, purity, and values.
2026-03-27 13:18:59 +01:00
Brummel 325e690cd9 Add format_errors to Diagnostics
Introduces a new method `format_errors` to the `Diagnostics` struct.
This method iterates through all diagnostics, filters for errors, and
formats them into a newline-joined string. This simplifies error
reporting in compilation results.
2026-03-27 13:17:58 +01:00
Brummel 9c5506b83e Implement unhygienic macro expansion for ~ident
This commit introduces support for unhygienic macro expansion using the
`~ident` syntax. When an identifier is prefixed with a tilde (`~`)
within a macro template, it is no longer subject to hygienic renaming.
Instead, it directly refers to a binding in the call site's environment.

This allows macros to interact with variables defined outside the
macro's scope, such as:
- Modifying call-site variables.
- Capturing call-site variables as upvalues in closures.
- Defining new variables that are visible in the call site.

A new test case `test_macro_tilde_nonparam_assign` has been added to
verify this functionality. Previously, unhygienic escapes were
implicitly handled by `SyntaxKind::Identifier` if they were not macro
parameters. This change makes this behavior explicit and correctly
handles non-parameter identifiers by returning a bare symbol.
2026-03-27 10:06:50 +01:00
Brummel adce3a6818 Fix: Simplify scoping tests
Removes outdated tests for macro expansion, destructuring, and if branch
scope leaks. These tests were either superseded by newer, more accurate
tests or are no longer relevant to the current implementation of the
compiler's scoping rules. The remaining test correctly asserts that
defining the same variable in different 'if' branches is functional.
2026-03-27 09:26:30 +01:00
Brummel 3a757b7551 Add tests for series and scoping features 2026-03-27 08:27:40 +01:00
Brummel cb4162e420 Refactor discover_globals to handle patterns
The `discover_globals` function has been refactored to better handle
pattern matching within definitions. It now uses a recursive helper
function `register_pattern` to correctly process identifiers and tuple
patterns. This ensures that all declared variables within a `Def` node
are registered with their corresponding scope and virtual ID.
Additionally, support for `Expansion` nodes has been added to ensure
that any nested global definitions within them are also discovered.
2026-03-27 08:27:31 +01:00