Commit Graph

105 Commits

Author SHA1 Message Date
Michael Schimmel cd3f63632f Update expected output for tak.myc benchmark 2026-02-20 00:59:31 +01:00
Michael Schimmel 30cd73aa63 Refactor multiple if let bindings
Replaces nested `if let` statements with sequential `if let` bindings,
improving readability. This change is applied to `Dumper::log_bound`,
`LambdaCollector::visit_bound`, `Environment::call_object_method`, and
`Environment::call_lambda`.
2026-02-19 23:56:50 +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 3c0f2ec8ce - Adjust Environment to use BoundNode for the function registry and
correctly initialize the `TypeChecker` with argument types during
  macro expansion.
- Refactor `Specializer::compile` to perform type checking with provided
  arguments before specialization and to correctly extract the return
  type.
- Enhance the `Dumper` to introspect and display specialized closure
  bodies.
- Update `LambdaCollector` to use `BoundNode` consistently.
- Modify `TypeChecker` to accept and inject specialized argument types
  for lambdas.
2026-02-19 23:18:04 +01:00
Michael Schimmel 16d9d41e3d Add LambdaCollector and Intrinsic Lookup 2026-02-19 22:26:33 +01:00
Michael Schimmel 1b49719d31 feat: Add lambda collection and specialization
Introduces `LambdaCollector` to gather lambda functions and populate the
function registry. This enables the `Specializer` to work with
user-defined functions.

The `Environment` struct is updated to manage the `function_registry`
and `monomorph_cache`, which are essential for the specialization
process.

The `link` method in `Environment` now incorporates lambda collection
and node specialization before applying TCO optimization. This ensures
that lambdas are properly processed and specialized for potential
performance gains.

The `Specializer`'s `new` constructor has been modified to accept and
initialize the `MonoCache` through an `Rc<RefCell<MonoCache>>`. This
allows the cache to be shared across different specialized functions.

Also includes minor refactoring and type adjustments in `specializer.rs`
for better clarity and consistency.
2026-02-19 22:26:24 +01:00
Michael Schimmel 55502cbb69 Perf: Reduce Fibonacci benchmark time 2026-02-19 17:12:37 +01:00
Michael Schimmel b8390a3431 Refactor specialization to handle RTL lookup
The specialization logic has been refactored to include a call to
`rtl_lookup` for host functions. This allows the specializer to
recognize and optimize calls to built-in runtime functions by directly
returning their specialized values.

Additionally, the `_rtl_lookup` field in `Specializer` has been renamed
to `rtl_lookup` for clarity. The `visit_call` method has also been
renamed to `specialize_call_logic` to better reflect its purpose, and it
now correctly handles `TailCall` nodes by preserving them.
2026-02-19 16:39:39 +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 98668cc683 Refactor testing guidelines and add specializer module
Update the testing section to clarify when warnings should be eliminated
and tests run.
Add the new `specializer` module to the compiler's public API.
Add the `type_registry` module to the `rtl` module's public API.
2026-02-19 16:06:13 +01:00
Michael Schimmel 5e03be17ad Fix: Use NOP instead of void in unless macro
The `unless` macro's expansion was updated to use `...` (NOP) instead of
`void`. This change also involved removing the `void` keyword from the
parser, as it is no longer used.
2026-02-19 14:05:32 +01:00
Michael Schimmel 125cf039d5 Fix: Parse boolean literals as identifiers
Boolean literals `true` and `false` are now parsed as identifiers,
matching the behavior of other constants like `NaN`. This change aligns
the AST representation of boolean literals with their runtime constants.
2026-02-19 13:56:49 +01:00
Michael Schimmel 07bf59eb47 Add RTL functions for arithmetic and comparisons
This commit introduces a new module `ast::rtl` to house the standard
runtime library functions for the language. It includes implementations
for arithmetic operators (+, -, *, /, //, %), logical operators (and,
or, xor, not), bitwise shifts (<<, >>), and comparison operators (=, <>,
<, >, <=, >=).

Additionally, a `date` function for parsing datetime strings has been
added. This enhances the language's capability to handle basic
mathematical and logical operations.
Add RTL functions for arithmetic and comparisons

