paintfuck interpreter written in pure lua
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
--[[ | |
This file is licensed under the license `CC BY-NC-ND 4.0`, visit "https://creativecommons.org/licenses/by-nc-nd/4.0/" for additional information. | |
author: wfrsk @ github.com | |
]] | |
local instruction_type = { up = 1, | |
down = 3, | |
right = 2, | |
left = 4, | |
loop_open = 5, | |
loop_close = 7, | |
flip_bit = 6 } | |
local character_map = { ["n"] = instruction_type.up, | |
["s"] = instruction_type.down, | |
["e"] = instruction_type.right, | |
["w"] = instruction_type.left, | |
["["] = instruction_type.loop_open, | |
["]"] = instruction_type.loop_close, | |
["*"] = instruction_type.flip_bit } | |
local function make_bitmap( x_bounds ) | |
local integers_required = math.ceil( x_bounds / 64 ) | |
local internal_bitmap, external_adapter do | |
internal_bitmap = { } do | |
for index = 1, integers_required do | |
internal_bitmap[ index ] = 0 | |
end | |
end | |
local function index_routine( _, bitspace_index ) | |
assert( type( bitspace_index ) == "number", "index must be an integer" ) | |
local integer_index, bit_index = math.ceil( bitspace_index / 64 ), bitspace_index % 64 | |
return ( assert( internal_bitmap[ integer_index ], "index given out of bounds for bitmap" ) & ( 1 << ( bit_index - 1 ) ) ) == ( 1 << ( bit_index - 1 ) ) and 1 or 0 | |
end | |
local function newindex_routine( _, bitspace_index, new_value ) | |
assert( type( bitspace_index ) == "number", "index must be an integer" ) | |
local integer_index, bit_index = math.ceil( bitspace_index / 64 ), bitspace_index % 64 | |
internal_bitmap[ integer_index ] = ( new_value & 1 ) == 1 and assert( internal_bitmap[ integer_index ], "index given out of bounds for bitmap" ) | ( 1 << ( bit_index - 1 ) ) or assert( internal_bitmap[ integer_index ], "index given out of bounds for bitmap" ) & ~( 1 << ( bit_index - 1 ) ) | |
end | |
external_adapter = setmetatable( { }, { __index = index_routine, __newindex = newindex_routine } ) | |
end | |
return external_adapter | |
end | |
local function serialize_bitmap_2d( target_bitmap_2d, x_bounds, y_bounds ) | |
local string_repr = { } do | |
for y_index = 1, y_bounds do | |
string_repr[ y_index ] = { } | |
for x_index = 1, x_bounds do | |
string_repr[ y_index ][ x_index ] = tostring( target_bitmap_2d[ x_index ][ y_index ] ) | |
end | |
string_repr[ y_index ] = table.concat( string_repr[ y_index ], "" ) | |
end | |
end | |
return table.concat( string_repr, "\r\n" ) | |
end | |
local function paintfuck_vm_routine( source_code, step_limit, x_bounds, y_bounds ) | |
local vm_state = { } do | |
vm_state.instruction_pointer = 0 | |
vm_state.instruction_list = { } do | |
for character in string.gmatch( source_code, "[%[%]nswe*]" ) do | |
vm_state.instruction_list[ #vm_state.instruction_list + 1 ] = character_map[ character ] | |
end | |
end | |
vm_state.memory_location = { x = 1, y = 1 } | |
vm_state.loop_stack = { } | |
vm_state.memory_bitmap = { } do | |
for index = 1, x_bounds do | |
vm_state.memory_bitmap[ index ] = make_bitmap( y_bounds ) | |
end | |
end | |
end | |
while vm_state.instruction_pointer <= #vm_state.instruction_list and step_limit ~= 0 do | |
vm_state.instruction_pointer = vm_state.instruction_pointer + 1 | |
step_limit = step_limit - 1 | |
local current_instruction = vm_state.instruction_list[ vm_state.instruction_pointer ] | |
if current_instruction == instruction_type.flip_bit then | |
vm_state.memory_bitmap[ vm_state.memory_location.x ][ vm_state.memory_location.y ] = vm_state.memory_bitmap[ vm_state.memory_location.x ][ vm_state.memory_location.y ] == 0 and 1 or 0 | |
elseif current_instruction == instruction_type.loop_open and vm_state.memory_bitmap[ vm_state.memory_location.x ][ vm_state.memory_location.y ] == 0 then | |
local ongoing_loops = 1 | |
repeat | |
vm_state.instruction_pointer = vm_state.instruction_pointer + 1 | |
if vm_state.instruction_list[ vm_state.instruction_pointer ] == instruction_type.loop_open then | |
ongoing_loops = ongoing_loops + 1 | |
elseif vm_state.instruction_list[ vm_state.instruction_pointer ] == instruction_type.loop_close then | |
ongoing_loops = ongoing_loops - 1 | |
end | |
until vm_state.instruction_list[ vm_state.instruction_pointer ] == instruction_type.loop_close and ongoing_loops == 0 | |
elseif current_instruction == instruction_type.loop_close and vm_state.memory_bitmap[ vm_state.memory_location.x ][ vm_state.memory_location.y ] ~= 0 then | |
local ongoing_loops = 1 | |
repeat | |
vm_state.instruction_pointer = vm_state.instruction_pointer - 1 | |
if vm_state.instruction_list[ vm_state.instruction_pointer ] == instruction_type.loop_open then | |
ongoing_loops = ongoing_loops - 1 | |
elseif vm_state.instruction_list[ vm_state.instruction_pointer ] == instruction_type.loop_close then | |
ongoing_loops = ongoing_loops + 1 | |
end | |
until vm_state.instruction_list[ vm_state.instruction_pointer ] == instruction_type.loop_open and ongoing_loops == 0 | |
elseif current_instruction == instruction_type.right then | |
vm_state.memory_location.x = vm_state.memory_location.x + 1 <= x_bounds and vm_state.memory_location.x + 1 or vm_state.memory_location.x + 1 - x_bounds | |
elseif current_instruction == instruction_type.left then | |
vm_state.memory_location.x = vm_state.memory_location.x - 1 > 0 and vm_state.memory_location.x - 1 or x_bounds | |
elseif current_instruction == instruction_type.up then | |
vm_state.memory_location.y = vm_state.memory_location.y - 1 > 0 and vm_state.memory_location.y - 1 or y_bounds | |
elseif current_instruction == instruction_type.down then | |
vm_state.memory_location.y = vm_state.memory_location.y + 1 <= y_bounds and vm_state.memory_location.y + 1 or vm_state.memory_location.y + 1 - y_bounds | |
end | |
end | |
return serialize_bitmap_2d( vm_state.memory_bitmap, x_bounds, y_bounds ) | |
end | |
return paintfuck_vm_routine |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment