Commit Graph

182 Commits

Author SHA1 Message Date
Michael Schimmel ef5c2367a7 Remove unused collect_parameter_slots
This function was no longer being called and was removed as part of a
refactoring.
2026-03-13 17:13:06 +01:00
Michael Schimmel 222fe64a1f Refactor stack size calculation
Introduces a `StackAllocator` to manage local slot mapping during
lowering. This allows for efficient calculation of stack sizes for
lambdas and the root node. Tail position marking is now handled more
accurately.
2026-03-13 16:50:57 +01:00
Michael Schimmel 5a6cae1866 Refactor TypeContext locals to HashMap
Change the `slots` field in `TypeContext` from a `Vec` to a `HashMap`.
This allows for sparse local variable storage and avoids the need to
pre-allocate for all slots, which is more efficient when not all locals
are used.
2026-03-13 16:37:00 +01:00
Michael Schimmel 84226f6a16 Refactor: Replace UntypedNode with SyntaxNode
This commit replaces the `UntypedNode` enum with the more accurately
named `SyntaxNode`. This change is primarily for clarity and better
reflects the role of these nodes as representing the structure of the
source code prior to semantic analysis.

The corresponding enum `UntypedKind` has also been renamed to
`SyntaxKind` to maintain consistency.

No functional changes are introduced by this refactoring; it is purely a
renaming and organizational update.
2026-03-13 14:21:28 +01:00
Michael Schimmel 7d72a99fa1 refactor: separate parser and compiler AST node structures
Simplified the AST architecture by removing the overly complex Node<K,
  T> structure and replacing it with specialized types for
  each phase:

   - Introduced UntypedNode in nodes.rs for the Parser and Macro system,
     eliminating redundant ty: () initializations.
   - Defined a new generic Node<T> in bound_nodes.rs for all compiler
     stages, where T represents the phase-specific metadata.
   - Updated the Binder to act as the bridge between UntypedNode and
     Node<()>.
   - Simplified type aliases: TypedNode, AnalyzedNode, and ExecNode now
     leverage the streamlined Node<T> structure.
   - Updated Parser, Macros, Type-Checker, Optimizer, and VM to reflect
     the architectural changes.
   - Fixed import chains and resolved needless borrows via clippy.

  This change improves type safety, reduces boilerplate code in the
  parser, and makes the compiler stages more idiomatic and
  readable.
2026-03-13 13:16:03 +01:00
Michael Schimmel bf86c76bb6 Refactor: Use root_purity instead of global_purity
This commit refactors the purity analysis from using a
`HashMap<GlobalIdx, Purity>` to a `Vec<Purity>` indexed by
`GlobalIdx.0`.

This change simplifies the data structure and makes purity lookups more
efficient. The `Binder`'s `globals` field has also been removed as it
was not being used.
2026-03-12 16:57:06 +01:00
Michael Schimmel dcb7685d29 Refactor: Pass global names to Binder
The `Binder` struct now accepts a `Rc<RefCell<HashMap<Symbol,
(GlobalIdx, Identity)>>>` for global names. This allows the binder to
directly access and manage global symbols during the binding process,
simplifying the logic and improving efficiency.

Additionally, `CompilerScope` now implements `Default`, and a type alias
`BindingResult` has been introduced for clarity. The `bind_root`
function signature has been updated to accept the `globals` argument.
2026-03-12 16:21:20 +01:00
Michael Schimmel a220815bd6 Refactor Binder initialization and root binding
The `Binder` and `FunctionCompiler` initialization has been refactored
to accept initial scopes and slot counts. This allows for more flexible
management of the compiler's state, particularly for the root scope.

The `bind_root` function now returns the final scopes and slot count of
the root function compiler, enabling the `Environment` to update its
state with these new bindings.

