úÎâlØ8¤      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£;Basic types for the Brainfuck compiler and virtual machine.(c) Sebastian Galkin, 2018GPL-3None "#.68:;=K>è$^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.#Every time the machine executes an 1 instruction, input will be taken from this list.#Every time the machine executes an ? instruction, output will be put into this list, in LIFO order.8Provide input and output to a Brainfuck virtual machine.:This class allows to run the VM in different monads, like ¥ or ¤.)The state of a Brainfuck virtual machine. /The full memory of the machine. This will be a  or a List. PThe current execution pointer, information is written and read at this position.  A list of s. opt will be one of  or : to distinguish both types of programs at the type level.(The list of instructions in the program.Marker type to distinguish  and unoptimized  s.)Marker type to distinguish optimized and   s.A direction to   for a memory position. & is in the direction of higher memory.'Scan in the direction of higher memory.&Scan in the direction of lower memory.A factor to multiply by in the  instruction._An offset into the Brainfuck VM memory. Positive numbers are in the direction of higher memory.<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.)Increment by the amount specified by the Int0Move the current pointer by the specified amount^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.`Repeatedly write the byte in the shifted position. Where the byte is written will depend on the  impleentation.%Native Brainfuck looping instruction.aOptimized instruction. Set the shifted position to zero. In Brainfuck this is usually written as [-]DOptimized 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. SFind the nearest zero in the given direction, starting at the offset position. See .!@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]" Create a * that will have the given input available.# Create a : that will have the given input available. ASCII encoding.$-Get the output after a VM has ran using this .%-Get the output after a VM has ran using this . ASCII encoding.&¦ with arguments reversed.'Helper function to convert a § into a ¨ and a © into a ª.(The « of the underlying List of instructions.)Apply ¬ to the underlying List of instructions.*¥- takes its input and output from stdin/stdout+¤6 takes its input and output from the lists inside the .'Write the byte to the output of the VM.)Read a byte from the input of the VM. If EOF has been reached, return ª'  !"#$%&'+  !)( *"#$%+&'   Brainfuck parsing(c) Sebastian Galkin, 2018GPL-3NoneMfNParser for a full  .OisRight $ parse program " +[->>+ +[<] ##garbage## ],.[-] can ignore garbage"TrueOParser for an , ignoring unknown characters.parse operation " +///"Right (Inc 1 0)%parse operation "fooo [+>] baaar "Right (Loop [Inc 1 0,Move 1])PMThe characters allowed in a Brainfuck program except for the loop characters [ and ].Q.The characters allowed in a Brainfuck program.RParser for unknown characters#parse garbage "this is @#! garbage" Right 't'isLeft $ parse garbage "+"TrueS)Parser for simple operations (not loops).parse simpleOp ">"Right (Move 1)parse simpleOp "."Right (Out 1 0)TParser for loops.parse loopOp "[+-]"!Right (Loop [Inc 1 0,Inc (-1) 0])U5Parse program stream. Returns an error or the parsed  NOPQRSTU NOPQRSTUBrainfuck Virtual Machine(c) Sebastian Galkin, 2018GPL-3None"#<VgÍV,Command line arguments for the VM evaluator.XAvailable memory in bytes.Y9Dump the contents of the memory after executing a programZPath to the compiled program[An alias for a / in which memory is an unboxed vector of bytes.\: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.]: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.^:Evaluate the given program returning the end state of the H. The evaluation happens in IO, so Input/Output is done to the console._: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.¯(Size of the default VM memory, in bytes.`A VM # with the default memory available.a*Create a new machine with the given memoryb!Default configuration for the VM.c&Parse a list of command line argumentsdDParse a list of command line arguments printing errors to the stderre:Parse command line arguments printing errors to the stderrVWXYZ[\]^_`abcde[\]^_`aVWXYZbdecVWXYZBrainfuck compilation to IR(c) Sebastian Galkin, 2018GPL-3None"#]Õ±1g;This parser is used to implement the mul optimization. See †.h,Command line flags to the Brainfuck compilerj%Where to put the compiled output, if ª* use the input basename with bfc extensionkEnable fusion optimizationlEnable clear loop optimizationmEnable mul loop optimizationnEnable scan loop optimizationo'Enable offset instructions optimizationp!Output more debugging informationq;Input source to the compiler, this should be Brainfuck coder?Helper datastructure to implement a stateful transformation in ‰.tThe optimized program so faruAThe current batch of instructions being optimized (between loops)v&The current offset since the last loopw3Helper type to apply the Fuse optimization using a «.zpCompilation summary for the user. It contains overview information and statistics about the compilation result.}-Encode the compiled file into the given path.~Use 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.*Summarize a compiled program creating the z€Use hp to read, compile, optimize, and save a program from/to the filesystem. Input and output files are provided by q and j.Apply optimizations to the Z program turning. The optimizations that will be available are the ones specified by the h given.‚Given a parsed program, turn it into an optimized one, but with the null optimization. Effectively this is only a type change.ƒ(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]„BHelper 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.…'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]†xCopy 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.‡¦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]ˆStart state for ‰.‰zImplement 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 []]ŠLoad a compiled program from } output.‹#Load a compiled program saved with }.ŽSDefault compiler options: all optimizations, not verbose, no input or output files.(Compiler options: all optimizations off.&Parse a list of command line arguments‘DParse a list of command line arguments printing errors to the stderr’:Parse command line arguments printing errors to the stderr“8Parse successfully if the token satisfies the predicate.”<Parse movement to the right (>), returning the offset value. Parsec.parse mrightP "" [Move 3]Right 38Data.Either.isLeft $ Parsec.parse mrightP "" [Move (-1)]True•:Parsemovement to the left (<), returning the offset value."Parsec.parse mleftP "" [Move (-3)]Right 34Data.Either.isLeft $ Parsec.parse mleftP "" [Move 1]True–+Parse increment, returning total increment.Parsec.parse plusP "" [Inc 3 0]Right 37Data.Either.isLeft $ Parsec.parse plusP "" [Inc (-2) 0]True—+Parse decrement, returning total decrement.#Parsec.parse minusP "" [Inc (-3) 0]Right 35Data.Either.isLeft $ Parsec.parse minusP "" [Inc 2 0]True˜-Sum the result of a parser applied repeatedly>Parsec.parse (summedP plusP) "" [Inc 3 0, Inc 1 0, Inc (-4) 0]Right 4™kFull 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)]š$Is the instruction a right movement?›#Is the instruction a left movement?œ Is the instruction an increment?Is the instruction a decrement?žUse the °" instance and an empty program as ±.ŸThis ° 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{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ:}~z{|€‚wxyŸžƒ„…†‡rstuvˆ‰Š‹hijklmnopqŒŽ‘’g“”•–—˜™š›œh ijklmnopqrstuvwxyz{|Safeز³´µ¶·¸¹º       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[[\]^_`abcdefghijkllmnopqrstuvwxyz{|}}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘ghi’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«©¬­©®¯©¬°©®±©®²©³´µ¶·µ¶¸¹©³º©®»¼½¾¿ÀÁÂÃÄ"hbf-0.1.0.0-1ym0N8EgUp7GIP1dsycGKE HBF.Parser HBF.TypesHBF.Eval HBF.CompilerData.Vector.UnboxedVector Paths_hbf&parsec-3.1.13.0-8LZZ7WXJK3p4xjNxyU5eyQText.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.2.0Control.Monad.Trans.State.LazyStateTghc-prim GHC.TypesIObase Data.Functor<$> Data.EitherRightGHC.BaseJustLeftNothingMonoidData.Semigroup<>(primitive-0.6.2.0-EI3NK1Xfv9zEcRtyXK2EwZControl.Monad.Primitive PrimMonad PrimState machineSize Semigroupmemptyversion getBinDir getLibDir getDynLibDir getDataDir getLibexecDir getSysconfDirgetDataFileName