refactor: move event system to reducer, remove engine package

Move the event emitter and lifecycle events from the engine into the reducer,
making the reducer the single point of orchestration for reduction.
This eliminates the engine package entirely.

- Add events.go to pkg/reducer with Start, Step, and Stop events.
- Extend Reducer interface to embed Emitter and add Expression() method.
- Update NormalOrderReducer to embed BaseEmitter and emit lifecycle events.
- Update all plugins to attach to Reducer instead of Engine.
- Remove internal/engine package.
- Add Off() method to BaseEmitter to complete Emitter interface.
- Fix Emitter.On signature to use generic type E instead of string.
This commit is contained in:
2026-01-16 18:50:52 -05:00
parent f8e1223463
commit bcc0331149
12 changed files with 99 additions and 112 deletions

View File

@@ -5,7 +5,6 @@ import (
"git.maximhutz.com/max/lambda/internal/cli"
"git.maximhutz.com/max/lambda/internal/config"
"git.maximhutz.com/max/lambda/internal/engine"
"git.maximhutz.com/max/lambda/internal/plugins"
"git.maximhutz.com/max/lambda/pkg/convert"
"git.maximhutz.com/max/lambda/pkg/lambda"
@@ -34,36 +33,35 @@ func main() {
compiled := convert.SaccharineToLambda(ast)
logger.Info("compiled λ expression", "tree", compiled.String())
// Create reduction engine with normal order reducer.
// Create reducer.
reducer := lambda.NewNormalOrderReducer()
process := engine.New(options, compiled, reducer)
// If the user selected to track CPU performance, attach a profiler to the
// process.
// If the user selected to track CPU performance, attach a profiler.
if options.Profile != "" {
plugins.NewPerformance(options.Profile, process)
plugins.NewPerformance(options.Profile, reducer)
}
// If the user selected to produce a step-by-step explanation, attach an
// observer here.
// observer.
if options.Explanation {
plugins.NewExplanation(process)
plugins.NewExplanation(reducer)
}
// If the user opted to track statistics, attach a tracker here, too.
// If the user opted to track statistics, attach a tracker.
if options.Statistics {
plugins.NewStatistics(process)
plugins.NewStatistics(reducer)
}
// If the user selected for verbose debug logs, attach a reduction tracker.
if options.Verbose {
plugins.NewLogs(logger, process)
plugins.NewLogs(logger, reducer)
}
process.Run()
// Run reduction.
reducer.Reduce(compiled)
// Return the final reduced result.
result := process.Expression.String()
result := reducer.Expression().String()
err = options.Destination.Write(result)
cli.HandleError(err)
}

View File

@@ -6,8 +6,6 @@ import (
"strings"
"testing"
"git.maximhutz.com/max/lambda/internal/config"
"git.maximhutz.com/max/lambda/internal/engine"
"git.maximhutz.com/max/lambda/pkg/convert"
"git.maximhutz.com/max/lambda/pkg/lambda"
"git.maximhutz.com/max/lambda/pkg/saccharine"
@@ -31,22 +29,11 @@ func runSample(samplePath string) (string, error) {
// Compile expression to lambda calculus.
compiled := convert.SaccharineToLambda(ast)
// Create minimal config for benchmarking.
cfg := &config.Config{
Source: config.StringSource{Data: ""},
Destination: config.StdoutDestination{},
Profile: "",
Explanation: false,
Statistics: false,
Verbose: false,
}
// Create and run the engine with normal order reducer.
// Create and run the reducer.
reducer := lambda.NewNormalOrderReducer()
process := engine.New(cfg, compiled, reducer)
process.Run()
reducer.Reduce(compiled)
return process.Expression.String() + "\n", nil
return reducer.Expression().String() + "\n", nil
}
// Test that all samples produce expected output.