package convert import ( "fmt" "git.maximhutz.com/max/lambda/pkg/lambda" "git.maximhutz.com/max/lambda/pkg/saccharine" ) func convertAtom(n *saccharine.Atom) lambda.Expression { return lambda.NewVariable(n.Name) } func convertAbstraction(n *saccharine.Abstraction) lambda.Expression { result := SaccharineToLambda(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 := result.GetFree() 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 convertApplication(n *saccharine.Application) lambda.Expression { result := SaccharineToLambda(n.Abstraction) arguments := []lambda.Expression{} for _, argument := range n.Arguments { convertedArgument := SaccharineToLambda(argument) arguments = append(arguments, convertedArgument) } for _, argument := range arguments { result = lambda.NewApplication(result, argument) } return result } func reduceLet(s *saccharine.LetStatement, e lambda.Expression) lambda.Expression { var value lambda.Expression if len(s.Parameters) == 0 { value = SaccharineToLambda(s.Body) } else { value = convertAbstraction(saccharine.NewAbstraction(s.Parameters, s.Body)) } return lambda.NewApplication( lambda.NewAbstraction(s.Name, e), value, ) } func reduceDeclare(s *saccharine.DeclareStatement, e lambda.Expression) lambda.Expression { freshVar := lambda.GenerateFreshName(e.GetFree()) return lambda.NewApplication( lambda.NewAbstraction(freshVar, e), SaccharineToLambda(s.Value), ) } func reduceStatement(s saccharine.Statement, e lambda.Expression) lambda.Expression { switch s := s.(type) { case *saccharine.DeclareStatement: return reduceDeclare(s, e) case *saccharine.LetStatement: return reduceLet(s, e) default: panic(fmt.Errorf("unknown statement type: %v", s)) } } func convertClause(n *saccharine.Clause) lambda.Expression { result := SaccharineToLambda(n.Returns) for i := len(n.Statements) - 1; i >= 0; i-- { result = reduceStatement(n.Statements[i], result) } return result } func SaccharineToLambda(n saccharine.Expression) lambda.Expression { switch n := n.(type) { case *saccharine.Atom: return convertAtom(n) case *saccharine.Abstraction: return convertAbstraction(n) case *saccharine.Application: return convertApplication(n) case *saccharine.Clause: return convertClause(n) default: panic(fmt.Errorf("unknown expression type: %T", n)) } }