This commit introduces the runtime library (RTL) functions for basic
arithmetic operations, logical/bitwise operations, and comparisons. It
also includes a `date` function for parsing datetime strings.
Integration tests have been updated to cover these new functionalities.
2026-02-19 13:47:14 +01:00
Michael Schimmel a5957f524b Add DateTime type and operations
This commit introduces the `DateTime` type to the language, enabling
users to work with dates and times. It includes:

- A new `DateTime` variant in the `Value` and `StaticType` enums.
- A `date` function for parsing date strings into `DateTime` values.
- Overloads for `+` and `-` operators to support `DateTime` arithmetic.
- Comparison operators (`>`, `<`) for `DateTime` values.
- Corresponding unit tests for `DateTime` operations.
- Updates to the `gemini.md` documentation to reflect the new
  functionality.
  Add DateTime type and operations

Introduce a new `DateTime` type to the language, allowing for date and
time manipulation. This includes:

*   Parsing dates and datetimes from strings.
*   Performing arithmetic operations (addition and subtraction) between
    `DateTime` and `Int` (representing milliseconds) and between two
    `DateTime` values (resulting in an `Int` duration).
*   Enabling comparison operations (`>`, `<`) between `DateTime` values.
2026-02-19 13:27:44 +01:00
Michael Schimmel 49db73800a Refactor type checking for functions and operators
This commit refactors the type checking logic for functions and
operators to improve type safety and expressiveness.

Key changes include:

- Introduced `StaticType::FunctionOverloads` to represent functions with
  multiple possible signatures, enabling better handling of operator
  overloading.
- Updated the `TypeChecker` to correctly infer function types and
  resolve calls with overloaded functions.
- Modified the `Environment` to register standard library functions with
  specific `FunctionOverloads` signatures, replacing the previous
  `StaticType::Any` approach.
- Enhanced the `StaticType::resolve_call` method to intelligently match
  argument types against expected parameters, including handling of
  overloaded functions.
- Added new tests to verify the correctness of type inference for lambda
  returns and operator overloading.
2026-02-19 13:10:28 +01:00
Michael Schimmel a611c50a92 Add type inference tests
Adds a suite of tests to verify type inference for constants, variable
propagation,
block expressions, lambda return types, and assignment updates.
2026-02-19 12:34:20 +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 c49561255e Refactor code editor layout configuration
Move the `.frame(false)` call to after `.desired_width(f32::INFINITY)`
for better readability.
2026-02-18 21:54:22 +01:00
Michael Schimmel 7e54b3f443 Add benchmark button to UI
The benchmark button is only enabled in release builds. If clicked, it
will trigger the benchmark suite.
2026-02-18 21:46:50 +01:00
Michael Schimmel 7a561ab69c Refactor UI layout and shortcuts
The UI layout has been significantly refactored to use
`egui::TopBottomPanel` and `egui::SidePanel` for a more organized
structure. A new menu bar has been introduced with File, Build, and
Tools menus, along with a toolbar for quick access to common actions.

Keyboard shortcuts have been updated and consolidated:
- `Shift + Enter` now compiles the code and is accessible from anywhere
  in the app.
- `Ctrl + S` saves the current file.

The `Save As` functionality has been moved into a dedicated group within
the bottom panel and is now triggered by a button in the File menu. The
output log and trace logs now use `egui::ScrollArea::both` for better
scrolling experience.

Minor adjustments to default panel heights and scroll area behaviors
have been made for improved usability.
2026-02-18 21:33:36 +01:00
Michael Schimmel 193414c1da Refactor: Move tester module to utils 2026-02-18 18:09:33 +01:00
Michael Schimmel b6d1d41c8b Replace lazy_static with OnceLock
This commit replaces the `lazy_static` crate with `std::sync::OnceLock`.
This removes an external dependency and utilizes a standard library
feature for lazy initialization.

