package main import ( "errors" "fmt" "strings" ) var noMatch = errors.New("no match") type Function func([]Expression) (Expression, error) type Expression interface { Step() (Expression, error) // Visit(func(Expression) error) } type List struct { els []Expression } type Value[T interface{ *Int | int | Function }] struct { value T } type Quoted struct { expr Expression } type Declaration struct { id *Identifier expr Expression } func (v Value[T]) String() string { return fmt.Sprint(v.value) } func (v Quoted) String() string { return fmt.Sprintf("'%s", v.expr) } func (v List) String() string { var s []string for _, e := range v.els { s = append(s, fmt.Sprint(e)) } return fmt.Sprintf("(%s)", strings.Join(s, " ")) } func parseQuotedObject(in *Input) (Expression, error) { start := in.Index() l := in.Pop() switch { case l.Equals(SingleQuote): n, err := consume(in) if err != nil { in.Seek(start) return nil, err } return &Quoted{n}, nil default: in.Seek(start) return nil, noMatch } } func parseSymbol(in *Input) (Expression, error) { start := in.Index() l := in.Pop() switch x := l.(type) { case *Identifier: return x, nil default: in.Seek(start) return nil, noMatch } } func parseValue(in *Input) (Expression, error) { start := in.Index() l := in.Pop() switch x := l.(type) { case *Int: return &Value[*Int]{x}, nil default: in.Seek(start) return nil, noMatch } } func parseList(in *Input) (Expression, error) { start := in.Index() openingParens := in.Pop() if !openingParens.Equals(Lparen) { in.Seek(start) return nil, noMatch } idx, ok := in.Find(Lparen, Rparen) if !ok { in.Seek(start) return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position()) } if idx == 0 { in.Seek(start) return nil, fmt.Errorf("no function declared at %s", openingParens.Position()) } list := in.Take(idx) var args = new(List) for list.Len() > 0 { arg, err := consume(list) if err != nil { in.Seek(start) return nil, err } args.els = append(args.els, arg) } _ = in.Pop() return args, nil } func parseLet(in *Input) (Expression, error) { start := in.Index() token := in.Pop() if !token.Equals(Let) { in.Seek(start) return nil, noMatch } id, ok := in.Pop().(*Identifier) if !ok { in.Seek(start) return nil, noMatch } expr, err := consume(in) if err != nil { in.Seek(start) return nil, noMatch } return &Declaration{id: id, expr: expr}, nil } type ParserFunc func(*Input) (Expression, error) func consume(in *Input) (n Expression, err error) { var parseFunctions = []ParserFunc{ parseQuotedObject, parseList, parseSymbol, parseValue, parseLet, } for _, f := range parseFunctions { n, err := f(in) if err != nil { if errors.Is(err, noMatch) { continue } else { return nil, err } } return n, nil } return nil, fmt.Errorf("unrecognized construction: %s", in) }