The global variable handling has been integrated into the scope
management, removing the direct reliance on a shared `HashMap` for
globals. This promotes a more consistent approach to symbol resolution.
2026-03-12 14:40:13 +01:00
Michael Schimmel 08b5bba2c4 Add purity to LocalInfo and initialize in binder
The `LocalInfo` struct now includes a `purity` field to track the purity
of local variables and function arguments. This is initialized to
`Purity::Impure` for local variables and arguments within functions and
when registering native functions. Additionally, the `Environment`
struct is updated to include `root_scopes` and `root_slot_count` to
support parallel mode compilation by populating the root scope with
initial function and native function information.
2026-03-12 14:07:27 +01:00
Michael Schimmel 3780674eb1 Refactor binder to use local scopes
Removes global variables and related logic from the Binder, simplifying
its responsibilities to managing local scopes and function compilers.
This change also streamlines the `define_variable` and `resolve_local`
methods within `FunctionCompiler` and removes unused fields from
`FunctionCompiler` and `Binder`.
2026-03-12 13:50:37 +01:00
Michael Schimmel bc13ce7abf Make LocalInfo and CompilerScope fields public 2026-03-12 12:57:04 +01:00
Michael Schimmel be2bef373f Refactor scope handling and immutability
Introduces `fixed_scope_idx` to `Binder` and `Environment` to track
immutable scopes.
This allows enforcing that definitions (`def`) cannot occur in scopes
that are considered fixed or immutable, such as the global scope or the
initial bootstrap scope.
The `FunctionCompiler` is updated to use `fixed_scope_idx` and `is_root`
to determine scope immutability.
2026-03-12 11:22:40 +01:00
Michael Schimmel bb77caf1af Refactor: Rename TCO module to lowering
The TCO (Tail Call Optimization) module has been renamed to `lowering`.
This change better reflects the module's broader responsibility, which
includes not only TCO but also general AST transformations and
preparation for VM execution.

The `optimize` function has been renamed to `lower` to align with the
module's new name.
2026-03-11 10:49:24 +01:00
Michael Schimmel db26719cad Extract calculate_stack_size to a standalone function
The `calculate_stack_size` method was duplicated in `bound_nodes.rs` and
`tco.rs`. This commit extracts it into a single standalone function in
`tco.rs` to avoid duplication. The stack size is now calculated and
stored in the `ExecNode`'s `ty` field during the TCO optimization phase.
2026-03-11 10:35:18 +01:00
Michael Schimmel efcb4e3685 feat: Add stack size to runtime metadata
Store the pre-calculated stack size of lambda bodies in the
RuntimeMetadata. This allows the VM to directly access this information
without recalculating it.
2026-03-10 20:25:04 +01:00
Michael Schimmel 8c865681ff Refactor: Implement late stack size calculation
This commit introduces a new mechanism for calculating the required
stack size for closures at bind time, rather than storing it in the AST.
This is achieved by adding a `calculate_stack_size` method to
`BoundNode`.

Key changes include:
- `BoundNode::calculate_stack_size`: Recursively traverses the bound AST
  to find the maximum `LocalSlot` index used.
- Recursion blocker for lambdas: Ensures that nested lambdas are not
  visited during stack size calculation for the outer closure,
  preventing incorrect stack size estimations.
- VM update: The `VM::run` method now accepts and uses the
  pre-calculated stack size for setting up call frames.
- `Closure` struct update: Stores the `stack_size` directly within the
  `Closure` struct.
- Binder and TypeChecker updates: Minor adjustments to accommodate the
  new strategy and error reporting.
- Optimizer enhancements: Constant and pure-lambda propagation for
  `Define` statements within blocks to ensure inlinability.

This refactoring addresses issues related to accurate stack size
management and improves the overall robustness of the binder and VM.
2026-03-10 20:05:32 +01:00
Michael Schimmel cb4d3525c2 Refactor binder to simplify root scope logic
The previous implementation of the binder had a slightly complex way of
handling the root scope. This commit simplifies that logic by directly
checking if the current scope is the root scope and the scope stack has
only one element. This makes the code more readable and maintainable.
2026-03-10 17:25:27 +01:00
Michael Schimmel a78e72d074 Refactor Binder to use new scope structure
This commit refactors the Binder implementation to better align with the
updated scope structure.
Key changes include:

- Introducing `ExprContext` to distinguish between statement and
  expression contexts.
- Modifying `define_variable` to handle both global and local scope
  definitions more robustly.
- Updating `resolve_variable` to correctly handle upvalue captures,
  especially for global addresses.
- Adjusting `bind` and related functions to use the new `ExprContext`.
- Updating the refactoring log to reflect completed phases.
2026-03-10 17:20:47 +01:00
Michael Schimmel 3b063dc2c9 Add block scoping and statement/expression distinction
Implement strict block scoping and distinguish between statements and
expressions.
This change introduces hierarchical scopes for functions and blocks,
enforces that `def` is a statement with no return value, and prevents
statements from appearing in expression positions or as the last element
of a block. A new example `design-flaw.myc` is added to demonstrate
the uninitialized variable issue solved by these changes.
2026-03-10 17:03:46 +01:00
Michael Schimmel 961168f3b6 Refactor analyzer to return impurity
The `Analyzer` is now responsible for determining the purity of `Define`
bindings. Previously, this responsibility was left to the caller.

