blob: bc14567d65852b77c70ad1ca679e777fc417098b [file] [log] [blame]
package repl
import (
"bufio"
"fmt"
"io"
"math"
"strings"
"matheval/evaluator"
"matheval/lexer"
"matheval/parser"
)
const prompt = ">> "
// Run starts the read-eval-print loop, reading from r and writing to w.
func Run(r io.Reader, w io.Writer) {
scanner := bufio.NewScanner(r)
fmt.Fprint(w, prompt)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" {
fmt.Fprint(w, prompt)
continue
}
result, err := evalLine(line)
if err != nil {
fmt.Fprintf(w, "error: %s\n", err)
} else {
fmt.Fprintln(w, formatResult(result))
}
fmt.Fprint(w, prompt)
}
}
// evalLine tokenizes, parses, and evaluates a single expression string.
func evalLine(line string) (float64, error) {
tokens, err := lexer.Tokenize(line)
if err != nil {
return 0, err
}
tree, err := parser.Parse(tokens)
if err != nil {
return 0, err
}
return evaluator.Eval(tree)
}
// formatResult formats a float64 for display.
// Whole numbers are printed without decimal points.
func formatResult(val float64) string {
if val == math.Trunc(val) && !math.IsInf(val, 0) && !math.IsNaN(val) {
return fmt.Sprintf("%g", val)
}
return fmt.Sprintf("%g", val)
}