## Description The codebase currently couples the engine and plugins directly to `lambda.Expression`. This PR introduces an abstract `expr.Expression` interface to enable future support for multiple evaluation modes. - Add `pkg/expr/expr.go` with an `Expression` interface requiring a `String()` method. - Update `lambda.Expression` to embed `expr.Expression`. - Add `String()` method to `Abstraction`, `Application`, and `Variable` types. - Update plugins to use `String()` instead of `lambda.Stringify()`. ### Decisions - The `expr.Expression` interface is minimal (only `String()`) to avoid over-constraining future expression types. - The engine still stores `*lambda.Expression` directly rather than `expr.Expression`, because Go's interface semantics require pointer indirection for in-place mutation during reduction. - Future evaluation modes will implement their own concrete types satisfying `expr.Expression`. ## Benefits - Establishes a foundation for supporting multiple evaluation modes (SKI combinators, typed lambda calculus, etc.). - Plugins now use the abstract `String()` method, making them more decoupled from the lambda-specific implementation. - Prepares the codebase for a Reducer interface abstraction in a future PR. ## Checklist - [x] Code follows conventional commit format. - [x] Branch follows naming convention (`<type>/<description>`). - [x] Tests pass (if applicable). - [ ] Documentation updated (if applicable). Reviewed-on: #30 Co-authored-by: M.V. Hutz <git@maximhutz.me> Co-committed-by: M.V. Hutz <git@maximhutz.me>
68 lines
1.7 KiB
Go
68 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
|
|
"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/saccharine"
|
|
)
|
|
|
|
func main() {
|
|
// Parse CLI arguments.
|
|
options, err := config.FromArgs()
|
|
cli.HandleError(err)
|
|
|
|
logger := options.GetLogger()
|
|
logger.Info("using program arguments", "args", os.Args)
|
|
logger.Info("parsed CLI options", "options", options)
|
|
|
|
// Get input.
|
|
input, err := options.Source.Extract()
|
|
cli.HandleError(err)
|
|
|
|
// Parse code into syntax tree.
|
|
ast, err := saccharine.Parse(input)
|
|
cli.HandleError(err)
|
|
logger.Info("parsed syntax tree", "tree", ast)
|
|
|
|
// Compile expression to lambda calculus.
|
|
compiled := convert.SaccharineToLambda(ast)
|
|
logger.Info("compiled λ expression", "tree", compiled.String())
|
|
|
|
// Create reduction engine.
|
|
process := engine.New(options, &compiled)
|
|
|
|
// If the user selected to track CPU performance, attach a profiler to the
|
|
// process.
|
|
if options.Profile != "" {
|
|
plugins.NewPerformance(options.Profile, process)
|
|
}
|
|
|
|
// If the user selected to produce a step-by-step explanation, attach an
|
|
// observer here.
|
|
if options.Explanation {
|
|
plugins.NewExplanation(process)
|
|
}
|
|
|
|
// If the user opted to track statistics, attach a tracker here, too.
|
|
if options.Statistics {
|
|
plugins.NewStatistics(process)
|
|
}
|
|
|
|
// If the user selected for verbose debug logs, attach a reduction tracker.
|
|
if options.Verbose {
|
|
plugins.NewLogs(logger, process)
|
|
}
|
|
|
|
process.Run()
|
|
|
|
// Return the final reduced result.
|
|
result := (*process.Expression).String()
|
|
err = options.Destination.Write(result)
|
|
cli.HandleError(err)
|
|
}
|