Skip to content

feat: Implement Tier 1 Core Language Features - Enums, Options, Maps#18

Closed
mjm918 wants to merge 13 commits intomainfrom
fix/codegen-compilation-errors
Closed

feat: Implement Tier 1 Core Language Features - Enums, Options, Maps#18
mjm918 wants to merge 13 commits intomainfrom
fix/codegen-compilation-errors

Conversation

@mjm918
Copy link
Copy Markdown
Contributor

@mjm918 mjm918 commented Jan 21, 2026

Summary

Implements the core Tier 1 language features from #15:

  • Enums with variants: Stack-allocated tagged unions with unit and data variants
  • Pattern matching: Destructuring in switch/case statements (case Suspended(reason):)
  • Option type: Built-in some/none with is_some(), is_none(), or_default() methods
  • Map type: Hash map runtime with string keys, FNV-1a hashing, linear probing

Changes

  • Add Pattern AST for destructuring patterns
  • Add pattern parser for switch cases
  • Add enum definition tracking in Cranelift codegen
  • Implement enum variant construction (unit and data variants)
  • Implement enum pattern matching with destructuring bindings
  • Implement option type as built-in enum
  • Add hash map runtime implementation
  • Implement map literals, indexing, and assignment in codegen

Test Plan

  • All 116 existing tests pass
  • examples/test_enum.naml - enum construction and pattern matching
  • examples/test_option.naml - option type methods
  • examples/test_map.naml - map operations
  • examples/tier1_test.naml - comprehensive integration test

Closes #15

🤖 Generated with Claude Code

mjm918 and others added 12 commits January 20, 2026 23:24
This commit addresses multiple categories of codegen errors in the Rust backend:

**Fixes:**
- Fix await expression throws detection for method calls
- Fix move/clone semantics by cloning function args and array elements
- Add compare() method transformation to use partial_cmp
- Fix integer literals to use unsuffixed format for type inference
- Fix printf/Display by using {:?} for non-Display types
- Fix E0507 move out of mutable reference with borrow+clone
- Fix var...else Box deref for recursive struct fields

**Changes:**
- expressions.rs: Add emit_function_arg helper for cloning
- expressions.rs: Add resolve_receiver_type_name for better type detection
- expressions.rs: Transform compare() to partial_cmp
- statements.rs: Add is_recursive_field_access for Box handling
- statements.rs: Improve var...else pattern for self fields
- mod.rs: Track recursive structs for proper Box wrapping

Reduces errors from 37 to 12. Remaining errors are mostly closure vs
fn pointer issues which require significant design changes to address.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace Rust codegen with Cranelift JIT for faster development iteration.
This enables direct execution via `naml run` without Rust compilation.

Changes:
- Add Cranelift JIT codegen (cranelift/mod.rs, types.rs)
- Remove Rust transpilation codegen (no longer needed)
- Add runtime system with value representation (runtime/value.rs)
- Add array runtime with heap allocation (runtime/array.rs)
- Add channel runtime for concurrency (runtime/channel.rs)
- Add cooperative scheduler for spawn tasks (runtime/scheduler.rs)
- Add example files demonstrating language features
- Update type inference for better generic support

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new Pattern AST nodes to support pattern matching in switch/case
statements. This enables enum destructuring like `case Suspended(reason):`

New types:
- Pattern enum (Literal, Identifier, Variant, Wildcard)
- LiteralPattern for matching literal values
- IdentPattern for binding/comparing identifiers
- VariantPattern for enum variant matching with bindings
- WildcardPattern for the `_` catch-all pattern

Updates SwitchCase to use Pattern instead of Expression.

Note: Parser, typechecker, and codegen updates pending in follow-up tasks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix misleading documentation claiming "Copy-free" allocation when
  VariantPattern uses Vec which allocates on the heap
- Add lifetime parameter to Pattern<'ast> for consistency with
  Expression<'ast> and Statement<'ast>
- Update SwitchCase to use Pattern<'ast> with proper lifetime
- Fix import style in statements.rs to use relative imports

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a dedicated pattern parser that supports:
- Literal patterns (int, float, string, bool, none)
- Identifier patterns (bindings or constant references)
- Variant patterns with optional bindings (e.g., Some(x), Status::Active)
- Wildcard pattern (_)

Update parse_switch_stmt to use parse_pattern instead of parse_expression.

Note: This introduces expected compilation errors in visitor, typechecker,
and codegen modules that will be addressed in subsequent tasks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add EnumDef and EnumVariantDef structs to the Cranelift JIT compiler
to track enum definitions during compilation. This infrastructure will
be used for generating code for enum construction and pattern matching.

