WASM demo - brainfuck

Brainfuck is an esoteric language that consists of only eight simple commands:

  • >    increment the data pointer (to point to the next cell to the right).
  • <    decrement the data pointer (to point to the next cell to the left).
  • +    increment (increase by one) the byte at the data pointer.
  • -    decrement (decrease by one) the byte at the data pointer.
  • .    output the byte at the data pointer.
  • ,    accept one byte of input, storing its value in the byte at the data pointer.
  • [    if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command.
  • ]    if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ command

Brainfuck is a simple language, but that does not mean that programming Brainfuck is easy!


In [ ]:
import wasmfun as wf

In [ ]:
def _commands2instructions(commands):
    """ Compile brainfuck commands to WASM instructions (as tuples).
    """    
    instructions = []
    while commands:
        c = commands.pop(0)
        if c == '>':
            instructions += [('get_local', 0), ('i32.const', 1), ('i32.add'), ('set_local', 0)]
        elif c == '<':
            instructions += [('get_local', 0), ('i32.const', 1), ('i32.sub'), ('set_local', 0)]
        elif c == '+':
            instructions += [('get_local', 0), ('get_local', 0),  # once for the read, once for the write
                             ('i32.load8_u', 0, 0),
                             ('i32.const', 1), ('i32.add'), ('i32.store8', 0, 0)]
        elif c == '-':
            instructions += [('get_local', 0), ('get_local', 0),  # once for the read, once for the write
                             ('i32.load8_u', 0, 0),
                             ('i32.const', 1), ('i32.sub'), ('i32.store8', 0, 0)]
        elif c == '.':
            instructions += [('get_local', 0), ('i32.load8_u', 0, 0), ('call', 0)]
        elif c == ',':
            # We don't support input, just set to zero
            instructions += [('get_local', 0), ('i32.const', 0), ('i32.store8', 0, 0)]
        elif c == '[':
            instructions += [('block', 'emptyblock'),
                                # if current data point == 0 goto end of block
                                ('get_local', 0), ('i32.load8_u', 0, 0), ('i32.const', 0), ('i32.eq'), ('br_if', 0),
                                ('loop', 'emptyblock'),
                                    ] + _commands2instructions(commands ) + [
                                    # if current data point > 0 goto start of block
                                    ('get_local', 0), ('i32.load8_u', 0, 0), ('i32.const', 0), ('i32.ne'), ('br_if', 0),
                                ('end'),
                             ('end')]
        elif c == ']':
            break
        else:
            raise ValueError('Unknown Brainfuck command: %r' % c)
    
    return instructions

Hello world example


In [ ]:
EXAMPLE1 = """
[This program prints "Hello World!" and a newline to the screen]
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.
>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
"""

In [ ]:
instructions = _commands2instructions([c for c in EXAMPLE1 if c in '><+-.,[]'])

In [ ]:
m = wf.Module(
    wf.ImportedFuncion('print_charcode', ['i32'], [], 'js', 'print_charcode'),
    wf.Function('$main', [], [], ['i32'], instructions),
    wf.MemorySection((1, 1)),
    wf.DataSection(),
    )

In [ ]:
len(m.to_bytes())

In [ ]:
wf.run_wasm_in_notebook(m)

Fibonacci example


In [ ]:
EXAMPLE2 = """
[Generate the fibonacci number sequence, (for numbers under 100). Taken from
http://esoteric.sange.fi/brainfuck/bf-source/prog/fibonacci.txt
]
+++++++++++>+>>>>++++++++++++++++++++++++++++++++++++++++++++>
++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>+<<<<<<<-]>>>>>>>
[<<<<<<<+>>>>>>>-]<[>++++++++++[-<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]
<[-]]>[<<[>>>+<<<-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>
[<<+>>[-]]<<<<<<<]>>>>>[++++++++++++++++++++++++++++++++++++++++++++++++.
[-]]++++++++++<[->-<]>++++++++++++++++++++++++++++++++++++++++++++++++.[-]
<<<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<[-]]<<[>>+>+<<<-]>>>
[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]
"""

In [ ]:
instructions = _commands2instructions([c for c in EXAMPLE2 if c in '><+-.,[]'])

In [ ]:
m = wf.Module(
    wf.ImportedFuncion('print_charcode', ['i32'], [], 'js', 'print_charcode'),
    wf.Function('$main', [], [], ['i32'], instructions),
    wf.MemorySection((1, 1)),
    wf.DataSection(),
    )

In [ ]:
wf.run_wasm_in_notebook(m)

In [ ]:
wf.run_wasm_in_node(m)

In [ ]: