diff --git a/.cursor/rules/specify-rules.mdc b/.cursor/rules/specify-rules.mdc index f8ccfa3..4cec1b1 100644 --- a/.cursor/rules/specify-rules.mdc +++ b/.cursor/rules/specify-rules.mdc @@ -9,6 +9,8 @@ Auto-generated from all feature plans. Last updated: 2025-12-19 - Haskell (GHC 9.10.3), Cabal build system + gram-hs (source repository), text, containers, megaparsec, mtl, hspec, QuickCheck (004-implementation-consistency-review) - N/A (documentation review, no data storage) (004-implementation-consistency-review) - N/A - In-memory data structures only (005-keywords-maps-sets) +- Haskell (GHC 9.10.3, base >=4.18 && <5) + gram-hs library (pattern, subject, gram packages), Cabal build system (006-gram-hs-migration) +- N/A (in-memory pattern structures) (006-gram-hs-migration) - Haskell with GHC 9.6.3 (see research.md for version selection rationale) + gram-hs (source repository from GitHub), text, containers, megaparsec, mtl, hspec, QuickCheck (001-pattern-lisp-init) @@ -29,9 +31,9 @@ tests/ Haskell with GHC 9.6.3 (see research.md for version selection rationale): Follow standard conventions ## Recent Changes +- 006-gram-hs-migration: Added Haskell (GHC 9.10.3, base >=4.18 && <5) + gram-hs library (pattern, subject, gram packages), Cabal build system - 005-keywords-maps-sets: Added Haskell (GHC 9.10.3) - 004-implementation-consistency-review: Added Haskell (GHC 9.10.3), Cabal build system + gram-hs (source repository), text, containers, megaparsec, mtl, hspec, QuickCheck -- 003-pattern-state-functions: Added Haskell with GHC 9.10.3 (as per existing project setup) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6ef6f83..4bbf4d0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -48,7 +48,8 @@ jobs: ${{ runner.os }}-dist-${{ matrix.ghc-version }}- - name: Configure Cabal - run: cabal update + run: | + cabal update - name: Build project run: cabal build --ghc-options="-Wall" all diff --git a/docs/pattern-state-lisp-design.md b/docs/pattern-state-lisp-design.md index a3c9eb1..46e1a15 100644 --- a/docs/pattern-state-lisp-design.md +++ b/docs/pattern-state-lisp-design.md @@ -38,7 +38,7 @@ Where: ```scheme ;; Pure function, runtime handles state threading (lambda (state) - (pattern-with + (pattern (pattern-value state) (cons new-item (pattern-elements state)))) ``` @@ -54,7 +54,7 @@ Tools in Pattern Agents are naturally `Pattern v -> Pattern v` transformations: (lambda (state) (let* ((user (pattern-find state is-user?)) (name (pattern-query user "$.name"))) - (pattern-with + (pattern {:greeting (string-append "Hello, " name)} (pattern-elements state)))) ``` @@ -72,7 +72,7 @@ Tools compose as functions: (define format-greeting (lambda (state) (let ((user (get-user state))) - (pattern {:greeting (string-append "Hello, " (pattern-value user))})))) + (pure {:greeting (string-append "Hello, " (pattern-value user))})))) ;; Compose: format-greeting ∘ get-user (define greet-user @@ -177,8 +177,8 @@ Pattern is a **native Lisp value type**, not accessed through host-calls. ```scheme ;; Pattern construction -(pattern value) ; Atomic pattern -(pattern-with value elements) ; Pattern with elements +(pure value) ; Atomic pattern +(pattern value elements) ; Pattern with elements (from-list value [v1 v2 v3]) ; Convenience constructor ;; Pattern transformation (returns new pattern) @@ -220,7 +220,7 @@ Since programs are pure, **host-calls** are the only mechanism for side effects: "SELECT * FROM users WHERE id = ?" user-id))) ;; Incorporate result into new state pattern - (pattern-with + (pattern {:query-result db-result} (pattern-elements state))))) ``` @@ -316,12 +316,12 @@ executeTool toolName runtime = do (db-result (host-call 'db-query "SELECT * FROM orders WHERE id = ?" order-id)) - (order-pattern (pattern-with + (order-pattern (pattern {:type "Order" :id order-id :data db-result} []))) - (pattern-with + (pattern (pattern-value state) (cons order-pattern (pattern-elements state))))) ] @@ -337,14 +337,14 @@ executeTool toolName runtime = do (db-result (host-call 'db-query "SELECT * FROM orders WHERE id = ?" order-id)) - (order-pattern (pattern-with - {:type "Order" - :id order-id - :data db-result} - []))) - (pattern-with - (pattern-value state) - (cons order-pattern (pattern-elements state))))) + (order-pattern (pattern + {:type "Order" + :id order-id + :data db-result} + []))) + (pattern + (pattern-value state) + (cons order-pattern (pattern-elements state))))) ``` ## Benefits for Pattern Agents diff --git a/docs/plisp-serialization-design.md b/docs/plisp-serialization-design.md index 9fc786b..144b2ea 100644 --- a/docs/plisp-serialization-design.md +++ b/docs/plisp-serialization-design.md @@ -606,7 +606,7 @@ Every Pattern Lisp runtime provides a standard environment (`initialEnv`) contai - Arithmetic primitives: `+`, `-`, `*`, `/` - Comparison primitives: `>`, `<`, `=`, `/=` - String primitives: `string-append`, `string-length`, `substring` -- Pattern primitives: `pattern`, `pattern-with`, `pattern-value`, etc. +- Pattern primitives: `pure`, `pattern`, `pattern-value`, etc. ### Environment Filtering @@ -1245,10 +1245,10 @@ Pattern Subject → Check Label: **S-expression**: ```scheme (lambda (state) - (pattern-with + (pattern (pattern-value state) (cons - (pattern "new-item") + (pure "new-item") (pattern-elements state)))) ``` @@ -1262,7 +1262,7 @@ Pattern Subject → Check Label: [:Parameters | state], [:Body | [:List | - [:Symbol {name: "pattern-with"}], + [:Symbol {name: "pattern"}], [:List | [:Symbol {name: "pattern-value"}], state], [:List | [:Symbol {name: "cons"}], diff --git a/examples/pattern-basics.plisp b/examples/pattern-basics.plisp index 71045d7..6d7a9e3 100644 --- a/examples/pattern-basics.plisp +++ b/examples/pattern-basics.plisp @@ -2,10 +2,10 @@ ;; Demonstrates creating and querying Pattern values ;; Create an atomic pattern -(define hello (pattern "hello")) +(define hello (pure "hello")) ;; Create a pattern with elements (empty for now) -(define root (pattern-with "root" '())) +(define root (pattern "root" '())) ;; Query pattern decoration (pattern-value hello) diff --git a/examples/pattern-predicates.plisp b/examples/pattern-predicates.plisp index d948e61..2fffce2 100644 --- a/examples/pattern-predicates.plisp +++ b/examples/pattern-predicates.plisp @@ -9,9 +9,9 @@ ;; ============================================================================ ;; Create some atomic patterns for testing -(define p1 (pattern 10)) -(define p2 (pattern 20)) -(define p3 (pattern 30)) +(define p1 (pure 10)) +(define p2 (pure 20)) +(define p3 (pure 30)) ;; pattern-find: Find the first matching subpattern ;; Returns the matching pattern, or empty list if no match diff --git a/specs/003-pattern-state-functions/quickstart.md b/specs/003-pattern-state-functions/quickstart.md index e026cf3..e5b0f07 100644 --- a/specs/003-pattern-state-functions/quickstart.md +++ b/specs/003-pattern-state-functions/quickstart.md @@ -35,11 +35,11 @@ cabal build all ```scheme ;; Create an atomic pattern -(define atomic (pattern "hello")) +(define atomic (pure "hello")) ;; Create a pattern with elements -(define with-elements (pattern-with "root" - (list (pattern "child1") (pattern "child2")))) +(define with-elements (pattern "root" + (list (pure "child1") (pure "child2")))) ``` ### 2. Querying Pattern Values @@ -64,10 +64,10 @@ All tools must follow the canonical form `(lambda (state) ...)`: ```scheme ;; Simple tool that adds a greeting (lambda (state) - (pattern-with + (pattern (pattern-value state) ; Preserve decoration (cons - (pattern "Hello from Pattern Lisp!") + (pure "Hello from Pattern Lisp!") (pattern-elements state)))) ``` @@ -173,13 +173,13 @@ Deserializes runtime from a Gram file and resumes execution. (lambda (state) (let ((count (pattern-size state)) (depth (pattern-depth state))) - (pattern-with + (pattern (pattern-value state) - (cons - (pattern-with "summary" - (list - (pattern count) - (pattern depth))) + (cons + (pattern "summary" + (list + (pure count) + (pure depth))) (pattern-elements state))))) ;; 2. Save to file: state-reader.plisp @@ -269,13 +269,13 @@ it "round-trips closures" $ do ;; Define multiple tools (define add-timestamp (lambda (state) - (pattern-with (pattern-value state) - (cons (pattern "timestamp") (pattern-elements state))))) + (pattern (pattern-value state) + (cons (pure "timestamp") (pattern-elements state))))) (define add-metadata (lambda (state) - (pattern-with (pattern-value state) - (cons (pattern "metadata") (pattern-elements state))))) + (pattern (pattern-value state) + (cons (pure "metadata") (pattern-elements state))))) ;; Compose tools (lambda (state) @@ -289,9 +289,9 @@ it "round-trips closures" $ do (lambda (state) (let ((incrementer (lambda (x) (+ x 1))) (doubler (lambda (x) (* x 2)))) - (pattern-with "functions" - (list (pattern incrementer) - (pattern doubler))))) + (pattern "functions" + (list (pure incrementer) + (pure doubler))))) ``` ### State Filtering @@ -302,7 +302,7 @@ it "round-trips closures" $ do (let ((filtered (pattern-find state (lambda (p) (> (pattern-size p) 1))))) - (pattern-with "filtered" (list filtered)))) + (pattern "filtered" (list filtered)))) ``` ## Troubleshooting diff --git a/specs/006-gram-hs-migration/checklists/requirements.md b/specs/006-gram-hs-migration/checklists/requirements.md new file mode 100644 index 0000000..7d063e9 --- /dev/null +++ b/specs/006-gram-hs-migration/checklists/requirements.md @@ -0,0 +1,38 @@ +# Specification Quality Checklist: Gram-HS Library Migration + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2025-01-28 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- Migration is a technical task but has been framed from developer/user perspective +- Success criteria include measurable outcomes (100% test pass rate, zero occurrences of old API) +- Edge cases cover nested patterns, closures, and serialization scenarios +- Scope is clearly bounded to constructor migration only + diff --git a/specs/006-gram-hs-migration/contracts/README.md b/specs/006-gram-hs-migration/contracts/README.md new file mode 100644 index 0000000..37fcbda --- /dev/null +++ b/specs/006-gram-hs-migration/contracts/README.md @@ -0,0 +1,40 @@ +# Contracts: Gram-HS Constructor Migration + +**Date**: 2025-01-28 + +## Overview + +This migration is an internal refactoring task that updates constructor function names. No external API contracts change - this is purely an internal implementation detail. + +## Internal API Changes + +### Pattern Constructor Functions + +**Before**: +- `pattern :: v -> Pattern v` (atomic) +- `patternWith :: v -> [Pattern v] -> Pattern v` (with elements) + +**After**: +- `point :: v -> Pattern v` (atomic) +- `pattern :: v -> [Pattern v] -> Pattern v` (with elements) + +## Impact + +- **External API**: No changes - Pattern Lisp public API unchanged +- **Internal API**: Constructor function names changed +- **Serialization Format**: Unchanged - gram notation format unchanged +- **Behavior**: Unchanged - only constructor names differ + +## Migration Contract + +All internal code using Pattern constructors must: +1. Use `point` for atomic patterns +2. Use `pattern` for patterns with elements +3. Import `Pattern.Core (point, pattern, ...)` instead of `Pattern.Core (pattern, patternWith, ...)` + +## Verification + +- Type checker enforces correct usage +- Test suite verifies functional correctness +- No external contract changes required + diff --git a/specs/006-gram-hs-migration/data-model.md b/specs/006-gram-hs-migration/data-model.md new file mode 100644 index 0000000..3e1bd67 --- /dev/null +++ b/specs/006-gram-hs-migration/data-model.md @@ -0,0 +1,78 @@ +# Data Model: Gram-HS Constructor Migration + +**Date**: 2025-01-28 + +## Overview + +This migration does not change the data model. Patterns remain the same structure; only the constructor function names change. This document describes the pattern structure for reference during migration. + +## Pattern Structure + +### Pattern Type +```haskell +Pattern v -- where v is the decoration type (Subject in our case) +``` + +### Atomic Pattern +**Old API**: `pattern :: v -> Pattern v` +**New API**: `point :: v -> Pattern v` + +**Structure**: Pattern with no elements, decoration only. + +**Example**: +```haskell +-- Old +atomic = pattern (Subject { ... }) + +-- New +atomic = point (Subject { ... }) +``` + +### Pattern with Elements +**Old API**: `patternWith :: v -> [Pattern v] -> Pattern v` +**New API**: `pattern :: v -> [Pattern v] -> Pattern v` + +**Structure**: Pattern with decoration and list of child patterns. + +**Example**: +```haskell +-- Old +withElements = patternWith decoration [child1, child2] + +-- New +withElements = pattern decoration [child1, child2] +``` + +## Entities + +### Pattern Constructor +- **Type**: Function +- **Old Names**: `pattern` (atomic), `patternWith` (with elements) +- **New Names**: `point` (atomic), `pattern` (with elements) +- **Signature**: `v -> Pattern v` (atomic) or `v -> [Pattern v] -> Pattern v` (with elements) + +### Pattern Value +- **Type**: `Pattern Subject` +- **Structure**: Unchanged - decoration (Subject) + optional elements (list of Pattern Subject) +- **Migration Impact**: None - structure unchanged, only construction changes + +## Relationships + +- Pattern can contain other Patterns as elements (nested structure) +- Pattern decoration is a Subject (unchanged) +- Pattern elements are list of Patterns (unchanged) + +## Validation Rules + +- Atomic patterns: Must use `point`, take single argument +- Patterns with elements: Must use `pattern`, take decoration and list of elements +- Type checker enforces correct usage + +## State Transitions + +N/A - This is a refactoring task, not a stateful system. + +## Migration Impact + +**No data model changes** - Only constructor function names change. All pattern structures, relationships, and validation rules remain identical. + diff --git a/specs/006-gram-hs-migration/plan.md b/specs/006-gram-hs-migration/plan.md new file mode 100644 index 0000000..52dab4f --- /dev/null +++ b/specs/006-gram-hs-migration/plan.md @@ -0,0 +1,105 @@ +# Implementation Plan: Gram-HS Library Migration + +**Branch**: `006-gram-hs-migration` | **Date**: 2025-01-28 | **Spec**: [spec.md](./spec.md) +**Input**: Feature specification from `/specs/006-gram-hs-migration/spec.md` + +**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow. + +## Summary + +Migrate Pattern Lisp codebase to use updated gram-hs library constructor API. The breaking change renames constructors: `patternWith` → `pattern` (for patterns with elements) and `pattern` → `point` (for atomic patterns). This is a straightforward refactoring task requiring systematic find-and-replace across source and test modules, including updates to code comments and documentation examples that reference the old API. Migration is followed by verification through compilation and test execution. + +## Technical Context + +**Language/Version**: Haskell (GHC 9.10.3, base >=4.18 && <5) +**Primary Dependencies**: gram-hs library (pattern, subject, gram packages), Cabal build system +**Storage**: N/A (in-memory pattern structures) +**Testing**: hspec, QuickCheck, cabal test +**Target Platform**: Linux/macOS (Haskell cross-platform) +**Project Type**: Library (Haskell library with CLI executable) +**Performance Goals**: No performance impact - API migration only +**Constraints**: Must maintain 100% test pass rate, zero compilation errors +**Scale/Scope**: ~50 occurrences across 7 source modules and 4 test modules, plus code comments and documentation examples + +## Constitution Check + +*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* + +### I. Library-First +✅ **PASS**: This is a migration of an existing library. No new library creation required. + +### II. CLI Interface +✅ **PASS**: No CLI changes required. Existing CLI functionality preserved. + +### III. Test-First (NON-NEGOTIABLE) +✅ **PASS**: Migration will be verified by existing test suite. All tests must pass after migration. + +### IV. Integration Testing +✅ **PASS**: Existing integration tests will verify pattern serialization/deserialization still works correctly. + +### V. Observability +✅ **PASS**: No observability changes required. Text I/O and logging unchanged. + +**Gate Status**: ✅ **ALL GATES PASS** - Proceed to Phase 0 + +### Post-Phase 1 Re-check + +*Re-evaluated after Phase 1 design completion.* + +### I. Library-First +✅ **PASS**: No new libraries created. Existing library structure maintained. + +### II. CLI Interface +✅ **PASS**: No CLI changes. Existing interface preserved. + +### III. Test-First (NON-NEGOTIABLE) +✅ **PASS**: Migration verified by existing test suite. All tests must pass. + +### IV. Integration Testing +✅ **PASS**: Integration tests verify serialization/deserialization correctness. + +### V. Observability +✅ **PASS**: No observability changes. Text I/O unchanged. + +**Post-Phase 1 Gate Status**: ✅ **ALL GATES PASS** - Ready for Phase 2 (task creation) + +## Project Structure + +### Documentation (this feature) + +```text +specs/006-gram-hs-migration/ +├── plan.md # This file (/speckit.plan command output) +├── research.md # Phase 0 output (/speckit.plan command) +├── data-model.md # Phase 1 output (/speckit.plan command) +├── quickstart.md # Phase 1 output (/speckit.plan command) +├── contracts/ # Phase 1 output (/speckit.plan command) +└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan) +``` + +### Source Code (repository root) + +```text +src/PatternLisp/ +├── Codec.hs # 30+ patternWith occurrences, imports Pattern.Core +├── PatternPrimitives.hs # 4 patternWith occurrences, imports Pattern.Core +├── Gram.hs # 1 pattern occurrence (atomic), imports Pattern.Core +├── Eval.hs # Qualified import only (PatternCore) +└── [other modules] # No Pattern.Core usage + +test/PatternLisp/ +├── CodecSpec.hs # Imports Pattern.Core +├── GramSpec.hs # 1 patternWith occurrence, imports Pattern.Core +├── GramSerializationSpec.hs # 1 patternWith occurrence, imports Pattern.Core +├── RuntimeSpec.hs # 1 pattern occurrence (atomic), imports Pattern.Core +└── [other test modules] # No Pattern.Core usage +``` + +**Structure Decision**: Existing single-project Haskell library structure. Migration affects specific modules that import and use Pattern.Core constructors, including: +- Source code: Constructor function calls +- Code comments: Haddock examples and inline comments referencing old API +- Module documentation: Example code snippets in module headers + +## Complexity Tracking + +> **No violations** - This is a straightforward API migration refactoring task with no complexity additions. diff --git a/specs/006-gram-hs-migration/quickstart.md b/specs/006-gram-hs-migration/quickstart.md new file mode 100644 index 0000000..f9d6484 --- /dev/null +++ b/specs/006-gram-hs-migration/quickstart.md @@ -0,0 +1,152 @@ +# Quickstart: Gram-HS Constructor Migration + +**Date**: 2025-01-28 + +## Overview + +This guide provides a quick reference for migrating Pattern Lisp codebase to use the new gram-hs constructor API. + +## Migration Steps + +### Step 1: Update Imports + +Find all modules importing `Pattern.Core`: + +```haskell +-- Old +import Pattern.Core (pattern, patternWith, ...) + +-- New +import Pattern.Core (point, pattern, ...) +``` + +**Affected Files**: +- `src/PatternLisp/Codec.hs` +- `src/PatternLisp/PatternPrimitives.hs` +- `src/PatternLisp/Gram.hs` +- `test/PatternLisp/CodecSpec.hs` +- `test/PatternLisp/GramSpec.hs` +- `test/PatternLisp/GramSerializationSpec.hs` +- `test/PatternLisp/RuntimeSpec.hs` + +### Step 2: Replace `patternWith` → `pattern` + +Find all occurrences of `patternWith`: + +```bash +grep -r "patternWith" src/ test/ +``` + +Replace each occurrence: +```haskell +-- Old +patternWith decoration elements + +-- New +pattern decoration elements +``` + +### Step 3: Replace Atomic `pattern` → `point` + +Find atomic pattern constructions (single argument, not a list): + +```haskell +-- Old +pattern subject +pattern $ valueToSubjectForGram val + +-- New +point subject +point $ valueToSubjectForGram val +``` + +**Key Indicator**: If `pattern` takes one argument (not a list), it should be `point`. + +### Step 4: Update Comments and Documentation + +Review code comments and module documentation for references to the old API: + +```haskell +-- Old (in Haddock comments) +-- > patternWith decoration [element1, element2] + +-- New +-- > pattern decoration [point element1, point element2] +``` + +**Areas to check**: +- Module header examples (Haddock `-- >` examples) +- Inline comments explaining pattern construction +- Function documentation examples + +### Step 5: Verify + +After each module migration: + +```bash +# Compile +cabal build + +# Run tests +cabal test +``` + +## Common Patterns + +### Atomic Pattern Creation +```haskell +-- Old +let pat = pattern $ valueToSubjectForGram (VNumber n) + +-- New +let pat = point $ valueToSubjectForGram (VNumber n) +``` + +### Pattern with Elements +```haskell +-- Old +let pat = patternWith decoration elementPatterns + +-- New +let pat = pattern decoration elementPatterns +``` + +### Nested Patterns +```haskell +-- Old +let nested = patternWith outerDecoration + [ patternWith middleDecoration + [ pattern innerSubject ] + ] + +-- New +let nested = pattern outerDecoration + [ pattern middleDecoration + [ point innerSubject ] + ] +``` + +## Verification Checklist + +- [ ] All imports updated +- [ ] All `patternWith` replaced with `pattern` +- [ ] All atomic `pattern` calls replaced with `point` +- [ ] Code comments and documentation examples updated +- [ ] Code compiles: `cabal build` +- [ ] All tests pass: `cabal test` +- [ ] No `patternWith` in codebase (except historical references in comments if appropriate): `grep -r "patternWith" src/ test/` + +## Troubleshooting + +### Compilation Error: "Not in scope: `patternWith`" +- Check imports: Should be `import Pattern.Core (point, pattern, ...)` +- Verify all `patternWith` calls replaced with `pattern` + +### Compilation Error: "Couldn't match type" +- Check if atomic pattern uses `point` (one argument) +- Check if pattern with elements uses `pattern` (two arguments: decoration and list) + +### Test Failures +- Verify pattern structure unchanged (only constructor names changed) +- Check serialization/deserialization round-trips still work + diff --git a/specs/006-gram-hs-migration/research.md b/specs/006-gram-hs-migration/research.md new file mode 100644 index 0000000..68e68b6 --- /dev/null +++ b/specs/006-gram-hs-migration/research.md @@ -0,0 +1,111 @@ +# Research: Gram-HS Constructor Migration + +**Date**: 2025-01-28 +**Status**: Complete + +## Migration Guide Analysis + +**Source**: `../gram-hs/docs/users/migration/rename-constructors.md` + +### Key Findings + +1. **Constructor Renaming**: + - `patternWith v es` → `pattern v es` (patterns with elements) + - `pattern v` → `point v` (atomic patterns) + +2. **Import Changes**: + - Old: `import Pattern.Core (pattern, patternWith, ...)` + - New: `import Pattern.Core (point, pattern, ...)` + +3. **Migration Strategy**: + - Manual migration recommended (not automated) due to ambiguity between `pattern` as function vs variable name + - Step 1: Update imports + - Step 2: Replace all `patternWith` → `pattern` + - Step 3: Review each `pattern` call to determine if atomic (use `point`) or has elements (keep `pattern`) + +## Codebase Analysis + +### Affected Modules + +**Source Modules**: +- `src/PatternLisp/Codec.hs`: 30+ `patternWith` occurrences, imports `Pattern.Core (pattern, patternWith)` +- `src/PatternLisp/PatternPrimitives.hs`: 4 `patternWith` occurrences, imports `Pattern.Core (pattern, patternWith)` +- `src/PatternLisp/Gram.hs`: 1 atomic `pattern` occurrence, imports `Pattern.Core (pattern)` +- `src/PatternLisp/Eval.hs`: Qualified import only (`PatternCore`), no direct constructor usage + +**Test Modules**: +- `test/PatternLisp/CodecSpec.hs`: Imports `Pattern.Core (pattern, patternWith)` +- `test/PatternLisp/GramSpec.hs`: 1 `patternWith` occurrence, imports `Pattern.Core (pattern, patternWith)` +- `test/PatternLisp/GramSerializationSpec.hs`: 1 `patternWith` occurrence, imports `Pattern.Core (pattern, patternWith)` +- `test/PatternLisp/RuntimeSpec.hs`: 1 atomic `pattern` occurrence, imports `Pattern.Core (pattern)` + +### Migration Pattern + +**Atomic Pattern Identification**: +- `pattern subject` where `subject` is a single value (not a list) +- Examples: `pattern $ valueToSubjectForGram (VNumber n)`, `pattern subject` + +**Pattern-with-Elements Identification**: +- `patternWith decoration elements` where `elements` is a list +- Examples: `patternWith decoration elementPatterns`, `patternWith (valueToSubjectForGram (VMap Map.empty)) elements` + +## Decisions + +### Decision 1: Migration Approach +**Chosen**: Manual, module-by-module migration with verification after each module + +**Rationale**: +- Migration guide recommends manual migration due to ambiguity +- Module-by-module allows incremental verification +- Type checker will catch errors immediately + +**Alternatives Considered**: +- Automated find-and-replace: Rejected due to risk of replacing variable names +- All-at-once migration: Rejected due to difficulty in debugging if errors occur + +### Decision 2: Verification Strategy +**Chosen**: Compile and test after each module migration + +**Rationale**: +- Ensures migration correctness incrementally +- Type checker provides immediate feedback +- Test suite validates functional correctness + +**Alternatives Considered**: +- Migrate all then verify: Rejected due to difficulty in locating errors + +### Decision 3: Atomic Pattern Detection +**Chosen**: Manual review of each `pattern` call to determine if it's atomic or has elements + +**Rationale**: +- Type signature: `point :: v -> Pattern v` (one argument) +- Type signature: `pattern :: v -> [Pattern v] -> Pattern v` (two arguments) +- Compiler will catch incorrect usage + +**Alternatives Considered**: +- Automated detection: Rejected due to complexity of distinguishing function calls from variable names + +### Decision 4: Comments and Documentation Updates +**Chosen**: Update code comments and documentation examples to use new API + +**Rationale**: +- Ensures consistency across codebase +- Prevents confusion for developers reading code +- Aligns with breaking change migration (no backwards compatibility) +- Haddock examples should reflect current API + +**Alternatives Considered**: +- Leave comments unchanged: Rejected - would create inconsistency and confusion +- Update only critical comments: Rejected - partial updates create maintenance burden + +## Migration Checklist + +1. ✅ Migration guide reviewed and understood +2. ✅ Affected modules identified +3. ✅ Migration strategy determined +4. ✅ Verification approach defined + +## Open Questions + +None - all technical questions resolved through migration guide and codebase analysis. + diff --git a/specs/006-gram-hs-migration/spec.md b/specs/006-gram-hs-migration/spec.md new file mode 100644 index 0000000..21b3795 --- /dev/null +++ b/specs/006-gram-hs-migration/spec.md @@ -0,0 +1,145 @@ +# Feature Specification: Gram-HS Library Migration + +**Feature Branch**: `006-gram-hs-migration` +**Created**: 2025-01-28 +**Status**: Draft +**Input**: User description: "Migrate to use updated gram-hs library, particularly the breaking change to constructors. Read ../gram-hs/docs/users/migration/rename-constructors.md for details" + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - Update Pattern Constructor Imports (Priority: P1) + +As a developer maintaining the Pattern Lisp codebase, I need to update all imports to use the new constructor names (`point` and `pattern`) so that the code compiles with the updated gram-hs library. + +**Why this priority**: Without updated imports, the code will fail to compile, blocking all other work. + +**Independent Test**: Can be fully tested by updating imports in all affected modules and verifying the build succeeds with `cabal build`. + +**Acceptance Scenarios**: + +1. **Given** a module that imports `Pattern.Core (pattern, patternWith)`, **When** the import is updated to `Pattern.Core (point, pattern)`, **Then** the module compiles successfully +2. **Given** all source modules, **When** imports are updated, **Then** no compilation errors related to missing constructors occur + +--- + +### User Story 2 - Replace Atomic Pattern Constructors (Priority: P1) + +As a developer maintaining the Pattern Lisp codebase, I need to replace all atomic `pattern` constructor calls with `point` so that atomic patterns are created correctly with the new API. + +**Why this priority**: Atomic pattern construction is fundamental to the system and must work correctly for all functionality to operate. + +**Independent Test**: Can be fully tested by searching for atomic `pattern` calls (where `pattern` takes a single argument, not a list), replacing them with `point`, and verifying the build and tests pass. + +**Acceptance Scenarios**: + +1. **Given** code that creates atomic patterns like `pattern "atom"` or `pattern 42`, **When** these are replaced with `point "atom"` or `point 42`, **Then** the code compiles and atomic patterns are created correctly +2. **Given** all atomic pattern constructions in the codebase, **When** they are migrated to use `point`, **Then** the code compiles and uses the new API correctly + +--- + +### User Story 3 - Replace Pattern-With-Elements Constructors (Priority: P1) + +As a developer maintaining the Pattern Lisp codebase, I need to replace all `patternWith` constructor calls with `pattern` so that patterns with elements are created correctly with the new API. + +**Why this priority**: Patterns with elements are used extensively throughout the codebase for serialization, closures, and data structures. This must work correctly for the system to function. + +**Independent Test**: Can be fully tested by searching for all `patternWith` calls, replacing them with `pattern`, and verifying the build and tests pass. + +**Acceptance Scenarios**: + +1. **Given** code that creates patterns with elements like `patternWith decoration elements`, **When** this is replaced with `pattern decoration elements`, **Then** the code compiles and patterns are created correctly +2. **Given** nested pattern constructions that mix atomic and non-atomic patterns, **When** atomic patterns use `point` and non-atomic patterns use `pattern`, **Then** nested structures are created correctly +3. **Given** all `patternWith` calls in the codebase, **When** they are migrated to use `pattern`, **Then** the code compiles and uses the new API correctly + +--- + +### User Story 4 - Verify Migration Completeness (Priority: P2) + +As a developer maintaining the Pattern Lisp codebase, I need to verify that all constructor calls have been migrated and no old API usage remains, ensuring the codebase is fully compatible with the updated library. + +**Why this priority**: Incomplete migration could lead to runtime errors or subtle bugs that are difficult to diagnose. + +**Independent Test**: Can be fully tested by searching the codebase for any remaining `patternWith` calls or incorrect `pattern` usage, running the full test suite, and verifying all tests pass. + +**Acceptance Scenarios**: + +1. **Given** the migrated codebase, **When** searching for `patternWith`, **Then** no occurrences are found (except possibly in comments or documentation) +2. **Given** the migrated codebase, **When** searching for atomic `pattern` calls (single argument, not list), **Then** all have been replaced with `point` +3. **Given** the full test suite, **When** running `cabal test`, **Then** all tests pass without errors +4. **Given** example programs, **When** running them through the interpreter, **Then** they produce the same results as before migration + +--- + +### Edge Cases + +- What happens when a pattern construction is deeply nested with mixed atomic and non-atomic patterns? +- How does the system handle patterns created in closures that capture patterns? +- What happens when serializing and deserializing patterns after migration? +- How are patterns with zero elements handled (empty lists, empty maps)? +- What happens when patterns are constructed dynamically at runtime? + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: System MUST update all imports from `Pattern.Core (pattern, patternWith)` to `Pattern.Core (point, pattern)` +- **FR-002**: System MUST replace all atomic pattern constructions (`pattern value`) with `point value` +- **FR-003**: System MUST replace all pattern-with-elements constructions (`patternWith decoration elements`) with `pattern decoration elements` +- **FR-004**: System MUST ensure nested pattern constructions correctly use `point` for atomic patterns and `pattern` for patterns with elements +- **FR-005**: System MUST update both direct gram-hs API usage AND pattern-lisp's reflection of patterns to use the new API with no backwards compatibility allowances +- **FR-010**: System MUST update code comments and documentation examples that reference the old constructor API to use the new API names +- **FR-006**: System MUST compile successfully with the updated gram-hs library +- **FR-007**: System MUST pass all existing tests after migration +- **FR-008**: System MUST correctly serialize and deserialize patterns using the new constructors +- **FR-009**: System MUST handle all pattern types correctly: atomic values, lists, maps, sets, closures, and nested structures + +### Key Entities *(include if feature involves data)* + +- **Pattern Constructor**: The function used to create Pattern values. Changed from `pattern`/`patternWith` to `point`/`pattern` +- **Atomic Pattern**: A pattern with no elements, created with `point` in the new API +- **Pattern with Elements**: A pattern containing child patterns, created with `pattern` in the new API +- **Migration Scope**: All modules that import or use Pattern constructors, including Codec, PatternPrimitives, Gram, and any test modules + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: All source files compile successfully with zero errors related to Pattern constructors +- **SC-002**: All existing tests pass with 100% success rate after migration +- **SC-003**: All example programs execute successfully using the new API (behavioral equivalence expected, but API usage must be fully migrated) +- **SC-004**: Codebase contains zero occurrences of `patternWith` function calls, and code comments/documentation examples have been updated to use the new API +- **SC-005**: All atomic pattern constructions use `point` instead of `pattern` +- **SC-006**: Pattern serialization and deserialization round-trips work correctly for all pattern types +- **SC-007**: Migration is completed within a single development session (no partial migration state) + +## Assumptions + +- The updated gram-hs library is available and compatible with the current GHC version +- The migration guide accurately describes all breaking changes +- Existing test coverage is sufficient to verify migration correctness +- No changes to pattern semantics are required beyond constructor name changes +- The migration can be done incrementally by module, but all modules must be migrated before the feature is complete +- This is a breaking change migration with no backwards compatibility requirements - both gram-hs API usage and pattern-lisp's reflection of patterns must be fully updated + +## Dependencies + +- Updated gram-hs library with renamed constructors +- Access to migration guide at `../gram-hs/docs/users/migration/rename-constructors.md` +- Existing test suite to verify migration correctness + +## Out of Scope + +- Backwards compatibility with old constructor names or patterns +- Maintaining support for old gram-hs API usage +- Gradual migration strategies or compatibility layers +- Changes to pattern semantics or behavior (beyond API changes) +- Performance optimizations +- New features or functionality +- Documentation updates beyond migration notes (code comments and examples within source files are included in migration scope) +- Changes to other gram-hs library APIs beyond constructor names + +## Clarifications + +### Session 2025-01-28 + +- Q: Should backwards compatibility be maintained for this migration? → A: No backwards compatibility required. Both gram-hs API usage and pattern-lisp's reflection of patterns must be fully updated with no allowance for backwards compatibility. diff --git a/specs/006-gram-hs-migration/tasks.md b/specs/006-gram-hs-migration/tasks.md new file mode 100644 index 0000000..0213813 --- /dev/null +++ b/specs/006-gram-hs-migration/tasks.md @@ -0,0 +1,275 @@ +# Tasks: Gram-HS Library Migration + +**Input**: Design documents from `/specs/006-gram-hs-migration/` +**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/ + +**Tests**: No new tests required - existing test suite verifies migration correctness. + +**Organization**: Tasks are organized by user story to enable independent implementation and testing of each story. + +## Format: `[ID] [P?] [Story] Description` + +- **[P]**: Can run in parallel (different files, no dependencies) +- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3) +- Include exact file paths in descriptions + +## Path Conventions + +- **Single project**: `src/`, `test/` at repository root +- Paths shown below use repository root structure + +--- + +## Phase 1: Setup (Prerequisites) + +**Purpose**: Verify prerequisites and understand migration requirements + +- [x] T001 Verify updated gram-hs library is available and compatible with current GHC version +- [x] T002 Read migration guide at `../gram-hs/docs/users/migration/rename-constructors.md` and understand breaking changes +- [x] T003 Verify existing test suite passes before migration: `cabal test` + +**Checkpoint**: Prerequisites verified - ready to begin migration + +--- + +## Phase 2: User Story 1 - Update Pattern Constructor Imports (Priority: P1) 🎯 MVP + +**Goal**: Update all imports from `Pattern.Core (pattern, patternWith)` to `Pattern.Core (point, pattern)` so code compiles with updated library. + +**Independent Test**: Update imports in all affected modules and verify build succeeds with `cabal build`. + +### Implementation for User Story 1 + +- [x] T004 [P] [US1] Update import in `src/PatternLisp/Codec.hs`: Change `import Pattern.Core (pattern, patternWith)` to `import Pattern.Core (point, pattern)` +- [x] T005 [P] [US1] Update import in `src/PatternLisp/PatternPrimitives.hs`: Change `import Pattern.Core (pattern, patternWith)` to `import Pattern.Core (point, pattern)` +- [x] T006 [P] [US1] Update import in `src/PatternLisp/Gram.hs`: Change `import Pattern.Core (pattern)` to `import Pattern.Core (point, pattern)` +- [x] T007 [P] [US1] Update import in `test/PatternLisp/CodecSpec.hs`: Change `import Pattern.Core (pattern, patternWith)` to `import Pattern.Core (point, pattern)` +- [x] T008 [P] [US1] Update import in `test/PatternLisp/GramSpec.hs`: Change `import Pattern.Core (pattern, patternWith)` to `import Pattern.Core (point, pattern)` +- [x] T009 [P] [US1] Update import in `test/PatternLisp/GramSerializationSpec.hs`: Change `import Pattern.Core (pattern, patternWith)` to `import Pattern.Core (point, pattern)` +- [x] T010 [P] [US1] Update import in `test/PatternLisp/RuntimeSpec.hs`: Change `import Pattern.Core (pattern)` to `import Pattern.Core (point, pattern)` +- [x] T011 [US1] Verify all imports updated: Run `grep -r "patternWith" src/ test/ | grep -i import` to confirm no old imports remain +- [x] T012 [US1] Verify compilation: Run `cabal build` to ensure no import-related errors + +**Checkpoint**: All imports updated - code should compile (may have errors from old constructor usage, which is expected) + +--- + +## Phase 3: User Story 2 - Replace Atomic Pattern Constructors (Priority: P1) + +**Goal**: Replace all atomic `pattern` constructor calls with `point` so atomic patterns are created correctly with the new API. + +**Independent Test**: Search for atomic `pattern` calls (single argument, not list), replace with `point`, and verify build and tests pass. + +### Implementation for User Story 2 + +- [x] T013 [P] [US2] Replace atomic `pattern` calls in `src/PatternLisp/Codec.hs`: Find all `pattern $` and `pattern subject` (single argument) and replace with `point $` and `point subject` +- [x] T014 [P] [US2] Replace atomic `pattern` calls in `src/PatternLisp/PatternPrimitives.hs`: Find all `pattern subject` (single argument) and replace with `point subject` +- [x] T015 [P] [US2] Replace atomic `pattern` calls in `src/PatternLisp/Gram.hs`: Replace `pattern subject` with `point subject` in `exprToGram` function +- [x] T016 [P] [US2] Replace atomic `pattern` calls in `test/PatternLisp/RuntimeSpec.hs`: Replace any atomic `pattern` calls with `point` +- [x] T017 [US2] Verify atomic patterns migrated: Run `grep -r "pattern \$" src/ test/` and `grep -r "pattern [^W]" src/ test/` to check for remaining atomic patterns (excluding `patternWith`) +- [x] T018 [US2] Verify compilation: Run `cabal build` to ensure atomic pattern replacements are correct + +**Checkpoint**: All atomic patterns use `point` - compilation should succeed for atomic patterns + +--- + +## Phase 4: User Story 3 - Replace Pattern-With-Elements Constructors (Priority: P1) + +**Goal**: Replace all `patternWith` constructor calls with `pattern` so patterns with elements are created correctly with the new API. + +**Independent Test**: Search for all `patternWith` calls, replace with `pattern`, and verify build and tests pass. + +### Implementation for User Story 3 + +- [x] T019 [P] [US3] Replace `patternWith` calls in `src/PatternLisp/Codec.hs`: Replace all ~30+ occurrences of `patternWith` with `pattern` +- [x] T020 [P] [US3] Replace `patternWith` calls in `src/PatternLisp/PatternPrimitives.hs`: Replace all 4 occurrences of `patternWith` with `pattern` +- [x] T021 [P] [US3] Replace `patternWith` calls in `test/PatternLisp/GramSpec.hs`: Replace `patternWith` with `pattern` +- [x] T022 [P] [US3] Replace `patternWith` calls in `test/PatternLisp/GramSerializationSpec.hs`: Replace `patternWith` with `pattern` +- [x] T023 [US3] Verify all `patternWith` replaced: Run `grep -r "patternWith" src/ test/` to confirm no function calls remain (comments may still reference) +- [x] T024 [US3] Verify compilation: Run `cabal build` to ensure all `patternWith` replacements are correct +- [x] T025 [US3] Verify nested patterns: Check that nested patterns correctly use `point` for atomic children and `pattern` for non-atomic children + +**Checkpoint**: All `patternWith` calls replaced with `pattern` - full migration of constructor calls complete + +--- + +## Phase 5: User Story 4 - Verify Migration Completeness (Priority: P2) + +**Goal**: Verify that all constructor calls have been migrated and no old API usage remains, ensuring codebase is fully compatible with updated library. + +**Independent Test**: Search codebase for remaining `patternWith` calls or incorrect `pattern` usage, run full test suite, and verify all tests pass. + +### Implementation for User Story 4 + +- [x] T026 [US4] Search for remaining `patternWith` function calls: Run `grep -r "patternWith" src/ test/` and verify only comments/documentation references remain +- [x] T027 [US4] Search for incorrect atomic `pattern` usage: Run `grep -r "pattern \$" src/ test/` and verify all are intentional (not atomic patterns that should be `point`) +- [x] T028 [US4] Verify compilation: Run `cabal build` and ensure zero errors related to Pattern constructors +- [x] T029 [US4] Run full test suite: Execute `cabal test` and verify 100% test pass rate +- [x] T030 [US4] Test example programs: Run example programs through interpreter and verify they produce same results as before migration +- [x] T031 [US4] Verify serialization round-trips: Test pattern serialization/deserialization for all pattern types (atomic, lists, maps, sets, closures, nested) + +**Checkpoint**: Migration verified complete - all tests pass, no old API usage remains + +--- + +## Phase 6: Polish & Cross-Cutting Concerns + +**Purpose**: Update code comments and documentation examples to reflect new API + +- [x] T032 [P] Update Haddock examples in `src/PatternLisp/PatternPrimitives.hs`: Replace `evalPatternWith` example comments to use new API if they reference constructors +- [x] T033 [P] Update inline comments in `src/PatternLisp/Codec.hs`: Review and update any comments that reference old constructor names +- [x] T034 [P] Update module documentation examples: Review module headers for example code snippets referencing old API +- [x] T035 [P] Update comments in `test/PatternLisp/` files: Review test file comments for old API references +- [x] T036 Verify comment updates: Run final `grep -r "patternWith" src/ test/` to confirm only historical references remain (if any) +- [x] T037 Final compilation check: Run `cabal build` one final time +- [x] T038 Final test check: Run `cabal test` one final time to ensure everything still works + +**Checkpoint**: Migration complete - code, tests, and documentation all updated + +--- + +## Dependencies & Execution Order + +### Phase Dependencies + +- **Setup (Phase 1)**: No dependencies - can start immediately +- **User Story 1 (Phase 2)**: Depends on Setup completion - BLOCKS all other migration work +- **User Story 2 (Phase 3)**: Depends on User Story 1 completion (imports must be updated first) +- **User Story 3 (Phase 4)**: Depends on User Story 1 completion (imports must be updated first) + - Can be done in parallel with User Story 2 (different files) +- **User Story 4 (Phase 5)**: Depends on User Stories 2 and 3 completion (all constructor calls must be migrated) +- **Polish (Phase 6)**: Depends on User Story 4 completion (verification must pass first) + +### User Story Dependencies + +- **User Story 1 (P1)**: Can start after Setup - No dependencies on other stories +- **User Story 2 (P1)**: Depends on User Story 1 - Imports must be updated before replacing atomic patterns +- **User Story 3 (P1)**: Depends on User Story 1 - Imports must be updated before replacing `patternWith` + - Can run in parallel with User Story 2 (different files, no conflicts) +- **User Story 4 (P2)**: Depends on User Stories 2 and 3 - All constructor calls must be migrated before verification + +### Within Each User Story + +- Import updates can be done in parallel (different files) +- Atomic pattern replacements can be done in parallel (different files) +- `patternWith` replacements can be done in parallel (different files) +- Verification tasks must run after all replacements complete + +### Parallel Opportunities + +- **Phase 2 (US1)**: All import updates (T004-T010) can run in parallel +- **Phase 3 (US2)**: All atomic pattern replacements (T013-T016) can run in parallel +- **Phase 4 (US3)**: All `patternWith` replacements (T019-T022) can run in parallel +- **Phase 6 (Polish)**: All comment updates (T032-T035) can run in parallel +- **Cross-phase**: User Stories 2 and 3 can be worked on in parallel after User Story 1 completes + +--- + +## Parallel Example: User Story 1 + +```bash +# Launch all import updates together (different files, no dependencies): +Task: "Update import in src/PatternLisp/Codec.hs" +Task: "Update import in src/PatternLisp/PatternPrimitives.hs" +Task: "Update import in src/PatternLisp/Gram.hs" +Task: "Update import in test/PatternLisp/CodecSpec.hs" +Task: "Update import in test/PatternLisp/GramSpec.hs" +Task: "Update import in test/PatternLisp/GramSerializationSpec.hs" +Task: "Update import in test/PatternLisp/RuntimeSpec.hs" +``` + +--- + +## Parallel Example: User Stories 2 and 3 + +```bash +# After User Story 1 completes, User Stories 2 and 3 can run in parallel: + +# Developer A: User Story 2 (Atomic patterns) +Task: "Replace atomic pattern calls in src/PatternLisp/Codec.hs" +Task: "Replace atomic pattern calls in src/PatternLisp/PatternPrimitives.hs" +Task: "Replace atomic pattern calls in src/PatternLisp/Gram.hs" + +# Developer B: User Story 3 (patternWith replacements) +Task: "Replace patternWith calls in src/PatternLisp/Codec.hs" +Task: "Replace patternWith calls in src/PatternLisp/PatternPrimitives.hs" +Task: "Replace patternWith calls in test/PatternLisp/GramSpec.hs" +``` + +--- + +## Implementation Strategy + +### MVP First (User Story 1 Only) + +1. Complete Phase 1: Setup +2. Complete Phase 2: User Story 1 (Update imports) +3. **STOP and VALIDATE**: Verify code compiles (may have constructor errors, which is expected) +4. This provides a working checkpoint where imports are correct + +### Incremental Delivery + +1. Complete Setup → Prerequisites verified +2. Add User Story 1 → Imports updated → Verify compilation +3. Add User Story 2 → Atomic patterns migrated → Verify compilation +4. Add User Story 3 → `patternWith` migrated → Verify compilation +5. Add User Story 4 → Verification complete → All tests pass +6. Add Polish → Comments updated → Final verification + +### Parallel Team Strategy + +With multiple developers: + +1. Team completes Setup together +2. Once Setup is done: + - Developer A: User Story 1 (all imports) - BLOCKS others +3. Once User Story 1 completes: + - Developer A: User Story 2 (atomic patterns) + - Developer B: User Story 3 (`patternWith` replacements) +4. Once User Stories 2 and 3 complete: + - Developer A: User Story 4 (verification) + - Developer B: Polish (comment updates) +5. Final verification together + +--- + +## Notes + +- [P] tasks = different files, no dependencies +- [Story] label maps task to specific user story for traceability +- Each user story should be independently completable and testable +- Commit after each phase or logical group +- Stop at any checkpoint to validate story independently +- Avoid: replacing variable names that happen to be called `pattern` or `patternWith` +- Be careful: `pattern` is now used for patterns with elements, so distinguish from atomic `point` usage +- Verification tasks (T026-T031) should catch any missed replacements + +--- + +## Task Summary + +**Total Tasks**: 38 + +**Tasks per User Story**: +- User Story 1 (Imports): 9 tasks +- User Story 2 (Atomic patterns): 6 tasks +- User Story 3 (patternWith): 7 tasks +- User Story 4 (Verification): 6 tasks +- Polish: 7 tasks +- Setup: 3 tasks + +**Parallel Opportunities Identified**: +- 7 import updates can run in parallel +- 4 atomic pattern replacements can run in parallel +- 4 `patternWith` replacements can run in parallel +- 4 comment updates can run in parallel +- User Stories 2 and 3 can run in parallel after User Story 1 + +**Independent Test Criteria**: +- **US1**: Build succeeds after import updates (constructor errors expected) +- **US2**: Build succeeds, atomic patterns use `point` +- **US3**: Build succeeds, all `patternWith` replaced with `pattern` +- **US4**: All tests pass, no old API usage remains + +**Suggested MVP Scope**: User Story 1 (Update imports) - provides working checkpoint + diff --git a/src/PatternLisp/Codec.hs b/src/PatternLisp/Codec.hs index 405069e..45b2b21 100644 --- a/src/PatternLisp/Codec.hs +++ b/src/PatternLisp/Codec.hs @@ -63,7 +63,7 @@ module PatternLisp.Codec import PatternLisp.Syntax import PatternLisp.Primitives (initialEnv) import Pattern (Pattern) -import Pattern.Core (pattern, patternWith) +import Pattern.Core (point, pattern) import qualified Pattern.Core as PatternCore import Subject.Core (Subject(..)) import qualified Subject.Core as SubjectCore @@ -581,10 +581,10 @@ valueToSubjectForGram (VClosure _) = Subject -- This follows the design in docs/plisp-serialization-design.md -- This is a pure function for serialization (unlike PatternPrimitives.valueToPatternSubject which is monadic) valueToPatternSubjectForGram :: Value -> Pattern Subject -valueToPatternSubjectForGram (VNumber n) = pattern $ valueToSubjectForGram (VNumber n) -valueToPatternSubjectForGram (VString s) = pattern $ valueToSubjectForGram (VString s) -valueToPatternSubjectForGram (VBool b) = pattern $ valueToSubjectForGram (VBool b) -valueToPatternSubjectForGram (VKeyword name) = pattern $ valueToSubjectForGram (VKeyword name) +valueToPatternSubjectForGram (VNumber n) = point $ valueToSubjectForGram (VNumber n) +valueToPatternSubjectForGram (VString s) = point $ valueToSubjectForGram (VString s) +valueToPatternSubjectForGram (VBool b) = point $ valueToSubjectForGram (VBool b) +valueToPatternSubjectForGram (VKeyword name) = point $ valueToSubjectForGram (VKeyword name) valueToPatternSubjectForGram (VMap m) = -- Serialize map as pattern with elements: alternating key-value pairs -- Keys can be keywords or strings, each serialized appropriately @@ -596,34 +596,34 @@ valueToPatternSubjectForGram (VMap m) = valuePatterns = map (\(_, v) -> valueToPatternSubjectForGram v) keyValuePairs -- Interleave keys and values: [key1, value1, key2, value2, ...] elements = concat $ zipWith (\k v -> [k, v]) keyPatterns valuePatterns - in patternWith (valueToSubjectForGram (VMap Map.empty)) elements + in pattern (valueToSubjectForGram (VMap Map.empty)) elements valueToPatternSubjectForGram (VSet s) = -- Serialize set as pattern with elements: each element as a Pattern Subject let elements = map valueToPatternSubjectForGram (Set.toList s) - in patternWith (valueToSubjectForGram (VSet Set.empty)) elements -valueToPatternSubjectForGram (VList vs) = patternWith + in pattern (valueToSubjectForGram (VSet Set.empty)) elements +valueToPatternSubjectForGram (VList vs) = pattern (valueToSubjectForGram (VList [])) (map valueToPatternSubjectForGram vs) valueToPatternSubjectForGram (VPattern pat) = -- A VPattern value is semantically a Pattern Subject with label "Pattern" -- containing the inner pattern as an element. -- Example: (pattern 42) → [:Pattern | [:Number {value: 42}]] - patternWith (Subject { identity = SubjectCore.Symbol "", labels = Set.fromList ["Pattern"], properties = Map.empty }) [pat] -valueToPatternSubjectForGram (VPrimitive prim) = pattern $ valueToSubjectForGram (VPrimitive prim) + pattern (Subject { identity = SubjectCore.Symbol "", labels = Set.fromList ["Pattern"], properties = Map.empty }) [pat] +valueToPatternSubjectForGram (VPrimitive prim) = point $ valueToSubjectForGram (VPrimitive prim) valueToPatternSubjectForGram (VClosure closure) = closureToPatternSubject closure -- | Internal version that uses State monad for scope ID generation -- This allows nested closures to share the same counter for unique IDs valueToPatternSubjectForGramWithState :: Value -> ScopeIdState (Pattern Subject) -valueToPatternSubjectForGramWithState (VNumber n) = return $ pattern $ valueToSubjectForGram (VNumber n) -valueToPatternSubjectForGramWithState (VString s) = return $ pattern $ valueToSubjectForGram (VString s) -valueToPatternSubjectForGramWithState (VBool b) = return $ pattern $ valueToSubjectForGram (VBool b) -valueToPatternSubjectForGramWithState (VKeyword name) = return $ pattern $ valueToSubjectForGram (VKeyword name) +valueToPatternSubjectForGramWithState (VNumber n) = return $ point $ valueToSubjectForGram (VNumber n) +valueToPatternSubjectForGramWithState (VString s) = return $ point $ valueToSubjectForGram (VString s) +valueToPatternSubjectForGramWithState (VBool b) = return $ point $ valueToSubjectForGram (VBool b) +valueToPatternSubjectForGramWithState (VKeyword name) = return $ point $ valueToSubjectForGram (VKeyword name) valueToPatternSubjectForGramWithState (VMap m) = return $ valueToPatternSubjectForGram (VMap m) valueToPatternSubjectForGramWithState (VSet s) = return $ valueToPatternSubjectForGram (VSet s) valueToPatternSubjectForGramWithState (VList vs) = do elementPatterns <- mapM valueToPatternSubjectForGramWithState vs - return $ patternWith + return $ pattern (Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["List"] @@ -632,7 +632,7 @@ valueToPatternSubjectForGramWithState (VList vs) = do elementPatterns valueToPatternSubjectForGramWithState (VPattern pat) = -- VPattern wraps a Pattern Subject - we need to wrap it with :Pattern label - return $ patternWith + return $ pattern (Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Pattern"] @@ -640,7 +640,7 @@ valueToPatternSubjectForGramWithState (VPattern pat) = }) [pat] valueToPatternSubjectForGramWithState (VClosure closure) = closureToPatternSubjectWithState closure -valueToPatternSubjectForGramWithState (VPrimitive prim) = return $ pattern $ valueToSubjectForGram (VPrimitive prim) +valueToPatternSubjectForGramWithState (VPrimitive prim) = return $ point $ valueToSubjectForGram (VPrimitive prim) -- | Converts a Pattern Subject back to a Value. -- This is the inverse of valueToPatternSubject. @@ -742,7 +742,7 @@ exprToPatternSubjectPure (List exprs) = , properties = Map.empty } elementPatterns = map exprToPatternSubjectPure [cond, thenExpr, elseExpr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "let")):bindingsExpr:bodyExpr:[] -> -- Let special form: [:Let | bindings, body] let decoration = Subject @@ -751,7 +751,7 @@ exprToPatternSubjectPure (List exprs) = , properties = Map.empty } elementPatterns = map exprToPatternSubjectPure [bindingsExpr, bodyExpr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "begin")):rest -> -- Begin special form: [:Begin | expr1, expr2, ...] let decoration = Subject @@ -760,7 +760,7 @@ exprToPatternSubjectPure (List exprs) = , properties = Map.empty } elementPatterns = map exprToPatternSubjectPure rest - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "define")):nameExpr:valueExpr:[] -> -- Define special form: [:Define | name, value] let decoration = Subject @@ -769,7 +769,7 @@ exprToPatternSubjectPure (List exprs) = , properties = Map.empty } elementPatterns = map exprToPatternSubjectPure [nameExpr, valueExpr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "quote")):expr:[] -> -- Quote special form: [:Quote | expr] let decoration = Subject @@ -778,7 +778,7 @@ exprToPatternSubjectPure (List exprs) = , properties = Map.empty } elementPatterns = [exprToPatternSubjectPure expr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns _ -> -- Regular function call or list: [:List | ...] let decoration = Subject @@ -787,7 +787,7 @@ exprToPatternSubjectPure (List exprs) = , properties = Map.empty } elementPatterns = map exprToPatternSubjectPure exprs - in patternWith decoration elementPatterns + in pattern decoration elementPatterns exprToPatternSubjectPure (Quote expr) = -- Quote expression: [:Quote | expr] let decoration = Subject @@ -796,11 +796,11 @@ exprToPatternSubjectPure (Quote expr) = , properties = Map.empty } elementPatterns = [exprToPatternSubjectPure expr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns exprToPatternSubjectPure expr = -- For atoms: convert to Subject, then wrap in atomic pattern let subject = exprToSubject expr - pat = pattern subject + pat = point subject in pat -- | Binding information for serialization @@ -873,12 +873,12 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , labels = Set.fromList ["Symbol"] , properties = Map.fromList [("name", SubjectValue.VString name)] } - in pattern subject + in point subject else case Map.lookup name bindingMap' of Just identifier -> -- Bound variable: create identifier reference pattern -- Identifier reference is a pattern with just the identifier (empty labels) - pattern $ Subject + point $ Subject { identity = identifier , labels = Set.empty , properties = Map.empty @@ -890,7 +890,7 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , labels = Set.fromList ["Symbol"] , properties = Map.fromList [("name", SubjectValue.VString name)] } - in pattern subject + in point subject -- Lists: handle special forms and function calls List exprs' -> case exprs' of @@ -901,7 +901,7 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , properties = Map.empty } elementPatterns = map (\e -> transformExprWithBindings e bindingMap' paramNames') [cond, thenExpr, elseExpr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "let")):bindingsExpr:bodyExpr:[] -> let decoration = Subject { identity = SubjectCore.Symbol "" @@ -909,7 +909,7 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , properties = Map.empty } elementPatterns = map (\e -> transformExprWithBindings e bindingMap' paramNames') [bindingsExpr, bodyExpr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "begin")):rest -> let decoration = Subject { identity = SubjectCore.Symbol "" @@ -917,7 +917,7 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , properties = Map.empty } elementPatterns = map (\e -> transformExprWithBindings e bindingMap' paramNames') rest - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "define")):nameExpr:valueExpr:[] -> let decoration = Subject { identity = SubjectCore.Symbol "" @@ -925,7 +925,7 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , properties = Map.empty } elementPatterns = map (\e -> transformExprWithBindings e bindingMap' paramNames') [nameExpr, valueExpr] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns (Atom (Symbol "quote")):expr'':[] -> let decoration = Subject { identity = SubjectCore.Symbol "" @@ -933,7 +933,7 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , properties = Map.empty } elementPatterns = [transformExprWithBindings expr'' bindingMap' paramNames'] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns _ -> -- Regular function call or list let decoration = Subject @@ -942,7 +942,7 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , properties = Map.empty } elementPatterns = map (\e -> transformExprWithBindings e bindingMap' paramNames') exprs' - in patternWith decoration elementPatterns + in pattern decoration elementPatterns -- Quote: transform the inner expression Quote expr'' -> let decoration = Subject @@ -951,11 +951,11 @@ exprToPatternSubjectWithBindings expr bindingMap paramNames , properties = Map.empty } elementPatterns = [transformExprWithBindings expr'' bindingMap' paramNames'] - in patternWith decoration elementPatterns + in pattern decoration elementPatterns -- Other atoms: convert normally _ -> let subject = exprToSubject expr' - in pattern subject + in point subject -- | State for tracking scope ID generation type ScopeIdState = State Int @@ -989,18 +989,18 @@ closureToPatternSubjectWithState (Closure paramNames bodyExpr capturedEnv) = do bodyPattern = exprToPatternSubjectWithBindings bodyExpr bindingMap paramNames -- Create parameters pattern with parameter names as elements -- Each parameter is a Symbol pattern - paramPatterns = map (\name -> pattern $ Subject + paramPatterns = map (\name -> point $ Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Symbol"] , properties = Map.fromList [("name", SubjectValue.VString name)] }) paramNames paramsPattern = if null paramPatterns - then pattern $ Subject + then point $ Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Parameters"] , properties = Map.empty } - else patternWith + else pattern (Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Parameters"] @@ -1017,7 +1017,7 @@ closureToPatternSubjectWithState (Closure paramNames bodyExpr capturedEnv) = do -- For nested closures: When a closure captures another closure, the captured closure's -- scope should reference the capturing closure's scope as its parent to preserve -- the lexical scope hierarchy. - parentScopeRef = pattern $ Subject + parentScopeRef = point $ Subject { identity = SubjectCore.Symbol "" -- Empty identity = program-level , labels = Set.empty , properties = Map.empty @@ -1044,19 +1044,19 @@ closureToPatternSubjectWithState (Closure paramNames bodyExpr capturedEnv) = do case nestedScopeElements of [] -> return nestedClosurePat -- Shouldn't happen (_oldParentRef : nestedBindings) -> do - let newParentRef = pattern $ Subject + let newParentRef = point $ Subject { identity = scopeId -- Reference to this closure's scope , labels = Set.empty , properties = Map.empty } newNestedScopeElements = newParentRef : nestedBindings - newNestedScopePat = patternWith nestedScopeSubj newNestedScopeElements + newNestedScopePat = pattern nestedScopeSubj newNestedScopeElements newNestedElements = newNestedScopePat : restNestedElements - return $ patternWith (PatternCore.value nestedClosurePat) newNestedElements + return $ pattern (PatternCore.value nestedClosurePat) newNestedElements _ -> do -- Not a closure - serialize normally valueToPatternSubjectForGramWithState (bindingValue bi) - return $ patternWith + return $ pattern (Subject { identity = bindingIdentifier bi , labels = Set.fromList ["Binding"] @@ -1067,7 +1067,7 @@ closureToPatternSubjectWithState (Closure paramNames bodyExpr capturedEnv) = do -- Build :Scope pattern elements: [parent_ref, binding1, binding2, ...] -- Always include parent reference (even if empty for program-level) let scopeElements = parentScopeRef : bindingPatterns - scopePattern = patternWith + scopePattern = pattern (Subject { identity = scopeId , labels = Set.fromList ["Scope"] @@ -1075,14 +1075,14 @@ closureToPatternSubjectWithState (Closure paramNames bodyExpr capturedEnv) = do }) scopeElements -- Create lambda pattern with parameters and body - lambdaPattern = patternWith + lambdaPattern = pattern (Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Lambda"] , properties = Map.empty }) [paramsPattern, bodyPattern] - return $ patternWith + return $ pattern (Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Closure"] @@ -1429,7 +1429,7 @@ extractParamName pat = do programToGram :: [Value] -> Env -> String programToGram values _runtimeEnv = -- Create file-level property record pattern - let fileMetadata = patternWith + let fileMetadata = pattern (Subject { identity = SubjectCore.Symbol "" , labels = Set.empty diff --git a/src/PatternLisp/Eval.hs b/src/PatternLisp/Eval.hs index c2b8753..0beed60 100644 --- a/src/PatternLisp/Eval.hs +++ b/src/PatternLisp/Eval.hs @@ -222,13 +222,14 @@ applyPrimitive Substring args = case args of then throwError $ TypeMismatch "Invalid substring indices" (VList []) else return $ VString $ T.take (endIdx - startIdx) $ T.drop startIdx str _ -> throwError $ ArityMismatch "substring" 3 (length args) -applyPrimitive PatternCreate args = case args of +applyPrimitive Pure args = case args of [val] -> evalPatternCreate val - _ -> throwError $ ArityMismatch "pattern" 1 (length args) -applyPrimitive PatternWith args = case args of + _ -> throwError $ ArityMismatch "pure" 1 (length args) +applyPrimitive PatternCreate args = case args of [decoration, VList elements] -> evalPatternWith decoration elements - [_, _] -> throwError $ TypeMismatch "pattern-with expects list of elements as second argument" (VList []) - _ -> throwError $ ArityMismatch "pattern-with" 2 (length args) + [_] -> throwError $ ArityMismatch "pattern" 2 (length args) + [_, _] -> throwError $ TypeMismatch "pattern expects list of elements as second argument" (VList []) + _ -> throwError $ ArityMismatch "pattern" 2 (length args) -- Pattern query primitives applyPrimitive PatternValue args = case args of [VPattern pat] -> evalPatternValue pat diff --git a/src/PatternLisp/Gram.hs b/src/PatternLisp/Gram.hs index 3a35f87..aaa9bda 100644 --- a/src/PatternLisp/Gram.hs +++ b/src/PatternLisp/Gram.hs @@ -24,7 +24,7 @@ module PatternLisp.Gram import PatternLisp.Syntax import PatternLisp.Codec import Pattern (Pattern) -import Pattern.Core (pattern) +import Pattern.Core (point) import qualified Pattern.Core as PatternCore import Subject.Core (Subject) import Gram.Serialize (toGram) @@ -61,7 +61,7 @@ gramToPattern = fromGram exprToGram :: Expr -> String exprToGram expr = let subject = exprToSubject expr - pat = pattern subject + pat = point subject in patternToGram pat -- | Deserialize gram notation string to an expression AST. diff --git a/src/PatternLisp/PatternPrimitives.hs b/src/PatternLisp/PatternPrimitives.hs index c3f3133..3e1263b 100644 --- a/src/PatternLisp/PatternPrimitives.hs +++ b/src/PatternLisp/PatternPrimitives.hs @@ -9,8 +9,8 @@ -- > import PatternLisp.PatternPrimitives -- > import PatternLisp.Eval -- > --- > evalPatternCreate (VString "hello") -- Creates atomic pattern --- > evalPatternWith (VString "root") [pattern1, pattern2] -- Creates pattern with elements +-- > evalPatternCreate (VString "hello") -- Creates atomic pattern (used by 'pure') +-- > evalPatternWith (VString "root") [pattern1, pattern2] -- Creates pattern with elements (used by 'pattern') module PatternLisp.PatternPrimitives ( evalPatternCreate , evalPatternWith @@ -28,7 +28,7 @@ module PatternLisp.PatternPrimitives import PatternLisp.Syntax import PatternLisp.Codec import Pattern (Pattern) -import Pattern.Core (pattern, patternWith) +import Pattern.Core (point, pattern) import qualified Pattern.Core as PatternCore import Subject.Core (Subject(..)) import qualified Subject.Core as SubjectCore @@ -57,11 +57,11 @@ exprToPatternSubject (List exprs) = do } -- Convert each element Expr to Pattern Subject recursively elementPatterns <- mapM exprToPatternSubject exprs - return $ patternWith decoration elementPatterns + return $ pattern decoration elementPatterns exprToPatternSubject expr = do -- For atoms and other Exprs: convert to Subject, then wrap in atomic pattern let subject = exprToSubject expr - pat = pattern subject + pat = point subject return pat -- | Creates an atomic Pattern from a Value. @@ -87,7 +87,7 @@ evalPatternWith decorationVal elementVals = do -- Convert elements: expect VPattern values patternElements <- mapM expectPattern elementVals -- Create pattern with elements - let pat = patternWith decoration patternElements + let pat = pattern decoration patternElements return $ VPattern pat -- | Helper to extract Pattern from Value, or convert Value to Pattern @@ -153,7 +153,7 @@ evalPatternValues pat = do -- This enables all s-expressions to be represented as Pattern Subject. -- -- * VPattern: Returns the pattern directly --- * VList: Converts to pattern-with with elements (empty list becomes atomic pattern) +-- * VList: Converts to pattern with elements (empty list becomes atomic pattern) -- * Other values: Converts to Subject and wraps in atomic pattern valueToPatternSubject :: Value -> EvalM (Pattern Subject) valueToPatternSubject (VPattern pat) = return pat @@ -164,9 +164,9 @@ valueToPatternSubject (VList []) = do , labels = Set.fromList ["List"] , properties = Map.empty } - return $ pattern emptySubject + return $ point emptySubject valueToPatternSubject (VList (v:vs)) = do - -- Non-empty list: convert to pattern-with + -- Non-empty list: convert to pattern with elements -- Decoration is empty Subject, elements are recursively converted let emptySubject = SubjectCore.Subject { identity = SubjectCore.Symbol "" @@ -175,7 +175,7 @@ valueToPatternSubject (VList (v:vs)) = do } -- Convert each element to Pattern Subject recursively elementPatterns <- mapM valueToPatternSubject (v:vs) - return $ patternWith emptySubject elementPatterns + return $ pattern emptySubject elementPatterns valueToPatternSubject (VClosure (Closure paramNames bodyExpr _capturedEnv)) = do -- Serialize Closure as Pattern Subject: -- - Decoration: Subject with labels ["Closure"] and properties {params: [...]} @@ -189,7 +189,7 @@ valueToPatternSubject (VClosure (Closure paramNames bodyExpr _capturedEnv)) = do } -- Convert body Expr to Pattern Subject (Expr is an s-expression, so it can be Pattern Subject) bodyPattern <- exprToPatternSubject bodyExpr - return $ patternWith decoration [bodyPattern] + return $ pattern decoration [bodyPattern] valueToPatternSubject val = do -- For atoms and other values: use Gram serialization approach -- This ensures consistency with serialization format diff --git a/src/PatternLisp/Primitives.hs b/src/PatternLisp/Primitives.hs index 1efa468..3b05c6c 100644 --- a/src/PatternLisp/Primitives.hs +++ b/src/PatternLisp/Primitives.hs @@ -5,7 +5,7 @@ -- * Arithmetic: +, -, *, / -- * Comparison: >, <, =, /= -- * String operations: string-append, string-length, substring --- * Pattern construction: pattern, pattern-with +-- * Pattern construction: pure (atomic), pattern (with elements) -- -- The initial environment is used as the starting point for evaluation -- and can be extended with user-defined bindings via 'define'. @@ -46,8 +46,8 @@ initialEnv = Map.fromList , ("string-append", VPrimitive StringAppend) , ("string-length", VPrimitive StringLength) , ("substring", VPrimitive Substring) + , ("pure", VPrimitive Pure) , ("pattern", VPrimitive PatternCreate) - , ("pattern-with", VPrimitive PatternWith) , ("pattern-value", VPrimitive PatternValue) , ("pattern-elements", VPrimitive PatternElements) , ("pattern-length", VPrimitive PatternLength) diff --git a/src/PatternLisp/Syntax.hs b/src/PatternLisp/Syntax.hs index 332c0de..f6c535f 100644 --- a/src/PatternLisp/Syntax.hs +++ b/src/PatternLisp/Syntax.hs @@ -143,8 +143,8 @@ data Primitive | Gt | Lt | Eq | Ne -- ^ Comparison | StringAppend | StringLength | Substring -- ^ String operations -- Pattern construction - | PatternCreate -- ^ (pattern value) - | PatternWith -- ^ (pattern-with value elements) + | Pure -- ^ (pure value) - creates atomic pattern + | PatternCreate -- ^ (pattern value elements) - creates pattern with elements -- Pattern queries | PatternValue -- ^ (pattern-value p) | PatternElements -- ^ (pattern-elements p) @@ -203,8 +203,8 @@ primitiveName Ne = "/=" primitiveName StringAppend = "string-append" primitiveName StringLength = "string-length" primitiveName Substring = "substring" +primitiveName Pure = "pure" primitiveName PatternCreate = "pattern" -primitiveName PatternWith = "pattern-with" primitiveName PatternValue = "pattern-value" primitiveName PatternElements = "pattern-elements" primitiveName PatternLength = "pattern-length" @@ -245,8 +245,8 @@ primitiveFromName "/=" = Just Ne primitiveFromName "string-append" = Just StringAppend primitiveFromName "string-length" = Just StringLength primitiveFromName "substring" = Just Substring +primitiveFromName "pure" = Just Pure primitiveFromName "pattern" = Just PatternCreate -primitiveFromName "pattern-with" = Just PatternWith primitiveFromName "pattern-value" = Just PatternValue primitiveFromName "pattern-elements" = Just PatternElements primitiveFromName "pattern-length" = Just PatternLength diff --git a/test/PatternLisp/CodecSpec.hs b/test/PatternLisp/CodecSpec.hs index 5472ac2..953530c 100644 --- a/test/PatternLisp/CodecSpec.hs +++ b/test/PatternLisp/CodecSpec.hs @@ -9,7 +9,7 @@ import PatternLisp.Codec (valueToPatternSubjectForGram, patternSubjectToValue, e import PatternLisp.Gram (patternToGram, gramToPattern) import PatternLisp.Syntax (Error(..), MapKey(..), KeywordKey(..)) import Pattern (Pattern) -import Pattern.Core (pattern, patternWith) +import Pattern.Core (point, pattern) import qualified Pattern.Core as PatternCore import Subject.Core (Subject(..)) import qualified Subject.Core as SubjectCore @@ -20,7 +20,7 @@ import qualified Data.Set as Set -- Helper to create a simple Pattern Subject for testing createTestPattern :: String -> Pattern Subject -createTestPattern s = pattern $ Subject +createTestPattern s = point $ Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["String"] , properties = Map.fromList [("text", SubjectValue.VString s)] @@ -159,7 +159,7 @@ spec = describe "PatternLisp.Codec - Complete Value Serialization" $ do it "missing primitive in registry errors correctly" $ do -- Create a pattern with an invalid primitive name - let invalidPat = pattern $ Subject + let invalidPat = point $ Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Primitive"] , properties = Map.fromList [("name", SubjectValue.VString "invalid-primitive")] @@ -286,7 +286,7 @@ spec = describe "PatternLisp.Codec - Complete Value Serialization" $ do describe "Error handling" $ do it "invalid pattern structures error correctly" $ do -- Test with missing properties in Number pattern - let invalidPat = pattern $ Subject + let invalidPat = point $ Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["Number"] , properties = Map.empty -- Missing "value" property diff --git a/test/PatternLisp/GramSerializationSpec.hs b/test/PatternLisp/GramSerializationSpec.hs index ff7d1c3..93a5b51 100644 --- a/test/PatternLisp/GramSerializationSpec.hs +++ b/test/PatternLisp/GramSerializationSpec.hs @@ -9,7 +9,7 @@ import PatternLisp.Gram import PatternLisp.PatternPrimitives import PatternLisp.Codec (patternSubjectToValue, valueToPatternSubjectForGram, programToGram, gramToProgram) import Pattern (Pattern) -import Pattern.Core (pattern, patternWith) +import Pattern.Core (point, pattern) import qualified Pattern.Core as PatternCore import Subject.Core (Subject) import qualified Subject.Core as SubjectCore @@ -228,7 +228,7 @@ spec = describe "PatternLisp.GramSerializationSpec - Gram Serialization" $ do describe "Round-trip: Complex structures" $ do it "pattern containing closures round-trips" $ do -- Create a pattern containing a closure - case parseExpr "(let ((f (lambda (x) (+ x 1)))) (pattern f))" of + case parseExpr "(let ((f (lambda (x) (+ x 1)))) (pure f))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err2 -> fail $ "Eval error: " ++ show err2 @@ -411,7 +411,7 @@ spec = describe "PatternLisp.GramSerializationSpec - Gram Serialization" $ do it "missing primitive in registry errors correctly" $ do -- Test that deserializing unknown primitive returns error -- Create a pattern with an unknown primitive name - let unknownPrimitivePat = patternWith + let unknownPrimitivePat = pattern (SubjectCore.Subject { SubjectCore.identity = SubjectCore.Symbol "" , SubjectCore.labels = Set.fromList ["Primitive"] diff --git a/test/PatternLisp/GramSpec.hs b/test/PatternLisp/GramSpec.hs index 45cdedc..e2e38df 100644 --- a/test/PatternLisp/GramSpec.hs +++ b/test/PatternLisp/GramSpec.hs @@ -9,7 +9,7 @@ import PatternLisp.PatternPrimitives import PatternLisp.Gram import PatternLisp.Codec import Pattern (Pattern) -import Pattern.Core (pattern, patternWith) +import Pattern.Core (point, pattern) import qualified Pattern.Core as PatternCore import Subject.Core (Subject(..), Symbol(..)) import qualified Subject.Core as SubjectCore @@ -22,7 +22,7 @@ import Control.Monad.Except (runExcept) -- | Helper to create a simple test pattern createTestPattern :: String -> Pattern Subject -createTestPattern str = pattern $ SubjectCore.Subject +createTestPattern str = point $ SubjectCore.Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["String"] , properties = Map.fromList [("text", SubjectValue.VString str)] @@ -52,7 +52,7 @@ spec = describe "PatternLisp.Gram - Gram Serialization" $ do } element1 = createTestPattern "child1" element2 = createTestPattern "child2" - pat = patternWith decoration [element1, element2] + pat = pattern decoration [element1, element2] gramText = patternToGram pat case gramToPattern gramText of Left err -> fail $ "Parse error: " ++ show err @@ -127,7 +127,7 @@ spec = describe "PatternLisp.Gram - Gram Serialization" $ do , labels = labelSet , properties = Map.fromList [("name", SubjectValue.VString "Alice")] } - pat = pattern subject + pat = point subject gramText = patternToGram pat -- Round-trip through gram notation case gramToPattern gramText of diff --git a/test/PatternLisp/PatternSpec.hs b/test/PatternLisp/PatternSpec.hs index c7eece8..c2c3f24 100644 --- a/test/PatternLisp/PatternSpec.hs +++ b/test/PatternLisp/PatternSpec.hs @@ -10,8 +10,8 @@ import qualified Data.Text as T spec :: Spec spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do describe "Pattern construction" $ do - it "pattern construction creates atomic pattern" $ do - case parseExpr "(pattern \"hello\")" of + it "pure creates atomic pattern" $ do + case parseExpr "(pure \"hello\")" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -19,8 +19,8 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do VPattern _ -> True `shouldBe` True _ -> fail $ "Expected VPattern, got: " ++ show val - it "pattern-with creates pattern with elements" $ do - case parseExpr "(pattern-with \"root\" '())" of + it "pattern creates pattern with elements" $ do + case parseExpr "(pattern \"root\" '())" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -30,14 +30,14 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do describe "Pattern queries" $ do it "pattern-value extracts decoration correctly" $ do - case parseExpr "(pattern-value (pattern \"hello\"))" of + case parseExpr "(pattern-value (pure \"hello\"))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err Right val -> val `shouldBe` VString (T.pack "hello") it "pattern-elements returns list of VPattern elements" $ do - case parseExpr "(pattern-elements (pattern-with \"root\" '()))" of + case parseExpr "(pattern-elements (pattern \"root\" '()))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -46,28 +46,28 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do _ -> fail $ "Expected empty list, got: " ++ show val it "pattern-length returns correct direct element count" $ do - case parseExpr "(pattern-length (pattern-with \"root\" '()))" of + case parseExpr "(pattern-length (pattern \"root\" '()))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err Right val -> val `shouldBe` VNumber 0 it "pattern-size counts all nodes recursively" $ do - case parseExpr "(pattern-size (pattern \"hello\"))" of + case parseExpr "(pattern-size (pure \"hello\"))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err Right val -> val `shouldBe` VNumber 1 it "pattern-depth returns max depth correctly" $ do - case parseExpr "(pattern-depth (pattern \"hello\"))" of + case parseExpr "(pattern-depth (pure \"hello\"))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err Right val -> val `shouldBe` VNumber 0 it "pattern-values flattens all values" $ do - case parseExpr "(pattern-values (pattern \"hello\"))" of + case parseExpr "(pattern-values (pure \"hello\"))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -77,9 +77,9 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do it "nested patterns work correctly" $ do -- Test with a pattern containing another pattern - -- Use pattern-with with empty list for now (nested pattern construction + -- Use pattern with empty list for now (nested pattern construction -- with multiple elements will be tested when list primitives are available) - case parseExpr "(let ((p1 (pattern \"child\"))) (pattern-with \"root\" '()))" of + case parseExpr "(let ((p1 (pure \"child\"))) (pattern \"root\" '()))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -104,7 +104,7 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do Left err -> fail $ "Unexpected error: " ++ show err Right _ -> fail "Expected ArityMismatch error" - case parseExpr "(pattern-elements (pattern \"a\") (pattern \"b\"))" of + case parseExpr "(pattern-elements (pure \"a\") (pure \"b\"))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left (ArityMismatch _ _ _) -> True `shouldBe` True @@ -114,7 +114,7 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do describe "Pattern predicates" $ do it "pattern-find finds matching subpattern" $ do -- Test pattern-find on atomic pattern that matches (using numbers since = only works for numbers) - case parseExpr "(pattern-find (pattern 42) (lambda (p) (= (pattern-value p) 42)))" of + case parseExpr "(pattern-find (pure 42) (lambda (p) (= (pattern-value p) 42)))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -124,7 +124,7 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do it "pattern-find returns nothing if no match" $ do -- Test pattern-find on atomic pattern that doesn't match - case parseExpr "(pattern-find (pattern 1) (lambda (p) (= (pattern-value p) 3)))" of + case parseExpr "(pattern-find (pure 1) (lambda (p) (= (pattern-value p) 3)))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -134,7 +134,7 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do it "pattern-any? checks existence correctly" $ do -- Test pattern-any? on atomic pattern that matches - case parseExpr "(pattern-any? (pattern 42) (lambda (p) (= (pattern-value p) 42)))" of + case parseExpr "(pattern-any? (pure 42) (lambda (p) (= (pattern-value p) 42)))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -142,7 +142,7 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do it "pattern-all? checks universal property correctly" $ do -- Test pattern-all? on atomic pattern - case parseExpr "(pattern-all? (pattern 10) (lambda (p) (= (pattern-value p) 10)))" of + case parseExpr "(pattern-all? (pure 10) (lambda (p) (= (pattern-value p) 10)))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -151,14 +151,14 @@ spec = describe "PatternLisp.Pattern - Pattern as First-Class Value" $ do it "pattern predicates work with closures" $ do -- Test that predicates can be closures with captured environment -- Use nested let to define variables in sequence - case parseExpr "(let ((target-val 42)) (let ((pred (lambda (p) (= (pattern-value p) target-val)))) (let ((p1 (pattern target-val))) (pattern-any? p1 pred))))" of + case parseExpr "(let ((target-val 42)) (let ((pred (lambda (p) (= (pattern-value p) target-val)))) (let ((p1 (pure target-val))) (pattern-any? p1 pred))))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err Right val -> val `shouldBe` VBool True it "pattern-find type error for non-closure predicate" $ do - case parseExpr "(pattern-find (pattern 1) \"not-a-closure\")" of + case parseExpr "(pattern-find (pure 1) \"not-a-closure\")" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left (TypeMismatch _ _) -> True `shouldBe` True diff --git a/test/PatternLisp/PrimitivesSpec.hs b/test/PatternLisp/PrimitivesSpec.hs index ac9bfe4..42f6d2d 100644 --- a/test/PatternLisp/PrimitivesSpec.hs +++ b/test/PatternLisp/PrimitivesSpec.hs @@ -126,8 +126,8 @@ spec = describe "PatternLisp.Primitives and PatternLisp.Eval" $ do Right _ -> fail "Expected ArityMismatch error" describe "Pattern construction operations" $ do - it "evaluates pattern construction (pattern \"hello\")" $ do - case parseExpr "(pattern \"hello\")" of + it "evaluates pure construction (pure \"hello\")" $ do + case parseExpr "(pure \"hello\")" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -135,8 +135,8 @@ spec = describe "PatternLisp.Primitives and PatternLisp.Eval" $ do VPattern _ -> True `shouldBe` True _ -> fail $ "Expected VPattern, got: " ++ show val - it "evaluates pattern-with construction (pattern-with \"root\" '())" $ do - case parseExpr "(pattern-with \"root\" '())" of + it "evaluates pattern construction (pattern \"root\" '())" $ do + case parseExpr "(pattern \"root\" '())" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left err -> fail $ "Eval error: " ++ show err @@ -144,28 +144,28 @@ spec = describe "PatternLisp.Primitives and PatternLisp.Eval" $ do VPattern _ -> True `shouldBe` True _ -> fail $ "Expected VPattern, got: " ++ show val - -- Note: Testing pattern-with with multiple elements requires list construction + -- Note: Testing pattern with multiple elements requires list construction -- primitives that aren't yet available. This will be tested more comprehensively -- in Phase 3 when pattern query operations are implemented. - it "handles pattern arity mismatch" $ do - case parseExpr "(pattern)" of + it "handles pure arity mismatch" $ do + case parseExpr "(pure)" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left (ArityMismatch _ _ _) -> True `shouldBe` True Left err -> fail $ "Unexpected error: " ++ show err Right _ -> fail "Expected ArityMismatch error" - it "handles pattern-with arity mismatch" $ do - case parseExpr "(pattern-with \"root\")" of + it "handles pattern arity mismatch (missing elements)" $ do + case parseExpr "(pattern \"root\")" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left (ArityMismatch _ _ _) -> True `shouldBe` True Left err -> fail $ "Unexpected error: " ++ show err Right _ -> fail "Expected ArityMismatch error" - it "handles pattern-with type error for non-list second argument" $ do - case parseExpr "(pattern-with \"root\" \"not-a-list\")" of + it "handles pattern type error for non-list second argument" $ do + case parseExpr "(pattern \"root\" \"not-a-list\")" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case evalExpr expr initialEnv of Left (TypeMismatch _ _) -> True `shouldBe` True diff --git a/test/PatternLisp/RuntimeSpec.hs b/test/PatternLisp/RuntimeSpec.hs index c9d673b..d4234ce 100644 --- a/test/PatternLisp/RuntimeSpec.hs +++ b/test/PatternLisp/RuntimeSpec.hs @@ -7,7 +7,7 @@ import PatternLisp.Eval import PatternLisp.Primitives import PatternLisp.Runtime import Pattern (Pattern) -import Pattern.Core (pattern) +import Pattern.Core (point, pattern) import qualified Pattern.Core as PatternCore import Subject.Core (Subject(..)) import qualified Subject.Core as SubjectCore @@ -18,7 +18,7 @@ import qualified Data.Set as Set -- Helper to create a simple Pattern Subject for testing createTestPattern :: String -> Pattern Subject -createTestPattern s = pattern $ Subject +createTestPattern s = point $ Subject { identity = SubjectCore.Symbol "" , labels = Set.fromList ["String"] , properties = Map.fromList [("text", SubjectValue.VString s)] @@ -78,8 +78,8 @@ spec = describe "PatternLisp.Runtime - Pure Function State Transformation" $ do properties inputSubj `shouldBe` properties outputSubj it "tool execution: tool transforms state correctly" $ do - -- Tool that adds a new element (simplified - using pattern-with) - case parseExpr "(lambda (state) (pattern-with \"transformed\" '()))" of + -- Tool that adds a new element (simplified - using pattern) + case parseExpr "(lambda (state) (pattern \"transformed\" '()))" of Left err -> fail $ "Parse error: " ++ show err Right expr -> case validateTool expr initialEnv of Left err -> fail $ "Validation error: " ++ show err