feat: move lambda reduction to "lambda reduce"
This commit is contained in:
@@ -4,8 +4,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"git.maximhutz.com/max/lambda/internal/config"
|
||||
)
|
||||
|
||||
func Lambda() *cobra.Command {
|
||||
@@ -14,73 +12,13 @@ func Lambda() *cobra.Command {
|
||||
Short: "Lambda calculus interpreter",
|
||||
Long: "A lambda calculus interpreter supporting multiple representations.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// Legacy behavior when no subcommand is given.
|
||||
options, err := config.FromArgs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger := options.GetLogger()
|
||||
logger.Info("using program arguments", "args", os.Args)
|
||||
logger.Info("parsed CLI options", "options", options)
|
||||
|
||||
r := GetRegistry()
|
||||
|
||||
// Get input.
|
||||
input, err := options.Source.Extract()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse code into syntax tree.
|
||||
repr, err := r.Unmarshal(input, "saccharine")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("parsed syntax tree", "tree", repr)
|
||||
|
||||
// Compile expression to lambda calculus.
|
||||
compiled, err := r.ConvertTo(repr, "lambda")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("compiled λ expression", "tree", compiled)
|
||||
|
||||
// Create reducer with the compiled expression.
|
||||
engine, err := r.GetDefaultEngine("lambda")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
process := engine.Load()
|
||||
err = process.Set(compiled)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run reduction.
|
||||
for process.Step(1) {
|
||||
}
|
||||
|
||||
// Return the final reduced result.
|
||||
result, err := process.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := r.Marshal(result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return options.Destination.Write(output)
|
||||
return cmd.Help()
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolP("verbose", "v", false, "Enable verbose output")
|
||||
|
||||
cmd.AddCommand(LambdaConvert())
|
||||
cmd.AddCommand(LambdaEngine())
|
||||
cmd.AddCommand(LambdaReduce())
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ func LambdaConvert() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&inputReprFlag, "input", "i", "", "Input representation (inferred from extension if unset)")
|
||||
cmd.Flags().StringVarP(&outputReprFlag, "output", "o", "", "Output representation (inferred from extension if unset)")
|
||||
cmd.Flags().StringVar(&inputReprFlag, "from", "", "Input representation (inferred from extension if unset)")
|
||||
cmd.Flags().StringVar(&outputReprFlag, "to", "", "Output representation (inferred from extension if unset)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
109
cmd/lambda/lambda_reduce.go
Normal file
109
cmd/lambda/lambda_reduce.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"git.maximhutz.com/max/lambda/internal/cli"
|
||||
"git.maximhutz.com/max/lambda/internal/config"
|
||||
)
|
||||
|
||||
func LambdaReduce() *cobra.Command {
|
||||
var inputReprFlag string
|
||||
var engineFlag string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "reduce <input-file>",
|
||||
Short: "Reduce a lambda calculus expression",
|
||||
SilenceUsage: true,
|
||||
Aliases: []string{"run"},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 1 {
|
||||
return cmd.Help()
|
||||
}
|
||||
|
||||
inputPath := args[0]
|
||||
|
||||
// Get input source.
|
||||
var source config.Source
|
||||
if inputPath == "-" {
|
||||
source = config.StdinSource{}
|
||||
} else {
|
||||
source = config.FileSource{Path: inputPath}
|
||||
}
|
||||
|
||||
destination := config.StdoutDestination{}
|
||||
|
||||
r := GetRegistry()
|
||||
|
||||
// Get input.
|
||||
input, err := source.Extract()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use flag if provided, otherwise infer from extension.
|
||||
inputRepr := inputReprFlag
|
||||
if inputRepr == "" {
|
||||
if inputRepr, err = inferReprFromPath(inputPath); err != nil {
|
||||
return fmt.Errorf("input file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Find engine.
|
||||
var engine cli.Engine
|
||||
if engineFlag == "" {
|
||||
if engine, err = r.GetDefaultEngine(inputRepr); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if engine, err = r.GetEngine(engineFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Parse code into syntax tree.
|
||||
repr, err := r.Unmarshal(input, inputRepr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Compile expression to lambda calculus.
|
||||
compiled, err := r.ConvertTo(repr, "lambda")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create process.
|
||||
process := engine.Load()
|
||||
err = process.Set(compiled)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run reduction.
|
||||
for process.Step(1) {
|
||||
}
|
||||
|
||||
// Return the final reduced result.
|
||||
result, err := process.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := r.Marshal(result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return destination.Write(output)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&inputReprFlag, "from", "", "Input representation (inferred from extension if unset)")
|
||||
cmd.Flags().StringVarP(&engineFlag, "engine", "e", "", "Reduction engine (inferred from '--input' if unset)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
Reference in New Issue
Block a user