summaryrefslogtreecommitdiff
path: root/docs/symbols.md
blob: df961a5f1bea03b721a316045e2ebe957002ff3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# Symbols (:x Syntax)

Symbols are named placeholders on the RPN stack. Unlike variables, which store resolved numeric values, symbols carry a name and remain unresolved until explicitly bound through an assignment operation.

Every bare identifier that has no matching variable or constant is automatically pushed as a symbol. The `:` prefix makes this explicit.

## Syntax

### `:x` — Push a Symbol

Prefix a single-letter identifier with `:` to push it as a symbol onto the stack:

```
:x          → :x
:A          → :A
:_          → :_
```

The identifier after `:` must be a single letter, uppercase or lowercase, or an underscore. Multi-character names and names starting with digits are not allowed:

```
:abc        → error: unknown token ':abc'
:1          → error: unknown token ':1'
:x!         → error: unknown token ':x!'
```

### `:` (bare colon) — Error

A colon with no identifier following it is rejected:

```
:           → error: symbol name cannot be empty after colon
```

## What Symbols Are

A symbol is a stack value that holds a name rather than a numeric value. When displayed, symbols are always prefixed with `:` to distinguish them from plain numbers and other values.

Internally, symbols implement the `StackValue` interface (so they can be placed on the stack) but not `NumericValue` (so they cannot participate in arithmetic). This means symbols work with stack-manipulation operators but not with arithmetic operators:

```
:x dup              → :x :x         (dup works on symbols)
:x 5 :x swap        → 5 :x :x       (swap works on symbols)
:x :y :z show       → :x :y :z      (show displays all stack values)
:x 1 +              → error: value ":x" is not numeric
```

## Symbols vs Variables

The key difference is **binding time**:

| | Variable | Symbol |
|---|---|---|
| **Binding** | Immediate — resolved to a value at use | Delayed — name pushed as-is |
| **Stack value** | Numeric (`Float` or `Rat`) | `Symbol` |
| **Arithmetic** | Works | Not supported |
| **Assignment** | Assigned with `:=`, `=:`, `=` | Used as the name side of `:=` or `=:` |

### Immediate Binding (Variables)

When a variable is defined and then referenced by bare name, the variable's current value is pushed:

```
x 5 :=          → x = 5
x               → 5           (pushes the value 5)
x x +           → 10          (each x resolves to 5)
```

### Delayed Binding (Symbols)

When the same name is used as a symbol (with `:` prefix), the name itself is pushed regardless of whether the variable exists:

```
x 5 :=          → x = 5
:x              → :x          (pushes the symbol, not the value 5)
:x dup          → :x :x       (symbol can be duplicated)
```

An undefined bare name also pushes a symbol — `x` and `:x` are equivalent when `x` is unbound:

```
x               → :x          (unbound, shown as symbol)
:x              → :x          (explicit symbol)
```

## Using Symbols with Assignment

Symbols are primarily useful as the name side of assignment operators. The `:` prefix makes the intent clear:

### Right Assignment (`:=`)

```
:x 5 :=         → x = 5
:a 10 :=        → a = 10
```

This is equivalent to `x 5 :=` when `x` is unbound (the bare name also pushes a symbol), but the `:` prefix is explicit and works the same way regardless of whether a variable named `x` already exists.

### Left Assignment (`=:`)

```
5 :x =:         → x = 5
10 :a =:        → a = 10
```

## Using Symbols for Variable Deletion

The `d` operator deletes a variable by name. Push the variable name as a symbol, then apply `d`:

```
x 5 :=            → x = 5
:x d              → (deletes x, no output)
x                 → :x        (x is now unbound)
```

Attempting to delete a variable that does not exist produces an error:

```
:x d              → error: variable not found: x
```

## Symbols on the Stack

Multiple symbols can coexist on the stack alongside numbers and other values:

```
:x :y :z          → :x :y :z
5 :x              → 5 :x
true :x show      → true :x
:x 5 3 +          → :x 8         (3+4=7 happens, :x stays)
```

### Stack Operations

Stack operators that work on any `StackValue` work with symbols:

```
:x dup              → :x :x
:x 5 :x swap        → 5 :x :x     (swaps top two items)
5 :x :y swap        → 5 :y :x
```

`pop` removes the top item but leaves the stack empty, which is reported as an error unless combined with an assignment:

```
:x pop              → error: empty result: expression evaluated to nothing
```

## Examples

### Explicit Variable Assignment

Using `:` prefix makes assignment intent clear and unambiguous:

```
:x 100 :=
:y 200 :=
:x :y show          → :x :y        (symbols pushed, not values)
x y +               → 300          (variables resolved to values)
```

### Delayed Binding for Symbolic Manipulation

Symbols can be pushed and rearranged on the stack before being used. This is useful when you want to defer resolution or manipulate the stack structure:

```
:x :y :z            → :x :y :z
:x :y :z dup        → :x :y :z :z
```

### Safe Variable Reference

When a variable might or might not be defined, using `:` prefix always produces a symbol, making the behavior predictable:

```
x                   → :x or 5      (depends on whether x was defined)
:x                  → :x           (always a symbol)
```

### Variable Cleanup

Combine symbols with `d` for explicit variable deletion:

```
x 10 :=             → x = 10
:x d                → (x deleted)
vars                → No variables defined
```

## Error Summary

| Input | Error | Reason |
|-------|-------|--------|
| `:` | symbol name cannot be empty after colon | No identifier after `:` |
| `:abc` | unknown token ':abc' | Multi-character identifiers not allowed |
| `:1` | unknown token ':1' | Identifier starts with digit |
| `:x!` | unknown token ':x!' | Special character in name |
| `:x 1 +` | value ":x" is not numeric | Symbols can't be used in arithmetic |
| `:x d` | variable not found: x | Variable x not defined |
| `:x pop` | empty result: expression evaluated to nothing | Stack empty after pop |