Added a new example `design-flaw.myc` to test this change.
Updated `soa_series.myc` due to the purity change.
2026-03-10 16:13:39 +01:00
Michael Schimmel 11fc1e0e48 Add 'again' macro for recursive expansion
The 'again' macro is a new addition to the macro system, allowing for
recursive macro expansion. This commit introduces the necessary AST
nodes, macro expansion logic, and an integration test to ensure its
functionality. The `soa_series.myc` example has also been updated to
demonstrate its usage.
2026-03-09 11:22:32 +01:00
Michael Schimmel fa23a4c125 Refactor UntypedKind::Parameter to Identifier
The `Parameter` kind in `UntypedKind` was only used for identifiers that
were being declared or referenced. This commit renames it to
`Identifier` and updates all the necessary code to reflect this change.
This simplifies the AST and makes it more consistent.

Additionally, a new macro `repeat` has been added to
`src/ast/system.myc`.
2026-03-09 11:08:30 +01:00
Michael Schimmel 595bcf09e5 Update examples to use StreamNode and Series with lookback
The `PipelineNode` has been refactored into `StreamNode`. This commit
updates the example files to reflect this change and also updates the
`series` constructor to accept a lookback parameter.

The `PipelineNode` was an artifact of a previous implementation and is
no longer needed. The `StreamNode` is the appropriate type for
representing the output of a pipe operation.

The `series` function now requires a `lookback` argument to specify the
maximum number of items to store. This makes the behavior of series more
explicit and prevents accidental unbounded memory growth.
2026-03-07 23:48:09 +01:00
Michael Schimmel d08fab4f73 Refactor inlining logic into try_inline function
This commit extracts the logic for inlining function calls into a new
private
method, `try_inline`. This improves code organization and reduces
duplication in the `Optimizer`'s `visit_node` method.

The extracted method handles the preparation of substitutions and the
recursive visiting of the inlined node. It also ensures that the
substitution map state is correctly synchronized back to the calling
context.
2026-03-07 21:10:48 +01:00
Michael Schimmel f88992da61 Add Stream support for field accessors
The type checker now correctly handles unwrapping `Stream(T)` types for
lambda arguments.
A new `build_map_stream` function has been added to `rtl/streams.rs` to
facilitate field access on streams.
The `create-random-ohlc` function now returns a `Stream` instead of a
`Series`.
Examples have been updated to reflect these changes and demonstrate
stream usage.
2026-03-07 20:47:05 +01:00
Michael Schimmel f797ac37bf Refactor: Simplify type checking context
The type checker's fallback logic for non-lambda nodes was unnecessarily
complex. This commit simplifies it by directly checking the node within
a new, basic type context.

Additionally, the environment now explicitly wraps non-lambda AST nodes
in a lambda before type checking, ensuring consistent handling. This
aligns the type checking process for all top-level expressions.
2026-03-06 23:19:52 +01:00
Michael Schimmel 8fa2ca4cb5 Fix: Reindex address in Set bound kind 2026-03-06 17:02:43 +01:00
Michael Schimmel dfc963ef13 Fix: Remove unnecessary Rc::new from LambdaCollector
The `LambdaCollector` was cloning nodes and wrapping them in `Rc`.
However, the `registry` itself is already holding `Rc` clones of the
nodes. This commit removes the redundant `Rc::new` to simplify the code.

This change also addresses a performance regression observed in
benchmarks due to unnecessary atomic overhead from `Arc` in the
`Keyword` type.
2026-03-06 14:18:51 +01:00
Michael Schimmel 1342c7ca8e Fix optimizer slot clash during inlining and correct closure reduction
order

   - Add new_for_inlining to SubstitutionMap to preserve the next_slot
     counter, preventing local slot collisions when merging
     scopes.
   - Update Inliner to request fresh slots for parameters during beta
     reduction instead of forcing identity mappings.
   - Fix execution order in Optimizer::visit_node for closure inlining
     to run prepare_beta_reduction before visiting the function
     body, preventing corrupted upvalue captures.
   - Fix CLI --no-opt flag to correctly disable the optimizer in the ast
     binary.
   - Add integration test to prevent future slot clash regressions.
