Try it!
You may need to wait or refresh to let it load
Source Code
def try_num(s):
try:
return float(s) if '.' in s else int(s)
except ValueError:
return s
def compile_forge(source):
lines = [l for l in source.splitlines() if l.strip()]
out = ["_mem = {}"]
def emit(words, indent=0):
pad = " " * indent
if not words:
return
cmd = words[0]
if cmd == 'set':
val = try_num(words[3])
out.append(f"{pad}_mem['{words[1]}'] = {repr(val)}")
elif cmd == 'print':
out.append(f"{pad}print(_mem.get('{words[1]}', 'undefined'))")
elif cmd == 'add':
out.append(f"{pad}print(_mem['{words[1]}'] + _mem['{words[3]}'])")
elif cmd == 'subtract':
out.append(f"{pad}print(_mem['{words[1]}'] - _mem['{words[3]}'])")
elif cmd == 'multiply':
out.append(f"{pad}print(_mem['{words[1]}'] * _mem['{words[3]}'])")
elif cmd == 'divide':
out.append(f"{pad}if _mem['{words[3]}'] == 0:")
out.append(f"{pad} print('Error: division by zero')")
out.append(f"{pad}else:")
out.append(f"{pad} print(_mem['{words[1]}'] / _mem['{words[3]}'])")
elif cmd == 'ask':
out.append(f"{pad}_raw = input('Enter {words[1]}: ')")
out.append(f"{pad}try:")
out.append(f"{pad} _mem['{words[1]}'] = float(_raw) if '.' in _raw else int(_raw)")
out.append(f"{pad}except ValueError:")
out.append(f"{pad} _mem['{words[1]}'] = _raw")
elif cmd == 'loop':
count = words[1]
try:
out.append(f"{pad}for _i in range({int(count)}):")
except ValueError:
out.append(f"{pad}for _i in range(int(_mem.get('{count}', 0))):")
emit(words[2:], indent + 1)
elif cmd == 'if':
var, op, raw = words[1], words[2], words[3]
b = try_num(raw)
then_i = words.index('then')
out.append(f"{pad}if _mem.get('{var}') {op} {repr(b)}:")
emit(words[then_i + 1:], indent + 1)
elif cmd == 'func':
name = words[1]
then_i = words.index('then')
out.append(f"{pad}def _fn_{name}():")
emit(words[then_i + 1:], indent + 1)
elif cmd == 'call':
out.append(f"{pad}_fn_{words[1]}()")
for line in lines:
emit(line.split())
return '\n'.join(out)
while True:
forge_lines = []
while True:
ln = input("forge> ")
if ln.strip().lower() == 'exit':
forge_lines = None
break
if ln.strip() == '':
break
forge_lines.append(ln)
if forge_lines is None:
break
if not forge_lines:
continue
python_code = compile_forge('\n'.join(forge_lines))
print(python_code)
exec(python_code)
Description
Challenges: The main shift was moving from executing one word-list at a time to emitting indented Python source. Nested constructs — loop, if...then, and func...then — required tracking indentation depth and recursing into emit() rather than run_cmd(). The compiler also had to handle the loop count being either a literal or a variable name, generating different Python for each case.
Result: A working Forge-to-Python transpiler. You enter a multi-line Forge program, hit a blank line, and the compiler prints the generated Python before running it — so you can see exactly what the compiler decided to produce. Example:
set x to 4
func double then multiply x and x
loop 2 call double
generates and runs the full Python equivalent, outputting 16 twice.
Previous Day
Next Day