style: moved functions around
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package ast
|
||||
package saccharine
|
||||
|
||||
type Expression interface {
|
||||
IsExpression()
|
||||
@@ -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)
|
||||
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 {
|
||||
IsStatement()
|
||||
@@ -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))
|
||||
|
||||
@@ -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() {
|
||||
Reference in New Issue
Block a user