style: moved functions around
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
9
pkg/deltanet/deltanet.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Package "deltanet" is a reduction strategy using ∆-nets.
|
||||||
|
package deltanet
|
||||||
|
|
||||||
|
type Graph struct {
|
||||||
|
nodes []Node
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node interface {
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package ast
|
package saccharine
|
||||||
|
|
||||||
type Expression interface {
|
type Expression interface {
|
||||||
IsExpression()
|
IsExpression()
|
||||||
@@ -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)
|
||||||
22
pkg/saccharine/saccharine.go
Normal file
22
pkg/saccharine/saccharine.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package ast
|
package saccharine
|
||||||
|
|
||||||
type Statement interface {
|
type Statement interface {
|
||||||
IsStatement()
|
IsStatement()
|
||||||
@@ -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))
|
||||||
|
|||||||
@@ -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() {
|
||||||
Reference in New Issue
Block a user