package main import ( "errors" "fmt" "strings" ) var ( noMatch = errors.New("no match") ) // type Progn struct { // *List // } 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.params { 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 (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 *Token: switch { case x.Equals(TrueTok): v := BoolValue(true) return &v, nil case x.Equals(NilTok): v := BoolValue(false) return &v, nil default: return nil, noMatch } 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 *IntToken: r := IntValue(x.value) return &r, nil case *FloatToken: r := FloatValue(x.value) return &r, nil default: return nil, noMatch } } func parseParamList(in *Input) (Expression, error) { list, err := in.TakeParens(Lparen, Rparen) if err != nil { return nil, err } var params []*Symbol for list.Len() > 0 { p, err := list.TakeParens(LsquareBracket, RsquareBracket) if err != nil { return nil, err } if p.Len() != 2 { return nil, fmt.Errorf("expected parameter in the following form: [identifier type]") } id, ok := p.Peek(0).(*Identifier) if !ok { return nil, noMatch } typ, ok := p.Peek(1).(*Identifier) if !ok { return nil, noMatch } params = append(params, &Symbol{ id: , }) } return args, nil } 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) _, ok = in.Pop() if !ok { return nil, noMatch } 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) if tok, ok := decl.Pop(); !ok || !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{params: args, body: body}, nil } func parseConditional(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) _, ok = in.Pop() tok, ok := decl.Pop() if !ok { return nil, noMatch } if !tok.Equals(If) { return nil, noMatch } predicate, err := consume(decl) if err != nil { return nil, err } ifTrue, err := consume(decl) if err != nil { return nil, err } ifFalse, err := consume(decl) if err != nil { return nil, err } return &Conditional{predicate: predicate, ifTrue: ifTrue, ifFalse: ifFalse}, nil } type ParserFunc func(*Input) (Expression, error) func consume(in *Input) (n Expression, err error) { var parseFunctions = []ParserFunc{ parseQuotedObject, parseLambda, parseConditional, 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 }