diff --git a/lex.go b/lex.go index b81c9b1..012e009 100644 --- a/lex.go +++ b/lex.go @@ -49,6 +49,7 @@ var ( Newline = &Token{value: "\n"} SingleQuote = &Token{value: "'"} Let = &Token{value: "let"} + LambdaTok = &Token{value: "lambda"} ) func (t Token) String() string { @@ -71,6 +72,7 @@ var knownTokens = []*Token{ Newline, SingleQuote, Let, + LambdaTok, } func (t *Token) Equals(a Lexeme) bool { diff --git a/main.go b/main.go index 712d034..adb1fe3 100644 --- a/main.go +++ b/main.go @@ -13,14 +13,35 @@ func (v *Value[T]) Step() (Expression, error) { return v, nil } +func (v *Value[T]) Replace(Id, Expression) { +} + func (v *Quoted) Step() (Expression, error) { return v, nil } +func (v *Quoted) Replace(Id, Expression) { +} + func (d *Declaration) Step() (Expression, error) { return &Value[int]{0}, nil } +func (v *Declaration) Replace(id Id, expr Expression) { + if id == v.id.value { + return + } else { + switch x := v.expr.(type) { + case *Identifier: + if x.value == id { + v.expr = expr + } + default: + x.Replace(id, expr) + } + } +} + func (v *Identifier) Step() (Expression, error) { switch v.value { case "+": @@ -37,7 +58,6 @@ func (v *Identifier) Step() (Expression, error) { sum += x.value.value default: return nil, fmt.Errorf("invalid type") - } } return &Value[int]{sum}, nil @@ -48,6 +68,50 @@ func (v *Identifier) Step() (Expression, error) { } } +func (v *Identifier) Replace(id Id, expr Expression) { + panic("!") +} + +func (l *Lambda) Step() (Expression, error) { + f := func(args []Expression) (Expression, error) { + if len(args) != len(l.args) { + return nil, fmt.Errorf("unexpected number of arguments") + } + for i, arg := range l.args { + argExpr := args[i] + for j, e := range l.body { + switch x := e.(type) { + case *Identifier: + if x.value == arg.value { + l.body[j] = argExpr + } + default: + e.Replace(arg.value, argExpr) + } + } + } + if len(l.body) == 0 { + return &Value[int]{0}, nil + } + for i, expr := range l.body { + if isValue(expr) { + continue + } + r, err := expr.Step() + if err != nil { + return nil, err + } + l.body[i] = r + } + return l.body[len(l.body)-1], nil + } + return &Value[Function]{f}, nil +} + +func (l *Lambda) Replace(id Id, expr Expression) { + panic("!") +} + func (v *List) Step() (Expression, error) { for i, expr := range v.els { if !isValue(expr) { @@ -73,6 +137,19 @@ func (v *List) Step() (Expression, error) { return r, nil } +func (v *List) Replace(id Id, expr Expression) { + for i, e := range v.els { + switch x := e.(type) { + case *Identifier: + if x.value == id { + v.els[i] = expr + } + default: + e.Replace(id, expr) + } + } +} + func isValue(e Expression) bool { switch e.(type) { case *Value[int], *Value[*Int], *Value[Function], *Quoted: @@ -86,7 +163,7 @@ func fullStep(e Expression) (Expression, error) { for !isValue(e) { n, err := e.Step() if err != nil { - return n, nil + return nil, err } e = n } diff --git a/parse.go b/parse.go index c099a59..785278d 100644 --- a/parse.go +++ b/parse.go @@ -12,6 +12,7 @@ type Function func([]Expression) (Expression, error) type Expression interface { Step() (Expression, error) + Replace(Id, Expression) // Visit(func(Expression) error) } @@ -32,6 +33,11 @@ type Declaration struct { expr Expression } +type Lambda struct { + args []*Identifier + body []Expression +} + func (v Value[T]) String() string { return fmt.Sprint(v.value) } @@ -48,69 +54,65 @@ func (v List) String() string { return fmt.Sprintf("(%s)", strings.Join(s, " ")) } +func (v *Lambda) String() string { + // var args = new(List) + // args.els = append(args.els, v.args...) + // + // var s []string + // for _, e := range v.args { + // s = append(s, fmt.Sprint(e)) + // } + return "fuck you" +} + 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) @@ -120,38 +122,79 @@ func parseList(in *Input) (Expression, error) { } 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 } +func parseLambda(in *Input) (Expression, error) { + openingParens := in.Pop() + 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 := decl.Pop() + 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 []*Identifier + for _, e := range list.els { + id, ok := e.(*Identifier) + if !ok { + return nil, noMatch + } + args = append(args, id) + } + var body []Expression + for decl.Len() > 0 { + n, err := consume(decl) + if err != nil { + return nil, err + } + body = append(body, n) + } + _ = in.Pop() + 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, parseList, parseSymbol, parseValue, parseLet, } for _, f := range parseFunctions { + start := in.Index() n, err := f(in) if err != nil { + in.Seek(start) if errors.Is(err, noMatch) { continue } else {