Created
July 19, 2023 12:05
-
-
Save folkertdev/ef1970afe9f00048f163f4d71d5f03f7 to your computer and use it in GitHub Desktop.
brainroc
This file contains hidden or 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
app "brainroc" | |
packages { | |
pf: "https://github.com/roc-lang/basic-cli/releases/download/0.3.2/tE4xS_zLdmmxmHwHih9kHWQ7fsXtJr7W7h3425-eZFk.tar.br", | |
} | |
imports [ | |
pf.File, | |
pf.Path, | |
pf.Stdout, | |
pf.Task, | |
] | |
provides [main] to pf | |
Instruction : { | |
operator: Operator, | |
operand: Nat | |
} | |
Operator : [ | |
IncrementPointer, | |
DecrementPointer, | |
IncrementByte, | |
DecrementByte, | |
Output, | |
JumpForward, | |
JumpBack, | |
] | |
Jump : Nat | |
tokenize : List U8 -> (Nat, List Instruction, List Jump) | |
tokenize = \bytes -> | |
List.walk bytes (0, [], []) \(pc, instructions, jumpStack), c -> | |
when c is | |
'>' -> | |
instruction = { operator: IncrementPointer, operand: 0 } | |
(pc + 1, List.append instructions instruction, jumpStack) | |
'<' -> | |
instruction = { operator: DecrementPointer, operand: 0 } | |
(pc + 1, List.append instructions instruction, jumpStack) | |
'+' -> | |
instruction = { operator: IncrementByte, operand: 0 } | |
(pc + 1, List.append instructions instruction, jumpStack) | |
'-' -> | |
instruction = { operator: DecrementByte, operand: 0 } | |
(pc + 1, List.append instructions instruction, jumpStack) | |
'.' -> | |
instruction = { operator: Output, operand: 0 } | |
(pc + 1, List.append instructions instruction, jumpStack) | |
'[' -> | |
instruction = { operator: JumpForward, operand: 0 } | |
( | |
pc + 1, | |
List.append instructions instruction, | |
List.append jumpStack pc, | |
) | |
']' -> | |
when List.last jumpStack is | |
Err _ -> crash "malformed program" | |
Ok jumpPc -> | |
instruction = { operator: JumpBack, operand: jumpPc } | |
( | |
pc + 1, | |
List.append instructions instruction |> List.update jumpPc \{ operator } -> { operator, operand: pc }, | |
List.dropLast jumpStack, | |
) | |
' ' | '\n' | '\t' -> (pc, instructions, jumpStack) | |
other -> | |
when Str.fromUtf8 [ other ] is | |
Ok str -> | |
crash "unexpected character: '\(str)'" | |
Err _ -> | |
crash "unexpected non-utf8 character" | |
dataSize = 30_000 | |
execute : List Instruction -> Str | |
execute = \instructions -> | |
output = executeHelp 0 instructions 0 (List.repeat 0 dataSize) [] | |
when Str.fromUtf8 output is | |
Err _ -> crash "invalid utf8 in the output" | |
Ok str -> str | |
executeHelp : Nat, List Instruction, Nat, List U8, List U8 -> List U8 | |
executeHelp = \pc, instructions, dataPtr, data, output -> | |
if pc < List.len instructions then | |
{ operator, operand } = when List.get instructions pc is | |
Ok v -> v | |
Err _ -> crash "out-of-bounds" | |
when operator is | |
IncrementPointer -> | |
executeHelp (pc + 1) instructions (Num.addWrap dataPtr 1) data output | |
DecrementPointer -> | |
executeHelp (pc + 1) instructions (Num.subWrap dataPtr 1) data output | |
IncrementByte -> | |
newData = List.update data dataPtr (\x -> Num.addWrap x 1) | |
executeHelp (pc + 1) instructions dataPtr newData output | |
DecrementByte -> | |
newData = List.update data dataPtr (\x -> Num.subWrap x 1) | |
executeHelp (pc + 1) instructions dataPtr newData output | |
Output -> | |
c = List.get data dataPtr |> Result.withDefault '$' | |
newOutput = List.append output c | |
executeHelp (pc + 1) instructions dataPtr data newOutput | |
JumpForward -> | |
when List.get data dataPtr is | |
Ok 0 -> | |
# question: add one to the operand here? | |
executeHelp (operand + 1) instructions dataPtr data output | |
_ -> | |
executeHelp (pc + 1) instructions dataPtr data output | |
JumpBack -> | |
when List.get data dataPtr is | |
Ok n if n > 0 -> | |
# question: add one to the operand here? | |
executeHelp (operand + 1) instructions dataPtr data output | |
_ -> | |
executeHelp (pc + 1) instructions dataPtr data output | |
else | |
output | |
main = | |
inputFilePath = "/home/folkertdev/roc/brainroc/examples/bench/bench-1.bf" | |
inputResult <- inputFilePath |> Path.fromStr |> File.readBytes |> Task.attempt | |
when inputResult is | |
# Run the interpreter | |
Ok bytes -> | |
(_pc, tokens, _jumpStack) = tokenize bytes | |
Stdout.line (execute tokens) | |
Err (FileReadErr _ _) -> "Failed to read the input file `\(inputFilePath)`." |> Stdout.line |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment