Commit Graph

53 Commits

Author SHA1 Message Date
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 b177aa8854 feat: Add SharedValueSeries and PipelineNode
Introduces `SharedValueSeries` for read-only access to generic `Value`
buffers, and `PipelineNode` which combines an `ObservableStream` with a
`Series` view. This is a foundational step for implementing the `pipe`
operator.
2026-03-01 23:12:09 +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 b74ddcfd61 Introduce unified Series trait
This commit introduces the `Series` trait to provide a unified interface
for accessing indexed data across different series types (RecordSeries,
SeriesView, and future SharedSeries). This simplifies the VM's indexer
logic and lays the groundwork for the dual series architecture.
2026-03-01 21:24:42 +01:00
Michael Schimmel 46b546446f Add RecordSeries::get_record and support for (my_ticks 0)
This commit introduces the `get_record` method to `RecordSeries`,
allowing for the dynamic reconstruction of a full record from its
constituent fields at a given index. This enables idiomatic access to
series data using indexing like `(my_ticks 0)`.

The `push-series` function has also been updated to correctly handle the
structure of records when pushing data into a `RecordSeries`.
2026-03-01 18:44:46 +01:00
Michael Schimmel b612df6e10 Add Series RTL and SeriesView
Introduces a new RTL module for handling series data, enabling efficient
storage and retrieval of time-series data in a Struct-of-Arrays (SoA)
format.

Includes `SeriesView`, a zero-copy wrapper that provides a fast,
read-only interface to individual columns within a `RecordSeries`,
optimizing performance for data access in the VM.

Registers new native functions `create-series` and `push-series` for
managing series data.
2026-02-28 21:47:14 +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 0dfbda5e15 Refactor VM to use trait objects for closures
The `CallFrame` struct and various VM methods now use `Rc<dyn Object>`
to hold closures, allowing for more flexibility and avoiding unnecessary
cloning.

This change also addresses the performance concern regarding deep copies
of closures, preferring `Rc<dyn Trait>` with local `downcast_ref` where
appropriate.

Additionally, a documentation note has been added to `gemini.md`
regarding this performance preference in Rust.
2026-02-28 14:26:29 +01:00
Michael Schimmel 3daf8ef94d Fix: Clone closure directly for tail calls 2026-02-28 13:13:17 +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 c64902726b Refactor address types to use newtype wrappers
This commit introduces newtype wrappers for `LocalSlot`, `UpvalueIdx`,
and `GlobalIdx` to improve type safety and clarity. These wrappers
replace direct use of `u32` for indices, making the code more robust and
easier to understand.

The changes include:
- Defining `LocalSlot`, `UpvalueIdx`, and `GlobalIdx` structs.
- Implementing `Display` for these new types to provide user-friendly
  output.
- Updating the `Address` enum to use these new types.
- Modifying various compiler components (analyzer, binder, optimizer,
  type checker, environment, VM) to use the new types.
- Adjusting tests to accommodate the changes.
2026-02-25 18:24:26 +01:00
Michael Schimmel c256a8a992 Refactor: Use generic Define bound kind
This commit consolidates `DefLocal` and `DefGlobal` into a single
`Define` bound kind. This simplifies the AST and makes it more
consistent.

It also introduces `DeclarationKind` to differentiate between variable
and parameter definitions.
2026-02-25 10:45:36 +01:00
Michael Schimmel f995aaf81b Formatting 2026-02-25 09:59:23 +01:00
Michael Schimmel 683d0f4dbe Simplify tuple flattening and destructuring
The `flatten_tuple` function was unnecessarily recursive. It can now
simply return the elements of the tuple directly. The VM's destructuring
logic has been updated to handle nested destructuring more efficiently.
A new integration test case for multi-level destructuring has been
added.
2026-02-24 10:10:47 +01:00
Michael Schimmel 51d83562de Refactor Destructure to handle assignments
Renames `DefDestructure` to `Destructure` to better reflect its use in
both definitions and assignments.
Introduces `bind_assign_pattern` to handle assignment destructuring in
the binder.
Adds `test_assign_destructuring` to verify assignment destructuring
functionality.
2026-02-24 08:51:24 +01:00
Michael Schimmel 2b0e7f49d7 Formatting 2026-02-24 08:41:18 +01:00
Michael Schimmel 252b725677 Add support for destructuring def
This commit introduces the `DefDestructure` bound kind and modifies the
binder, analyzer, type checker, and VM to support destructuring in `def`
statements. This allows for pattern matching on the right-hand side of a
`def` to bind multiple variables.

The parser has been updated to accept patterns in `def` statements. The
binder now handles `UntypedKind::Def` with a `target` pattern, rather
than a simple `name`. This enables destructuring.

The `Gemini.md` documentation has been updated to include a new rule for
incremental development.
2026-02-24 08:40:45 +01:00
Michael Schimmel eeb6621280 Formatting 2026-02-24 07:27:13 +01:00
Michael Schimmel 4905b08548 Add 'again' keyword for recursive calls
The `again` keyword is introduced to facilitate explicit recursive
function calls.
It is restricted to tail-call positions to prevent dead code and ensure
TCO
optimization. Type checking is enhanced to validate argument types
against
function parameters.
2026-02-23 20:33:50 +01:00
Michael Schimmel be7ce31408 Refactor VM evaluation for observer pattern
The `dispatch_eval` macro has been replaced with explicit
`eval_internal` and `eval_core` methods. This change aims to streamline
the evaluation process and better support the observer pattern by
providing clearer hooks for observing VM execution.
2026-02-23 18:10:20 +01:00
Michael Schimmel 2fdeff1db4 Refactor: Analyze node purity and recursion
The Analyzer has been refactored to decorate `TypedNode`s with their
purity and recursion status. This involves creating a new `AnalyzedNode`
type and a `NodeMetrics` struct to hold this information. The `Analyzer`
now returns an `AnalyzedNode` instead of a separate `Analysis` struct.
This change lays the groundwork for future optimizations and analysis
passes.
2026-02-22 16:11:46 +01:00
Michael Schimmel cb94f20c0b Refactor native function registration and instantiation
Introduces `register_native` for direct registration of `NativeFunction`
and `register_native_fn` for convenience from closures. The
`Environment::run`
method is removed, and its functionality is now handled by
`Environment::instantiate`,
which packages the linked AST into an invokable `NativeFunction`. This
streamlines
the execution path and better separates compilation/linking from runtime
execution.
2026-02-22 11:56:46 +01:00
Michael Schimmel a726b79d8a Refactor Purity enum and NativeFunction struct
Move `Purity` enum definition from `optimizer.rs` to `types.rs` and
create a `NativeFunction` struct to hold the function and its purity.
Update `Value::Function` to store `Rc<NativeFunction>` and
`Value::make_function`
helper to simplify creation.

This change allows tracking the purity of native functions, which is
useful
for optimization and static analysis.
2026-02-22 10:50:37 +01:00
Michael Schimmel 329b885c4b Formatting 2026-02-22 02:35:06 +01:00
Michael Schimmel ff1024ee49 Remove is_tail field from Call node
The `is_tail` field on the `BoundKind::Call` node was an intermediate
representation for tail-call optimization and is no longer needed as a
distinct field. The TCO pass now embeds this information directly into
the `RuntimeMetadata` of the `ExecNode`, which is the VM's internal AST.
This simplifies the `BoundKind::Call` structure and removes redundant
information.
2026-02-21 22:01:03 +01:00
Michael Schimmel 78dff07930 Refactor Call to include is_tail flag
The `TailCall` variant has been merged into `Call` by adding an
`is_tail` boolean field. This simplifies the AST by reducing the number
of node variants and makes it easier to handle tail call optimization.
The `tco.rs` module is responsible for setting this flag when a call
occurs in tail position.
2026-02-21 21:12:20 +01:00
Michael Schimmel d645f36700 clippy 2026-02-21 15:18:29 +01:00
Michael Schimmel dc81b7d616 Refactor Tuple and Record to share ValueList
Introduce `ValueList` type alias for `Rc<Vec<Value>>` to reduce
boilerplate and improve readability.
Add `as_slice()` method to `Value` to provide a unified way to access
the underlying values of Tuples and Records.
Update `flatten_value` and `unpack` in `VM` to utilize the new
`as_slice()` method, simplifying logic and improving consistency.
2026-02-21 15:16:04 +01:00
Michael Schimmel 212afd76df Refactor: Rename map to record
This commit renames `Map` to `Record` and updates all related AST nodes,
binders, type checkers, and runtime values to reflect this change. This
is a semantic change to better align with common programming language
terminology.
2026-02-21 14:51:34 +01:00
Michael Schimmel 87259584ee Refactor Record and List to use TupleData
The `Value::List` and `Value::Record` variants have been consolidated
into a single `Value::Tuple` variant. This new variant uses a
`TupleData` struct to store values and an optional `Rc<Vec<Keyword>>`
for keys, allowing it to represent both ordered lists/tuples and
key-value records.

This change simplifies the internal representation and improves
performance by allowing schema sharing for records. It also includes
updates to the compiler, runtime, and tests to reflect the new
structure.
2026-02-20 16:13:38 +01:00
Michael Schimmel ca2c85a8a4 Refactor map and record representation
Replaces the use of `BTreeMap` and `HashMap` for maps and records with
`Vec<(Keyword, Value)>` and `Vec<(Keyword, StaticType)>`. This
simplifies the data structure and allows for ordered iteration, which is
important for serialization and comparison.

Also updates the `unpack` function in `vm.rs` to handle records as well
as lists when destructuring.
2026-02-20 15:10:07 +01:00
Michael Schimmel 4e812c1afb Add positional_count field to Lambda
This field is used for static optimization, determining if parameters
are purely positional.
2026-02-20 14:40:56 +01:00
Michael Schimmel e2279f214b Refactor lambda binding and parameter handling
Introduce `BoundKind::Parameter` to represent function parameters.
Modify `Binder` to correctly handle parameters within lambda
definitions, ensuring they are only defined within function scopes.
Update `LambdaCollector` to register the body of lambdas as templates
for global definitions.
Adjust `Dumper` to accurately represent lambda parameters.
Update `Specializer` and `TCO` to handle the new `BoundKind::Parameter`.
Refactor `Call` and `TailCall` to use a single `args` node, often a
tuple.
Adjust type signatures in RTL to use `StaticType::Tuple` for function
parameters.
2026-02-20 12:14:22 +01:00
Michael Schimmel 1331aabbe1 Update benchmarks and adjust tests
This commit updates benchmark values in several example files to reflect
minor performance variations. It also includes adjustments to
integration
and unit tests to align with recent changes in the type checking and VM
logic, specifically concerning closures and TCO handling.
2026-02-19 23:54:53 +01:00
Michael Schimmel e7628e5cdf Add symbol name to bound kinds
The `Get`, `DefLocal`, and `DefGlobal` bound kinds now store the symbol
name associated with the variable. This information is useful for
debugging and provides more context in the compiled output.
2026-02-19 16:25:17 +01:00
Michael Schimmel d93727e198 feat: Add type checking to the compiler
Introduces the `TypeChecker` struct and its associated `TypeContext` for
performing static type analysis on the abstract syntax tree.

This change includes:
- A new `type_checker.rs` module.
- Integration of `TypeChecker` into the `Environment::compile` method.
- Updates to `Environment` to manage global types.
- Renaming `bound_nodes.rs`'s `BoundNode` to `TypedNode` to reflect its
  type-checked nature.
- Refinements in binder and macro expansion to accommodate type
  information.
2026-02-19 12:22:39 +01:00
Michael Schimmel 4673ea78b9 Refactor Binder to use simpler types
The Binder has been refactored to simplify its internal types and reduce
redundancy.
Key changes include:
- Removed StaticType from LocalInfo, as it's not strictly needed for the
  binder.
- Simplified `define` in CompilerScope to not take a StaticType.
- Removed StaticType from upvalues in FunctionCompiler.
- Adjusted global mappings to store only the index, not the type.
- Updated BoundKind to use a generic type parameter `T` for metadata,
  defaulting to `()` for untyped bound nodes.
- Introduced `BoundNode` and `TypedNode` type aliases for clarity.
- Minor adjustments to dumper and VM to accommodate the new generic
  BoundKind.
2026-02-19 12:07:28 +01:00
Michael Schimmel 76586c0903 Refactor: Use Symbol for identifiers and macro hygiene
Introduces a `Symbol` struct to represent identifiers, incorporating
macro hygiene context. Updates various parts of the AST compiler and
environment to use `Symbol` instead of raw `Rc<str>` for identifiers,
improving robustness for macro expansions.

Also includes:
- Adds a new example `macro_hygiene.myc`.
- Updates `.gitignore`.
- Refactors `MacroExpander` to use `ExpansionState` for cleaner template
  expansion.
- Adjusts `VM::eval_observed` to ensure `after_eval` is called
  correctly.
- Resets `Environment` for each test run and compilation/dumping in
  `main.rs`.
2026-02-18 14:32:09 +01:00
Michael Schimmel 94fc6bf56d feat: Implement AST macros and templates
This commit introduces support for AST macros and templates, enabling
users to define and use custom, reusable components within the visual
DSL.

Key changes include:
- A new `MacroRegistry` to manage macro definitions.
- A `MacroExpander` to process macro calls and expand templates.
- A `MacroEvaluator` trait for evaluating expressions during expansion.
- The `Expansion` node in `BoundKind` to preserve the original macro
  call and its expanded form for debugging.
- Updates to the `Binder`, `Dumper`, and `UpvalueAnalyzer` to handle the
  new macro constructs.
- New examples demonstrating various macro functionalities like
  `unless`, splicing, and nested macros.
2026-02-18 12:51:07 +01:00
Michael Schimmel 98deb8f3fe Refactor VM evaluation to use macro
The `eval` and `eval_observed` methods in the `VM` struct were very
similar, with the primary difference being the call to the `VMObserver`
trait. This commit refactors these methods into a single macro,
`dispatch_eval!`, which reduces code duplication and improves
maintainability.

The `Value::TailCallRequest` variant was also updated to use `Box` for
its contents, which helps keep the `Value` enum size consistent.

Finally, the benchmarks in the `examples` directory have been updated to
reflect minor performance changes resulting from these code
modifications.
2026-02-18 02:01:27 +01:00
Michael Schimmel 9b16bc47be Refactor regex compilation and use is_some_and
This commit introduces several improvements:

- Pre-compiles regular expressions in `ast/tester.rs` to avoid redundant
  compilation, improving performance.
- Replaces `.extension().map_or(false, |ext| ext == "myc")` with the
  more concise and readable `.extension().is_some_and(|ext| ext ==
  "myc")`.
- Simplifies upvalue capture logic by using `.or_default()` instead of
  `.or_insert_with(HashSet::new)`.
- Adds a `Default` implementation for `TracingObserver`.
- Optimizes string literal parsing in `highlight_myc` to correctly
  handle escape sequences.
- Uses `saturating_sub` for bracket depth to prevent underflow.
2026-02-18 01:24:28 +01:00
Michael Schimmel faada16723 Add debug mode and VM tracing
Introduce a `debug_mode` flag to the `Environment` and a new `run_debug`
method. This method uses a `TracingObserver` to log the VM's execution
flow, including node evaluation and scope state changes. This allows for
detailed inspection of script execution.

The `BoundKind` enum now also includes a `display_name` method for
better log readability.
2026-02-18 00:56:29 +01:00
Michael Schimmel 25e3bc1d01 Add AST dumper and improve upvalue analysis
The `UpvalueAnalyzer` now correctly identifies which lambdas capture
which variable declarations, rather than just marking declarations that
need boxing. This information is stored in a `capture_map`.

The `Binder` has been updated to use this new `capture_map` instead of a
`HashSet` of boxed declarations. The `DefLocal` node in `bound_nodes.rs`
now stores a `captured_by` field, which is a list of lambda identities
that capture the local variable.

A new `dumper` module has been added to provide a human-readable
representation of the bound AST, including information about captured
variables.

The `VM` has been updated to use the `captured_by` field to determine if
a local variable needs to be stored in a `Cell`, rather than relying on
a boolean `is_boxed` flag.

An example script `extreme_capture.myc` has been added to test deep
nesting and variable capture.

A new "Dump AST" button has been added to the UI, which uses the new
`Dumper` to display the bound AST.
2026-02-18 00:35:08 +01:00
Michael Schimmel 4d9adccab5 Introduce boxing for captured variables
The binder now uses an `UpvalueAnalyzer` to identify local variables
that are captured by nested functions. These identified variables are
marked with `is_boxed: true` during `DefLocal` node creation. The VM
then uses this flag to wrap such variables in a `Value::Cell` (using
`Rc<RefCell<_>>`) to ensure they can be mutated across function calls.
feat: Introduce boxing for captured variables

Add UpvalueAnalyzer to identify variables captured by nested lambdas.
Modify Binder to use the analyzer and mark captured local variables for
boxing.
Update BoundKind::DefLocal to include an `is_boxed` flag.
Update VM to box captured variables when they are defined.
Add tests for upvalue capture detection.
2026-02-18 00:09:46 +01:00
Michael Schimmel 98d3344912 feat: Add tail call optimization
Introduce a TCO pass to the compiler and modify the VM to handle tail
calls.
This allows for deep recursion without stack overflow.
2026-02-17 23:10:55 +01:00
Michael Schimmel 9afde5a301 Add tuple and map literals
This commit introduces support for tuple and map literals in the AST.
Tuples are now represented by `UntypedKind::Tuple` and maps by
`UntypedKind::Map`.
The `Binder` has been updated to correctly handle these new node types
and infer their types.
The `VM` now also supports evaluating tuple and map literals.
2026-02-17 13:07:17 +01:00
Michael Schimmel d55422272b Refactor: Use Rc/RefCell for shared mutable state
This commit replaces `Arc<Mutex<T>>` with `Rc<RefCell<T>>` for managing
shared mutable state within the AST and VM. This change is primarily an
internal refactoring to leverage Rust's standard library more
effectively for single-threaded scenarios, improving performance by
avoiding the overhead of mutexes.

The following types and their usage have been updated:
- `Environment.global_names` and `Environment.global_values`
- `Binder.globals`
- `bound_nodes::BoundKind::Lambda.body` (now `Rc<Node>`)
- `ast::types::NodeIdentity` (now `Rc<NodeIdentity>`)
- `ast::types::Value::List`, `Value::Record`, `Value::Function`,
  `Value::Object`, `Value::Cell`
- `ast::nodes::Scope` and `ast::nodes::Context`
- `ast::vm::Closure.function_node` and `Closure.upvalues`
- `ast::vm::VM.globals`

This change does not alter the external behavior of the library but
streamlines internal data management.
2026-02-17 13:00:25 +01:00