Skip to content

Instantly share code, notes, and snippets.

@menduz
Created November 17, 2017 21:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save menduz/9302c246a17ce83e74004bbbc2308e39 to your computer and use it in GitHub Desktop.
Save menduz/9302c246a17ce83e74004bbbc2308e39 to your computer and use it in GitHub Desktop.
Brainfuck implementation written in DataWeave
%dw 2.0
output application/dw
import mergeWith from dw::core::Objects
type Stream<T> = {|
data: Array<T>,
position: Number
|}
type Machine = {|
heap: Stream<Number>,
stack: Array<Number>,
program: Stream<String>,
in: Array<Number>,
out: Array<Number>
|}
fun findIndex<T>(array: Array<T>, elem: T, carry: Number = 0): Number =
array match {
case [] -> -1
case [head ~ tail] ->
if(head == elem)
carry
else
findIndex(tail, elem, carry + 1)
}
fun replaceAt(array: Array<Number>, what: Number, at: Number = 0) = do {
fun setAt(array: Array<Number>, carry: Number = 0) =
array match {
case [] -> []
case [head ~ tail] ->
if(carry == at)
[what ~ tail]
else
[head ~ setAt(tail, carry + 1)]
}
---
setAt(array, 0)
}
fun parse(code: String): Array<String> = code replace /[^-+<>.,\[\]]/ with '' splitBy ''
fun moveHead<T>(stream: Stream<T>, offset: Number) = {
data: stream.data,
position: stream.position + offset
}
fun matchingBracketPosition(string, position: Number, stack = 0) =
if(position > sizeOf(string))
-1
else
string[position] match {
case '[' -> matchingBracketPosition(string, position + 1, stack + 1)
case ']' ->
if(stack == 0)
position
else
matchingBracketPosition(string, position + 1, stack - 1)
else -> matchingBracketPosition(string, position + 1, stack)
}
fun step(machine: Machine): Machine = do {
var instruction = machine.program.data[machine.program.position]
var x = log('Executing $instruction', machine.program.position)
var cell = machine.heap.data[machine.heap.position]
---
instruction match {
// > increment the data pointer (to point to the next cell to the right).
case '>' -> machine mergeWith {
heap: moveHead(machine.heap, 1),
program: moveHead(machine.program, 1)
}
// < decrement the data pointer (to point to the next cell to the left).
case '<' -> machine mergeWith {
heap: moveHead(machine.heap, -1),
program: moveHead(machine.program, 1)
}
// + increment (increase by one) the byte at the data pointer.
case '+' -> machine mergeWith {
heap: {
data: replaceAt(machine.heap.data, machine.heap.data[machine.heap.position] + 1, machine.heap.position),
position: machine.heap.position
},
program: moveHead(machine.program, 1)
}
// - decrement (decrease by one) the byte at the data pointer.
case '-' -> machine mergeWith {
heap: {
data: replaceAt(machine.heap.data, machine.heap.data[machine.heap.position] - 1, machine.heap.position),
position: machine.heap.position
},
program: moveHead(machine.program, 1)
}
// . output the byte at the data pointer.
case '.' -> do {
var value = machine.heap.data[machine.heap.position]
var x = log('Write', value)
---
machine mergeWith {
out: machine.out + value,
program: moveHead(machine.program, 1)
}
}
// , accept one byte of input, storing its value in the byte at the data pointer.
case ',' -> do {
var value = machine.heap.data[machine.heap.position]
var x = log('Read', value)
---
machine mergeWith {
heap: {
data: replaceAt(machine.heap.data, machine.in[0], machine.heap.position),
position: machine.heap.position
},
in: machine.in[1 to sizeOf(machine.in)],
program: moveHead(machine.program, 1)
}
}
// [ 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.
case '[' -> do {
if(cell == 0) do {
var nextPosition = log('Jump to', matchingBracketPosition(machine.program.data, machine.program.position))
---
machine mergeWith {
program: moveHead(
machine.program,
nextPosition - machine.program.position
)
}
} else
machine mergeWith {
stack: machine.stack << log('Push stack at', machine.program.position),
program: moveHead(machine.program, 1)
}
// interprete(tail[nextPosition to sizeOf(tail)], machine)
}
// ] 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.
case ']' -> do {
if(cell != 0)
machine mergeWith {
program: {
data: machine.program.data,
position: machine.stack[-1]
}
}
else
machine mergeWith {
stack: machine.stack[0 to sizeOf(machine.stack) - 1],
program: moveHead(machine.program, 1)
}
}
}
}
fun while<T>(a, b: (T) -> Boolean) = do {
var r = a()
fun innerWhile(x) = do {
var r = a(x)
---
b(r) match {
case true -> [r ~ innerWhile(r)]
case false -> [r]
}
}
---
[r ~ innerWhile(r)]
}
fun execute(m: Machine) = do {
(x = m) -> step(x)
} while $.program.position < sizeOf($.program.data)
---
execute({
heap: {
data: 1 to 256 map 0,
position: 0
},
stack: [],
program: {
data: parse('++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.'),
position: 0
},
in: [],
out: []
} as Machine)[-1].out map (dw::core::Strings::fromCharCode($)) joinBy ''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment