Useless brainlang module

brainlang is an esoteric programming language developed in the early 90s. its essentially 1 giant 30,000 cell tape, and a pointer pointing to the current cell you’re on, whose max value is 255. cells wrap around 256 (mod 256), and the pointer wraps around 30000. BF has 8 functions:
+ adds 1 to the current cell
- subtracts 1
> shifts to the right
< shifts to the left
[ begins a loop
] ends a loop
. adds the current cells ascii to the output
, takes in an input

what I’ve done is made it compatible with Roblox functions. i believe most things in Lua are possible in the bf i made. i added a couple features for debugging as well. honestly just let your imagination roam wild- at work i made a bf interpreter in office script and found it really enjoyable programming my own draw function to draw lines and skulls w/ different colors. it was a time-killer and extremely challenging but engaging. and i encourage you to try it out, try experimenting and coming up w equations, and do something unprecedented- its completely useless, but its not like there’s anything more useful than brainfuck.
also its cross compatible as long as you don’t use the custom symbols i added.


= basically toggles the stack output flag. when its true, everything printed using . will be pushed into an array called the stack output. ? prints this array, and / clears it. there’s also _ which makes it so that anything printed with . will be added to a string- its also a toggle.

for debugging, $ prints the value of the cell w/o ascii, and @ prints the address of it.

for functions
# puts the most recent stacked output item (w/o removing it) into an array called the stack index
* removes the top stack index item.

% does the same thing as # except for an array called the stack function arguments
same with ~

^ connects everything in the stacked index array, and calls it with the stack function arguments

and lastly | (the absolute value symbol) yields for 10ms

if you want to leave feedback, or you find any bugs, or you want me to add anything that doesnt go against the nature of BF, leave a comment.

-- ilucere

local brainfog = {}
brainfog.__index = brainfog

local instructionCodes = {
	-- you should know these
	['+'] = 1,
	['-'] = 2,
	['<'] = 3,
	['>'] = 4,
	['['] = 5,
	[']'] = 6,
	[','] = 7,
	['.'] = 8,
	
	-- STRINGS
	['='] = 9, -- STACK OUTPUT FLAG (two blocks on top of each other)
	['?'] = 10, -- PRINT STACKED OUTPUT (what is our output?)
	['/'] = 11, -- CLEAR STACKED OUTPUT (slash it out of here)
	['_'] = 12, -- TOGGLE STRING MODE ON OUTPUT (missing character....)
	
	-- DEBUGGING
	['$'] = 13, -- PRINT CELL VALUE (money has value)
	['@'] = 14, -- PRINT CELL INDEX (at what index)
	
	-- FUNCTIONS
	['#'] = 15, -- STACK INDEXING [basically puts your recent STACKED OUTPUT in an array so you can do workspace.Object for example]
	['*'] = 16, -- REMOVE RECENT STACK INDEXING (* makes the most sense to me for a clear. dont remember why)
	
	['%'] = 17, -- SET STACKED OUTPUT AS FUNCTION ARG (two objects next to each other)
	['~'] = 18, -- REMOVE RECENT FUNCTION ARGS ITEM
	
	['^'] = 19, -- CALL STACKED INDICES AS FUNCTION
	
	-- QOL
	['|'] = 20, -- HALT. stop for 10ms
}

-- v 0-0-1

-- stdBFTapeCells
-- if true, the tape is 30,000 cells, and each cell has a max of 255. if false, the max tape size is 100,000

local stdCellMax, stdTapeMax = 256, 30
local customTapeMax = 100000
function brainfog.New(stdBFTapeCells)
	return setmetatable({
		stdBFTapeCells=stdBFTapeCells,
		tapeMax=stdBFTapeCells and (stdTapeMax) or (customTapeMax),
		tape=stdBFTapeCells and (table.create(stdTapeMax, 0)) or (table.create(customTapeMax, 0)),
		
		env=0,
		argTape={},
		stackOutputTape={},
		stackIndexTape={},
	}, brainfog)
end

