package main import ( "errors" "fmt" "strings" ) var ( noMatch = errors.New("no match") zero = &Value[int]{0} ) type Function func([]Expression) (Expression, error) type Expression interface { Step() (Expression, error) Replace(Id, Expression) } type List struct { els []Expression } type Value[T interface{ int | float64 | Function }] struct { value T // rng Range } type Quoted struct { expr Expression } type Declaration struct { variables []*Symbol body []Expression } type Lambda struct { args []*Symbol body []Expression } type Symbol struct { id *Identifier expr Expression } // type Progn struct { // *List // } 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 (v Lambda) String() string { var args List for _, arg := range v.args { args.els = append(args.els, arg) } var s []string for _, e := range v.body { s = append(s, fmt.Sprint(e)) } return fmt.Sprintf("(lambda %v %v)", &args, strings.Join(s, " ")) } func (v Function) String() string { return "(lambda (..) (..))" } func (t Symbol) String() string { return fmt.Sprintf("%v", t.id.value) } func parseQuotedObject(in *Input) (Expression, error) { l, ok := in.Pop() if !ok { return nil, noMatch } switch { case l.Equals(SingleQuote): n, err := consume(in) if err != nil { return nil, err } return &Quoted{n}, nil default: return nil, noMatch } } func parseSymbol(in *Input) (Expression, error) { l, ok := in.Pop() if !ok { return nil, noMatch } switch x := l.(type) { case *Identifier: return &Symbol{id: x}, nil default: return nil, noMatch } } func parseValue(in *Input) (Expression, error) { l, ok := in.Pop() if !ok { return nil, noMatch } switch x := l.(type) { case *Int: return &Value[int]{x.value}, nil case *Float: return &Value[float64]{x.value}, nil default: return nil, noMatch } } func parseList(in *Input) (Expression, error) { openingParens, ok := in.Pop() if !ok { return nil, noMatch } if !openingParens.Equals(Lparen) { return nil, noMatch } idx, ok := in.Find(Lparen, Rparen) if !ok { return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position()) } list := in.Take(idx) var args = new(List) for list.Len() > 0 { arg, err := consume(list) if err != nil { return nil, err } args.els = append(args.els, arg) } _, ok = in.Pop() if !ok { return nil, noMatch } return args, nil } func parseLet(in *Input) (Expression, error) { openingParens, ok := in.Pop() if !ok { return nil, noMatch } if !openingParens.Equals(Lparen) { return nil, noMatch } idx, ok := in.Find(Lparen, Rparen) if !ok { return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position()) } decl := in.Take(idx) tok, ok := decl.Pop() if !ok { return nil, noMatch } if !tok.Equals(Let) { return nil, noMatch } l, err := parseList(decl) if err != nil { return nil, err } list, ok := l.(*List) if !ok { return nil, noMatch } var variables []*Symbol for _, e := range list.els { l, ok := e.(*List) if !ok { return nil, noMatch } if len(l.els) != 2 { return nil, noMatch } d, ok := l.els[0].(*Symbol) if !ok { return nil, noMatch } d.expr = l.els[1] variables = append(variables, d) } body, err := consumeAll(decl) if err != nil { return nil, err } return &Declaration{variables: variables, body: body}, nil } func parseLambda(in *Input) (Expression, error) { openingParens, ok := in.Pop() if !ok { return nil, noMatch } if !openingParens.Equals(Lparen) { return nil, noMatch } idx, ok := in.Find(Lparen, Rparen) if !ok { return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position()) } decl := in.Take(idx) tok, ok := decl.Pop() if !ok { return nil, noMatch } if !tok.Equals(LambdaTok) { return nil, noMatch } l, err := parseList(decl) if err != nil { return nil, err } list, ok := l.(*List) if !ok { return nil, noMatch } var args []*Symbol for _, e := range list.els { id, ok := e.(*Symbol) if !ok { return nil, noMatch } args = append(args, id) } body, err := consumeAll(decl) if err != nil { return nil, err } _, ok = in.Pop() if !ok { return nil, noMatch } return &Lambda{args: args, body: body}, nil } type ParserFunc func(*Input) (Expression, error) func consume(in *Input) (n Expression, err error) { var parseFunctions = []ParserFunc{ parseQuotedObject, parseLambda, parseLet, parseList, parseSymbol, parseValue, } for _, f := range parseFunctions { start := in.Index() n, err := f(in) if err != nil { in.Seek(start) if errors.Is(err, noMatch) { continue } else { return nil, err } } return n, nil } return nil, fmt.Errorf("unrecognized construction: %s", in) } func consumeAll(in *Input) (e []Expression, err error) { for in.Len() > 0 { start := in.Index() n, err := consume(in) if err != nil { in.Seek(start) return nil, err } e = append(e, n) } return e, err }