úÎ!çoÝ;¤      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£;Basic types for the Brainfuck compiler and virtual machine.(c) Sebastian Galkin, 2018GPL-3None "#.68:;=K@ü$hbf^A data structure for mocking input and output to the VM. This can be used to run the VM in a ¤ monad for testing purposes.hbf#Every time the machine executes an 1 instruction, input will be taken from this list.hbf#Every time the machine executes an ? instruction, output will be put into this list, in LIFO order.hbf8Provide input and output to a Brainfuck virtual machine.:This class allows to run the VM in different monads, like ¥ or ¤.hbf)The state of a Brainfuck virtual machine. hbf/The full memory of the machine. This will be a  or a List. hbfPThe current execution pointer, information is written and read at this position. hbf A list of s. opt will be one of  or : to distinguish both types of programs at the type level.hbf(The list of instructions in the program.hbfMarker type to distinguish  and unoptimized  s.hbf)Marker type to distinguish optimized and   s.hbfA direction to   for a memory position. & is in the direction of higher memory.hbf'Scan in the direction of higher memory.hbf&Scan in the direction of lower memory.hbfA factor to multiply by in the  instruction.hbf_An offset into the Brainfuck VM memory. Positive numbers are in the direction of higher memory.hbf<Operations or instructions in the Brainfuck virtual machine.ÎSome of these operations are "native" to Brainfuck and others are the result of optimization during compilation. The compiler generates these types of instructions and the virtual machine can execute them.In all these instructions the  represents a shift relative to the current position of the pointer. The operation will refer and apply its action to this shifted position.hbf)Increment by the amount specified by the Inthbf0Move the current pointer by the specified amounthbf^Repeatedly read a byte into the machine and write the last one read to the shifted position. n_ is usually 1 in real programs, but not always. Where the byte is read from will depend on the  impleentation.hbf`Repeatedly write the byte in the shifted position. Where the byte is written will depend on the  impleentation.hbf%Native Brainfuck looping instruction.hbfaOptimized instruction. Set the shifted position to zero. In Brainfuck this is usually written as [-]hbfDOptimized instruction. Multiply by the factor the byte in the first  MemOffset&, writting to the second one. Second  MemOffsetg is relative to the first one. In brainfuck this is usually written as [->+<] and similar expressions. hbfSFind the nearest zero in the given direction, starting at the offset position. See .!hbf@Return the full list of instructions in a program, by unrolling  instructions into the list.7flattened $ Program [Inc 1 0, Loop [Move 1, Scan Up 0]][Inc 1 0,Move 1,Scan Up 0]"hbf Create a * that will have the given input available.#hbf Create a : that will have the given input available. ASCII encoding.$hbf-Get the output after a VM has ran using this .%hbf-Get the output after a VM has ran using this . ASCII encoding.&hbf¦ with arguments reversed.'hbfHelper function to convert a § into a ¨ and a © into a ª.(hbfThe « of the underlying List of instructions.)hbfApply ¬ to the underlying List of instructions.*hbf¥- takes its input and output from stdin/stdout+hbf¤6 takes its input and output from the lists inside the .hbf'Write the byte to the output of the VM.hbf)Read a byte from the input of the VM. If EOF has been reached, return ª'  !"#$%&''  ! "#$%&'Brainfuck parsing(c) Sebastian Galkin, 2018GPL-3NoneOXNhbfParser for a full  .OisRight $ parse program " +[->>+ +[<] ##garbage## ],.[-] can ignore garbage"TrueOhbfParser for an , ignoring unknown characters.parse operation " +///"Right (Inc 1 0)%parse operation "fooo [+>] baaar "Right (Loop [Inc 1 0,Move 1])PhbfMThe characters allowed in a Brainfuck program except for the loop characters [ and ].Qhbf.The characters allowed in a Brainfuck program.RhbfParser for unknown characters#parse garbage "this is @#! garbage" Right 't'isLeft $ parse garbage "+"TrueShbf)Parser for simple operations (not loops).parse simpleOp ">"Right (Move 1)parse simpleOp "."Right (Out 1 0)ThbfParser for loops.parse loopOp "[+-]"!Right (Loop [Inc 1 0,Inc (-1) 0])Uhbf5Parse program stream. Returns an error or the parsed  NOPQRSTU NOPQRSTUBrainfuck Virtual Machine(c) Sebastian Galkin, 2018GPL-3None"#<VjVhbf,Command line arguments for the VM evaluator.XhbfAvailable memory in bytes.Yhbf9Dump the contents of the memory after executing a programZhbfPath to the compiled program[hbfAn alias for a / in which memory is an unboxed vector of bytes.\hbf:Evaluate the given program returning the end state of the $. The evaluation can happen in any ­, for which we can do I/O. The reason to use ®9 is that we will use mutable vectors for the evaluation.]hbf:Evaluate the given program returning the end state of the $. The evaluation can happen in any ­, for which we can do I/O. The reason to use ®: is that we will use mutable vectors for the evaluation. VP are used to tune the details of the VM, like available memory, verbosity, etc.^hbf:Evaluate the given program returning the end state of the H. The evaluation happens in IO, so Input/Output is done to the console._hbf:Evaluate the given program returning the end state of the $. The evaluation can happen in any ­, for which we can do I/O. The reason to use ®: is that we will use mutable vectors for the evaluation. V{ are used to tune the details of the VM, like memory available, verbosity, etc. The evaluation starts with the specified [E, so the memory and initial pointer can be configured before running.¯hbf(Size of the default VM memory, in bytes.`hbfA VM # with the default memory available.ahbf*Create a new machine with the given memorybhbf!Default configuration for the VM.chbf&Parse a list of command line argumentsdhbfDParse a list of command line arguments printing errors to the stderrehbf:Parse command line arguments printing errors to the stderrVWXYZ[\]^_`abcde[\]^_`aVWXYZbdecBrainfuck compilation to IR(c) Sebastian Galkin, 2018GPL-3None"#]Û1ghbf;This parser is used to implement the mul optimization. See †.hhbf,Command line flags to the Brainfuck compilerjhbf%Where to put the compiled output, if ª* use the input basename with bfc extensionkhbfEnable fusion optimizationlhbfEnable clear loop optimizationmhbfEnable mul loop optimizationnhbfEnable scan loop optimizationohbf'Enable offset instructions optimizationphbf!Output more debugging informationqhbf;Input source to the compiler, this should be Brainfuck coderhbf?Helper datastructure to implement a stateful transformation in ‰.thbfThe optimized program so faruhbfAThe current batch of instructions being optimized (between loops)vhbf&The current offset since the last loopwhbf3Helper type to apply the Fuse optimization using a «.zhbfpCompilation summary for the user. It contains overview information and statistics about the compilation result.}hbf-Encode the compiled file into the given path.~hbfUse the given h] to parse, compile and optimize the text representation of a Brainfuck program into the IR. q and j% in the compiler options are ignored.hbf*Summarize a compiled program creating the z€hbfUse hp to read, compile, optimize, and save a program from/to the filesystem. Input and output files are provided by q and j.hbfApply optimizations to the Z program turning. The optimizations that will be available are the ones specified by the h given.‚hbfGiven a parsed program, turn it into an optimized one, but with the null optimization. Effectively this is only a type change.ƒhbf(Apply the fusion optimization using the w « instance.€The fusion optimization consist of turning multiple instructions into one. For example if the original Brainfuck code contains ++++, this would be parsed as   [ 1 0,  1 0,  1 0,  1 0] 2but it would be fused to a single IR instruction: Inc 4 0.8fusionOpt $ Program [Inc 1 0, Inc 1 0, Inc 1 0, Inc 1 0] [Inc 4 0]%Similarly, other instructions, like , , ,  and  O can be fused as long as the offset at which they must be applied is the same.'Non fusable operation remain unchanged:&fusionOpt $ Program [Inc 1 0, Inc 1 1][Inc 1 0,Inc 1 1]„hbfBHelper function used to implement optimizations Iterate over all   instructions searching for  s. For each  apply f. If f\ returns a list of new operations, replace the original loop with the new instructions. If f returns ª,, process recursively the loop instructions.…hbf'Basic optimization that turns the loop [-] into a single instruction €. Useful because clearing a memory position is a pretty common operation in Brainfuck and very expensive if treated as a loop.:set -XOverloadedStrings=Right (res, _) = inMemoryCompile defaultCompilerOptions "[-]"res [Clear 0]†hbfxCopy and multiply optimization. A very common usage of loops is to copy the value of a memory position to a different: [->>+<<] this will move the contents of the current memory position to places to the right, also clearing the original position to zero. If we change the number of +A operations we get multiplication, if we have several groups of ++..F operations we get multiple copies. In the general case, for example::set -XOverloadedStringsJRight (res, _) = inMemoryCompile defaultCompilerOptions "[->+>++>++++<<<]"res'[Mul 1 0 1,Mul 2 0 2,Mul 4 0 3,Clear 0]ÿGThe original Brainfuck copies the current position one place to the right, doubles the current position two places to the right, and quadruples the current position three places to the right; finally zeroing the current position. With the mul optimization in this function, all that loop would be replaced by 4 instructions.‡hbf¦Implement the scan optimization. Another common operation in Brainfuck is to search for the first zero in the neighboring memory, either to the right or to the left [>] or [<]R. These loops can be replaced for a more optimal search, represented as a single    or    instruction.!scanOpt $ Program [Loop [Move 1]] [Scan Up 0]ˆhbfStart state for ‰.‰hbfzImplement the offset instruction optimization. This is probably the most complex optimization implemented in the library.ÿJIn streams of instructions between loops, there is no need to keep updating the current position if we can keep track of where the different operations should be applied. This is a trade-off of time (not updating the pointer) by space (keeping track of the offset in every operation). For example the following unoptimized code_offsetInstructionOpt $ Program [Loop [], Move 1, Inc 1 0, Move 2, Clear 0, Mul 2 0 1, Loop []]2[Loop [],Inc 1 1,Clear 3,Mul 2 3 1,Move 3,Loop []]$And the optimization eliminated one P instruction. In general, for larger programs the gain will be more noticeable.1An important detail to take into account is that  y operations break the stream of operations that can be optimized together, and turn the accumulated offset back to zero:WoffsetInstructionOpt $ Program [Loop [], Move 1, Inc 1 0, Scan Up 0, Inc 0 2, Loop []]+[Loop [],Inc 1 1,Scan Up 1,Inc 0 2,Loop []]ŠhbfLoad a compiled program from } output.‹hbf#Load a compiled program saved with }.ŽhbfSDefault compiler options: all optimizations, not verbose, no input or output files.hbf(Compiler options: all optimizations off.hbf&Parse a list of command line arguments‘hbfDParse a list of command line arguments printing errors to the stderr’hbf:Parse command line arguments printing errors to the stderr“hbf8Parse successfully if the token satisfies the predicate.”hbf<Parse movement to the right (>), returning the offset value. Parsec.parse mrightP "" [Move 3]Right 38Data.Either.isLeft $ Parsec.parse mrightP "" [Move (-1)]True•hbf:Parsemovement to the left (<), returning the offset value."Parsec.parse mleftP "" [Move (-3)]Right 34Data.Either.isLeft $ Parsec.parse mleftP "" [Move 1]True–hbf+Parse increment, returning total increment.Parsec.parse plusP "" [Inc 3 0]Right 37Data.Either.isLeft $ Parsec.parse plusP "" [Inc (-2) 0]True—hbf+Parse decrement, returning total decrement.#Parsec.parse minusP "" [Inc (-3) 0]Right 35Data.Either.isLeft $ Parsec.parse minusP "" [Inc 2 0]True˜hbf-Sum the result of a parser applied repeatedly>Parsec.parse (summedP plusP) "" [Inc 3 0, Inc 1 0, Inc (-4) 0]Right 4™hbfkFull multiple copy/multiply operation parser. Returns the set of factors and relative, incremental offsets.NParsec.parse mulP "" [Inc (-1) 0, Move 1, Inc 2 0, Move 3, Inc 1 0, Move (-4)]Right [(2,1),(1,3)]šhbf$Is the instruction a right movement?›hbf#Is the instruction a left movement?œhbf Is the instruction an increment?hbfIs the instruction a decrement?žhbfUse the °" instance and an empty program as ±.ŸhbfThis ° for wb does all the fusion optimization work. When two contiguous optimizations can be fused into one, ¬* will reduce the size of the list in the w.Examples of fusable operations:3(Inc a offset) (Inc b offset) -> (Inc (a+b) offset)*(Move 3 offset) (Move (-3) offset) -> NoOp-(Clear offset) (Clear offset) -> Clear offset3(Scan Up offset) (Scan _ offset') -> Scan Up offset8ghipqjlmnokrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ8ghipqjlmnokrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œSafeݲ³´µ¶·¸¹º       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[[\]^_`abcdefghijkllmnopqrstuvwxyz{|}}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘ghi’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«©¬­©®¯©¬°©®±©®²©®³´µ¶´µ·¸©®¹©®º»¼½¾¿ÀÁÂÃ"hbf-0.2.0.0-GkXEOQI3blwH3jTV0FEOUj HBF.Parser HBF.TypesHBF.Eval HBF.CompilerData.Vector.UnboxedVector Paths_hbfparsec-3.1.13.0Text.Parsec.Error ParseErrorMockIO machineIn machineOut MachineIOputBytegetByteMachinememorypointerProgram instructions Unoptimized Optimized DirectionUpDown MulFactor MemOffsetOpIncMoveInOutLoopClearMulScan flattenedmkMockIO mkMockIOS mockOutput mockOutputS<&> eitherToMaybe$fMonoidProgram$fSemigroupProgram $fMachineIOIO$fMachineIOStateT$fGenericMemOffset$fShowMemOffset $fEqMemOffset$fNumMemOffset$fOrdMemOffset$fBinaryMemOffset$fNFDataMemOffset$fGenericMulFactor$fShowMulFactor $fEqMulFactor$fNumMulFactor$fBinaryMulFactor$fNFDataMulFactor$fShowDirection $fEqDirection$fGenericDirection$fBinaryDirection$fNFDataDirection$fShowOp$fEqOp $fGenericOp $fBinaryOp $fNFDataOp$fGenericProgram $fShowProgram $fEqProgram$fBinaryProgram$fNFDataProgram $fShowMachine $fEqMachine $fShowMockIO $fEqMockIO$fGenericMockIO$fNFDataMockIOprogram operationbfSimpleTokensbfTokensgarbagesimpleOploopOp parseProgram VMOptionsvmOptsMemoryBytesvmOptsDumpMemoryvmOptsProgramPath MachineTypeevalevalWith evalWithIOevalWithMachine emptyMachine mkMachinedefaultVMOptions parsePure unsafeParseparse$fShowVMOptions ProgramParserCompilerOptionscOptsOutcOptsFusionOptimizationcOptsClearLoopOptimizationcOptsMulOptimizationcOptsScanOptimization#cOptsOffsetInstructionsOptimization cOptsVerbose cOptsSource OffsetStateOffSt stOptimizedstBatchstOffset FusedProgramFusedunfusedCompilationSummarycompNumInstructionssaveCompilerOutputinMemoryCompilesummarizeCompilationcompileoptimizetoIR fusionOptliftLoopclearOptmulOptscanOpt emptyStateoffsetInstructionOptloadloadFileoptionsPoptionsdefaultCompilerOptionsnoOptimizationCompilerOptionssatisfy'mrightPmleftPplusPminusPsummedPmulPisRightisLeftisPlusisMinus$fMonoidFusedProgram$fSemigroupFusedProgram$fShowCompilationSummary$fShowFusedProgram$fShowOffsetState$fShowCompilerOptionstransformers-0.5.5.0 Control.Monad.Trans.State.StrictStateTghc-prim GHC.TypesIObase Data.Functor<$> Data.EitherRightGHC.BaseJustLeftNothingMonoid<>(primitive-0.6.4.0-39Pwmm1zkQX6bM7xFUT3JcControl.Monad.Primitive PrimMonad PrimState machineSize Semigroupmemptyversion getBinDir getLibDir getDynLibDir getDataDir getLibexecDir getSysconfDirgetDataFileName