Skip to content

Commit c89bdc4

Browse files
johnnytclaude
andauthored
Refactors datamodel (#49)
* Refactors datamodel Major changes: - Create dedicated Statifier.Datamodel module for all datamodel operations - Rename DataElement to Data for consistency with SCXML <data> elements - Extract common In() function setup to reduce code duplication - Consolidate datamodel tests into single comprehensive test file Datamodel module features: - Initialize datamodel from <data> elements with expression evaluation - Build evaluation contexts for conditions and expressions - Support for datamodel variable access (get/set/has/merge) - Proper event data merging as top-level variables in conditions - Session ID generation and SCXML built-in variables Code quality improvements: - Fix all credo consistency issues (meaningful unused variable names) - Eliminate duplicate code between ConditionEvaluator and ValueEvaluator - Extract common test setup with helper functions - Pass all dialyzer type checks with no errors - Achieve 0 credo issues with --strict flag Testing improvements: - Combine datamodel_test.exs and datamodel_init_test.exs - Add comprehensive edge case testing - Use setup blocks and helper functions to reduce duplication - All 361 tests passing with 91.2% coverage 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Improves context handling This refactor simplifies context building across evaluators and improves naming consistency: - Replace complex tuple-based context with direct StateChart parameter - Unify context building in `Datamodel.build_evaluation_context/2` - Eliminate redundant `|| %{}` checks (field is always a map) - Single source of truth for SCXML context preparation - Rename StateChart field: `data_model` → `datamodel` - Update helper function: `update_data_model/2` → `update_datamodel/2` - Use proper typing: `Statifier.Datamodel.t()` instead of generic `map()` - Consistent naming across codebase matches module name - Cleaner evaluator APIs: `evaluate_condition(compiled, state_chart)` - Remove complex context building from individual modules - Better type safety and Dialyzer compliance (0 warnings) - More intuitive parameter passing throughout - Reduced code duplication across evaluators - Better type documentation and IDE support - Simplified test code with cleaner StateChart initialization - All 566 tests passing with 91.9% coverage maintained 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Consolidates evaluators and improves datamodel - Consolidate ConditionEvaluator and ValueEvaluator into unified Statifier.Evaluator module - Move put_in_path function from Evaluator to Datamodel module for better separation of concerns - Update all imports across codebase to use new unified evaluator - Remove old evaluator modules and tests, create comprehensive consolidated test suite - Improve error handling in Datamodel.put_in_path with proper {:ok, result} | {:error, reason} pattern - Prepare architecture for future pluggable datamodel support (ECMAScript, XPath) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Adds new passing SCION and SCXML tests - Mark datamodel and data_elements as :supported in feature registry - Update feature detector tests to reflect new datamodel support status - Add 13 new passing tests to baseline (9 SCION, 4 W3C) - New test categories: assign actions, data model initialization, foreach loops, if/else control flow - Significant progress in SCXML compliance: 61/184 total tests now passing (33%) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Adds datamodel, evaluator improvements to docs - Document unified Statifier.Evaluator module consolidation - Detail enhanced Datamodel module with improved error handling - Record 13 new passing tests unlocked by these improvements - Track progress from 48/184 to 61/184 total tests passing (33% compliance) - Update feature detection improvements and test baseline changes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 39408bd commit c89bdc4

25 files changed

Lines changed: 1388 additions & 965 deletions

.githooks/pre-push

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ fi
6767

6868
# Run type checking (optional - can be slow)
6969
# Uncomment if you want type checking in the pre-push hook
70-
# echo "🔬 Running type checking (Dialyzer)..."
71-
# if ! mix dialyzer; then
72-
# echo "❌ Dialyzer type checking failed."
73-
# exit 1
74-
# fi
70+
echo "🔬 Running type checking (Dialyzer)..."
71+
if ! mix dialyzer; then
72+
echo "❌ Dialyzer type checking failed."
73+
exit 1
74+
fi
7575

7676
echo "✅ All validation checks passed! Ready to push."

CHANGELOG.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
#### Architecture Improvements
13+
14+
- **Unified `Statifier.Evaluator` Module**: Consolidated `ConditionEvaluator` and `ValueEvaluator` into single module
15+
- **Single Entry Point**: One module for all expression evaluation (conditions and values)
16+
- **Improved Maintainability**: Eliminated code duplication between evaluator modules
17+
- **Future Extensibility**: Better prepared for pluggable datamodel architectures (ECMAScript, XPath)
18+
- **Consistent API**: Unified function signatures and error handling patterns
19+
20+
- **Enhanced `Statifier.Datamodel` Module**: Improved data model operations and separation of concerns
21+
- **`put_in_path/3` Function**: Moved from Evaluator to Datamodel for better architecture
22+
- **Improved Error Handling**: Returns `{:ok, result} | {:error, reason}` instead of raising exceptions
23+
- **Type Safety**: Proper `Datamodel.t()` typing throughout the codebase
24+
- **Data Model Operations**: Centralized location for all data model manipulation logic
25+
26+
- **Feature Detection Updates**: Enhanced SCXML feature tracking for better test validation
27+
- **Datamodel Support**: Marked `:datamodel` and `:data_elements` as `:supported` in feature registry
28+
- **Accurate Test Results**: Prevents false test failures from unsupported feature detection
29+
- **Better Compliance Tracking**: Improved visibility into SCXML feature implementation status
30+
31+
### Changed
32+
33+
#### Test Coverage Improvements
34+
35+
- **13 New Passing Tests**: Unlocked additional test coverage through datamodel improvements
36+
- **9 SCION Tests**: Including assign actions, current small step assignments, data initialization
37+
- **4 W3C Tests**: Including executable content evaluation, foreach loops, conditional execution
38+
- **Test Categories**: `assign/`, `assign_current_small_step/`, `data/`, `foreach/`, `if_else/`
39+
- **Overall Progress**: Improved from 48/184 to 61/184 total tests passing (33% compliance)
40+
41+
- **Updated Test Baseline**: Added new passing tests to regression test suite
42+
- **SCION Tests**: 44 → 53 passing tests
43+
- **W3C Tests**: 5 → 9 passing tests
44+
- **Maintained Quality**: All 98 regression tests continue to pass
45+
1046
## [1.1.0] 2025-08-26
1147

1248
### Added
@@ -42,9 +78,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4278

4379
#### StateChart Data Model Enhancement
4480

45-
- **Data Model Storage**: Added `data_model` field to `Statifier.StateChart` for variable persistence
81+
- **Datamodel Storage**: Added `datamodel` field to `Statifier.StateChart` for variable persistence
4682
- **Current Event Context**: Added `current_event` field for expression evaluation context
47-
- **Helper Methods**: `update_data_model/2` and `set_current_event/2` for state management
83+
- **Helper Methods**: `update_datamodel/2` and `set_current_event/2` for state management
4884
- **SCXML Context Building**: Enhanced context building for comprehensive expression evaluation
4985

5086
#### Parser Extensions

CLAUDE.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Also use this initial Elixir implementation as reference: <https://github.com/ca
7171
- Built via `Document.build_lookup_maps/1` during validation phase
7272
- **`Statifier.State`** - Individual state with `id`, optional `initial` state, nested `states` list, and `transitions` list
7373
- **`Statifier.Transition`** - State transitions with optional `event`, `target`, and `cond` attributes
74-
- **`Statifier.DataElement`** - Datamodel elements with required `id` and optional `expr` and `src` attributes
74+
- **`Statifier.Data`** - Datamodel elements with required `id` and optional `expr` and `src` attributes
7575

7676
### Parsers (Parse Phase)
7777

@@ -124,7 +124,7 @@ Also use this initial Elixir implementation as reference: <https://github.com/ca
124124
- **`Statifier.StateChart`** - Runtime container for SCXML state machines
125125
- Combines document, configuration, event queues, and data model
126126
- Maintains internal and external event queues per SCXML specification
127-
- **Data model storage**: Persistent variable storage with `data_model` field
127+
- **Datamodel storage**: Persistent variable storage with `datamodel` field
128128
- **Current event context**: Tracks current event for expression evaluation
129129
- **`Statifier.Configuration`** - Active state configuration management
130130
- Stores only leaf states for efficient memory usage
@@ -207,7 +207,7 @@ The implementation follows a clean **Parse → Validate → Optimize** architect
207207

208208
All parsed SCXML elements include precise source location information for validation error reporting:
209209

210-
- **Element locations**: Each parsed element (`Statifier.Document`, `Statifier.State`, `Statifier.Transition`, `Statifier.DataElement`) includes a `source_location` field with line/column information
210+
- **Element locations**: Each parsed element (`Statifier.Document`, `Statifier.State`, `Statifier.Transition`, `Statifier.Data`) includes a `source_location` field with line/column information
211211
- **Attribute locations**: Individual attributes have dedicated location fields (e.g., `name_location`, `id_location`, `event_location`) for precise error reporting
212212
- **Multiline support**: Accurately tracks locations for both single-line and multiline XML element definitions
213213
- **SAX-based tracking**: Uses Saxy's event-driven parsing to maintain position information throughout the parsing process
@@ -332,7 +332,7 @@ XML content within triple quotes uses 4-space base indentation.
332332

333333
**Completed:**
334334

335-
- Core data structures (Document, State, Transition, DataElement) with location tracking
335+
- Core data structures (Document, State, Transition, Data) with location tracking
336336
- SCXML parser using Saxy SAX parser for accurate position tracking
337337
- **Parse → Validate → Optimize architecture** with clean separation of concerns
338338
- Complete interpreter infrastructure (Interpreter, StateChart, Configuration, Event, Validator)

README.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ The next major areas for development focus on expanding SCXML feature support:
107107
### **High Priority Features**
108108

109109
- **Executable Content** - `<script>` elements (`<onentry>`, `<onexit>`, `<assign>` now supported!)
110-
- **Datamodel Support** - `<data>` elements with expression evaluation
111110
- **History States** - Shallow and deep history state support
112111

113112
### **Medium Priority Features**
@@ -273,7 +272,7 @@ xml = """
273272
{:ok, state_chart} = Statifier.interpret(document)
274273

275274
# Check the data model after onentry execution
276-
data_model = state_chart.data_model
275+
datamodel = state_chart.datamodel
277276
# Returns: %{
278277
# "userName" => "John Doe",
279278
# "counter" => 43, # incremented to 43 in working state
@@ -306,7 +305,7 @@ The project maintains high code quality through automated checks:
306305
mix format # Auto-fix formatting
307306
mix test.regression # Run critical regression tests (22 tests)
308307
mix credo --strict # Static code analysis
309-
mix dialyzer # Type checking
308+
mix dialyzer # Type checking
310309
```
311310

312311
### Regression Testing
@@ -367,7 +366,7 @@ mix test test/statifier/parser/scxml_test.exs
367366
- **`Statifier.Document`** - Root SCXML document with states, metadata, and O(1) lookup maps
368367
- **`Statifier.State`** - Individual states with transitions and hierarchical nesting support
369368
- **`Statifier.Transition`** - State transitions with events and targets
370-
- **`Statifier.DataElement`** - Datamodel elements with expressions
369+
- **`Statifier.Data`** - Datamodel elements with expressions
371370

372371
### Architecture Flow
373372

@@ -486,7 +485,7 @@ git push origin feature-branch
486485
- All code is formatted with `mix format`
487486
- Static analysis with Credo (strict mode)
488487
- Type checking with Dialyzer
489-
- Comprehensive test coverage (95%+ maintained)
488+
- Comprehensive test coverage (90%+ maintained)
490489
- Detailed documentation with `@moduledoc` and `@doc`
491490
- Pattern matching preferred over multiple assertions in tests
492491
- Git pre-push hook enforces validation workflow automatically
@@ -500,5 +499,3 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
500499

501500
- [W3C SCXML Specification](https://www.w3.org/TR/scxml/) - Official specification
502501
- [SCION Test Suite](https://github.com/jbeard4/SCION) - Comprehensive test cases
503-
- [ex_statechart](https://github.com/camshaft/ex_statechart) - Reference implementation
504-

lib/statifier/actions/assign_action.ex

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ defmodule Statifier.Actions.AssignAction do
2727
2828
"""
2929

30-
alias Statifier.{StateChart, ValueEvaluator}
30+
alias Statifier.{Evaluator, StateChart}
3131

3232
require Logger
3333

@@ -73,7 +73,7 @@ defmodule Statifier.Actions.AssignAction do
7373

7474
# Safely compile expressions, returning nil on error
7575
defp compile_safe(expr, _type) do
76-
case ValueEvaluator.compile_expression(expr) do
76+
case Evaluator.compile_expression(expr) do
7777
{:ok, compiled} -> compiled
7878
{:error, _reason} -> nil
7979
end
@@ -82,7 +82,7 @@ defmodule Statifier.Actions.AssignAction do
8282
@doc """
8383
Execute the assign action by evaluating the expression and assigning to the location.
8484
85-
This uses Statifier.ValueEvaluator to:
85+
This uses Statifier.Evaluator to:
8686
1. Validate the assignment location path
8787
2. Evaluate the expression to get the value
8888
3. Perform the assignment in the data model
@@ -91,18 +91,16 @@ defmodule Statifier.Actions.AssignAction do
9191
"""
9292
@spec execute(t(), StateChart.t()) :: StateChart.t()
9393
def execute(%__MODULE__{} = assign_action, %StateChart{} = state_chart) do
94-
context = build_evaluation_context(state_chart)
95-
96-
# Use ValueEvaluator.evaluate_and_assign with pre-compiled expression if available
97-
case ValueEvaluator.evaluate_and_assign(
94+
# Use Evaluator.evaluate_and_assign with pre-compiled expression if available
95+
case Evaluator.evaluate_and_assign(
9896
assign_action.location,
9997
assign_action.expr,
100-
context,
98+
state_chart,
10199
assign_action.compiled_expr
102100
) do
103-
{:ok, updated_data_model} ->
104-
# Update the state chart with the new data model
105-
%{state_chart | data_model: updated_data_model}
101+
{:ok, updated_datamodel} ->
102+
# Update the state chart with the new datamodel
103+
%{state_chart | datamodel: updated_datamodel}
106104

107105
{:error, reason} ->
108106
# Log the error and continue without modification
@@ -114,13 +112,4 @@ defmodule Statifier.Actions.AssignAction do
114112
state_chart
115113
end
116114
end
117-
118-
# Build evaluation context for assign action execution
119-
defp build_evaluation_context(%StateChart{} = state_chart) do
120-
%{
121-
configuration: state_chart.configuration,
122-
current_event: state_chart.current_event,
123-
data_model: state_chart.data_model || %{}
124-
}
125-
end
126115
end

lib/statifier/condition_evaluator.ex

Lines changed: 0 additions & 143 deletions
This file was deleted.
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
defmodule Statifier.DataElement do
1+
defmodule Statifier.Data do
22
@moduledoc """
33
Represents a data element in an SCXML datamodel.
4+
5+
Corresponds to SCXML `<data>` elements which define variables in the state machine's datamodel.
6+
Each data element has an `id` (required) and optional `expr` or `src` for initialization.
47
"""
58

69
defstruct [

0 commit comments

Comments
 (0)