style: moved functions around

This commit is contained in:
2025-12-30 15:58:14 -05:00
parent 412d3924eb
commit 2499921679
10 changed files with 115 additions and 93 deletions

View File

@@ -28,19 +28,14 @@ func main() {
input, err := options.Source.Extract() input, err := options.Source.Extract()
cli.HandleError(err) cli.HandleError(err)
// Parse tokens. // Parse code into syntax tree.
tokens, err := saccharine.GetTokens(input) ast, err := saccharine.Parse(input)
cli.HandleError(err) cli.HandleError(err)
logger.Info("parsed tokens", "tokens", tokens) logger.Info("parsed syntax tree", "tree", ast)
// Turn tokens into syntax tree.
expression, err := saccharine.Parse(tokens)
cli.HandleError(err)
logger.Info("parsed syntax tree", "tree", saccharine.Stringify(expression))
// Compile expression to lambda calculus. // Compile expression to lambda calculus.
compiled := convert.SaccharineToLambda(expression) compiled := convert.SaccharineToLambda(ast)
logger.Info("compiled lambda expression", "tree", lambda.Stringify(compiled)) logger.Info("compiled λ expression", "tree", lambda.Stringify(compiled))
// Create reduction engine. // Create reduction engine.
process := engine.New(options, &compiled) process := engine.New(options, &compiled)

View File

@@ -1,5 +1,5 @@
// Package "engine" provides an extensible interface for users to interfact with // Package "engine" provides an extensible interface for users to interfact with
// lambda calculus. // λ-calculus.
package engine package engine
import ( import (
@@ -8,14 +8,14 @@ import (
"git.maximhutz.com/max/lambda/pkg/lambda" "git.maximhutz.com/max/lambda/pkg/lambda"
) )
// A process for reducing one lambda expression. // A process for reducing one λ-expression.
type Engine struct { type Engine struct {
Config *config.Config Config *config.Config
Expression *lambda.Expression Expression *lambda.Expression
emitter.Emitter emitter.Emitter
} }
// Create a new engine, given an unreduced lambda expression. // Create a new engine, given an unreduced λ-expression.
func New(config *config.Config, expression *lambda.Expression) *Engine { func New(config *config.Config, expression *lambda.Expression) *Engine {
return &Engine{Config: config, Expression: expression} return &Engine{Config: config, Expression: expression}
} }

View File

@@ -4,14 +4,14 @@ import (
"fmt" "fmt"
"git.maximhutz.com/max/lambda/pkg/lambda" "git.maximhutz.com/max/lambda/pkg/lambda"
"git.maximhutz.com/max/lambda/pkg/saccharine/ast" "git.maximhutz.com/max/lambda/pkg/saccharine"
) )
func convertAtom(n *ast.Atom) lambda.Expression { func convertAtom(n *saccharine.Atom) lambda.Expression {
return lambda.NewVariable(n.Name) return lambda.NewVariable(n.Name)
} }
func convertAbstraction(n *ast.Abstraction) lambda.Expression { func convertAbstraction(n *saccharine.Abstraction) lambda.Expression {
result := SaccharineToLambda(n.Body) result := SaccharineToLambda(n.Body)
parameters := n.Parameters parameters := n.Parameters
@@ -31,7 +31,7 @@ func convertAbstraction(n *ast.Abstraction) lambda.Expression {
return result return result
} }
func convertApplication(n *ast.Application) lambda.Expression { func convertApplication(n *saccharine.Application) lambda.Expression {
result := SaccharineToLambda(n.Abstraction) result := SaccharineToLambda(n.Abstraction)
arguments := []lambda.Expression{} arguments := []lambda.Expression{}
@@ -47,13 +47,13 @@ func convertApplication(n *ast.Application) lambda.Expression {
return result return result
} }
func reduceLet(s *ast.LetStatement, e lambda.Expression) lambda.Expression { func reduceLet(s *saccharine.LetStatement, e lambda.Expression) lambda.Expression {
var value lambda.Expression var value lambda.Expression
if len(s.Parameters) == 0 { if len(s.Parameters) == 0 {
value = SaccharineToLambda(s.Body) value = SaccharineToLambda(s.Body)
} else { } else {
value = convertAbstraction(ast.NewAbstraction(s.Parameters, s.Body)) value = convertAbstraction(saccharine.NewAbstraction(s.Parameters, s.Body))
} }
return lambda.NewApplication( return lambda.NewApplication(
@@ -62,7 +62,7 @@ func reduceLet(s *ast.LetStatement, e lambda.Expression) lambda.Expression {
) )
} }
func reduceDeclare(s *ast.DeclareStatement, e lambda.Expression) lambda.Expression { func reduceDeclare(s *saccharine.DeclareStatement, e lambda.Expression) lambda.Expression {
freshVar := lambda.GenerateFreshName(lambda.GetFreeVariables(e)) freshVar := lambda.GenerateFreshName(lambda.GetFreeVariables(e))
return lambda.NewApplication( return lambda.NewApplication(
@@ -71,18 +71,18 @@ func reduceDeclare(s *ast.DeclareStatement, e lambda.Expression) lambda.Expressi
) )
} }
func reduceStatement(s ast.Statement, e lambda.Expression) lambda.Expression { func reduceStatement(s saccharine.Statement, e lambda.Expression) lambda.Expression {
switch s := s.(type) { switch s := s.(type) {
case *ast.DeclareStatement: case *saccharine.DeclareStatement:
return reduceDeclare(s, e) return reduceDeclare(s, e)
case *ast.LetStatement: case *saccharine.LetStatement:
return reduceLet(s, e) return reduceLet(s, e)
default: default:
panic(fmt.Errorf("unknown statement type: %v", s)) panic(fmt.Errorf("unknown statement type: %v", s))
} }
} }
func convertClause(n *ast.Clause) lambda.Expression { func convertClause(n *saccharine.Clause) lambda.Expression {
result := SaccharineToLambda(n.Returns) result := SaccharineToLambda(n.Returns)
for i := len(n.Statements) - 1; i >= 0; i-- { for i := len(n.Statements) - 1; i >= 0; i-- {
@@ -92,15 +92,15 @@ func convertClause(n *ast.Clause) lambda.Expression {
return result return result
} }
func SaccharineToLambda(n ast.Expression) lambda.Expression { func SaccharineToLambda(n saccharine.Expression) lambda.Expression {
switch n := n.(type) { switch n := n.(type) {
case *ast.Atom: case *saccharine.Atom:
return convertAtom(n) return convertAtom(n)
case *ast.Abstraction: case *saccharine.Abstraction:
return convertAbstraction(n) return convertAbstraction(n)
case *ast.Application: case *saccharine.Application:
return convertApplication(n) return convertApplication(n)
case *ast.Clause: case *saccharine.Clause:
return convertClause(n) return convertClause(n)
default: default:
panic(fmt.Errorf("unknown expression type: %T", n)) panic(fmt.Errorf("unknown expression type: %T", n))

9
pkg/deltanet/deltanet.go Normal file
View File

@@ -0,0 +1,9 @@
// Package "deltanet" is a reduction strategy using ∆-nets.
package deltanet
type Graph struct {
nodes []Node
}
type Node interface {
}

View File

@@ -1,4 +1,4 @@
package ast package saccharine
type Expression interface { type Expression interface {
IsExpression() IsExpression()

View File

@@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"git.maximhutz.com/max/lambda/pkg/iterator" "git.maximhutz.com/max/lambda/pkg/iterator"
"git.maximhutz.com/max/lambda/pkg/saccharine/ast"
"git.maximhutz.com/max/lambda/pkg/saccharine/token" "git.maximhutz.com/max/lambda/pkg/saccharine/token"
"git.maximhutz.com/max/lambda/pkg/trace" "git.maximhutz.com/max/lambda/pkg/trace"
) )
@@ -75,8 +74,8 @@ func parseList[U any](i *TokenIterator, fn func(*TokenIterator) (U, error), mini
} }
} }
func parseAbstraction(i *TokenIterator) (*ast.Abstraction, error) { func parseAbstraction(i *TokenIterator) (*Abstraction, error) {
return iterator.Do(i, func(i *TokenIterator) (*ast.Abstraction, error) { return iterator.Do(i, func(i *TokenIterator) (*Abstraction, error) {
if _, err := parseToken(i, token.Slash, true); err != nil { if _, err := parseToken(i, token.Slash, true); err != nil {
return nil, trace.Wrap(err, "no function slash (col %d)", i.MustGet().Column) return nil, trace.Wrap(err, "no function slash (col %d)", i.MustGet().Column)
} else if parameters, err := parseList(i, parseString, 0); err != nil { } else if parameters, err := parseList(i, parseString, 0); err != nil {
@@ -86,13 +85,13 @@ func parseAbstraction(i *TokenIterator) (*ast.Abstraction, error) {
} else if body, err := parseExpression(i); err != nil { } else if body, err := parseExpression(i); err != nil {
return nil, err return nil, err
} else { } else {
return ast.NewAbstraction(parameters, body), nil return NewAbstraction(parameters, body), nil
} }
}) })
} }
func parseApplication(i *TokenIterator) (*ast.Application, error) { func parseApplication(i *TokenIterator) (*Application, error) {
return iterator.Do(i, func(i *TokenIterator) (*ast.Application, error) { return iterator.Do(i, func(i *TokenIterator) (*Application, error) {
if _, err := parseToken(i, token.OpenParen, true); err != nil { if _, err := parseToken(i, token.OpenParen, true); err != nil {
return nil, trace.Wrap(err, "no openning brackets (col %d)", i.MustGet().Column) return nil, trace.Wrap(err, "no openning brackets (col %d)", i.MustGet().Column)
} else if expressions, err := parseList(i, parseExpression, 1); err != nil { } else if expressions, err := parseList(i, parseExpression, 1); err != nil {
@@ -100,21 +99,21 @@ func parseApplication(i *TokenIterator) (*ast.Application, error) {
} else if _, err := parseToken(i, token.CloseParen, true); err != nil { } else if _, err := parseToken(i, token.CloseParen, true); err != nil {
return nil, trace.Wrap(err, "no closing brackets (col %d)", i.MustGet().Column) return nil, trace.Wrap(err, "no closing brackets (col %d)", i.MustGet().Column)
} else { } else {
return ast.NewApplication(expressions[0], expressions[1:]), nil return NewApplication(expressions[0], expressions[1:]), nil
} }
}) })
} }
func parseAtom(i *TokenIterator) (*ast.Atom, error) { func parseAtom(i *TokenIterator) (*Atom, error) {
if tok, err := parseToken(i, token.Atom, true); err != nil { if tok, err := parseToken(i, token.Atom, true); err != nil {
return nil, trace.Wrap(err, "no variable (col %d)", i.Index()) return nil, trace.Wrap(err, "no variable (col %d)", i.Index())
} else { } else {
return ast.NewAtom(tok.Value), nil return NewAtom(tok.Value), nil
} }
} }
func parseStatements(i *TokenIterator) ([]ast.Statement, error) { func parseStatements(i *TokenIterator) ([]Statement, error) {
statements := []ast.Statement{} statements := []Statement{}
//nolint:errcheck //nolint:errcheck
parseList(i, parseBreak, 0) parseList(i, parseBreak, 0)
@@ -132,15 +131,15 @@ func parseStatements(i *TokenIterator) ([]ast.Statement, error) {
return statements, nil return statements, nil
} }
func parseClause(i *TokenIterator, braces bool) (*ast.Clause, error) { func parseClause(i *TokenIterator, braces bool) (*Clause, error) {
if braces { if braces {
if _, err := parseToken(i, token.OpenBrace, true); err != nil { if _, err := parseToken(i, token.OpenBrace, true); err != nil {
return nil, err return nil, err
} }
} }
var stmts []ast.Statement var stmts []Statement
var last *ast.DeclareStatement var last *DeclareStatement
var err error var err error
var ok bool var ok bool
@@ -148,7 +147,7 @@ func parseClause(i *TokenIterator, braces bool) (*ast.Clause, error) {
return nil, err return nil, err
} else if len(stmts) == 0 { } else if len(stmts) == 0 {
return nil, fmt.Errorf("no statements in clause") return nil, fmt.Errorf("no statements in clause")
} else if last, ok = stmts[len(stmts)-1].(*ast.DeclareStatement); !ok { } else if last, ok = stmts[len(stmts)-1].(*DeclareStatement); !ok {
return nil, fmt.Errorf("this clause contains no final return value (col %d)", i.MustGet().Column) return nil, fmt.Errorf("this clause contains no final return value (col %d)", i.MustGet().Column)
} }
@@ -158,11 +157,11 @@ func parseClause(i *TokenIterator, braces bool) (*ast.Clause, error) {
} }
} }
return ast.NewClause(stmts[:len(stmts)-1], last.Value), nil return NewClause(stmts[:len(stmts)-1], last.Value), nil
} }
func parseExpression(i *TokenIterator) (ast.Expression, error) { func parseExpression(i *TokenIterator) (Expression, error) {
return iterator.Do(i, func(i *TokenIterator) (ast.Expression, error) { return iterator.Do(i, func(i *TokenIterator) (Expression, error) {
passSoftBreaks(i) passSoftBreaks(i)
switch peek := i.MustGet(); peek.Type { switch peek := i.MustGet(); peek.Type {
@@ -180,8 +179,8 @@ func parseExpression(i *TokenIterator) (ast.Expression, error) {
}) })
} }
func parseLet(i *TokenIterator) (*ast.LetStatement, error) { func parseLet(i *TokenIterator) (*LetStatement, error) {
return iterator.Do(i, func(i *TokenIterator) (*ast.LetStatement, error) { return iterator.Do(i, func(i *TokenIterator) (*LetStatement, error) {
if parameters, err := parseList(i, parseString, 1); err != nil { if parameters, err := parseList(i, parseString, 1); err != nil {
return nil, err return nil, err
} else if _, err := parseToken(i, token.Assign, true); err != nil { } else if _, err := parseToken(i, token.Assign, true); err != nil {
@@ -189,20 +188,20 @@ func parseLet(i *TokenIterator) (*ast.LetStatement, error) {
} else if body, err := parseExpression(i); err != nil { } else if body, err := parseExpression(i); err != nil {
return nil, err return nil, err
} else { } else {
return ast.NewLet(parameters[0], parameters[1:], body), nil return NewLet(parameters[0], parameters[1:], body), nil
} }
}) })
} }
func parseDeclare(i *TokenIterator) (*ast.DeclareStatement, error) { func parseDeclare(i *TokenIterator) (*DeclareStatement, error) {
if value, err := parseExpression(i); err != nil { if value, err := parseExpression(i); err != nil {
return nil, err return nil, err
} else { } else {
return ast.NewDeclare(value), nil return NewDeclare(value), nil
} }
} }
func parseStatement(i *TokenIterator) (ast.Statement, error) { func parseStatement(i *TokenIterator) (Statement, error) {
if let, letErr := parseLet(i); letErr == nil { if let, letErr := parseLet(i); letErr == nil {
return let, nil return let, nil
} else if declare, declErr := parseDeclare(i); declErr == nil { } else if declare, declErr := parseDeclare(i); declErr == nil {
@@ -213,7 +212,7 @@ func parseStatement(i *TokenIterator) (ast.Statement, error) {
} }
// Given a list of tokens, attempt to parse it into an syntax tree. // Given a list of tokens, attempt to parse it into an syntax tree.
func Parse(tokens []token.Token) (ast.Expression, error) { func parse(tokens []token.Token) (Expression, error) {
i := iterator.Of(tokens) i := iterator.Of(tokens)
exp, err := parseClause(i, false) exp, err := parseClause(i, false)

View File

@@ -0,0 +1,22 @@
// Package "saccharine" provides a simple language built on top of λ-calculus,
// to facilitate productive coding using it.
package saccharine
import (
"git.maximhutz.com/max/lambda/pkg/saccharine/token"
)
// Convert a piece of valid saccharine code into an expression.
func Parse(code string) (Expression, error) {
tokens, err := token.Parse(code)
if err != nil {
return nil, err
}
return parse(tokens)
}
// Convert a parsed saccharine expression back into source code.
func Stringify(expression Expression) string {
return stringifyExpression(expression)
}

View File

@@ -1,4 +1,4 @@
package ast package saccharine
type Statement interface { type Statement interface {
IsStatement() IsStatement()

View File

@@ -3,67 +3,65 @@ package saccharine
import ( import (
"fmt" "fmt"
"strings" "strings"
"git.maximhutz.com/max/lambda/pkg/saccharine/ast"
) )
func stringifyAtom(n *ast.Atom) string { func stringifyAtom(n *Atom) string {
return n.Name return n.Name
} }
func stringifyAbstraction(n *ast.Abstraction) string { func stringifyAbstraction(n *Abstraction) string {
return "\\" + strings.Join(n.Parameters, " ") + "." + Stringify(n.Body) return "\\" + strings.Join(n.Parameters, " ") + "." + stringifyExpression(n.Body)
} }
func stringifyApplication(n *ast.Application) string { func stringifyApplication(n *Application) string {
arguments := []string{Stringify(n.Abstraction)} arguments := []string{stringifyExpression(n.Abstraction)}
for _, argument := range n.Arguments { for _, argument := range n.Arguments {
arguments = append(arguments, Stringify(argument)) arguments = append(arguments, stringifyExpression(argument))
} }
return "(" + strings.Join(arguments, " ") + ")" return "(" + strings.Join(arguments, " ") + ")"
} }
func stringifyLet(s *ast.LetStatement) string { func stringifyLet(s *LetStatement) string {
return s.Name + " " + strings.Join(s.Parameters, " ") + " := " + Stringify(s.Body) return s.Name + " " + strings.Join(s.Parameters, " ") + " := " + stringifyExpression(s.Body)
} }
func stringifyDeclare(s *ast.DeclareStatement) string { func stringifyDeclare(s *DeclareStatement) string {
return Stringify(s.Value) return stringifyExpression(s.Value)
} }
func stringifyStatement(s ast.Statement) string { func stringifyStatement(s Statement) string {
switch s := s.(type) { switch s := s.(type) {
case *ast.DeclareStatement: case *DeclareStatement:
return stringifyDeclare(s) return stringifyDeclare(s)
case *ast.LetStatement: case *LetStatement:
return stringifyLet(s) return stringifyLet(s)
default: default:
panic(fmt.Errorf("unknown statement type: %v", s)) panic(fmt.Errorf("unknown statement type: %v", s))
} }
} }
func stringifyClause(n *ast.Clause) string { func stringifyClause(n *Clause) string {
stmts := "" stmts := ""
for _, statement := range n.Statements { for _, statement := range n.Statements {
stmts += stringifyStatement(statement) + "; " stmts += stringifyStatement(statement) + "; "
} }
return "{ " + stmts + Stringify(n.Returns) + " }" return "{ " + stmts + stringifyExpression(n.Returns) + " }"
} }
// Convert an expression back into valid source code. // Convert an expression back into valid source code.
func Stringify(n ast.Expression) string { func stringifyExpression(n Expression) string {
switch n := n.(type) { switch n := n.(type) {
case *ast.Atom: case *Atom:
return stringifyAtom(n) return stringifyAtom(n)
case *ast.Abstraction: case *Abstraction:
return stringifyAbstraction(n) return stringifyAbstraction(n)
case *ast.Application: case *Application:
return stringifyApplication(n) return stringifyApplication(n)
case *ast.Clause: case *Clause:
return stringifyClause(n) return stringifyClause(n)
default: default:
panic(fmt.Errorf("unknown expression type: %T", n)) panic(fmt.Errorf("unknown expression type: %T", n))

View File

@@ -1,4 +1,4 @@
package saccharine package token
import ( import (
"errors" "errors"
@@ -6,7 +6,6 @@ import (
"unicode" "unicode"
"git.maximhutz.com/max/lambda/pkg/iterator" "git.maximhutz.com/max/lambda/pkg/iterator"
"git.maximhutz.com/max/lambda/pkg/saccharine/token"
"git.maximhutz.com/max/lambda/pkg/trace" "git.maximhutz.com/max/lambda/pkg/trace"
) )
@@ -43,7 +42,7 @@ func parseCharacter(i *iterator.Iterator[rune], expected rune) (rune, error) {
// Pulls the next token from an iterator over runes. If it cannot, it will // Pulls the next token from an iterator over runes. If it cannot, it will
// return nil. If an error occurs, it will return that. // return nil. If an error occurs, it will return that.
func getToken(i *iterator.Iterator[rune]) (*token.Token, error) { func getToken(i *iterator.Iterator[rune]) (*Token, error) {
index := i.Index() index := i.Index()
if i.Done() { if i.Done() {
@@ -57,27 +56,27 @@ func getToken(i *iterator.Iterator[rune]) (*token.Token, error) {
switch { switch {
case letter == '(': case letter == '(':
return token.NewOpenParen(index), nil return NewOpenParen(index), nil
case letter == ')': case letter == ')':
return token.NewCloseParen(index), nil return NewCloseParen(index), nil
case letter == '.': case letter == '.':
return token.NewDot(index), nil return NewDot(index), nil
case letter == '\\': case letter == '\\':
return token.NewSlash(index), nil return NewSlash(index), nil
case letter == '\n': case letter == '\n':
return token.NewSoftBreak(index), nil return NewSoftBreak(index), nil
case letter == '{': case letter == '{':
return token.NewOpenBrace(index), nil return NewOpenBrace(index), nil
case letter == '}': case letter == '}':
return token.NewCloseBrace(index), nil return NewCloseBrace(index), nil
case letter == ':': case letter == ':':
if _, err := parseCharacter(i, '='); err != nil { if _, err := parseCharacter(i, '='); err != nil {
return nil, err return nil, err
} else { } else {
return token.NewAssign(index), nil return NewAssign(index), nil
} }
case letter == ';': case letter == ';':
return token.NewHardBreak(index), nil return NewHardBreak(index), nil
case unicode.IsSpace(letter): case unicode.IsSpace(letter):
return nil, nil return nil, nil
case isVariable(letter): case isVariable(letter):
@@ -91,16 +90,16 @@ func getToken(i *iterator.Iterator[rune]) (*token.Token, error) {
} }
} }
return token.NewAtom(string(atom), index), nil return NewAtom(string(atom), index), nil
} }
return nil, fmt.Errorf("unknown character '%v'", string(letter)) return nil, fmt.Errorf("unknown character '%v'", string(letter))
} }
// Parse a string into tokens. // Parse a string into tokens.
func GetTokens(input string) ([]token.Token, error) { func Parse(input string) ([]Token, error) {
i := iterator.Of([]rune(input)) i := iterator.Of([]rune(input))
tokens := []token.Token{} tokens := []Token{}
errorList := []error{} errorList := []error{}
for !i.Done() { for !i.Done() {