blob: bc14567d65852b77c70ad1ca679e777fc417098b [file] [log] [blame]
Sketch🕴️cd59d222026-02-28 19:28:26 +04001package repl
2
3import (
4 "bufio"
5 "fmt"
6 "io"
7 "math"
8 "strings"
9
10 "matheval/evaluator"
11 "matheval/lexer"
12 "matheval/parser"
13)
14
15const prompt = ">> "
16
17// Run starts the read-eval-print loop, reading from r and writing to w.
18func Run(r io.Reader, w io.Writer) {
19 scanner := bufio.NewScanner(r)
20 fmt.Fprint(w, prompt)
21
22 for scanner.Scan() {
23 line := strings.TrimSpace(scanner.Text())
24 if line == "" {
25 fmt.Fprint(w, prompt)
26 continue
27 }
28
29 result, err := evalLine(line)
30 if err != nil {
31 fmt.Fprintf(w, "error: %s\n", err)
32 } else {
33 fmt.Fprintln(w, formatResult(result))
34 }
35
36 fmt.Fprint(w, prompt)
37 }
38}
39
40// evalLine tokenizes, parses, and evaluates a single expression string.
41func evalLine(line string) (float64, error) {
42 tokens, err := lexer.Tokenize(line)
43 if err != nil {
44 return 0, err
45 }
46
47 tree, err := parser.Parse(tokens)
48 if err != nil {
49 return 0, err
50 }
51
52 return evaluator.Eval(tree)
53}
54
55// formatResult formats a float64 for display.
56// Whole numbers are printed without decimal points.
57func formatResult(val float64) string {
58 if val == math.Trunc(val) && !math.IsInf(val, 0) && !math.IsNaN(val) {
59 return fmt.Sprintf("%g", val)
60 }
61 return fmt.Sprintf("%g", val)
62}