Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions docs/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ Structural — not instructions, not on the stack.
| `🔢` | MOD | `( a b -- a%b )` | Integer remainder. Error on zero. |
| `🎲` | RANDOM | `( -- float )` | Push random float in [0.0, 1.0). GPU: Philox-4x32-10 PRNG. |

### Math

| Emoji | Name | Stack effect | Notes |
|:---:|---|:---:|---|
| `🔋` | POW | `( a b -- a^b )` | Power / exponentiation |
| `🌱` | SQRT | `( a -- √a )` | Square root. Error on negative input. |
| `📈` | SIN | `( a -- sin(a) )` | Sine (radians) |
| `📉` | COS | `( a -- cos(a) )` | Cosine (radians) |
| `🚀` | EXP | `( a -- e^a )` | Natural exponential |
| `📓` | LOG | `( a -- ln(a) )` | Natural logarithm. Error on non-positive input. |
| `💪` | ABS | `( a -- |a| )` | Absolute value. Preserves int type. |
| `⬇️` | MIN | `( a b -- min(a,b) )` | Minimum of two values. Also `⬇`. |
| `⬆️` | MAX | `( a b -- max(a,b) )` | Maximum of two values. Also `⬆`. |

### Comparison & Logic

All comparison ops consume both operands and push `1` (true) or `0` (false).
Expand Down Expand Up @@ -308,15 +322,18 @@ result = tool.execute_python("print(42)", n=1000)

**Supported Python subset:**
- Literals: `int`, `float`, `True`, `False`
- Arithmetic: `+`, `-`, `*`, `/`, `//`, `%`
- Comparisons: `==`, `!=`, `<`, `>`, `<=`, `>=`
- Arithmetic: `+`, `-`, `*`, `/`, `//`, `%`, `**`
- Comparisons: `==`, `!=`, `<`, `>`, `<=`, `>=`, chained (`a < b < c`)
- Boolean: `and`, `or`, `not`
- Control flow: `if`/`elif`/`else`, `while`, `for x in range()`, `break`, `continue`
- Functions: `def`/`return` (including recursion)
- I/O: `print()` (single/multi-arg, `end=""`)
- Random: `import random` + `random.random()`
- Math: `math.sqrt()`, `math.sin()`, `math.cos()`, `math.exp()`, `math.log()`
- Constants: `math.pi`, `math.e`
- Builtins: `abs()`, `min()`, `max()`
- Random: `import random` + `random.random()`, `random.uniform(a, b)`, `random.gauss(mu, sigma)`

**Not supported:** strings, lists, dicts, classes, exceptions, generators, f-strings, `**`, `import` beyond random/math.
**Not supported:** strings, lists, dicts, classes, exceptions, generators, f-strings, `import` beyond random/math.

---

Expand Down
18 changes: 18 additions & 0 deletions emojiasm/bytecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@
Op.MUL: 0x12,
Op.DIV: 0x13,
Op.MOD: 0x14,
Op.POW: 0x15,
Op.SQRT: 0x16,
Op.SIN: 0x17,
Op.COS: 0x18,
Op.EXP: 0x19,
Op.LOG: 0x1A,
Op.ABS: 0x1B,
Op.MIN: 0x1C,
Op.MAX: 0x1D,
# Comparison & Logic
Op.CMP_EQ: 0x20,
Op.CMP_LT: 0x21,
Expand Down Expand Up @@ -247,6 +256,15 @@ def _build_string_table(program: Program) -> tuple[dict[str, int], list[str]]:
Op.MUL: -1,
Op.DIV: -1,
Op.MOD: -1,
Op.POW: -1, # pops 2, pushes 1
Op.SQRT: 0, # pops 1, pushes 1
Op.SIN: 0,
Op.COS: 0,
Op.EXP: 0,
Op.LOG: 0,
Op.ABS: 0,
Op.MIN: -1, # pops 2, pushes 1
Op.MAX: -1, # pops 2, pushes 1
Op.CMP_EQ: -1,
Op.CMP_LT: -1,
Op.CMP_GT: -1,
Expand Down
56 changes: 56 additions & 0 deletions emojiasm/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def _lbl(func_hex: str, label: str) -> str:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

/* EmojiASM AOT compiled output (numeric-only fast path) */

Expand All @@ -48,6 +49,7 @@ def _lbl(func_hex: str, label: str) -> str:
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>

/* EmojiASM AOT compiled output */

