Created
November 17, 2017 21:46
-
-
Save menduz/9302c246a17ce83e74004bbbc2308e39 to your computer and use it in GitHub Desktop.
Brainfuck implementation written in DataWeave
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%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