diff --git a/pkg/saccharine/expression.go b/pkg/saccharine/expression.go deleted file mode 100644 index 3cf127c..0000000 --- a/pkg/saccharine/expression.go +++ /dev/null @@ -1,31 +0,0 @@ -package saccharine - -type Expression interface { - expression() -} - -/** ------------------------------------------------------------------------- */ - -type Abstraction struct { - Parameters []string - Body Expression -} - -type Application struct { - Abstraction Expression - Arguments []Expression -} - -type Atom struct { - Name string -} - -type Clause struct { - Statements []Statement - Returns Expression -} - -func (Abstraction) expression() {} -func (Application) expression() {} -func (Atom) expression() {} -func (Clause) expression() {} diff --git a/pkg/saccharine/parse.go b/pkg/saccharine/parse.go index 3bb9285..60a8736 100644 --- a/pkg/saccharine/parse.go +++ b/pkg/saccharine/parse.go @@ -7,10 +7,10 @@ import ( "git.maximhutz.com/max/lambda/pkg/iterator" ) -type TokenIterator = iterator.Iterator[Token] +type tokenIterator = iterator.Iterator[Token] -func parseRawToken(i *TokenIterator, expected TokenType) (*Token, error) { - return iterator.Do(i, func(i *TokenIterator) (*Token, error) { +func parseRawToken(i *tokenIterator, expected TokenType) (*Token, error) { + return iterator.Do(i, func(i *tokenIterator) (*Token, error) { if tok, err := i.Next(); err != nil { return nil, err } else if tok.Type != expected { @@ -21,7 +21,7 @@ func parseRawToken(i *TokenIterator, expected TokenType) (*Token, error) { }) } -func passSoftBreaks(i *TokenIterator) { +func passSoftBreaks(i *tokenIterator) { for { if _, err := parseRawToken(i, TokenSoftBreak); err != nil { return @@ -29,8 +29,8 @@ func passSoftBreaks(i *TokenIterator) { } } -func parseToken(i *TokenIterator, expected TokenType, ignoreSoftBreaks bool) (*Token, error) { - return iterator.Do(i, func(i *TokenIterator) (*Token, error) { +func parseToken(i *tokenIterator, expected TokenType, ignoreSoftBreaks bool) (*Token, error) { + return iterator.Do(i, func(i *tokenIterator) (*Token, error) { if ignoreSoftBreaks { passSoftBreaks(i) } @@ -39,7 +39,7 @@ func parseToken(i *TokenIterator, expected TokenType, ignoreSoftBreaks bool) (*T }) } -func parseString(i *TokenIterator) (string, error) { +func parseString(i *tokenIterator) (string, error) { if tok, err := parseToken(i, TokenAtom, true); err != nil { return "", fmt.Errorf("no variable (col %d): %w", i.Index(), err) } else { @@ -47,7 +47,7 @@ func parseString(i *TokenIterator) (string, error) { } } -func parseBreak(i *TokenIterator) (*Token, error) { +func parseBreak(i *tokenIterator) (*Token, error) { if tok, softErr := parseRawToken(i, TokenSoftBreak); softErr == nil { return tok, nil } else if tok, hardErr := parseRawToken(i, TokenHardBreak); hardErr == nil { @@ -57,7 +57,7 @@ func parseBreak(i *TokenIterator) (*Token, error) { } } -func parseList[U any](i *TokenIterator, fn func(*TokenIterator) (U, error), minimum int) ([]U, error) { +func parseList[U any](i *tokenIterator, fn func(*tokenIterator) (U, error), minimum int) ([]U, error) { results := []U{} for { @@ -72,8 +72,8 @@ func parseList[U any](i *TokenIterator, fn func(*TokenIterator) (U, error), mini } } -func parseAbstraction(i *TokenIterator) (*Abstraction, error) { - return iterator.Do(i, func(i *TokenIterator) (*Abstraction, error) { +func parseAbstraction(i *tokenIterator) (*Abstraction, error) { + return iterator.Do(i, func(i *tokenIterator) (*Abstraction, error) { if _, err := parseToken(i, TokenSlash, true); err != nil { return nil, fmt.Errorf("no function slash (col %d): %w", i.MustGet().Column, err) } else if parameters, err := parseList(i, parseString, 0); err != nil { @@ -88,8 +88,8 @@ func parseAbstraction(i *TokenIterator) (*Abstraction, error) { }) } -func parseApplication(i *TokenIterator) (*Application, error) { - return iterator.Do(i, func(i *TokenIterator) (*Application, error) { +func parseApplication(i *tokenIterator) (*Application, error) { + return iterator.Do(i, func(i *tokenIterator) (*Application, error) { if _, err := parseToken(i, TokenOpenParen, true); err != nil { return nil, fmt.Errorf("no openning brackets (col %d): %w", i.MustGet().Column, err) } else if expressions, err := parseList(i, parseExpression, 1); err != nil { @@ -102,7 +102,7 @@ func parseApplication(i *TokenIterator) (*Application, error) { }) } -func parseAtom(i *TokenIterator) (*Atom, error) { +func parseAtom(i *tokenIterator) (*Atom, error) { if tok, err := parseToken(i, TokenAtom, true); err != nil { return nil, fmt.Errorf("no variable (col %d): %w", i.Index(), err) } else { @@ -110,7 +110,7 @@ func parseAtom(i *TokenIterator) (*Atom, error) { } } -func parseStatements(i *TokenIterator) ([]Statement, error) { +func parseStatements(i *tokenIterator) ([]Statement, error) { statements := []Statement{} //nolint:errcheck @@ -129,7 +129,7 @@ func parseStatements(i *TokenIterator) ([]Statement, error) { return statements, nil } -func parseClause(i *TokenIterator, braces bool) (*Clause, error) { +func parseClause(i *tokenIterator, braces bool) (*Clause, error) { if braces { if _, err := parseToken(i, TokenOpenBrace, true); err != nil { return nil, err @@ -158,8 +158,8 @@ func parseClause(i *TokenIterator, braces bool) (*Clause, error) { return &Clause{Statements: stmts[:len(stmts)-1], Returns: last.Value}, nil } -func parseExpression(i *TokenIterator) (Expression, error) { - return iterator.Do(i, func(i *TokenIterator) (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 { @@ -177,8 +177,8 @@ func parseExpression(i *TokenIterator) (Expression, error) { }) } -func parseLet(i *TokenIterator) (*LetStatement, error) { - return iterator.Do(i, func(i *TokenIterator) (*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, TokenAssign, true); err != nil { @@ -191,7 +191,7 @@ func parseLet(i *TokenIterator) (*LetStatement, error) { }) } -func parseDeclare(i *TokenIterator) (*DeclareStatement, error) { +func parseDeclare(i *tokenIterator) (*DeclareStatement, error) { if value, err := parseExpression(i); err != nil { return nil, err } else { @@ -199,7 +199,7 @@ func parseDeclare(i *TokenIterator) (*DeclareStatement, error) { } } -func parseStatement(i *TokenIterator) (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 { diff --git a/pkg/saccharine/saccharine.go b/pkg/saccharine/saccharine.go new file mode 100644 index 0000000..a4b2d50 --- /dev/null +++ b/pkg/saccharine/saccharine.go @@ -0,0 +1,60 @@ +// Package saccharine defines the AST for the Saccharine language, a sugared +// lambda calculus with let bindings and multi-statement clauses. +package saccharine + +// An Expression is a node in the Saccharine abstract syntax tree. +// It is a sealed interface; only types in this package may implement it. +type Expression interface { + expression() +} + +// An Abstraction is a lambda expression with zero or more parameters. +// A zero-parameter abstraction is treated as a thunk. +type Abstraction struct { + Parameters []string + Body Expression +} + +// An Application applies an expression to zero or more arguments. +type Application struct { + Abstraction Expression + Arguments []Expression +} + +// An Atom is a named variable. +type Atom struct { + Name string +} + +// A Clause is a sequence of statements followed by a return expression. +type Clause struct { + Statements []Statement + Returns Expression +} + +func (Abstraction) expression() {} +func (Application) expression() {} +func (Atom) expression() {} +func (Clause) expression() {} + +// A Statement is a declaration within a Clause. +// It is a sealed interface; only types in this package may implement it. +type Statement interface { + statement() +} + +// A LetStatement binds a name (with optional parameters) to an expression. +type LetStatement struct { + Name string + Parameters []string + Body Expression +} + +// A DeclareStatement evaluates an expression for its side effects within a +// clause. +type DeclareStatement struct { + Value Expression +} + +func (LetStatement) statement() {} +func (DeclareStatement) statement() {} diff --git a/pkg/saccharine/statement.go b/pkg/saccharine/statement.go deleted file mode 100644 index 03e5302..0000000 --- a/pkg/saccharine/statement.go +++ /dev/null @@ -1,20 +0,0 @@ -package saccharine - -type Statement interface { - statement() -} - -/** ------------------------------------------------------------------------- */ - -type LetStatement struct { - Name string - Parameters []string - Body Expression -} - -type DeclareStatement struct { - Value Expression -} - -func (LetStatement) statement() {} -func (DeclareStatement) statement() {}