2026-03-06 11:58:28 +01:00
Michael Schimmel 6ebf31e2a0 Refactor specializer to not fold scalars
The specializer now correctly identifies when a compiled value is a
scalar and avoids folding it into a constant node. Instead, it updates
the callee to the specialized version if it's an object. This ensures
that scalar folding does not interfere with the program's execution.
2026-03-05 14:35:29 +01:00
Michael Schimmel 831525b402 Add series, SMA, and WMA indicators
Introduce new indicators for Simple Moving Average (SMA) and Weighted
Moving Average (WMA), along with their Hull Moving Average (HMA)
derivative.

Also refactors series implementation to use `RefCell` for interior
mutability and adds `SeriesMember` trait for better dynamic series
access. Updates `soa_series.myc` example to reflect new series creation
and push syntax.
2026-03-05 14:07:42 +01:00
Michael Schimmel 8c4db9a5ba Refactor function signatures to use slices 2026-03-03 18:13:20 +01:00
Michael Schimmel 7c38dee243 Refactor AST nodes to use Rc
This commit refactors various AST node types to use `Rc` (Reference
Counting) instead of `Box`. This change is primarily driven by the need
for shared ownership and more efficient handling of potentially
recursive or shared data structures within the AST.

The main benefits of this change include:

- **Reduced cloning:** `Rc` allows multiple parts of the AST to refer to
  the same node without needing to clone the entire node. This is
  particularly beneficial for optimization passes where nodes might be
  visited multiple times.
- **Enabling sharing:** It makes it easier to represent scenarios where
  a single AST node might be a child of multiple parent nodes.
- **Performance improvements:** By avoiding unnecessary deep copies of
  AST nodes, this change can lead to performance gains, especially
  during complex compilation phases.
2026-03-03 16:07:42 +01:00
Michael Schimmel 78c36cf08d Refactor MacroRegistry to use Rc<MacroMap>
This change introduces Rc<MacroMap> to allow for copy-on-write semantics
when defining macros in nested scopes. When a macro is defined in a
scope that is already shared, the MacroMap is cloned before
modification, ensuring that changes to one scope do not affect others
that share the same map.
2026-03-03 15:55:55 +01:00
Michael Schimmel 078b520c37 Add type aliases for registries
Introduces `GlobalFunctionRegistry` and `GlobalAnalyzedRegistry` type
aliases to clarify the usage of `HashMap`s for storing global functions
and their analyzed versions. This change also refactors the
`LambdaCollector` and `Optimizer` to use these new aliases, improving
code readability and maintainability.
2026-03-03 15:51:47 +01:00
Michael Schimmel 2eb7a2e136 Formatting 2026-03-02 23:13:36 +01:00
Michael Schimmel 5bc69c267b Refactor Binder to use Diagnostics
The Binder and its helper functions have been updated to accept and
propagate a `Diagnostics` struct. This allows for better error reporting
during the binding phase, enabling the compiler to continue processing
even after encountering errors and collect all issues before halting.

The `BoundKind::Error` node and `StaticType::Error` are introduced as
"poison" nodes/types. These nodes indicate that an error occurred during
compilation, preventing further valid processing of that specific AST
fragment but allowing the compiler to continue with other parts of the
code.

The `Parser` has also been updated to return a `Diagnostics` struct,
enabling it to report errors during the initial parsing stage while
still attempting to build a partial AST. This adheres to the same error
recovery strategy.
2026-03-02 23:12:51 +01:00
Michael Schimmel f7cb6655af feat: Specialize pipeline types for performance
Introduces type specialization for reactive pipeline nodes and their
data buffers. This eliminates the overhead of generic `Value` enums and
`SharedValueSeries` when dealing with known scalar or record types.

The architecture shifts buffer instantiation from the VM to the runtime
(RTL), leveraging type information from the AST. A new `out_type` field
is added to `BoundKind::Pipe` to store the static type of the pipeline's
output, determined by the type checker.

This enables the creation of specialized `RingBuffer<T>` and
`SharedRecordSeries` (for Struct-of-Arrays layout) when the output type
is known, significantly improving memory usage and processing speed for
time-series data, especially in financial analysis.
2026-03-02 22:03:24 +01:00
Michael Schimmel 2457eec1bf feat: Implement Pipeline support
Adds support for pipelines, allowing streams to be chained together and
transformed.
This includes new types for `PipeStream` and `SourceAdapter`, along with
modifications
to the `Environment` to manage pipeline execution. A new example
`pipeline.myc`
demonstrates its usage.
2026-03-02 00:32:07 +01:00
Michael Schimmel 807903efbb Add Optional type for filter pipes
Introduces `StaticType::Optional` to represent values that can be either
of a specific type `T` or `Void`. This is crucial for handling
situations in filter pipes where an expression might not always produce
a value.

