package saccharine import ( "fmt" "git.maximhutz.com/max/lambda/pkg/iterator" ) func isVariableToken(t Token) bool { return t.Type == TokenVariable } func ParseExpression(i *iterator.Iterator[Token]) (Node, error) { token, err := i.Pop() if err != nil { return nil, fmt.Errorf("could not get next token: %w", err) } switch token.Type { case TokenVariable: return NewVariable(token.Value), nil case TokenDot: return nil, fmt.Errorf("token '.' found without a corresponding slash (column %d)", token.Index) case TokenSlash: tokens := i.PopWhile(isVariableToken) variables := []string{} for _, token := range tokens { variables = append(variables, token.Value) } if dot, dotErr := i.Pop(); dotErr != nil { return nil, fmt.Errorf("could not find parameter terminator: %w", dotErr) } else if dot.Type != TokenDot { return nil, fmt.Errorf("expected '.', got '%v' (column %d)", dot.Value, dot.Index) } body, bodyErr := ParseExpression(i) if bodyErr != nil { return nil, fmt.Errorf("could not parse function body: %w", bodyErr) } return NewAbstraction(variables, body), nil case TokenOpenParen: fn, fnErr := ParseExpression(i) if fnErr != nil { return nil, fmt.Errorf("could not parse call function: %w", fnErr) } args := []Node{} for { if next, nextErr := i.Peek(); nextErr == nil && next.Type == TokenCloseParen { break } arg, argErr := ParseExpression(i) if argErr != nil { return nil, fmt.Errorf("could not parse call argument: %w", argErr) } args = append(args, arg) } closing, closingErr := i.Pop() if closingErr != nil { return nil, fmt.Errorf("could not parse call terminating parenthesis: %w", closingErr) } else if closing.Type != TokenCloseParen { return nil, fmt.Errorf("expected call terminating parenthesis, got '%v' (column %v)", closing.Value, closing.Index) } return NewApplication(fn, args), nil } return nil, fmt.Errorf("unexpected token '%v' (column %d)", token.Value, token.Index) } func GetTree(tokens []Token) (Node, error) { return ParseExpression(iterator.New(tokens)) }