← Back to Realms

Realm

gno.land/r/moul/x/daily/calc/v0

Overview

Realm Path
gno.land/r/moul/x/daily/calc/v0
Exported Functions
5
State Entries
3
Source Files
2
Total Package Entries
8

Exported Functions

5 exported functions

State

3 state entries

Source Code

FILES
calc.gno
go
1package calc
2
3import (
4	"chain"
5	"errors"
6	"strconv"
7	"strings"
8)
9
10// stack holds the shared RPN operand stack, bottom (index 0) to top.
11var stack []int
12
13// ErrUnderflow is raised when an operator needs more operands than available.
14var ErrUnderflow = errors.New("stack underflow: operator needs two operands")
15
16// ErrDivByZero is raised on division by zero.
17var ErrDivByZero = errors.New("division by zero")
18
19// Push consumes a single token: an integer is pushed onto the stack; an
20// operator (+, -, *, /) pops two operands and pushes the result.
21func Push(cur realm, token string) {
22	token = strings.TrimSpace(token)
23	if token == "" {
24		panic("empty token")
25	}
26
27	switch token {
28	case "+", "-", "*", "/":
29		if len(stack) < 2 {
30			panic(ErrUnderflow.Error())
31		}
32		b := stack[len(stack)-1]
33		a := stack[len(stack)-2]
34		stack = stack[:len(stack)-2]
35
36		var r int
37		switch token {
38		case "+":
39			r = a + b
40		case "-":
41			r = a - b
42		case "*":
43			r = a * b
44		case "/":
45			if b == 0 {
46				panic(ErrDivByZero.Error())
47			}
48			r = a / b
49		}
50		stack = append(stack, r)
51		chain.Emit("Op", "op", token, "result", strconv.Itoa(r))
52	default:
53		n, err := strconv.Atoi(token)
54		if err != nil {
55			panic("invalid token: expected integer or one of + - * /, got " + token)
56		}
57		stack = append(stack, n)
58		chain.Emit("Push", "value", strconv.Itoa(n))
59	}
60}
61
62// Clear empties the shared stack.
63func Clear(cur realm) {
64	stack = nil
65	chain.Emit("Clear")
66}
67
68// Depth returns the number of values currently on the stack.
69func Depth() int {
70	return len(stack)
71}
72
73// Top returns the top value and whether the stack is non-empty.
74func Top() (int, bool) {
75	if len(stack) == 0 {
76		return 0, false
77	}
78	return stack[len(stack)-1], true
79}
80
81// Render renders the current stack, the top value as the result, and a
82// short usage guide.
83func Render(path string) string {
84	var sb strings.Builder
85	sb.WriteString("# RPN Calculator\n\n")
86
87	sb.WriteString("## Result\n\n")
88	if top, ok := Top(); ok {
89		sb.WriteString("**")
90		sb.WriteString(strconv.Itoa(top))
91		sb.WriteString("**\n\n")
92	} else {
93		sb.WriteString("_(empty stack)_\n\n")
94	}
95
96	sb.WriteString("## Stack (bottom → top)\n\n")
97	if len(stack) == 0 {
98		sb.WriteString("_empty_\n\n")
99	} else {
100		for i, v := range stack {
101			sb.WriteString(strconv.Itoa(i))
102			sb.WriteString(". ")
103			sb.WriteString(strconv.Itoa(v))
104			sb.WriteString("\n")
105		}
106		sb.WriteString("\n")
107	}
108
109	sb.WriteString("## Usage\n\n")
110	sb.WriteString("Reverse Polish Notation: operands first, operator last.\n\n")
111	sb.WriteString("- `Push(\"5\")` then `Push(\"3\")` then `Push(\"+\")` → `8`\n")
112	sb.WriteString("- Supported operators: `+`, `-`, `*`, `/` (integer division)\n")
113	sb.WriteString("- An operator pops the top two values (a, b) and pushes `a op b`.\n")
114	sb.WriteString("- `Clear()` empties the stack.\n")
115	sb.WriteString("- Divide-by-zero and underflow abort the transaction.\n")
116
117	return sb.String()
118}
119

Raw Package Data

Raw JSON data