Skip to content
vic

joshsharp/python-braid

Learning to build a language with RPython.

joshsharp/python-braid.json
{
"createdAt": "2015-07-11T11:58:09Z",
"defaultBranch": "master",
"description": "Learning to build a language with RPython.",
"fullName": "joshsharp/python-braid",
"homepage": "",
"language": "Python",
"name": "python-braid",
"pushedAt": "2017-06-10T06:23:07Z",
"stargazersCount": 21,
"topics": [],
"updatedAt": "2025-03-24T02:04:32Z",
"url": "https://github.com/joshsharp/python-braid"
}

Learning to build a language interpreter with RPython and RPly

I don’t really know what I’m doing but I’m interested in writing a toy language and interpreter. I’ve chosen RPython and RPly because I know Python quite well and the RPython EBNF parsing libs were confusing. RPly’s interface is a bit higher level.

This project is no longer being actively maintained.

pip install -r requirements.txt

python braid.py for REPL, python braid.py [filename].bd for interpreting a file

:a gives you the AST of the last statement, :e to list environment variables, :q or Ctrl-C to quit. The REPL now supports multi-line input too — it’ll just keep appending code and trying to interpret it until it’s valid (eg. you closed the block or whatever), or you break it ;)

Basic arithmetic, floats, integers, booleans, and strings, variable assignment, if expressions, and a print() function.

>>> 5 == 5
= true
>>> 5 != 5
= false
>>> let a = 5
= 5
>>> print(a)
5
>>> print(a + 25)
30
>>> "hi" + 'hi'
= hihi
>>> "hi" * 5 - 1
= hihihihih
# if expressions
>>> if false: print("no") else: print("yes") end
yes
>>> let a = (if true: 1 else: 5 end)
= 1
let a = 50
if a == 50 and true:
print("doing stuff")
else:
print("not this though")
end
>>> 5 >= 6
= false
# assignment via if
>>> let a = if true: 5 end
= 5
>>> :a
Program(BinaryOp(Variable('a'), If(Boolean(True))Then(Integer(5))Else(None)))
# arrays
>>> [5, 6, ["hi", 7.0]]
= [5, 6, [hi, 7.0]]
# functions
func a(b):
b + 1
end
>>> b(1)
= 2
# immutability means loops become recursion
func p_message(msg, n):
if n > 0:
print(msg)
p_message(msg, n - 1)
end
end
>>> p_message("hellooo",2)
hellooo
hellooo
# functions can be passed around
func a():
1
end
>>> let b = a
>>> b()
= 1

You will need pypy so you can use RPython’s compiler. Then, like so:

python path/to/rpython/bin/rpython target.py

This will provide a target-c binary which you can use as a compiled substitute for main.py.

A language which can do things I find interesting, and the tools necessary to execute it.

  • Define the language (ongoing)
  • Lexer
  • Parser
  • Bytecode compiler
  • Interpreter/VM
  • Compiles to RPython (mostly but sometimes broken)
  • JIT
  • Immutability (initial support anyway)
  • First-class functions (sort of)
  • Structs and traits
  • FP concepts like map/reduce
  • Pattern matching
  • Concurrency via message passing
  • Standard library

I’ve abandoned this as I’m no longer interested in building a language on RPython. You can follow me on twitter at @joshsharp if you’re interested in the other stuff I’m working on.