package parser import ( "fmt" "git.maximhutz.com/max/lambda/pkg/iterator" "git.maximhutz.com/max/lambda/pkg/lambda" "git.maximhutz.com/max/lambda/pkg/tokenizer" ) func ParseExpression(i *iterator.Iterator[tokenizer.Token]) (lambda.Expression, error) { token, err := i.Next() if err != nil { return nil, fmt.Errorf("could not get next token: %w", err) } switch token.Type { case tokenizer.TokenVariable: return lambda.NewVariable(token.Value), nil case tokenizer.TokenDot: return nil, fmt.Errorf("token '.' found without a corresponding slash (column %d)", token.Index) case tokenizer.TokenSlash: atoms := []string{} for { atom, atom_err := i.Next() if atom_err != nil { return nil, fmt.Errorf("could not find parameter or terminator of function: %w", atom_err) } else if atom.Type == tokenizer.TokenVariable { atoms = append(atoms, atom.Value) } else if atom.Type == tokenizer.TokenDot { break } else { return nil, fmt.Errorf("expected function parameter or terminator, got '%v' (column %d)", atom.Value, atom.Index) } } if len(atoms) == 0 { return nil, fmt.Errorf("every function must have atleast one parameter (column %d)", token.Index) } body, body_err := ParseExpression(i) if body_err != nil { return nil, fmt.Errorf("could not parse function body: %w", body_err) } // Construction. result := body for i := len(atoms) - 1; i >= 0; i-- { result = lambda.NewAbstraction(atoms[i], result) } return result, nil case tokenizer.TokenOpenParen: fn, fn_err := ParseExpression(i) if fn_err != nil { return nil, fmt.Errorf("could not parse call function: %w", fn_err) } args := []lambda.Expression{} for { if next, next_err := i.Peek(); next_err == nil && next.Type == tokenizer.TokenCloseParen { break } arg, arg_err := ParseExpression(i) if arg_err != nil { return nil, fmt.Errorf("could not parse call argument: %w", arg_err) } args = append(args, arg) } close, close_err := i.Next() if close_err != nil { return nil, fmt.Errorf("Could not parse call terminating parenthesis: %w", close_err) } else if close.Type != tokenizer.TokenCloseParen { return nil, fmt.Errorf("expected call terminating parenthesis, got '%v' (column %v)", close.Value, close.Index) } // Construction. result := fn for _, arg := range args { result = lambda.NewApplication(result, arg) } return result, nil case tokenizer.TokenCloseParen: return nil, fmt.Errorf("token ')' found without a corresponding openning parenthesis (column %d)", token.Index) default: return nil, fmt.Errorf("unknown token '%v' (column %d)", token.Value, token.Index) } } func GetTree(tokens []tokenizer.Token) (lambda.Expression, error) { i := iterator.New(tokens) return ParseExpression(&i) }