Commit Graph

21 Commits

Author SHA1 Message Date
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 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 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 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 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 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 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 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