feat: tokenizer accepts braces, line terminator, and equal sign
This commit is contained in:
@@ -1,18 +1,18 @@
|
|||||||
package convert
|
package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"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/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type compileVisitor struct{}
|
func convertAtom(n *ast.Atom) lambda.Expression {
|
||||||
|
|
||||||
func (v compileVisitor) VisitAtom(n *ast.Atom) lambda.Expression {
|
|
||||||
return lambda.NewVariable(n.Name)
|
return lambda.NewVariable(n.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v compileVisitor) VisitAbstraction(n *ast.Abstraction) lambda.Expression {
|
func convertAbstraction(n *ast.Abstraction) lambda.Expression {
|
||||||
result := ast.Visit(v, n.Body)
|
result := SaccharineToLambda(n.Body)
|
||||||
|
|
||||||
parameters := n.Parameters
|
parameters := n.Parameters
|
||||||
|
|
||||||
@@ -31,12 +31,12 @@ func (v compileVisitor) VisitAbstraction(n *ast.Abstraction) lambda.Expression {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v compileVisitor) VisitApplication(n *ast.Application) lambda.Expression {
|
func convertApplication(n *ast.Application) lambda.Expression {
|
||||||
result := ast.Visit(v, n.Abstraction)
|
result := SaccharineToLambda(n.Abstraction)
|
||||||
|
|
||||||
arguments := []lambda.Expression{}
|
arguments := []lambda.Expression{}
|
||||||
for _, argument := range n.Arguments {
|
for _, argument := range n.Arguments {
|
||||||
convertedArgument := ast.Visit(v, argument)
|
convertedArgument := SaccharineToLambda(argument)
|
||||||
arguments = append(arguments, convertedArgument)
|
arguments = append(arguments, convertedArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,5 +48,14 @@ func (v compileVisitor) VisitApplication(n *ast.Application) lambda.Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SaccharineToLambda(n ast.Expression) lambda.Expression {
|
func SaccharineToLambda(n ast.Expression) lambda.Expression {
|
||||||
return ast.Visit(&compileVisitor{}, n)
|
switch n := n.(type) {
|
||||||
|
case *ast.Atom:
|
||||||
|
return convertAtom(n)
|
||||||
|
case *ast.Abstraction:
|
||||||
|
return convertAbstraction(n)
|
||||||
|
case *ast.Application:
|
||||||
|
return convertApplication(n)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unknown expression type: %v", n))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func (v *stringifyVisitor) VisitApplication(c *Application) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Stringify(e Expression) string {
|
func Stringify(e Expression) string {
|
||||||
b := &stringifyVisitor{}
|
b := &stringifyVisitor{builder: strings.Builder{}}
|
||||||
e.Accept(b)
|
e.Accept(b)
|
||||||
return b.builder.String()
|
return b.builder.String()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,15 @@ type Atom struct {
|
|||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Clause struct {
|
||||||
|
Statements []Statement
|
||||||
|
Returns Expression
|
||||||
|
}
|
||||||
|
|
||||||
func (Abstraction) IsExpression() {}
|
func (Abstraction) IsExpression() {}
|
||||||
func (Application) IsExpression() {}
|
func (Application) IsExpression() {}
|
||||||
func (Atom) IsExpression() {}
|
func (Atom) IsExpression() {}
|
||||||
|
func (Clause) IsExpression() {}
|
||||||
|
|
||||||
/** ------------------------------------------------------------------------- */
|
/** ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@@ -37,3 +43,7 @@ func NewApplication(abstraction Expression, arguments []Expression) *Application
|
|||||||
func NewAtom(name string) *Atom {
|
func NewAtom(name string) *Atom {
|
||||||
return &Atom{Name: name}
|
return &Atom{Name: name}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewClause(statements []Statement, returns Expression) *Clause {
|
||||||
|
return &Clause{Statements: statements, Returns: returns}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
type Program struct {
|
|
||||||
Statements []Statement
|
|
||||||
}
|
|
||||||
@@ -7,11 +7,6 @@ type Statement interface {
|
|||||||
/** ------------------------------------------------------------------------- */
|
/** ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
type LetStatement struct {
|
type LetStatement struct {
|
||||||
Variable string
|
|
||||||
Value Expression
|
|
||||||
}
|
|
||||||
|
|
||||||
type MethodStatement struct {
|
|
||||||
Name string
|
Name string
|
||||||
Parameters []string
|
Parameters []string
|
||||||
Body Expression
|
Body Expression
|
||||||
@@ -22,7 +17,6 @@ type DeclareStatement struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (LetStatement) IsStatement() {}
|
func (LetStatement) IsStatement() {}
|
||||||
func (MethodStatement) IsStatement() {}
|
|
||||||
func (DeclareStatement) IsStatement() {}
|
func (DeclareStatement) IsStatement() {}
|
||||||
|
|
||||||
/** ------------------------------------------------------------------------- */
|
/** ------------------------------------------------------------------------- */
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type Visitor[T any] interface {
|
|
||||||
VisitAtom(*Atom) T
|
|
||||||
VisitAbstraction(*Abstraction) T
|
|
||||||
VisitApplication(*Application) T
|
|
||||||
}
|
|
||||||
|
|
||||||
func Visit[T any](visitor Visitor[T], node Expression) T {
|
|
||||||
switch node := node.(type) {
|
|
||||||
case *Atom:
|
|
||||||
return visitor.VisitAtom(node)
|
|
||||||
case *Abstraction:
|
|
||||||
return visitor.VisitAbstraction(node)
|
|
||||||
case *Application:
|
|
||||||
return visitor.VisitApplication(node)
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unknown node %t", node))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +1,39 @@
|
|||||||
package saccharine
|
package saccharine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.maximhutz.com/max/lambda/pkg/saccharine/ast"
|
"git.maximhutz.com/max/lambda/pkg/saccharine/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stringifyVisitor struct{}
|
func stringifyAtom(n *ast.Atom) string {
|
||||||
|
|
||||||
func (v stringifyVisitor) VisitAtom(n *ast.Atom) string {
|
|
||||||
return n.Name
|
return n.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v stringifyVisitor) VisitAbstraction(n *ast.Abstraction) string {
|
func stringifyAbstraction(n *ast.Abstraction) string {
|
||||||
return "\\" + strings.Join(n.Parameters, " ") + "." + ast.Visit(v, n.Body)
|
return "\\" + strings.Join(n.Parameters, " ") + "." + Stringify(n.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v stringifyVisitor) VisitApplication(n *ast.Application) string {
|
func stringifyApplication(n *ast.Application) string {
|
||||||
arguments := []string{ast.Visit(v, n.Abstraction)}
|
arguments := []string{Stringify(n.Abstraction)}
|
||||||
|
|
||||||
for _, argument := range n.Arguments {
|
for _, argument := range n.Arguments {
|
||||||
arguments = append(arguments, ast.Visit(v, argument))
|
arguments = append(arguments, Stringify(argument))
|
||||||
}
|
}
|
||||||
|
|
||||||
return "(" + strings.Join(arguments, " ") + ")"
|
return "(" + strings.Join(arguments, " ") + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
func Stringify(n ast.Expression) string {
|
func Stringify(n ast.Expression) string {
|
||||||
return ast.Visit(&stringifyVisitor{}, n)
|
switch n := n.(type) {
|
||||||
|
case *ast.Atom:
|
||||||
|
return stringifyAtom(n)
|
||||||
|
case *ast.Abstraction:
|
||||||
|
return stringifyAbstraction(n)
|
||||||
|
case *ast.Application:
|
||||||
|
return stringifyApplication(n)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unknown expression type: %v", n))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ type Type int
|
|||||||
const (
|
const (
|
||||||
OpenParen Type = iota // Denotes the '(' token.
|
OpenParen Type = iota // Denotes the '(' token.
|
||||||
CloseParen // Denotes the ')' token.
|
CloseParen // Denotes the ')' token.
|
||||||
|
OpenBrace // Denotes the '{' token.
|
||||||
|
CloseBrace // Denotes the '}' token.
|
||||||
|
End // Denotes the ';' token.
|
||||||
|
Assign // Denotes the ':=' token.
|
||||||
Atom // Denotes an alpha-numeric variable.
|
Atom // Denotes an alpha-numeric variable.
|
||||||
Slash // Denotes the '/' token.
|
Slash // Denotes the '/' token.
|
||||||
Dot // Denotes the '.' token.
|
Dot // Denotes the '.' token.
|
||||||
@@ -27,10 +31,26 @@ func NewCloseParen(column int) *Token {
|
|||||||
return &Token{Type: CloseParen, Column: column, Value: ")"}
|
return &Token{Type: CloseParen, Column: column, Value: ")"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewOpenBrace(column int) *Token {
|
||||||
|
return &Token{Type: OpenBrace, Column: column, Value: "{"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCloseBrace(column int) *Token {
|
||||||
|
return &Token{Type: CloseBrace, Column: column, Value: "}"}
|
||||||
|
}
|
||||||
|
|
||||||
func NewDot(column int) *Token {
|
func NewDot(column int) *Token {
|
||||||
return &Token{Type: Dot, Column: column, Value: "."}
|
return &Token{Type: Dot, Column: column, Value: "."}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewEnd(column int) *Token {
|
||||||
|
return &Token{Type: End, Column: column, Value: ";"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAssign(column int) *Token {
|
||||||
|
return &Token{Type: Assign, Column: column, Value: ":="}
|
||||||
|
}
|
||||||
|
|
||||||
func NewSlash(column int) *Token {
|
func NewSlash(column int) *Token {
|
||||||
return &Token{Type: Slash, Column: column, Value: "\\"}
|
return &Token{Type: Slash, Column: column, Value: "\\"}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,19 @@ func parseRune(i *iterator.Iterator[rune], expected func(rune) bool) (rune, erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseCharacter(i *iterator.Iterator[rune], expected rune) (rune, error) {
|
||||||
|
i2 := i.Copy()
|
||||||
|
|
||||||
|
if r, err := i2.Next(); err != nil {
|
||||||
|
return r, err
|
||||||
|
} else if r != expected {
|
||||||
|
return r, fmt.Errorf("got unexpected rune %v'", r)
|
||||||
|
} else {
|
||||||
|
i.Sync(i2)
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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.Token, error) {
|
||||||
@@ -53,6 +66,18 @@ func getToken(i *iterator.Iterator[rune]) (*token.Token, error) {
|
|||||||
return token.NewSlash(index), nil
|
return token.NewSlash(index), nil
|
||||||
case letter == '\n':
|
case letter == '\n':
|
||||||
return token.NewNewline(index), nil
|
return token.NewNewline(index), nil
|
||||||
|
case letter == '{':
|
||||||
|
return token.NewNewline(index), nil
|
||||||
|
case letter == '}':
|
||||||
|
return token.NewNewline(index), nil
|
||||||
|
case letter == ':':
|
||||||
|
if _, err := parseCharacter(i, '='); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return token.NewAssign(index), nil
|
||||||
|
}
|
||||||
|
case letter == ';':
|
||||||
|
return token.NewEnd(index), nil
|
||||||
case unicode.IsSpace(letter):
|
case unicode.IsSpace(letter):
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case isVariable(letter):
|
case isVariable(letter):
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
0 := \f x.x
|
(true x y) := x
|
||||||
(inc n) := \f x.(f (n f x))
|
(false x y) := y
|
||||||
(add n m) := (m inc n)
|
|
||||||
(mult n m) := (m (n f))
|
|
||||||
(exp m n) := (m n)
|
|
||||||
|
|
||||||
# This is the final output.
|
(pair a b) := \c.(c a b)
|
||||||
5 := (inc (inc (inc (inc (inc 0)))))
|
(left p) := (p true)
|
||||||
(exp 5 5)
|
(false p) := (p false)
|
||||||
|
|
||||||
|
zero 0 1 x = x
|
||||||
|
|
||||||
|
inc n := \0 1 x.{
|
||||||
|
initial := (pair true x)
|
||||||
|
(on_zero p) := (pair false ((left p 1 0) (right p)))
|
||||||
|
(on_one p) := (pair (left p) (1 (right p)))
|
||||||
|
|
||||||
|
(n on_zero on_one initial)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user