feat: error for when there is more source code than parsed

This commit is contained in:
2025-12-27 02:08:18 -05:00
parent df53409887
commit 884180de92
6 changed files with 54 additions and 13 deletions

View File

@@ -25,7 +25,7 @@ func main() {
cli.HandleError(err) cli.HandleError(err)
// Parse tokens. // Parse tokens.
tokens, err := saccharine.GetTokens([]rune(input)) tokens, err := saccharine.GetTokens(input)
cli.HandleError(err) cli.HandleError(err)
logger.Info("parsed tokens", "tokens", tokens) logger.Info("parsed tokens", "tokens", tokens)

View File

@@ -39,6 +39,15 @@ func (i Iterator[T]) Get() (T, error) {
return i.items[i.index], nil return i.items[i.index], nil
} }
func (i Iterator[T]) MustGet() T {
var null T
if i.Done() {
return null
}
return i.items[i.index]
}
// Create a new iterator, over a set of items. // Create a new iterator, over a set of items.
func (i *Iterator[T]) Next() (T, error) { func (i *Iterator[T]) Next() (T, error) {
item, err := i.Get() item, err := i.Get()

View File

@@ -17,7 +17,7 @@ func parseToken(i *TokenIterator, expected token.Type) (*token.Token, error) {
if tok, err := i2.Next(); err != nil { if tok, err := i2.Next(); err != nil {
return nil, err return nil, err
} else if tok.Type != expected { } else if tok.Type != expected {
return nil, fmt.Errorf("expected token, got %v'", tok.Value) return nil, fmt.Errorf("expected token %v, got %v'", token.Name(expected), tok.Value)
} else { } else {
i.Sync(i2) i.Sync(i2)
return &tok, nil return &tok, nil
@@ -56,11 +56,11 @@ func parseAbstraction(i *TokenIterator) (*ast.Abstraction, error) {
i2 := i.Copy() i2 := i.Copy()
if _, err := parseToken(i2, token.Slash); err != nil { if _, err := parseToken(i2, token.Slash); err != nil {
return nil, err return nil, fmt.Errorf("no function slash (col %d): %w", i2.MustGet().Index, err)
} else if parameters, err := parseParameters(i2); err != nil { } else if parameters, err := parseParameters(i2); err != nil {
return nil, err return nil, err
} else if _, err = parseToken(i2, token.Dot); err != nil { } else if _, err = parseToken(i2, token.Dot); err != nil {
return nil, err return nil, fmt.Errorf("no function dot (col %d): %w", i2.MustGet().Index, err)
} else if body, err := parseExpression(i2); err != nil { } else if body, err := parseExpression(i2); err != nil {
return nil, err return nil, err
} else { } else {
@@ -74,7 +74,7 @@ func parseApplication(i *TokenIterator) (*ast.Application, error) {
expressions := []ast.Expression{} expressions := []ast.Expression{}
if _, err := parseToken(i2, token.OpenParen); err != nil { if _, err := parseToken(i2, token.OpenParen); err != nil {
return nil, err return nil, fmt.Errorf("no openning brackets (col %d): %w", i2.MustGet().Index, err)
} }
for { for {
@@ -86,7 +86,7 @@ func parseApplication(i *TokenIterator) (*ast.Application, error) {
} }
if _, err := parseToken(i2, token.CloseParen); err != nil { if _, err := parseToken(i2, token.CloseParen); err != nil {
return nil, err return nil, fmt.Errorf("no closing brackets (col %d): %w", i2.MustGet().Index, err)
} }
if len(expressions) == 0 { if len(expressions) == 0 {
@@ -99,12 +99,23 @@ func parseApplication(i *TokenIterator) (*ast.Application, error) {
func parseAtom(i *TokenIterator) (*ast.Atom, error) { func parseAtom(i *TokenIterator) (*ast.Atom, error) {
if tok, err := parseToken(i, token.Atom); err != nil { if tok, err := parseToken(i, token.Atom); err != nil {
return nil, err return nil, fmt.Errorf("no variable (col %d): %w", i.Index(), err)
} else { } else {
return ast.NewAtom(tok.Value), nil return ast.NewAtom(tok.Value), nil
} }
} }
func Parse(i *TokenIterator) (ast.Expression, error) { func Parse(tokens []token.Token) (ast.Expression, error) {
return parseExpression(i) i := iterator.Of(tokens)
exp, err := parseExpression(i)
if err != nil {
return nil, err
}
if !i.Done() {
return nil, fmt.Errorf("expected EOF, found more code (col %d)", i.MustGet().Index)
}
return exp, nil
} }

View File

@@ -45,3 +45,24 @@ func NewSlash(index int) *Token {
func NewAtom(name string, index int) *Token { func NewAtom(name string, index int) *Token {
return &Token{Type: Atom, Index: index, Value: name} return &Token{Type: Atom, Index: index, Value: name}
} }
func Name(typ Type) string {
switch typ {
case OpenParen:
return "("
case CloseParen:
return ")"
case Slash:
return "\\"
case Dot:
return "."
case Atom:
return "ATOM"
default:
return "?"
}
}
func (t Token) Name() string {
return Name(t.Type)
}

View File

@@ -70,8 +70,8 @@ func getToken(i *iterator.Iterator[rune]) (*token.Token, error) {
} }
// Parses a list of runes into tokens. All error encountered are returned, as well. // Parses a list of runes into tokens. All error encountered are returned, as well.
func GetTokens(input []rune) (*iterator.Iterator[token.Token], error) { func GetTokens(input string) ([]token.Token, error) {
i := iterator.Of(input) i := iterator.Of([]rune(input))
tokens := []token.Token{} tokens := []token.Token{}
errorList := []error{} errorList := []error{}
@@ -84,5 +84,5 @@ func GetTokens(input []rune) (*iterator.Iterator[token.Token], error) {
} }
} }
return iterator.Of(tokens), errors.Join(errorList...) return tokens, errors.Join(errorList...)
} }

View File

@@ -7,7 +7,7 @@
\n m.(m n) \n m.(m n)
) )
\m n f.(m (n f)) \m n f.(m (n f))
) ))
\n m.(m inc n) \n m.(m inc n)
) )
\n f x.(f (n f x)) \n f x.(f (n f x))