From d21dde40e9a03d824891d04fc48dbcc59c097f6e Mon Sep 17 00:00:00 2001 From: "M.V. Hutz" Date: Thu, 5 Feb 2026 22:55:33 -0500 Subject: [PATCH] feat: move lambda reduction to "lambda reduce" --- cmd/lambda/lambda.go | 66 +-------------------- cmd/lambda/lambda_convert.go | 4 +- cmd/lambda/lambda_reduce.go | 109 +++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 66 deletions(-) create mode 100644 cmd/lambda/lambda_reduce.go diff --git a/cmd/lambda/lambda.go b/cmd/lambda/lambda.go index 7d7982d..e8effcb 100644 --- a/cmd/lambda/lambda.go +++ b/cmd/lambda/lambda.go @@ -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 } diff --git a/cmd/lambda/lambda_convert.go b/cmd/lambda/lambda_convert.go index b2fd20c..bd7ad9e 100644 --- a/cmd/lambda/lambda_convert.go +++ b/cmd/lambda/lambda_convert.go @@ -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 } diff --git a/cmd/lambda/lambda_reduce.go b/cmd/lambda/lambda_reduce.go new file mode 100644 index 0000000..a6f1039 --- /dev/null +++ b/cmd/lambda/lambda_reduce.go @@ -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 ", + 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 +}