1package calc23import (4 "chain"5 "errors"6 "strconv"7 "strings"8)910// stack holds the shared RPN operand stack, bottom (index 0) to top.11var stack []int1213// ErrUnderflow is raised when an operator needs more operands than available.14var ErrUnderflow = errors.New("stack underflow: operator needs two operands")1516// ErrDivByZero is raised on division by zero.17var ErrDivByZero = errors.New("division by zero")1819// Push consumes a single token: an integer is pushed onto the stack; an20// 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 }2627 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]3536 var r int37 switch token {38 case "+":39 r = a + b40 case "-":41 r = a - b42 case "*":43 r = a * b44 case "/":45 if b == 0 {46 panic(ErrDivByZero.Error())47 }48 r = a / b49 }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}6162// Clear empties the shared stack.63func Clear(cur realm) {64 stack = nil65 chain.Emit("Clear")66}6768// Depth returns the number of values currently on the stack.69func Depth() int {70 return len(stack)71}7273// Top returns the top value and whether the stack is non-empty.74func Top() (int, bool) {75 if len(stack) == 0 {76 return 0, false77 }78 return stack[len(stack)-1], true79}8081// Render renders the current stack, the top value as the result, and a82// short usage guide.83func Render(path string) string {84 var sb strings.Builder85 sb.WriteString("# RPN Calculator\n\n")8687 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 }9596 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 }108109 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")116117 return sb.String()118}119Clear(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})
Depth() int
Push(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, token string)
Render(path string) string
Top() (int, bool)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.