Expand Down Expand Up @@ -308,6 +310,60 @@ def _emit_inst(inst: Instruction, lines: list, fhex: str, mem: dict, numeric_onl
elif op == Op.RANDOM:
A(' PUSH_N((double)rand() / (double)RAND_MAX);')

elif op == Op.POW:
if numeric_only:
A(' { double b=POP(),a=POP(); PUSH_N(pow(a,b)); }')
else:
A(' { Val b=POP(),a=POP(); PUSH_N(pow(a.num,b.num)); }')

elif op == Op.SQRT:
if numeric_only:
A(' { double a=POP(); PUSH_N(sqrt(a)); }')
else:
A(' { Val a=POP(); PUSH_N(sqrt(a.num)); }')

elif op == Op.SIN:
if numeric_only:
A(' { double a=POP(); PUSH_N(sin(a)); }')
else:
A(' { Val a=POP(); PUSH_N(sin(a.num)); }')

elif op == Op.COS:
if numeric_only:
A(' { double a=POP(); PUSH_N(cos(a)); }')
else:
A(' { Val a=POP(); PUSH_N(cos(a.num)); }')

elif op == Op.EXP:
if numeric_only:
A(' { double a=POP(); PUSH_N(exp(a)); }')
else:
A(' { Val a=POP(); PUSH_N(exp(a.num)); }')

elif op == Op.LOG:
if numeric_only:
A(' { double a=POP(); PUSH_N(log(a)); }')
else:
A(' { Val a=POP(); PUSH_N(log(a.num)); }')

elif op == Op.ABS:
if numeric_only:
A(' { double a=POP(); PUSH_N(fabs(a)); }')
else:
A(' { Val a=POP(); PUSH_N(fabs(a.num)); }')

elif op == Op.MIN:
if numeric_only:
A(' { double b=POP(),a=POP(); PUSH_N(fmin(a,b)); }')
else:
A(' { Val b=POP(),a=POP(); PUSH_N(fmin(a.num,b.num)); }')

elif op == Op.MAX:
if numeric_only:
A(' { double b=POP(),a=POP(); PUSH_N(fmax(a,b)); }')
else:
A(' { Val b=POP(),a=POP(); PUSH_N(fmax(a.num,b.num)); }')


# ── Main compiler entry point ───────────────────────────────────────────────

Expand Down
10 changes: 10 additions & 0 deletions emojiasm/gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@
# I/O
"PRINT": 0x50,
"PRINTLN": 0x51,
# Math
"POW": 0x15,
"SQRT": 0x16,
"SIN": 0x17,
"COS": 0x18,
"EXP": 0x19,
"LOG": 0x1A,
"ABS": 0x1B,
"MIN": 0x1C,
"MAX": 0x1D,
# Random
"RANDOM": 0x60,
}
Expand Down
106 changes: 106 additions & 0 deletions emojiasm/metal/vm.metal
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ constant uint8_t OP_PRINTLN = 0x51;
// Random
constant uint8_t OP_RANDOM = 0x60;

// Math
constant uint8_t OP_POW = 0x15;
constant uint8_t OP_SQRT = 0x16;
constant uint8_t OP_SIN = 0x17;
constant uint8_t OP_COS = 0x18;
constant uint8_t OP_EXP = 0x19;
constant uint8_t OP_LOG = 0x1A;
constant uint8_t OP_ABS = 0x1B;
constant uint8_t OP_MIN = 0x1C;
constant uint8_t OP_MAX = 0x1D;

// ── Status codes ────────────────────────────────────────────────────────

constant uint32_t STATUS_OK = 0;
Expand Down Expand Up @@ -620,6 +631,101 @@ kernel void emojiasm_vm(
break;
}

// ── Math ──────────────────────────────────────────────────────────

case OP_POW: {
if (sp < 2) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
sp--;
stack[sp - 1] = pow(stack[sp - 1], stack[sp]);
break;
}

case OP_SQRT: {
if (sp < 1) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
stack[sp - 1] = sqrt(stack[sp - 1]);
break;
}

case OP_SIN: {
if (sp < 1) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
stack[sp - 1] = sin(stack[sp - 1]);
break;
}

case OP_COS: {
if (sp < 1) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
stack[sp - 1] = cos(stack[sp - 1]);
break;
}

case OP_EXP: {
if (sp < 1) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
stack[sp - 1] = exp(stack[sp - 1]);
break;
}

case OP_LOG: {
if (sp < 1) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
stack[sp - 1] = log(stack[sp - 1]);
break;
}

case OP_ABS: {
if (sp < 1) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
stack[sp - 1] = fabs(stack[sp - 1]);
break;
}

case OP_MIN: {
if (sp < 2) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
sp--;
stack[sp - 1] = min(stack[sp - 1], stack[sp]);
break;
}

case OP_MAX: {
if (sp < 2) {
status[tid] = STATUS_ERROR;
running = false;
break;
}
sp--;
stack[sp - 1] = max(stack[sp - 1], stack[sp]);
break;
}

// ── Unknown opcode ──────────────────────────────────────────────

default: {
Expand Down
20 changes: 20 additions & 0 deletions emojiasm/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ class Op(IntEnum):
STR2NUM = auto()
NUM2STR = auto()
RANDOM = auto()
POW = auto()
SQRT = auto()
SIN = auto()
COS = auto()
EXP = auto()
LOG = auto()
ABS = auto()
MIN = auto()
MAX = auto()


# Emoji -> Opcode mapping
Expand Down Expand Up @@ -85,6 +94,17 @@ class Op(IntEnum):
"🔁": Op.STR2NUM,
"🔤": Op.NUM2STR,
"🎲": Op.RANDOM,
"🔋": Op.POW,
"🌱": Op.SQRT,
"📈": Op.SIN,
"📉": Op.COS,
"🚀": Op.EXP,
"📓": Op.LOG,
"💪": Op.ABS,
"⬇️": Op.MIN,
"⬇": Op.MIN,
"⬆️": Op.MAX,
"⬆": Op.MAX,
}

# Reverse mapping for disassembly
Expand Down
Loading