function brainfog:Tokenization(text)
	if (type(text) ~= 'string') then
		error('not a string')
	end
	
	local instructions = {}
	local loops = {}
	local loopStack = {}
	local index, maxLength = 1, string.len(text)
	
	local position = 0
	while (index <= maxLength) do
		local character = string.sub(text, index, index)
		if (character == ':') then
			index += 1
			while (string.sub(text, index, index) ~= '\n' and index <= maxLength) do
				index += 1
			end
			continue
		end
		
		local characterCode = instructionCodes[character]
		if (characterCode) then
			position += 1
			local repetitions = 0
			
			if (character == '[') then
				repetitions = 1
				index += 1
				
				table.insert(loopStack, position)
			elseif (character == ']') then
				repetitions = 1
				index += 1
				
				local insertion = table.remove(loopStack, #loopStack)
				loops[insertion] = position
				loops[position] = insertion
			else
				while (string.sub(text, index, index) == character) do
					repetitions += 1
					index += 1
				end
			end
			
			table.insert(instructions, {characterCode, repetitions, position})
		else
			index += 1
		end
	end
	
	if (#loopStack ~= 0) then
		error('unbalanced loops')
	end
	
	self.loops = loops
	self.instructions = instructions
	
	return self
end


--[1] add
function brainfog._stdBFAdd(initial, count)
	return (initial + count) % stdCellMax
end

function brainfog._nccBFAdd(initial, count)
	return (initial + count)
end

--[2] subtract
function brainfog._stdBFSub(initial, count)
	return (initial - count) % stdCellMax
end

function brainfog._nccBFSub(initial, count)
	return (initial - count)
end

--[3] left
function brainfog._stdBFLeft(ptr, count)
	return (ptr - count) % stdTapeMax
end

function brainfog._nccBFLeft(ptr, count)
	return (ptr - count) % customTapeMax
end

--[4] right
function brainfog._stdBFRight(ptr, count)
	return (ptr + count) % stdTapeMax
end

function brainfog._nccBFRight(ptr, count)
	return (ptr + count) % customTapeMax
end



local UserInputService = game:GetService('UserInputService')
function brainfog:Execute(env)
	local add, sub, left, right;
	if (self.stdBFTapeCells) then
		add, sub, left, right = brainfog._stdBFAdd, brainfog._stdBFSub, brainfog._stdBFLeft, brainfog._stdBFRight
	else
		add, sub, left, right = brainfog._nccBFAdd, brainfog._nccBFSub, brainfog._nccBFLeft, brainfog._nccBFRight
	end
	
	local pointer = 1
	local stackedOutput, stringMode = false, false
	
	local compiledString = ''
	local index = 1
	while (index <= #self.instructions) do
		local instructionInfo = self.instructions[index]
		local instructionCode, repetitions, position = instructionInfo[1], instructionInfo[2], instructionInfo[3]
		
		if (instructionCode == instructionCodes['+']) then
			self.tape[pointer] = add(self.tape[pointer], repetitions)
			
		elseif (instructionCode == instructionCodes['-']) then
			self.tape[pointer] = sub(self.tape[pointer], repetitions)
			
		elseif (instructionCode == instructionCodes['<']) then
			pointer = left(pointer, repetitions)
			print('left', repetitions)
			
		elseif (instructionCode == instructionCodes['>']) then
			pointer = right(pointer, repetitions)
			print('right', repetitions)
			
		elseif (instructionCode == instructionCodes['[']) then
			if (self.tape[pointer] == 0) then
				index = self.loops[position]
			end
			
		elseif (instructionCode == instructionCodes[']']) then
			if (self.tape[pointer] ~= 0) then
				index = self.loops[position]
			end
			
		elseif (instructionCode == instructionCodes['.']) then
			local cell = utf8.char(self.tape[pointer])
			if (stackedOutput) then
				if (stringMode) then
					compiledString ..= cell
				else
					table.insert(self.stackOutputTape, cell)
				end
			else
				print(cell)
			end
			
		elseif (instructionCode == instructionCodes['_']) then
			if (compiledString ~= '') then
				table.insert(self.stackOutputTape, compiledString)
			end
			stringMode = not stringMode
			
		elseif (instructionCode == instructionCodes[',']) then
			local input = UserInputService.InputBegan:Wait()
			local fixedInput = input.KeyCode == Enum.KeyCode.Unknown and (input.UserInputType.Name) or (input.KeyCode.Name)
			table.insert(self.stackOutputTape, fixedInput)
			
		elseif (instructionCode == instructionCodes['=']) then
			stackedOutput = not stackedOutput
			
		elseif (instructionCode == instructionCodes['/']) then
			table.clear(self.stackOutputTape)
			
		elseif (instructionCode == instructionCodes['?']) then
			print(table.unpack(self.stackOutputTape))
			
		elseif (instructionCode == instructionCodes['$']) then
			print(self.tape[pointer])
			
		elseif (instructionCode == instructionCodes['@']) then
			print(pointer)
			
		elseif (instructionCode == instructionCodes['|']) then
			task.wait(.1) -- this is fine
			
		elseif (instructionCode == instructionCodes['#']) then
			local value = self.stackOutputTape[#self.stackOutputTape]
			if (value) then
				table.insert(self.stackIndexTape, value)
			end

		elseif (instructionCode == instructionCodes['*']) then
			table.remove(self.stackIndexTape, #self.stackIndexTape)
			
		elseif (instructionCode == instructionCodes['%']) then
			local value = self.stackOutputTape[#self.stackOutputTape]
			if (value) then
				table.insert(self.argTape, value)
			end

		elseif (instructionCode == instructionCodes['~']) then
			table.remove(self.argTape, #self.argTape)
			
		elseif (instructionCode == instructionCodes['^']) then
			local init = (env or getfenv(2))
			print(init)
			for _, v in (self.stackIndexTape) do
				init = init[v]
			end
			print(self.stackIndexTape)
			init(table.unpack(self.argTape))
		end
		
		index += 1
	end
end

return brainfog

example:

local bf = require(script.Parent.brainfog).New(true)


local env = {}
env.A = function(x)
	print('sheesh', utf8.codepoint(x, 1, 1))
end
bf:Tokenization('>+++++[<+++++++++++++> -]< =.=# /[-] =+++++.=% ^'):Execute(env)

brainfog.lua (7.4 KB)

5 Likes