diff --git a/bin/rpl b/bin/rpl index aeace47..5b47f35 100755 --- a/bin/rpl +++ b/bin/rpl @@ -71,13 +71,7 @@ class RplRepl end def print_display - puts @interpreter.framebuffer - .to_i - .to_s(2) - .scan(/.{1,#{@interpreter.display_width}}/) - .join("\n") - .gsub( '0', '_' ) - .gsub( '1', '.' ) + puts @interpreter.display_grob.to_text end def print_stack diff --git a/lib/rpl/interpreter.rb b/lib/rpl/interpreter.rb index cf388bb..f4e68b7 100644 --- a/lib/rpl/interpreter.rb +++ b/lib/rpl/interpreter.rb @@ -7,60 +7,24 @@ require 'bigdecimal/util' require 'rpl/dictionary' require 'rpl/types' -class BitArray - def initialize - @mask = 0 - end - - def []=(position, value) - if value.zero? - @mask ^= (1 << position) - else - @mask |= (1 << position) - end - end - - def [](position) - @mask[position] - end - - def to_i - @mask.to_i - end - - def from_i( value ) - @mask = value.to_i - end -end - class Interpreter include BigMath include Types attr_reader :stack, - :framebuffer, + :display_grob, :dictionary, :version - attr_accessor :show_display, - :display_width, - :display_height, - :precision + attr_accessor :show_display def initialize( stack: [], dictionary: Dictionary.new ) @dictionary = dictionary @stack = stack - initialize_framebuffer - end - - def initialize_framebuffer - @framebuffer = BitArray.new - - @display_width = 131 - @display_height = 64 - @show_display = false + + @display_grob = RplGrOb.new( 'GROB:131:64:0' ) end def run!( input ) diff --git a/lib/rpl/types/grob.rb b/lib/rpl/types/grob.rb index d78e0f7..37e5b43 100644 --- a/lib/rpl/types/grob.rb +++ b/lib/rpl/types/grob.rb @@ -2,38 +2,88 @@ require 'rpl/parser' +class BitArray + def initialize + @mask = 0 + end + + def []=(position, value) + if value.zero? + @mask ^= (1 << position) + else + @mask |= (1 << position) + end + end + + def [](position) + @mask[position] + end + + def to_i + @mask.to_i + end + + def from_i( value ) + @mask = value.to_i + end +end + module Types class RplGrOb - attr_reader :width, - :height, - :bits, - :value + attr_accessor :width, + :height, + :bits - def initialize( value ) - raise RplTypeError unless self.class.can_parse?( value ) + def initialize( init ) + raise RplTypeError unless self.class.can_parse?( init ) - parsed = /^GROB:(?\d+):(?\d+):(?[0-9a-f]+)$/.match( value ) + parsed = if init.instance_of?( RplGrOb ) + init.value + else + /^GROB:(?\d+):(?\d+):(?[0-9a-f]+)$/.match( init ) + end @width = parsed[:width].to_i @height = parsed[:height].to_i - @bits = parsed[:bits].to_i( 16 ) + @bits = BitArray.new + @bits.from_i( parsed[:bits].to_i( 16 ) ) + end - @value = [@width, @height, @bits] + def value + { width: @width, + height: @height, + bits: @bits.to_i.to_s( 16 ) } end def to_s - "GROB:#{@width}:#{@height}:#{@bits.to_s( 16 )}" + "GROB:#{@width}:#{@height}:#{@bits.to_i.to_s( 16 )}" end def self.can_parse?( value ) - value.instance_of?( String ) && value.match?(/^GROB:\d+:\d+:[0-9a-f]+$/) + value.instance_of?( RplGrOb ) || + ( value.instance_of?( String ) && value.match?(/^GROB:\d+:\d+:[0-9a-f]+$/) ) end def ==( other ) other.class == RplGrOb && - other.width == width && - other.height == height && - other.bits == bits + other.width == @width && + other.height == @height && + other.bits.to_i == @bits.to_i + end + + def to_text + @bits.to_i + .to_s(2) + .ljust(@width * @height, '0') + .slice(0, @width * @height) + .scan(/.{1,#{@width}}/) + .join("\n") + .gsub( '0', '_' ) + .gsub( '1', '.' ) + end + + def set_pixel( pos_x, pos_y, value ) + @bits[ ( pos_y * @height ) + pos_x ] = value end end end diff --git a/lib/rpl/words/graphics.rb b/lib/rpl/words/graphics.rb index 9036bcd..3b5b2ce 100644 --- a/lib/rpl/words/graphics.rb +++ b/lib/rpl/words/graphics.rb @@ -52,17 +52,17 @@ module RplLang @show_display = false end ) - @dictionary.add_word!( ['displaywidth→', 'displaywidth->'], + @dictionary.add_word!( ['displaywidth'], category, '( -- i ) put framebuffer\'s width on stack', proc do - @stack << RplNumeric.new( @display_width.to_i ) + @stack << RplNumeric.new( @display_grob.width ) end ) - @dictionary.add_word!( ['displayheight→', 'displayheight->'], + @dictionary.add_word!( ['displayheight'], category, '( -- i ) put framebuffer\'s height on stack', proc do - @stack << RplNumeric.new( @display_height.to_i ) + @stack << RplNumeric.new( @display_grob.height ) end ) @dictionary.add_word!( ['→displaywidth', '->displaywidth'], @@ -71,7 +71,7 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - @display_width = args[0].value.to_i + @display_grob.width = args[0].value.to_i end ) @dictionary.add_word!( ['→displayheight', '->displayheight'], category, @@ -79,23 +79,23 @@ module RplLang proc do args = stack_extract( [[RplNumeric]] ) - @display_height = args[0].value.to_i + @display_grob.height = args[0].value.to_i end ) @dictionary.add_word!( ['display→', 'display->'], category, '( -- g ) export framebuffer to GrOb', proc do - @stack << RplGrOb.new( "GROB:#{@display_width}:#{@display_height}:#{@framebuffer.to_i.to_s( 16 )}" ) + @stack << RplGrOb.new( @display_grob ) end ) - # @dictionary.add_word!( ['→display', '->display'], - # category, - # '( g -- ) import GrOb into framebuffer', - # proc do - # args = stack_extract( [[RplNumeric]] ) + @dictionary.add_word!( ['→display', '->display'], + category, + '( g -- ) import GrOb into framebuffer', + proc do + args = stack_extract( [[RplGrOb]] ) - # @framebuffer = args[0].value.to_i - # end ) + @display_grob = RplGrOb.new( args[0] ) + end ) @dictionary.add_word!( ['pixon'], category, @@ -106,7 +106,7 @@ module RplLang x = args[1].value.to_i y = args[0].value.to_i - @framebuffer[ ( y * @display_height ) + x ] = 1 + @display_grob.set_pixel(x, y, 1) end ) @dictionary.add_word!( ['pixoff'], category, @@ -117,7 +117,7 @@ module RplLang x = args[1].value.to_i y = args[0].value.to_i - @framebuffer[ ( y * @display_height ) + x ] = 0 + @display_grob.set_pixel(x, y, 0) end ) end end