Additionally, a benchmark regression test has been added to
`src/ast/tester.rs`.
2026-02-18 16:00:21 +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 73ddd644c1 Add redefinition checks for variables
Ensure that variables are not redefined within the same scope, both for
global and function-local variables. This commit modifies the `define`
method in `CompilerScope` to return a `Result` and includes checks for
existing definitions. The `Binder`'s logic for handling global variables
and function parameters is also updated to incorporate these new checks
and return appropriate errors.
2026-02-18 13:23:08 +01:00
Michael Schimmel 3630cb3c6c Refactor trace log display and handling
Truncate trace logs to improve GUI performance and prevent excessive
display. This change also introduces line length limits for individual
log entries, adding "..." for truncated lines. The display logic for
trace logs has been updated to use `egui::ScrollArea` for better user
experience.
2026-02-18 13:08:38 +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 1d1b54ed16 Add syntax highlighting to editor and logs
Introduce a `highlight_myc` function to provide syntax highlighting for
the source code editor and trace logs, improving code readability.
2026-02-18 01:08:39 +01:00
Michael Schimmel 799f3a2123 feat: Add debug mode and trace logs
Introduce a debug mode that collects and displays execution trace logs.
This involves adding an `AppTab` enum to manage UI state and modifying
the
`compile` function to handle debug execution.
2026-02-18 00:59:42 +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 83f6cfb8e1 Add save functionality and shortcuts 2026-02-17 23:19:08 +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 e6eaf70836 Add check for trailing tokens
Ensure that a script does not contain any tokens after the main
expression. This prevents accidental trailing expressions and enforces a
clearer script structure.
2026-02-17 22:33:49 +01:00
Michael Schimmel b0f139f389 feat: Add testing and benchmarking capabilities
This commit introduces a new `tester` module to the `ast` crate,
enabling functional tests and performance benchmarks for MYC scripts.

Functional tests are executed by reading `.myc` files from the
`examples` directory, parsing expected output comments, and comparing
them against the actual script execution results.

Benchmarking involves measuring the execution time of scripts,
calculating median durations, and comparing them against stored
baselines. The commit also adds support for updating these baselines.

The `ast.rs` CLI and the `main.rs` GUI application have been updated to
expose these new testing and benchmarking features. The `Cargo.toml` and
`Cargo.lock` files have been updated to include the `regex` dependency
required for parsing benchmark comments.
2026-02-17 14:47:04 +01:00
Michael Schimmel b1ca16149d Add chrono dependency and example files
This commit introduces the `chrono` dependency to the project, enabling
the use of time-related functionalities. Additionally, it adds several
example files (`closure.myc`, `fib.myc`, `hof.myc`) to showcase the
language's features like closures, recursion, and higher-order
functions.

The `Cargo.lock` and `Cargo.toml` files have been updated to reflect the
new dependency. The `integration_test.rs` file now includes a test to
run all `.myc` files found in the `examples` directory, ensuring their
correctness. The `main.rs` file has also been updated to load and
display these examples in the UI.
2026-02-17 14:21:31 +01:00
Michael Schimmel 97542b5ca4 Refactor: Migrate to clap for CLI argument parsing
The project now uses the `clap` crate for handling command-line
arguments, replacing the previous manual parsing approach. This includes
adding `clap` as a dependency and creating a `Cli` struct to define the
command-line interface. The `main` function has been updated to parse
these arguments and handle file input or direct script evaluation.
2026-02-17 13:35:59 +01:00
Michael Schimmel 3cca0e06c2 Refactor Binder to support recursion and add stdlib operators
This commit introduces two main changes:

1.  **Binder Refactoring**: The `Binder` has been refactored to support
    recursive definitions by pre-declaring names in the scope before
    binding their values. This ensures that a name is visible to itself
    when its definition is being processed.

2.  **Stdlib Operator Implementation**: Several standard library
    operators, including `+`, `-`, `*`, `/`, `>`, and `<`, have been
    implemented. These operators now correctly handle both `Int` and
    `Float` types for numerical operations and comparisons.
    Additionally, the display formatting for `Value::List` and
    `Value::Record` has been improved for better readability. The
    default source code in `main.rs` has also been updated to include a
    Fibonacci example, demonstrating the new recursive capabilities.