The enum representation uses stack-allocated fixed-size tagged unions:
- Layout: | tag: u32 | padding: u32 | data: [u8; max_size] |
- Size = 8 + max variant data size (aligned to 8 bytes)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for constructing enum values in Cranelift JIT:
- Add enum_defs to CompileContext for enum type information
- Handle Expression::Path for unit variants (e.g., Color::Red)
- Handle Expression::Call for variants with data (e.g., Status::Suspended("reason"))

Enum layout: | tag: u32 | padding: u32 | data fields... |
Values are stack-allocated with pointers returned.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add visit_pattern method to visitor trait for proper pattern traversal
- Add walk_pattern function to traverse pattern nodes
- Fix switch case handling in visitor to use visit_pattern instead of visit_expr
- Add infer_pattern method to type inferrer for pattern type inference
- Fix switch case handling in typechecker to use infer_pattern
- Fix convert_ast_type to resolve named types (enum/struct) from symbol table
- Add compile_pattern_match function to compile pattern comparisons
- Add bind_pattern_vars function to bind variables in destructuring patterns
- Update switch statement codegen to use pattern matching functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add built-in option enum as a polymorphic type with some/none variants.
Implements some() expression, none literal, and is_some/is_none/or_default
method calls using stack-allocated 16-byte option representation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds NamlMap type with FNV-1a hashing and linear probing for naml's
map<K, V> type with string keys.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wire up the map runtime functions to the Cranelift codegen:
- Register naml_map_* symbols in JIT compiler
- Handle Expression::Map for map literal compilation
- Support map indexing with string keys (m["key"])
- Support map index assignment (m["key"] = value)
- Add map methods: contains, set
- Add naml_string_from_cstr to convert C strings to NamlStrings
- Add test file examples/test_map.naml

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive integration test that exercises all Tier 1 features:
- Enums with unit variants and pattern matching via switch
- Option type (some, none, is_some, is_none, or_default)
- Maps (creation, string key indexing, assignment)
- Structs (definition, instantiation, field access)
- Arrays (creation, len(), for loop iteration)
- Control flow (if/else, while, for, switch)
- Combined feature tests (enums in arrays, options with arithmetic)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude bot commented Jan 21, 2026

Code Review

I've reviewed this PR and found 3 high-signal issues:


🚨 Critical: Use-after-free bug in resize_map

File: namlc/src/runtime/map.rs, lines 196-199

Issue: The resize_map function calls decref() on the key string before calling naml_map_set() to reinsert it. This creates a use-after-free vulnerability.

The problem:

  1. Line 197 decrements the key's reference count
  2. If the refcount was 1, it becomes 0 (object should be freed)
  3. Line 199 calls naml_map_set which tries to use the key (hash it, incref it)

The code currently "works by accident" because it uses raw header.decref() instead of naml_string_decref(), but this is a latent bug that will manifest if anyone changes the decref call to use the proper string decref function (like the one used in naml_map_decref at line 168).

The fix: Remove the decref() call entirely. When resizing, we're just moving the same key pointer to a new location in the same map structure. The reference counting should remain unchanged - the map still owns one reference to the key.

Code reference:

if (*entry).occupied {
if (*entry).key != 0 {
(*((*entry).key as *mut NamlString)).header.decref();
}
naml_map_set(map, (*entry).key, (*entry).value);
}


⚠️ CLAUDE.md violation: File size limits

Rule: "All source files must stay under 1000 lines. If a file approaches this limit, split it into logical submodules."
Source: .claude/claude.md

Violations:

  1. namlc/src/codegen/cranelift/mod.rs - 2,691 lines (169% over limit)

    • Consider splitting into submodules like:
      • cranelift/builtins.rs (builtin functions)
      • cranelift/expressions.rs (expression codegen)
      • cranelift/statements.rs (statement codegen)
      • cranelift/types.rs (type handling)
      • cranelift/enums.rs (enum-specific codegen)
  2. namlc/src/typechecker/infer.rs - 1,594 lines (59% over limit)

    • Consider splitting into submodules like:
      • infer/expressions.rs
      • infer/statements.rs
      • infer/patterns.rs

Summary: Found 1 critical memory safety bug and 2 code organization violations. Please address the use-after-free bug before merging.

…eanup

- Add memory management test files to validate heap allocation, reference counting, and cleanup for strings, arrays, maps, and structs.
- Introduce field heap type tracking in `StructDef` for nested cleanup during decref.
- Register enhanced runtime symbols for specialized decref methods for strings, arrays, maps, and structs.
- Implement per-struct decref function generation for structs with heap-allocated fields.
- Update codegen to manage heap variable lifecycle using incref and decref during assignments and returns.
@mjm918 mjm918 closed this Jan 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tier 1: Core Language Features - Enums, Options, Maps, Generics

1 participant