From 8f5b16878fedd5434953d42b592165f5851947d3 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Sun, 25 May 2025 21:56:22 -0300 Subject: [PATCH] Let --- input.go | 7 +- lex.go | 30 +++++-- main.go | 234 +++++++++++++++++++++++++++++++++++-------------------- parse.go | 189 ++++++++++++++++++++++++++++++++------------ 4 files changed, 316 insertions(+), 144 deletions(-) diff --git a/input.go b/input.go index 0676d21..4d9c012 100644 --- a/input.go +++ b/input.go @@ -28,10 +28,13 @@ func (in *Input) Peek(i int) Lexeme { return in.input[in.index+i] } -func (in *Input) Pop() Lexeme { +func (in *Input) Pop() (Lexeme, bool) { + if in.index > len(in.input)-1 { + return nil, false + } v := in.input[in.index] in.index++ - return v + return v, true } func (in *Input) Seek(i int) { diff --git a/lex.go b/lex.go index 012e009..46892df 100644 --- a/lex.go +++ b/lex.go @@ -39,6 +39,8 @@ type Token token[string] type Int token[int] +type Float token[float64] + type Identifier token[Id] var ( @@ -84,9 +86,8 @@ func (t *Token) Equals(a Lexeme) bool { } } -func (t *Int) Equals(a Lexeme) bool { - return false -} +func (t *Int) Equals(a Lexeme) bool { return false } +func (t *Float) Equals(a Lexeme) bool { return false } func (t *Identifier) Equals(a Lexeme) bool { switch x := a.(type) { @@ -97,17 +98,18 @@ func (t *Identifier) Equals(a Lexeme) bool { } } -var matchNumbers = regexp.MustCompile(`-?\d+`) +var matchInt = regexp.MustCompile(`-?\d+`) +var matchFloat = regexp.MustCompile(`-?\d+\.\d*`) var matchIdentifier = regexp.MustCompile(`[^\'() ]+`) func lex(source string) (*Input, error) { var ( - pos, line, column int + pos, line, column int = 1, 1, 1 tokens []Lexeme ) outer: for len(source) > 0 { - p := position{pos: pos, line: line, column: column, filepath: "sourceinput"} + p := position{pos: pos, line: line, column: column, filepath: "stdin"} for _, try := range knownTokens { if !strings.HasPrefix(source, try.value) { continue @@ -130,7 +132,21 @@ outer: } continue outer } - index := matchNumbers.FindStringSubmatchIndex(source) + index := matchFloat.FindStringSubmatchIndex(source) + if index != nil && index[0] == 0 { + a := source[index[0]:index[1]] + conv, err := strconv.ParseFloat(a, 64) + if err == nil { + var i = &Float{position: p, value: conv} + tokens = append(tokens, i) + l := len(a) + source = source[l:] + column += l + pos += l + continue outer + } + } + index = matchInt.FindStringSubmatchIndex(source) if index != nil && index[0] == 0 { a := source[index[0]:index[1]] conv, err := strconv.Atoi(a) diff --git a/main.go b/main.go index adb1fe3..6e3a970 100644 --- a/main.go +++ b/main.go @@ -1,75 +1,74 @@ package main import ( + "flag" "fmt" + "log" "os" ) -var source = ` - (+ 1 2 3 4) - ` +var source = "" -func (v *Value[T]) Step() (Expression, error) { - return v, nil -} +func (v *Value[T]) Step() (Expression, error) { return v, nil } +func (v *Value[T]) Replace(Id, Expression) {} -func (v *Value[T]) Replace(Id, Expression) { -} - -func (v *Quoted) Step() (Expression, error) { - return v, nil -} - -func (v *Quoted) 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 + for _, v := range d.variables { + if isValue(v.expr) { + continue + } + n, err := v.expr.Step() + if err != nil { + return nil, err + } + v.expr = n + return d, nil + } + for _, v := range d.variables { + for _, b := range d.body { + b.Replace(v.id.value, v.expr) + } + } + if len(d.body) == 0 { + return zero, nil + } + for i, b := range d.body { + if isValue(b) { + continue + } + n, err := b.Step() + if err != nil { + return nil, err + } + d.body[i] = n + return d, nil + } + return d.body[len(d.body)-1], 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 (d *Declaration) Replace(id Id, expr Expression) { + for _, v := range d.variables { + v.expr.Replace(id, expr) + } + for _, b := range d.body { + b.Replace(id, expr) } } -func (v *Identifier) Step() (Expression, error) { - switch v.value { - case "+": - f := func(args []Expression) (Expression, error) { - sum := 0 - for _, arg := range args { - if !isValue(arg) { - panic("!") - } - switch x := arg.(type) { - case *Value[int]: - sum += x.value - case *Value[*Int]: - sum += x.value.value - default: - return nil, fmt.Errorf("invalid type") - } - } - return &Value[int]{sum}, nil - } - return &Value[Function]{f}, nil - default: - panic("!") +func (v *Symbol) Step() (Expression, error) { + if v.expr == nil { + return nil, fmt.Errorf("unbound symbol %s at %s", v.id, v.id.position) } + return v.expr, nil } -func (v *Identifier) Replace(id Id, expr Expression) { - panic("!") +func (v *Symbol) Replace(id Id, expr Expression) { + if v.id.value == id { + v.expr = expr + } } func (l *Lambda) Step() (Expression, error) { @@ -78,20 +77,12 @@ func (l *Lambda) Step() (Expression, error) { 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) - } + for _, e := range l.body { + e.Replace(arg.id.value, args[i]) } } if len(l.body) == 0 { - return &Value[int]{0}, nil + return zero, nil } for i, expr := range l.body { if isValue(expr) { @@ -109,7 +100,9 @@ func (l *Lambda) Step() (Expression, error) { } func (l *Lambda) Replace(id Id, expr Expression) { - panic("!") + for _, b := range l.body { + b.Replace(id, expr) + } } func (v *List) Step() (Expression, error) { @@ -124,7 +117,7 @@ func (v *List) Step() (Expression, error) { } } if len(v.els) == 0 { - return nil, fmt.Errorf("empty list") + return zero, nil } f, ok := v.els[0].(*Value[Function]) if !ok { @@ -138,21 +131,14 @@ func (v *List) Step() (Expression, error) { } 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) - } + for _, e := range v.els { + e.Replace(id, expr) } } func isValue(e Expression) bool { switch e.(type) { - case *Value[int], *Value[*Int], *Value[Function], *Quoted: + case *Value[int], *Value[float64], *Value[Function], *Quoted: return true default: return false @@ -170,25 +156,101 @@ func fullStep(e Expression) (Expression, error) { return e, nil } +func stdlib(expr Expression) { + functions := map[Id]Function{ + "+": func(args []Expression) (Expression, error) { + sum := 0 + for _, arg := range args { + if !isValue(arg) { + panic("!") + } + switch x := arg.(type) { + case *Value[int]: + sum += x.value + default: + return nil, fmt.Errorf("invalid type") + } + } + return &Value[int]{sum}, nil + }, + "-": func(args []Expression) (Expression, error) { + v0, ok := args[0].(*Value[int]) + if !ok { + return nil, fmt.Errorf("integer value was expected") + } + v1, ok := args[1].(*Value[int]) + if !ok { + return nil, fmt.Errorf("integer value was expected") + } + return &Value[int]{v0.value - v1.value}, nil + }, + "*": func(args []Expression) (Expression, error) { + v0, ok := args[0].(*Value[int]) + if !ok { + return nil, fmt.Errorf("integer value was expected") + } + v1, ok := args[1].(*Value[int]) + if !ok { + return nil, fmt.Errorf("integer value was expected") + } + return &Value[int]{v0.value * v1.value}, nil + }, + "/": func(args []Expression) (Expression, error) { + v0, ok := args[0].(*Value[int]) + if !ok { + return nil, fmt.Errorf("integer value was expected") + } + v1, ok := args[1].(*Value[int]) + if !ok { + return nil, fmt.Errorf("integer value was expected") + } + return &Value[int]{v0.value / v1.value}, nil + }, + "/.": func(args []Expression) (Expression, error) { + v0, ok := args[0].(*Value[float64]) + if !ok { + return nil, fmt.Errorf("float value was expected") + } + v1, ok := args[1].(*Value[float64]) + if !ok { + return nil, fmt.Errorf("float value was expected") + } + return &Value[float64]{float64(v0.value) / float64(v1.value)}, nil + }, + } + for id, f := range functions { + expr.Replace(id, &Value[Function]{f}) + } +} + func main() { - if len(os.Args) > 1 { - source = os.Args[1] + logger := log.New(os.Stderr, "error: ", 0) + evalString := flag.String("eval", "", "evaluate an expression and return its value") + flag.Parse() + args := flag.Args() + if len(args) > 0 { + bytes, err := os.ReadFile(os.Args[1]) + if err != nil { + logger.Fatal(fmt.Errorf("file not found")) + } + source = string(bytes) + } else if *evalString != "" { + source = *evalString + } else { + logger.Fatal(fmt.Errorf("missing input file")) } tk, err := lex(source) if err != nil { - panic(err) + logger.Fatal(err) } p, err := consume(tk) if err != nil { - panic(err) + logger.Fatal(err) } - s, err := p.Step() + stdlib(p) + result, err := fullStep(p) if err != nil { - panic(err) - } - result, err := fullStep(s) - if err != nil { - panic(err) + logger.Fatal(err) } fmt.Println(result) } diff --git a/parse.go b/parse.go index 785278d..cf0a486 100644 --- a/parse.go +++ b/parse.go @@ -6,22 +6,25 @@ import ( "strings" ) -var noMatch = errors.New("no match") +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) - // Visit(func(Expression) error) } type List struct { els []Expression } -type Value[T interface{ *Int | int | Function }] struct { +type Value[T interface{ int | float64 | Function }] struct { value T + // rng Range } type Quoted struct { @@ -29,14 +32,23 @@ type Quoted struct { } type Declaration struct { + variables []*Symbol + body []Expression +} + +type Lambda struct { + args []*Symbol + body []Expression +} + +type Symbol struct { id *Identifier expr Expression } -type Lambda struct { - args []*Identifier - body []Expression -} +// type Progn struct { +// *List +// } func (v Value[T]) String() string { return fmt.Sprint(v.value) @@ -54,19 +66,31 @@ 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 (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 := in.Pop() + l, ok := in.Pop() + if !ok { + return nil, noMatch + } switch { case l.Equals(SingleQuote): n, err := consume(in) @@ -80,27 +104,38 @@ func parseQuotedObject(in *Input) (Expression, error) { } func parseSymbol(in *Input) (Expression, error) { - l := in.Pop() + l, ok := in.Pop() + if !ok { + return nil, noMatch + } switch x := l.(type) { case *Identifier: - return x, nil + return &Symbol{id: x}, nil default: return nil, noMatch } } func parseValue(in *Input) (Expression, error) { - l := in.Pop() + l, ok := in.Pop() + if !ok { + return nil, noMatch + } switch x := l.(type) { case *Int: - return &Value[*Int]{x}, nil + 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 := in.Pop() + openingParens, ok := in.Pop() + if !ok { + return nil, noMatch + } if !openingParens.Equals(Lparen) { return nil, noMatch } @@ -117,28 +152,18 @@ func parseList(in *Input) (Expression, error) { } args.els = append(args.els, arg) } - _ = in.Pop() + _, ok = in.Pop() + if !ok { + return nil, noMatch + } return args, nil } func parseLet(in *Input) (Expression, error) { - token := in.Pop() - if !token.Equals(Let) { - return nil, noMatch - } - id, ok := in.Pop().(*Identifier) + openingParens, ok := in.Pop() if !ok { return nil, noMatch } - expr, err := consume(in) - if err != nil { - 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 } @@ -147,7 +172,61 @@ func parseLambda(in *Input) (Expression, error) { return nil, fmt.Errorf("unmatched parenthesis starting at %s", openingParens.Position()) } decl := in.Take(idx) - tok := decl.Pop() + 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 } @@ -159,23 +238,22 @@ func parseLambda(in *Input) (Expression, error) { if !ok { return nil, noMatch } - var args []*Identifier + var args []*Symbol for _, e := range list.els { - id, ok := e.(*Identifier) + id, ok := e.(*Symbol) 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) + body, err := consumeAll(decl) + if err != nil { + return nil, err + } + _, ok = in.Pop() + if !ok { + return nil, noMatch } - _ = in.Pop() return &Lambda{args: args, body: body}, nil } @@ -185,10 +263,10 @@ func consume(in *Input) (n Expression, err error) { var parseFunctions = []ParserFunc{ parseQuotedObject, parseLambda, + parseLet, parseList, parseSymbol, parseValue, - parseLet, } for _, f := range parseFunctions { start := in.Index() @@ -205,3 +283,16 @@ func consume(in *Input) (n Expression, err error) { } 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 +}