2026-02-17 13:22:04 +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
Michael Schimmel ce166f39e3 Introduce Value::Cell for mutable upvalues, allowing closures to
modify captured variables.
Implement `capture_upvalue` and `get_value`/`set_value` methods in the
`VM` to handle these mutable upvalues.

Refactor number parsing to support integers and floats

Separate the `TokenKind::Number` into `TokenKind::Integer` and
`TokenKind::Float`.
Update the lexer to distinguish between integer and float literals.
Update the parser to correctly map these new token kinds to their
respective `Value` types.

Add integration tests for parsing integers and floats, and for closure
modification of captured variables.
2026-02-17 12:35:39 +01:00
Michael Schimmel 12791a7f8f Add gemini.md to .gitignore 2026-02-17 12:09:00 +01:00
Michael Schimmel 49a879045e feat: Add StaticType and type checking
This commit introduces `StaticType` and enhances the `Binder` to perform
basic type checking during the binding phase.

Key changes include:

- **`StaticType` enum:** Represents static types such as `Any`, `Void`,
  `Bool`, `Int`, `Float`, `Text`, `List`, `Record`, and `Function`.
- **`Node<K, T>`:** The generic `Node` now includes a `ty` field to
  store its inferred static type.
- **Binder enhancements:**
    - `CompilerScope` now stores `LocalInfo` containing the variable's
      slot and `StaticType`.
    - `FunctionCompiler` stores upvalues with their associated
      `StaticType`.
    - `Binder::bind` now returns `Node<BoundKind, StaticType>`,
      propagating type information.
    - Type checking is added for `If` conditions and `Assign`
      operations.
    - `Def` nodes now infer and store the type of the defined variable.
- **`Value::static_type()`:** A new method to determine the `StaticType`
  of a `Value`.
- **Environment modifications:** `global_names` now stores `(u32,
  StaticType)` to associate global variables with their types.
- **Parser modifications:** The `ty` field of nodes is initialized to
  `()` by default.
- **VM modifications:** `VM::run` and `VM::eval` now operate on
  `Node<BoundKind, StaticType>`.
- **Tests:** Added basic evaluation and type error tests.
  feat: Add StaticType and type checking

Introduces `StaticType` enum and integrates it into the AST. The binder
now performs type checking during compilation, ensuring that expressions
conform to expected types, especially for control flow structures like
`if`. This lays the groundwork for static type analysis and error
reporting.
2026-02-17 11:54:52 +01:00
Michael Schimmel 2c612adc49 Fixed warnings 2026-02-17 11:33:32 +01:00
Michael Schimmel b19fd4b097 Add is_first_frame flag to CompilerApp
Introduces a new `is_first_frame` boolean flag to the `CompilerApp`
struct to manage initial UI state, specifically for requesting focus on
the source code editor on the first frame. This commit also moves the
compilation logic into a dedicated `compile` method for better
organization and introduces a Shift+Enter keyboard shortcut for
compilation.
2026-02-17 11:31:30 +01:00
Michael Schimmel 7042206ab6 feat: Implement AST binder and VM
Adds a new `Binder` struct that traverses the AST and resolves variable
references to concrete `Address` types (Local, Upvalue, Global). This
information is crucial for the Virtual Machine's execution phase.

Introduces the `BoundKind` enum to represent the AST after binding.

The `VM` is updated to handle `BoundKind` nodes and execute the bound
AST.
It now manages a call stack, local variables, and closures for function
calls and upvalue capturing.

The `Environment` struct is enhanced to manage global variables and
provide
a unified interface for parsing, binding, and executing scripts. It also
includes basic standard library functions.
2026-02-17 02:00:51 +01:00
Michael Schimmel 874a6f39a4 feat: Add assignment operator and recursive scope assignment
Introduces the `Assign` AST node and a corresponding `assign` method on
the `Scope` struct. This allows for updating existing variables within
the current scope or any parent scope.

The `assign` method recursively traverses the scope chain until it finds
the variable or determines it's undefined. This enables reassigning
variables defined in outer scopes.
2026-02-17 00:58:29 +01:00