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

@@ -4,14 +4,14 @@ import (
"fmt"
"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)
}
func convertAbstraction(n *ast.Abstraction) lambda.Expression {
func convertAbstraction(n *saccharine.Abstraction) lambda.Expression {
result := SaccharineToLambda(n.Body)
parameters := n.Parameters
@@ -31,7 +31,7 @@ func convertAbstraction(n *ast.Abstraction) lambda.Expression {
return result
}
func convertApplication(n *ast.Application) lambda.Expression {
func convertApplication(n *saccharine.Application) lambda.Expression {
result := SaccharineToLambda(n.Abstraction)
arguments := []lambda.Expression{}
@@ -47,13 +47,13 @@ func convertApplication(n *ast.Application) lambda.Expression {
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
if len(s.Parameters) == 0 {
value = SaccharineToLambda(s.Body)
} else {
value = convertAbstraction(ast.NewAbstraction(s.Parameters, s.Body))
value = convertAbstraction(saccharine.NewAbstraction(s.Parameters, s.Body))
}
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))
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) {
case *ast.DeclareStatement:
case *saccharine.DeclareStatement:
return reduceDeclare(s, e)
case *ast.LetStatement:
case *saccharine.LetStatement:
return reduceLet(s, e)
default:
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)
for i := len(n.Statements) - 1; i >= 0; i-- {
@@ -92,15 +92,15 @@ func convertClause(n *ast.Clause) lambda.Expression {
return result
}
func SaccharineToLambda(n ast.Expression) lambda.Expression {
func SaccharineToLambda(n saccharine.Expression) lambda.Expression {
switch n := n.(type) {
case *ast.Atom:
case *saccharine.Atom:
return convertAtom(n)
case *ast.Abstraction:
case *saccharine.Abstraction:
return convertAbstraction(n)
case *ast.Application:
case *saccharine.Application:
return convertApplication(n)
case *ast.Clause:
case *saccharine.Clause:
return convertClause(n)
default:
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 {
IsExpression()

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"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/trace"
)
@@ -75,8 +74,8 @@ func parseList[U any](i *TokenIterator, fn func(*TokenIterator) (U, error), mini
}
}
func parseAbstraction(i *TokenIterator) (*ast.Abstraction, error) {
return iterator.Do(i, func(i *TokenIterator) (*ast.Abstraction, error) {
func parseAbstraction(i *TokenIterator) (*Abstraction, error) {
return iterator.Do(i, func(i *TokenIterator) (*Abstraction, error) {
if _, err := parseToken(i, token.Slash, true); err != nil {
return nil, trace.Wrap(err, "no function slash (col %d)", i.MustGet().Column)
} 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 {
return nil, err
} else {
return ast.NewAbstraction(parameters, body), nil
return NewAbstraction(parameters, body), nil
}
})
}
func parseApplication(i *TokenIterator) (*ast.Application, error) {
return iterator.Do(i, func(i *TokenIterator) (*ast.Application, error) {
func parseApplication(i *TokenIterator) (*Application, error) {
return iterator.Do(i, func(i *TokenIterator) (*Application, error) {
if _, err := parseToken(i, token.OpenParen, true); err != nil {
return nil, trace.Wrap(err, "no openning brackets (col %d)", i.MustGet().Column)
} 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 {
return nil, trace.Wrap(err, "no closing brackets (col %d)", i.MustGet().Column)
} 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 {
return nil, trace.Wrap(err, "no variable (col %d)", i.Index())
} else {
return ast.NewAtom(tok.Value), nil
return NewAtom(tok.Value), nil
}
}
func parseStatements(i *TokenIterator) ([]ast.Statement, error) {
statements := []ast.Statement{}
func parseStatements(i *TokenIterator) ([]Statement, error) {
statements := []Statement{}
//nolint:errcheck
parseList(i, parseBreak, 0)
@@ -132,15 +131,15 @@ func parseStatements(i *TokenIterator) ([]ast.Statement, error) {
return statements, nil
}
func parseClause(i *TokenIterator, braces bool) (*ast.Clause, error) {
func parseClause(i *TokenIterator, braces bool) (*Clause, error) {
if braces {
if _, err := parseToken(i, token.OpenBrace, true); err != nil {
return nil, err
}
}
var stmts []ast.Statement
var last *ast.DeclareStatement
var stmts []Statement
var last *DeclareStatement
var err error
var ok bool
@@ -148,7 +147,7 @@ func parseClause(i *TokenIterator, braces bool) (*ast.Clause, error) {
return nil, err
} else if len(stmts) == 0 {
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)
}
@@ -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) {
return iterator.Do(i, func(i *TokenIterator) (ast.Expression, error) {
func parseExpression(i *TokenIterator) (Expression, error) {
return iterator.Do(i, func(i *TokenIterator) (Expression, error) {
passSoftBreaks(i)
switch peek := i.MustGet(); peek.Type {
@@ -180,8 +179,8 @@ func parseExpression(i *TokenIterator) (ast.Expression, error) {
})
}
func parseLet(i *TokenIterator) (*ast.LetStatement, error) {
return iterator.Do(i, func(i *TokenIterator) (*ast.LetStatement, error) {
func parseLet(i *TokenIterator) (*LetStatement, error) {
return iterator.Do(i, func(i *TokenIterator) (*LetStatement, error) {
if parameters, err := parseList(i, parseString, 1); err != nil {
return nil, err
} 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 {
return nil, err
} 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 {
return nil, err
} 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 {
return let, 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.
func Parse(tokens []token.Token) (ast.Expression, error) {
func parse(tokens []token.Token) (Expression, error) {
i := iterator.Of(tokens)
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 {
IsStatement()

View File

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

View File

@@ -1,4 +1,4 @@
package saccharine
package token
import (
"errors"
@@ -6,7 +6,6 @@ import (
"unicode"
"git.maximhutz.com/max/lambda/pkg/iterator"
"git.maximhutz.com/max/lambda/pkg/saccharine/token"
"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
// 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()
if i.Done() {
@@ -57,27 +56,27 @@ func getToken(i *iterator.Iterator[rune]) (*token.Token, error) {
switch {
case letter == '(':
return token.NewOpenParen(index), nil
return NewOpenParen(index), nil
case letter == ')':
return token.NewCloseParen(index), nil
return NewCloseParen(index), nil
case letter == '.':
return token.NewDot(index), nil
return NewDot(index), nil
case letter == '\\':
return token.NewSlash(index), nil
return NewSlash(index), nil
case letter == '\n':
return token.NewSoftBreak(index), nil
return NewSoftBreak(index), nil
case letter == '{':
return token.NewOpenBrace(index), nil
return NewOpenBrace(index), nil
case letter == '}':
return token.NewCloseBrace(index), nil
return NewCloseBrace(index), nil
case letter == ':':
if _, err := parseCharacter(i, '='); err != nil {
return nil, err
} else {
return token.NewAssign(index), nil
return NewAssign(index), nil
}
case letter == ';':
return token.NewHardBreak(index), nil
return NewHardBreak(index), nil
case unicode.IsSpace(letter):
return nil, nil
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))
}
// Parse a string into tokens.
func GetTokens(input string) ([]token.Token, error) {
func Parse(input string) ([]Token, error) {
i := iterator.Of([]rune(input))
tokens := []token.Token{}
tokens := []Token{}
errorList := []error{}
for !i.Done() {