aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--calculator.go62
-rw-r--r--ui.go6
2 files changed, 58 insertions, 10 deletions
diff --git a/calculator.go b/calculator.go
index 08193b4..d2371b7 100644
--- a/calculator.go
+++ b/calculator.go
@@ -1,6 +1,9 @@
package main
-import "strconv"
+import (
+ "fmt"
+ "strconv"
+)
type Stack []float64
@@ -9,18 +12,61 @@ type Calculator struct {
buf string
}
-// add performs addition when the user inputs the '+' operator.
-func (c *Calculator) add() {
+// performOp performs the specified arithmetic operation and returns nil or
+// OpError if op is not a valid operator.
+func (c *Calculator) performOp(op byte) error {
if len(c.stack) < 1 {
- return
+ return nil
}
+
+ fn, err := parseOp(op)
+ if err != nil {
+ return err
+ }
+
if con := parseConstant(c.buf); con != nil {
- c.stack[len(c.stack)-1] += *con
- } else if f, err := strconv.ParseFloat(c.buf, 64); err == nil {
- c.stack[len(c.stack)-1] += f
+ fn(&c.stack[len(c.stack)-1], *con)
+ } else if fl, err := strconv.ParseFloat(c.buf, 64); err == nil {
+ fn(&c.stack[len(c.stack)-1], fl)
} else if len(c.stack) > 1 {
- c.stack[len(c.stack)-2] += c.stack[len(c.stack)-1]
+ fn(&c.stack[len(c.stack)-2], c.stack[len(c.stack)-1])
c.stack = c.stack[:len(c.stack)-1]
}
c.buf = ""
+ return nil
+}
+
+// parseOp returns a closure that performs the specified arithmetic operation,
+// or OpError if op is not a valid operator.
+func parseOp(op byte) (func(lhs *float64, rhs float64), error) {
+ switch op {
+ case '+':
+ return func(lhs *float64, rhs float64) { *lhs += rhs }, nil
+ case '-':
+ return func(lhs *float64, rhs float64) { *lhs -= rhs }, nil
+ case '*':
+ return func(lhs *float64, rhs float64) { *lhs *= rhs }, nil
+ case '/':
+ return func(lhs *float64, rhs float64) {
+ if rhs != 0 {
+ *lhs /= rhs
+ }
+ }, nil
+ case '%':
+ return func(lhs *float64, rhs float64) {
+ if rhs != 0 {
+ *lhs = float64(int64(*lhs) % int64(rhs))
+ }
+ }, nil
+ }
+ return nil, OpError{op}
+}
+
+// OpError records an invalid arithmetic operator.
+type OpError struct {
+ c byte
+}
+
+func (e OpError) Error() string {
+ return fmt.Sprintf("invalid operator: %c", e.c)
}
diff --git a/ui.go b/ui.go
index 931e8a5..5996a9c 100644
--- a/ui.go
+++ b/ui.go
@@ -37,8 +37,10 @@ func (ui UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.String() {
case "ctrl+c", "Q":
return ui, tea.Quit
- case "+":
- ui.calc.add()
+ case "+", "-", "*", "/", "%":
+ if err := ui.calc.performOp(msg.String()[0]); err != nil {
+ panic(err)
+ }
case "backspace":
if len(ui.calc.buf) > 0 {
ui.calc.buf = ui.calc.buf[:len(ui.calc.buf)-1]