new RplGrOb type and related words, plus display management words

This commit is contained in:
Gwenhael Le Moine 2023-07-06 16:51:32 +02:00
parent 422a7828a5
commit 3fa79fe97d
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
10 changed files with 157 additions and 65 deletions

17
bin/rpl
View file

@ -60,7 +60,7 @@ class RplRepl
end
end
refresh_lcd if @interpreter.show_lcd
print_display if @interpreter.show_display
print_stack
rescue Interrupt
@ -70,13 +70,14 @@ class RplRepl
end
end
def refresh_lcd
@interpreter.lcd_width.times do |x|
@interpreter.lcd_height.times do |y|
putc @interpreter.frame_buffer[ ( y * @interpreter.lcd_height ) + x ].zero? ? '_' : '.'
end
puts "\n"
end
def print_display
puts @interpreter.framebuffer
.to_i
.to_s(2)
.scan(/.{1,#{@interpreter.display_width}}/)
.join("\n")
.gsub( '0', '_' )
.gsub( '1', '.' )
end
def print_stack

View file

@ -49,7 +49,6 @@ class Rpl < Interpreter
end
prepend RplLang::Words::Branch
prepend RplLang::Words::Display
prepend RplLang::Words::FileSystem
prepend RplLang::Words::General
prepend RplLang::Words::Graphics

View file

@ -23,6 +23,14 @@ class BitArray
def [](position)
@mask[position]
end
def to_i
@mask.to_i
end
def from_i( value )
@mask = value.to_i
end
end
class Interpreter
@ -30,30 +38,29 @@ class Interpreter
include Types
attr_reader :stack,
:frame_buffer,
:framebuffer,
:dictionary,
:version,
:lcd_width,
:lcd_height
:version
attr_accessor :show_lcd,
attr_accessor :show_display,
:display_width,
:display_height,
:precision
def initialize( stack: [], dictionary: Dictionary.new )
@dictionary = dictionary
@stack = stack
initialize_frame_buffer
initialize_framebuffer
end
def initialize_frame_buffer
@frame_buffer = BitArray.new
def initialize_framebuffer
@framebuffer = BitArray.new
# TODO: make this configurable from rpl?
@lcd_width = 131
@lcd_height = 64
@display_width = 131
@display_height = 64
@show_lcd = false
@show_display = false
end
def run!( input )

View file

@ -103,6 +103,8 @@ class Parser
Types.new_object( RplString, element )
elsif RplProgram.can_parse?( element )
Types.new_object( RplProgram, element )
elsif RplGrOb.can_parse?( element )
Types.new_object( RplGrOb, element )
elsif RplName.can_parse?( element )
Types.new_object( RplName, element )
end

View file

@ -7,6 +7,7 @@ require 'rpl/types/string'
require 'rpl/types/program'
require 'rpl/types/numeric'
require 'rpl/types/complex'
require 'rpl/types/grob'
module Types
module_function

39
lib/rpl/types/grob.rb Normal file
View file

@ -0,0 +1,39 @@
# frozen_string_literal: true
require 'rpl/parser'
module Types
class RplGrOb
attr_reader :width,
:height,
:bits,
:value
def initialize( value )
raise RplTypeError unless self.class.can_parse?( value )
parsed = /^GROB:(?<width>\d+):(?<height>\d+):(?<bits>[0-9a-f]+)$/.match( value )
@width = parsed[:width].to_i
@height = parsed[:height].to_i
@bits = parsed[:bits].to_i( 16 )
@value = [@width, @height, @bits]
end
def to_s
"GROB:#{@width}:#{@height}:#{@bits.to_s( 16 )}"
end
def self.can_parse?( value )
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
end
end
end

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'rpl/words/branch'
require 'rpl/words/display'
require 'rpl/words/general'
require 'rpl/words/mode'
require 'rpl/words/operations-reals'

View file

@ -1,29 +0,0 @@
# frozen_string_literal: true
module RplLang
module Words
module Display
include Types
def populate_dictionary
super
category = 'Display'
@dictionary.add_word!( ['erase'],
category,
'( -- ) erase display',
proc do
initialize_frame_buffer
end )
@dictionary.add_word!( ['display→', 'display->'],
category,
'( -- pict ) put current display state on stack',
proc do
@stack << @frame_buffer # FIXME: RplPict type
end )
end
end
end
end

View file

@ -8,23 +8,94 @@ module RplLang
def populate_dictionary
super
category = 'Graphics'
category = 'GrOb (Graphic Objects)'
@dictionary.add_word!( ['lcdon'],
@dictionary.add_word!( ['→grob', '->grob'],
category,
'( -- ) display lcd',
'( w h d -- g ) make a GrOb from 3 numerics: width, height, data',
proc do
# Sets on a boolean that the REPL will survey and show the Gosu window when true
@show_lcd = true
args = stack_extract( [[RplNumeric], [RplNumeric], [RplNumeric]] )
@stack << RplGrOb.new( "GROB:#{args[2].value.to_i}:#{args[1].value.to_i}:#{args[0].value.to_i.to_s( 16 )}" )
end )
@dictionary.add_word!( ['grob→', 'grob->'],
category,
'( g -- w h d ) split a GrOb into its 3 basic numerics',
proc do
args = stack_extract( [[RplGrOb]] )
@stack << RplNumeric.new( args[0].width )
@stack << RplNumeric.new( args[0].height )
@stack << RplNumeric.new( args[0].bits, 16 )
end )
@dictionary.add_word!( ['grob2asciiart'],
category,
'( g -- s ) render a GrOb as a string',
proc do
args = stack_extract( [[RplGrOb]] )
@stack << RplString.new( "\"#{args[0].bits.to_s(2).scan(/.{1,#{args[0].width}}/).join("\n")}\"" )
end )
@dictionary.add_word!( ['lcdoff'],
category = 'Display management and manipulation'
@dictionary.add_word!( ['displayon'],
category,
'( -- ) hide lcd',
'( -- ) display display',
proc do
# Sets on a boolean that the REPL will survey and hide the Gosu window when false
@show_lcd = false
@show_display = true
end )
@dictionary.add_word!( ['displayoff'],
category,
'( -- ) hide display',
proc do
@show_display = false
end )
@dictionary.add_word!( ['displaywidth→', 'displaywidth->'],
category,
'( -- i ) put framebuffer\'s width on stack',
proc do
@stack << RplNumeric.new( @display_width.to_i )
end )
@dictionary.add_word!( ['displayheight→', 'displayheight->'],
category,
'( -- i ) put framebuffer\'s height on stack',
proc do
@stack << RplNumeric.new( @display_height.to_i )
end )
@dictionary.add_word!( ['→displaywidth', '->displaywidth'],
category,
'( i -- ) set framebuffer\'s width',
proc do
args = stack_extract( [[RplNumeric]] )
@display_width = args[0].value.to_i
end )
@dictionary.add_word!( ['→displayheight', '->displayheight'],
category,
'( i -- ) set framebuffer\'s height',
proc do
args = stack_extract( [[RplNumeric]] )
@display_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 )}" )
end )
# @dictionary.add_word!( ['→display', '->display'],
# category,
# '( g -- ) import GrOb into framebuffer',
# proc do
# args = stack_extract( [[RplNumeric]] )
# @framebuffer = args[0].value.to_i
# end )
@dictionary.add_word!( ['pixon'],
category,
@ -32,11 +103,10 @@ module RplLang
proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] )
puts "DEBUG: turn on pixel(x: #{args[1].value}, y: #{args[0].value})"
x = args[1].value.to_i
y = args[0].value.to_i
@frame_buffer[ ( y * @lcd_height ) + x ] = 1
@framebuffer[ ( y * @display_height ) + x ] = 1
end )
@dictionary.add_word!( ['pixoff'],
category,
@ -44,7 +114,10 @@ module RplLang
proc do
args = stack_extract( [[RplNumeric], [RplNumeric]] )
puts "DEBUG: turn off pixel(x: #{args[1].value}, y: #{args[0].value})"
x = args[1].value.to_i
y = args[0].value.to_i
@framebuffer[ ( y * @display_height ) + x ] = 0
end )
end
end

View file

@ -84,8 +84,8 @@ module RplLang
category,
'() print internal state of framebuffer',
proc do
pp @show_lcd
pp @frame_buffer
pp @show_display
pp @framebuffer
end )
end
end