The type checker now correctly deduces and propagates this `Optional`
type, and the pipeline operator (`pipe`) is updated to unwrap
`Optional(T)` results, yielding `T`. This ensures that the type system
accurately reflects the potential absence of values in intermediate
pipeline steps.

Also includes a minor rename in the tuple-struct example from `pipe` to
`p` for clarity, and registers the `streams` module.
2026-03-01 23:19:00 +01:00
Michael Schimmel 50f33b2c30 Feat: Add Pipe Node
Introduces a new `Pipe` node to the Abstract Syntax Tree (AST).
This node represents a functional composition pattern, allowing
for chaining of operations.

The changes include:
- Defining the `Pipe` variant in `BoundKind` and `UntypedKind`.
- Implementing parsing logic for the `pipe` keyword.
- Adding handling for the `Pipe` node in various compiler passes
  (analyzer, binder, captures, dumper, macros, optimizer, TCO,
  type checker).
- Including a placeholder implementation for `Pipe` execution in the
  VM.
- Updating integration tests to use the new `pipe` syntax.
2026-03-01 21:52:10 +01:00
Michael Schimmel eab3e02199 Refactor Record's internal representation
This commit refactors the internal representation of `BoundKind::Record`
to store a `RecordLayout` and a `Vec` of values, rather than a `Vec` of
key-value pairs. This change simplifies the representation and improves
efficiency by decoupling the record's structure from its specific values
during compilation and analysis.

The `RecordLayout` now defines the structure of the record, and the
values are stored in a separate vector, ordered according to the layout.
This allows for better optimization and type checking, as the record's
shape is explicitly defined and immutable once created.
2026-02-28 16:47:23 +01:00
Michael Schimmel 3f5d2620ec Refactor: Use new_inner for substitution maps
The `SubstitutionMap::new_inner()` method provides a more robust way to
create nested substitution maps, ensuring that only global substitutions
are inherited. This prevents potential issues with overlapping local and
upvalue addresses in nested scopes, such as during lambda inlining.

This change also includes:
- A new `try_fold_record` method in `folder.rs` to optimize record
  literals into constant values.
- Updates to `inliner.rs` to recognize `Value::Record` for inlining.
- Various test cases to verify record optimization and constant folding.
2026-02-28 16:01:56 +01:00
Michael Schimmel 7126668934 Add prelude and while macro
This commit introduces a new prelude file that defines the `while` macro
and registers it during environment bootstrapping. The `again` macro has
been updated to accept multiple arguments for its recursive call, and
several examples have been adjusted to reflect this change.
Additionally, the `MacroRegistry` in the compiler is now cloneable and
can be moved out of the `MacroExpander`.
2026-02-28 12:41:19 +01:00
Michael Schimmel 512193febc Add object-oriented records example 2026-02-26 21:54:26 +01:00
Michael Schimmel bf74795e01 Refactor: Implement Record Layouts and Optimized Field Access
Introduces a new `RecordLayout` system for efficient and type-safe
record handling.

Key changes:
- `RecordLayout` struct with `O(1)` field lookup using FMap
  optimization.
- Field accessors (`.name`) are now first-class callable values.
- Parser recognizes dot-prefixed identifiers as field accessors.
- Binder and TypeChecker handle field accessors.
- Optimizer transforms field accessor calls into specialized `GetField`
  nodes.
- VM executes `GetField` efficiently by directly accessing record
  values.
- Adds a new `records.myc` example showcasing record features.
- Improves comparison logic for records to use pointer equality for
  layout.
2026-02-26 21:38:20 +01:00
Michael Schimmel 2ad2eb5d43 Remove unused record destructuring tests
These tests were for record destructuring, which has been removed.
The code for record destructuring was also removed from the type checker
and types modules.
2026-02-26 10:58:46 +01:00
Michael Schimmel 81c805f07e Refactor optimizer utilities
Removes unused `flatten_tuple` function from optimizer utilities. The
functionality was moved to the `Folder` struct, making it more
contextually appropriate. This change streamlines the utility module and
improves code organization.
2026-02-25 21:26:12 +01:00
Michael Schimmel cf87bbeac5 Refactor tuple argument handling in inliner
Remove redundant tuple flattening logic in `map_params_to_args`. The
existing logic for iterating through tuple elements already correctly
handles nested tuples and records by recursively calling
`map_params_to_args`.
2026-02-25 21:19:12 +01:00
Michael Schimmel 42ad8455b0 Refactor tuple flattening in Specializer 2026-02-25 21:09:38 +01:00