From df534098872d3176747373d0988742d6bd03c6bc Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 27 Dec 2025 01:41:00 -0500 Subject: [PATCH] fix: parameters converted in opposite order --- Makefile | 2 +- cmd/lambda/lambda.go | 29 +++++++++------- pkg/convert/saccharine_to_lambda.go | 52 +++++++++++++++++++++++++++++ samples/simple.txt | 2 +- 4 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 pkg/convert/saccharine_to_lambda.go diff --git a/Makefile b/Makefile index 5add4ca..ea3bfed 100644 --- a/Makefile +++ b/Makefile @@ -5,4 +5,4 @@ it: @ chmod +x ${BINARY_NAME} ex: it - @ ./lambda.exe -v - < ./samples/simple.txt \ No newline at end of file + @ ./lambda.exe - < ./samples/simple.txt \ No newline at end of file diff --git a/cmd/lambda/lambda.go b/cmd/lambda/lambda.go index 75cd86f..bb6fd95 100644 --- a/cmd/lambda/lambda.go +++ b/cmd/lambda/lambda.go @@ -7,6 +7,8 @@ import ( "git.maximhutz.com/max/lambda/internal/cli" "git.maximhutz.com/max/lambda/internal/config" + "git.maximhutz.com/max/lambda/pkg/convert" + "git.maximhutz.com/max/lambda/pkg/lambda" "git.maximhutz.com/max/lambda/pkg/saccharine" ) @@ -16,8 +18,8 @@ func main() { cli.HandleError(err) logger := options.GetLogger() - logger.Info("Using program arguments.", "args", os.Args) - logger.Info("Parsed CLI options.", "options", options) + logger.Info("using program arguments", "args", os.Args) + logger.Info("parsed CLI options", "options", options) input, err := options.Source.Pull() cli.HandleError(err) @@ -25,29 +27,32 @@ func main() { // Parse tokens. tokens, err := saccharine.GetTokens([]rune(input)) cli.HandleError(err) - logger.Info("Parsed tokens.", "tokens", tokens) + logger.Info("parsed tokens", "tokens", tokens) // Turn tokens into syntax tree. expression, err := saccharine.Parse(tokens) cli.HandleError(err) - logger.Info("Parsed syntax tree.", "tree", expression) + logger.Info("parsed syntax tree", "tree", saccharine.Stringify(expression)) + + compiled := convert.SaccharineToLambda(expression) + logger.Info("compiled lambda expression", "tree", lambda.Stringify(compiled)) // Reduce expression. start := time.Now() if options.Explanation { - fmt.Println(saccharine.Stringify(expression)) + fmt.Println(lambda.Stringify(compiled)) } - // for lambda.ReduceOnce(&expression) { - // logger.Info("Reduction.", "tree", saccharine.Stringify(expression)) - // if options.Explanation { - // fmt.Println(" =", saccharine.Stringify(expression)) - // } - // } + for lambda.ReduceOnce(&compiled) { + logger.Info("reduction", "tree", lambda.Stringify(compiled)) + if options.Explanation { + fmt.Println(" =", lambda.Stringify(compiled)) + } + } elapsed := time.Since(start).Milliseconds() - fmt.Println(saccharine.Stringify(expression)) + fmt.Println(lambda.Stringify(compiled)) fmt.Fprintln(os.Stderr, "Time Spent:", elapsed, "ms") } diff --git a/pkg/convert/saccharine_to_lambda.go b/pkg/convert/saccharine_to_lambda.go new file mode 100644 index 0000000..9c39c15 --- /dev/null +++ b/pkg/convert/saccharine_to_lambda.go @@ -0,0 +1,52 @@ +package convert + +import ( + "git.maximhutz.com/max/lambda/pkg/lambda" + "git.maximhutz.com/max/lambda/pkg/saccharine/ast" +) + +type compileVisitor struct{} + +func (v compileVisitor) VisitAtom(n *ast.Atom) lambda.Expression { + return lambda.NewVariable(n.Name) +} + +func (v compileVisitor) VisitAbstraction(n *ast.Abstraction) lambda.Expression { + result := ast.Visit(v, n.Body) + + parameters := n.Parameters + + // If the function has no parameters, it is a thunk. Lambda calculus still + // requires _some_ parameter exists, so generate one. + if len(parameters) == 0 { + freeVars := lambda.GetFreeVariables(result) + freshName := lambda.GenerateFreshName(freeVars) + parameters = append(parameters, freshName) + } + + for i := len(parameters) - 1; i >= 0; i-- { + result = lambda.NewAbstraction(parameters[i], result) + } + + return result +} + +func (v compileVisitor) VisitApplication(n *ast.Application) lambda.Expression { + result := ast.Visit(v, n.Abstraction) + + arguments := []lambda.Expression{} + for _, argument := range n.Arguments { + convertedArgument := ast.Visit(v, argument) + arguments = append(arguments, convertedArgument) + } + + for _, argument := range arguments { + result = lambda.NewApplication(result, argument) + } + + return result +} + +func SaccharineToLambda(n ast.Expression) lambda.Expression { + return ast.Visit(&compileVisitor{}, n) +} diff --git a/samples/simple.txt b/samples/simple.txt index 5e8fabc..0b88432 100644 --- a/samples/simple.txt +++ b/samples/simple.txt @@ -3,7 +3,7 @@ (\add. (\mult. (\exp. - (exp (inc (inc (inc (inc (inc 0))))) (inc (inc (inc (inc (inc 0)))))) + (exp (inc (inc (inc (inc 0)))) (inc (inc (inc (inc (inc 0)))))) \n m.(m n) ) \m n f.(m (n f))