# Volatile

Volatile is an esoteric programming language invented by User:A that can only push random numbers onto an unbounded stack that can push unbounded numbers. It is inspired by Keg; 7 of the 7 instructions are borrowed from Keg.

## Syntax

```~: Push a random number in any range of numbers. The range is determined by what the implementors like.
+: Pop 2 values and push the sum of the 2 values
-: Like +, but subtracts
*: Multiply
/: Divide. 0-division will result in an error.
:: Duplicate the top of the stack
(...): Execute ... inside a while loop when the top of the stack is not 0
```

### Debugging features (not part of the language)

This instruction is frequently used in these examples below. However, they are examples and are expected to be understood by the readers.

```.: Output the top of the stack, without popping
```

It is quite obvious that it does not have a discard operation.

## Examples

These examples may randomly fail due to Volatile being non-deterministic.

```:-+
```

```~:/+
```

```~:/-
```

### Create an error

You can definitely be sure on this one.

```~:-:/
```

```:*
```

### NOT the top of the stack

```~:-~:/-*~:/+
```

### Display the word "Hi"

```~:/:+:*:*~:/:::+++*~:/:::+++:++.~:/::::++++~:/:::+++*::::++++~:/::::+++++.
```

Note: It only prints the ASCII values of the letters H and i (72 and 105 respectively)

### Hello, world! program

This program is created mechanically, see the code.

`~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++.~:/::::::::::++++++++++.`

```~()
```

### Looping counter

`~:-.~:/+.(~:/+.)`

## Number tricks

You obviously cannot wish that the random operation("~") will push the number that you want. (You have to be very lucky.)

So, you need a technique that reverses this probability. (Getting a number that you don't want is highly unlikely.)

You can use these code snippets to push 0 or 1 onto the stack.

To push 0(it definitely will not cause an error): `~:-`

To push 1(not 100% deterministic; 0-division exception): `~:/`

Another way to push 1(crashes in a different manner(array index out of bounds exception in Java interpreter, no-op in Python interpreter)): `~(:/~:-)+`

Also, to represent larger integers(like 4), you only have to add by 1's. (Split 4 into 1+1+1+1, and do the push-1 operations.)

Almost every Volatile program relies on duplicating the top of the stack and pushing random numbers.

### How to discard the top of the stack

It seems impossible to discard the top of the stack using only numeric operations. However, what we need is just a way to ignore the top of the stack.

The way to achieve this is to multiply the top of the stack by 0(recycling the top-stack number) and add. (This deletes the top-of stack 0 and preserves the bottom-of stack value.)

## Computational Class

Volatile is Turing-complete. See the talk page for details.

## Python Interpreter

```#Volatile Interpreter
#https://esolangs.org/wiki/Volatile

import random, sys

source = input()
stack = []

push = stack.append

ip = 0
loop_mode = False
loops = []

while ip < len(source):
char = source[ip]

if loop_mode:
if char == "(":
loop_mode = False
else:
ip += 1; continue

if char == "~": push(random.randint(-sys.maxsize, sys.maxsize))
elif char in "+-/*":
a, b = stack.pop(), stack.pop()
push(eval(f"{b}{char}{a}"))
elif char == ":": push(stack[-1])
elif char == ".": print(*[chr(stack[-1]) if 10 <= stack[-1] <= 256 else stack[-1]])
elif char == "(": loop_mode = stack[-1] == 0; loops.append(ip)
elif char == ")":
if stack[-1] != 0:
ip = loops[-1] + 1
continue
else:
loops.pop()
else: continue

ip += 1
```

## (Another) Python 3 interpreter

Implements the spec fully with support for unbounded numbers and nested loops.

```# Python interpreter for Volatile
# https://esolangs.org/wiki/Volatile
# No rights reserved

import random
import sys

rand = lambda: random.randint(-(2**31), (2**31)-1)

def pop(stack, k=0):
if not stack:
raise IndexError("stack empty")
if k:
return stack[-1]
return stack.pop()

def _op(stack, f, d):
b = pop(stack)
a = pop(stack)
if d and not b:
raise ArithmeticError("division by zero")
stack.append(f(a, b))

def op(f, d=0):
return lambda stack: _op(stack, f, d)

cmd = {
"~": lambda stack: stack.append(rand()),
"+": op(lambda a, b: a + b),
"-": op(lambda a, b: a - b),
"*": op(lambda a, b: a * b),
"/": op(lambda a, b: a // b, 1),
":": lambda stack: stack.append(pop(stack, 1)),
".": lambda stack: print(pop(stack, 1)),
}

def volatile_eval(ast, stack=[]):
for x in ast:
if isinstance(x, list):
while pop(stack, 1):
volatile_eval(x, stack)
else:
cmd[x](stack)
return stack

def parse(s):
st = [[]]
for c in s:
if c == "(":
st.append([])
elif c == ")":
x = st.pop()
if not st:
raise SyntaxError("unbalanced parentheses")
st[-1].append(x)
elif c in "~+-*/:.":
st[-1].append(c)
if len(st) > 1:
raise SyntaxError("unbalanced parentheses")
return st.pop()

if __name__ == "__main__":
if len(sys.argv) < 2 or \
(sys.argv[1] == "-f" and len(sys.argv) != 3) or \
(sys.argv[1] != "-f" and len(sys.argv) != 2):
print("usage: %s {CODE | -f FILE}" % sys.argv[0])
exit(1)
if sys.argv[1] == "-f":
with open(sys.argv[2]) as f:
else:
code = sys.argv[1]
try:
ast = parse(code)
stack = volatile_eval(ast)
if stack:
print("stack:", end=" ")
for x in stack[:-1]:
print(x, end=" ")
print("|%d|" % stack[-1], end="")
print()
except Exception as ex:
print(ex)
```

## More Interpreters

CGCC User Lyxal asked a question on codegolf.stackexchange.com to create Volatile interpreters. Here's the question: https://codegolf.stackexchange.com/questions/191573/interpret-volatile?r=SearchResults.