rpl 0.16.2 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/rpl +6 -0
- data/lib/rpl/interpreter.rb +11 -24
- data/lib/rpl/parser.rb +2 -0
- data/lib/rpl/types/grob.rb +111 -0
- data/lib/rpl/types.rb +1 -0
- data/lib/rpl/words/graphics.rb +140 -0
- data/lib/rpl/words/repl.rb +8 -0
- data/lib/rpl/words.rb +1 -1
- data/lib/rpl.rb +3 -3
- metadata +20 -5
- data/lib/rpl/words/display.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9503bcb52c319c657b082e69d395d55afc2bd2d0426d6fd58a488296dfb401fe
|
4
|
+
data.tar.gz: 01cf9eece63336abf8ce25c27faae3bffc67e678cc2267eaf6c91e9ba4302053
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b47ac5a4038fc602f7cb1ee3b279d6bdb9df8321ccf92be432324928c016c53e01f6886176902763193a0a120a41d2d9887845cd6692aa27e348a8fd82d0b04
|
7
|
+
data.tar.gz: 8995e27122d1223676bb2dc060079b8c6f07c8dad03ac288394b9b5fedfd54f8a324224a0c7fcd52dc30513db099964d954c2cfcf6961cdbbe49c11633420734
|
data/bin/rpl
CHANGED
@@ -60,6 +60,8 @@ class RplRepl
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
print_lcd if @interpreter.show_lcd
|
64
|
+
|
63
65
|
print_stack
|
64
66
|
rescue Interrupt
|
65
67
|
puts '^C'
|
@@ -68,6 +70,10 @@ class RplRepl
|
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
73
|
+
def print_lcd
|
74
|
+
puts @interpreter.lcd_grob.to_braille
|
75
|
+
end
|
76
|
+
|
71
77
|
def print_stack
|
72
78
|
stack_size = @interpreter.stack.size
|
73
79
|
|
data/lib/rpl/interpreter.rb
CHANGED
@@ -7,44 +7,24 @@ require 'bigdecimal/util'
|
|
7
7
|
require 'rpl/dictionary'
|
8
8
|
require 'rpl/types'
|
9
9
|
|
10
|
-
class BitArray
|
11
|
-
def initialize
|
12
|
-
@mask = 0
|
13
|
-
end
|
14
|
-
|
15
|
-
def []=(position, value)
|
16
|
-
if value.zero?
|
17
|
-
@mask ^= (1 << position)
|
18
|
-
else
|
19
|
-
@mask |= (1 << position)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def [](position)
|
24
|
-
@mask[position]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
10
|
class Interpreter
|
29
11
|
include BigMath
|
30
12
|
include Types
|
31
13
|
|
32
14
|
attr_reader :stack,
|
33
|
-
:
|
15
|
+
:lcd_grob,
|
34
16
|
:dictionary,
|
35
17
|
:version
|
36
18
|
|
37
|
-
attr_accessor :
|
19
|
+
attr_accessor :show_lcd
|
38
20
|
|
39
21
|
def initialize( stack: [], dictionary: Dictionary.new )
|
40
22
|
@dictionary = dictionary
|
41
23
|
@stack = stack
|
42
24
|
|
43
|
-
|
44
|
-
end
|
25
|
+
@show_lcd = false
|
45
26
|
|
46
|
-
|
47
|
-
@frame_buffer = BitArray.new
|
27
|
+
@lcd_grob = RplGrOb.new( 'GROB:131:64:0' )
|
48
28
|
end
|
49
29
|
|
50
30
|
def run!( input )
|
@@ -97,6 +77,13 @@ class Interpreter
|
|
97
77
|
args
|
98
78
|
end
|
99
79
|
|
80
|
+
def export_lcd
|
81
|
+
lcd_as_string = "@ LCD:\n"
|
82
|
+
lcd_as_string += "#{@lcd_grob} →lcd\n"
|
83
|
+
|
84
|
+
lcd_as_string
|
85
|
+
end
|
86
|
+
|
100
87
|
def export_vars
|
101
88
|
vars_as_string = "@ variables:\n"
|
102
89
|
vars_as_string += @dictionary.vars
|
data/lib/rpl/parser.rb
CHANGED
@@ -103,6 +103,8 @@ class Parser
|
|
103
103
|
Types.new_object( RplString, element )
|
104
104
|
elsif RplProgram.can_parse?( element )
|
105
105
|
Types.new_object( RplProgram, element )
|
106
|
+
elsif RplGrOb.can_parse?( element )
|
107
|
+
Types.new_object( RplGrOb, element )
|
106
108
|
elsif RplName.can_parse?( element )
|
107
109
|
Types.new_object( RplName, element )
|
108
110
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'drawille'
|
4
|
+
|
5
|
+
require 'rpl/parser'
|
6
|
+
|
7
|
+
class BitArray
|
8
|
+
def initialize
|
9
|
+
@mask = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(position, value)
|
13
|
+
if value.zero?
|
14
|
+
@mask &= ~(1 << position)
|
15
|
+
else
|
16
|
+
@mask |= (1 << position)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](position)
|
21
|
+
@mask[position]
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_i
|
25
|
+
@mask.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def from_i( value )
|
29
|
+
@mask = value.to_i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Types
|
34
|
+
class RplGrOb
|
35
|
+
attr_accessor :width,
|
36
|
+
:height,
|
37
|
+
:bits
|
38
|
+
|
39
|
+
def initialize( init )
|
40
|
+
raise RplTypeError unless self.class.can_parse?( init )
|
41
|
+
|
42
|
+
parsed = if init.instance_of?( RplGrOb )
|
43
|
+
init.value
|
44
|
+
else
|
45
|
+
/^GROB:(?<width>\d+):(?<height>\d+):(?<bits>[0-9a-f]+)$/.match( init )
|
46
|
+
end
|
47
|
+
|
48
|
+
@width = parsed[:width].to_i
|
49
|
+
@height = parsed[:height].to_i
|
50
|
+
@bits = BitArray.new
|
51
|
+
@bits.from_i( parsed[:bits].to_i( 16 ) )
|
52
|
+
end
|
53
|
+
|
54
|
+
def value
|
55
|
+
{ width: @width,
|
56
|
+
height: @height,
|
57
|
+
bits: @bits.to_i.to_s( 16 ) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"GROB:#{@width}:#{@height}:#{@bits.to_i.to_s( 16 )}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.can_parse?( value )
|
65
|
+
value.instance_of?( RplGrOb ) ||
|
66
|
+
( value.instance_of?( String ) && value.match?(/^GROB:\d+:\d+:[0-9a-f]+$/) )
|
67
|
+
end
|
68
|
+
|
69
|
+
def ==( other )
|
70
|
+
other.class == RplGrOb &&
|
71
|
+
other.width == @width &&
|
72
|
+
other.height == @height &&
|
73
|
+
other.bits.to_i == @bits.to_i
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_text
|
77
|
+
@bits.to_i
|
78
|
+
.to_s(2)
|
79
|
+
.ljust(@width * @height, '0')
|
80
|
+
.slice(0, @width * @height)
|
81
|
+
.scan(/.{1,#{@width}}/)
|
82
|
+
.join("\n")
|
83
|
+
.gsub( '0', '_' )
|
84
|
+
.gsub( '1', '.' )
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_braille
|
88
|
+
canvas = Drawille::Canvas.new
|
89
|
+
|
90
|
+
@height.times do |y|
|
91
|
+
@width.times do |x|
|
92
|
+
canvas[x, y] = @bits[ ( y * @width ) + x ] == 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
canvas.frame
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_pixel( pos_x, pos_y )
|
100
|
+
@bits[ ( pos_y * @width ) + pos_x ]
|
101
|
+
end
|
102
|
+
|
103
|
+
def set_pixel( pos_x, pos_y, value )
|
104
|
+
@bits[ ( pos_y * @width ) + pos_x ] = value.to_i.zero? ? 0 : 1
|
105
|
+
end
|
106
|
+
|
107
|
+
def clear
|
108
|
+
@bits.from_i( 0 )
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/lib/rpl/types.rb
CHANGED
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RplLang
|
4
|
+
module Words
|
5
|
+
module Graphics
|
6
|
+
include Types
|
7
|
+
|
8
|
+
def populate_dictionary
|
9
|
+
super
|
10
|
+
|
11
|
+
category = 'GrOb (Graphic Objects)'
|
12
|
+
|
13
|
+
@dictionary.add_word!( ['→grob', '->grob'],
|
14
|
+
category,
|
15
|
+
'( w h d -- g ) make a GrOb from 3 numerics: width, height, data',
|
16
|
+
proc do
|
17
|
+
args = stack_extract( [[RplNumeric], [RplNumeric], [RplNumeric]] )
|
18
|
+
|
19
|
+
@stack << RplGrOb.new( "GROB:#{args[2].value.to_i}:#{args[1].value.to_i}:#{args[0].value.to_i.to_s( 16 )}" )
|
20
|
+
end )
|
21
|
+
@dictionary.add_word!( ['grob→', 'grob->'],
|
22
|
+
category,
|
23
|
+
'( g -- w h d ) split a GrOb into its 3 basic numerics',
|
24
|
+
proc do
|
25
|
+
args = stack_extract( [[RplGrOb]] )
|
26
|
+
|
27
|
+
@stack << RplNumeric.new( args[0].width )
|
28
|
+
@stack << RplNumeric.new( args[0].height )
|
29
|
+
@stack << RplNumeric.new( args[0].bits, 16 )
|
30
|
+
end )
|
31
|
+
@dictionary.add_word!( ['blank'],
|
32
|
+
category,
|
33
|
+
'( w h -- g ) create an empty GrOb',
|
34
|
+
proc do
|
35
|
+
args = stack_extract( [[RplNumeric], [RplNumeric]] )
|
36
|
+
|
37
|
+
w = args[1].value.to_i
|
38
|
+
h = args[0].value.to_i
|
39
|
+
|
40
|
+
@stack << RplGrOb.new( "GROB:#{w}:#{h}:0" )
|
41
|
+
end )
|
42
|
+
|
43
|
+
category = 'Lcd management and manipulation'
|
44
|
+
|
45
|
+
@dictionary.add_word!( ['lcdon'],
|
46
|
+
category,
|
47
|
+
'( -- ) display lcd',
|
48
|
+
proc do
|
49
|
+
@show_lcd = true
|
50
|
+
end )
|
51
|
+
@dictionary.add_word!( ['lcdoff'],
|
52
|
+
category,
|
53
|
+
'( -- ) hide lcd',
|
54
|
+
proc do
|
55
|
+
@show_lcd = false
|
56
|
+
end )
|
57
|
+
|
58
|
+
@dictionary.add_word!( ['lcdwidth'],
|
59
|
+
category,
|
60
|
+
'( -- i ) put framebuffer\'s width on stack',
|
61
|
+
proc do
|
62
|
+
@stack << RplNumeric.new( @lcd_grob.width )
|
63
|
+
end )
|
64
|
+
@dictionary.add_word!( ['lcdheight'],
|
65
|
+
category,
|
66
|
+
'( -- i ) put framebuffer\'s height on stack',
|
67
|
+
proc do
|
68
|
+
@stack << RplNumeric.new( @lcd_grob.height )
|
69
|
+
end )
|
70
|
+
|
71
|
+
@dictionary.add_word!( ['→lcdwidth', '->lcdwidth'],
|
72
|
+
category,
|
73
|
+
'( i -- ) set framebuffer\'s width',
|
74
|
+
proc do
|
75
|
+
args = stack_extract( [[RplNumeric]] )
|
76
|
+
|
77
|
+
@lcd_grob.width = args[0].value.to_i
|
78
|
+
end )
|
79
|
+
@dictionary.add_word!( ['→lcdheight', '->lcdheight'],
|
80
|
+
category,
|
81
|
+
'( i -- ) set framebuffer\'s height',
|
82
|
+
proc do
|
83
|
+
args = stack_extract( [[RplNumeric]] )
|
84
|
+
|
85
|
+
@lcd_grob.height = args[0].value.to_i
|
86
|
+
end )
|
87
|
+
|
88
|
+
@dictionary.add_word!( ['lcd→', 'lcd->'],
|
89
|
+
category,
|
90
|
+
'( -- g ) export framebuffer to GrOb',
|
91
|
+
proc do
|
92
|
+
@stack << RplGrOb.new( @lcd_grob )
|
93
|
+
end )
|
94
|
+
@dictionary.add_word!( ['→lcd', '->lcd'],
|
95
|
+
category,
|
96
|
+
'( g -- ) import GrOb into framebuffer',
|
97
|
+
proc do
|
98
|
+
args = stack_extract( [[RplGrOb]] )
|
99
|
+
|
100
|
+
@lcd_grob = RplGrOb.new( args[0] )
|
101
|
+
end )
|
102
|
+
|
103
|
+
# Pixel manipulation
|
104
|
+
@dictionary.add_word!( ['pixon'],
|
105
|
+
category,
|
106
|
+
'( x y -- ) turn on pixel at x y coordinates',
|
107
|
+
proc do
|
108
|
+
args = stack_extract( [[RplNumeric], [RplNumeric]] )
|
109
|
+
|
110
|
+
x = args[1].value.to_i
|
111
|
+
y = args[0].value.to_i
|
112
|
+
|
113
|
+
@lcd_grob.set_pixel(x, y, 1)
|
114
|
+
end )
|
115
|
+
@dictionary.add_word!( ['pixoff'],
|
116
|
+
category,
|
117
|
+
'( x y -- ) turn off pixel at x y coordinates',
|
118
|
+
proc do
|
119
|
+
args = stack_extract( [[RplNumeric], [RplNumeric]] )
|
120
|
+
|
121
|
+
x = args[1].value.to_i
|
122
|
+
y = args[0].value.to_i
|
123
|
+
|
124
|
+
@lcd_grob.set_pixel(x, y, 0)
|
125
|
+
end )
|
126
|
+
@dictionary.add_word!( ['pix?'],
|
127
|
+
category,
|
128
|
+
'( x y -- b ) return boolean state of pixel at x y coordinates',
|
129
|
+
proc do
|
130
|
+
args = stack_extract( [[RplNumeric], [RplNumeric]] )
|
131
|
+
|
132
|
+
x = args[1].value.to_i
|
133
|
+
y = args[0].value.to_i
|
134
|
+
|
135
|
+
@stack << RplBoolean.new( @lcd_grob.get_pixel(x, y) == 1 )
|
136
|
+
end )
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
data/lib/rpl/words/repl.rb
CHANGED
@@ -79,6 +79,14 @@ module RplLang
|
|
79
79
|
category,
|
80
80
|
'() print internal state of local variables layers',
|
81
81
|
proc { pp @dictionary.local_vars_layers } )
|
82
|
+
|
83
|
+
@dictionary.add_word!( ['.fb'],
|
84
|
+
category,
|
85
|
+
'() print internal state of framebuffer',
|
86
|
+
proc do
|
87
|
+
pp @show_display
|
88
|
+
pp @framebuffer
|
89
|
+
end )
|
82
90
|
end
|
83
91
|
end
|
84
92
|
end
|
data/lib/rpl/words.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rpl/words/branch'
|
4
|
-
require 'rpl/words/display'
|
5
4
|
require 'rpl/words/general'
|
6
5
|
require 'rpl/words/mode'
|
7
6
|
require 'rpl/words/operations-reals'
|
@@ -19,3 +18,4 @@ require 'rpl/words/trig'
|
|
19
18
|
require 'rpl/words/logarithm'
|
20
19
|
require 'rpl/words/filesystem'
|
21
20
|
require 'rpl/words/list'
|
21
|
+
require 'rpl/words/graphics'
|
data/lib/rpl.rb
CHANGED
@@ -5,7 +5,7 @@ require 'rpl/types'
|
|
5
5
|
require 'rpl/words'
|
6
6
|
|
7
7
|
class Rpl < Interpreter
|
8
|
-
VERSION = '0.
|
8
|
+
VERSION = '0.17.1'
|
9
9
|
|
10
10
|
include Types
|
11
11
|
|
@@ -37,7 +37,7 @@ class Rpl < Interpreter
|
|
37
37
|
def persist_state
|
38
38
|
return if @persistence_filename.nil?
|
39
39
|
|
40
|
-
File.write(@persistence_filename, "#{export_vars}\n#{export_stack}")
|
40
|
+
File.write(@persistence_filename, "#{export_lcd}\n#{export_vars}\n#{export_stack}")
|
41
41
|
end
|
42
42
|
|
43
43
|
def run!( input )
|
@@ -49,9 +49,9 @@ class Rpl < Interpreter
|
|
49
49
|
end
|
50
50
|
|
51
51
|
prepend RplLang::Words::Branch
|
52
|
-
prepend RplLang::Words::Display
|
53
52
|
prepend RplLang::Words::FileSystem
|
54
53
|
prepend RplLang::Words::General
|
54
|
+
prepend RplLang::Words::Graphics
|
55
55
|
prepend RplLang::Words::List
|
56
56
|
prepend RplLang::Words::Logarithm
|
57
57
|
prepend RplLang::Words::Mode
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rpl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.17.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gwenhael Le Moine
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
12
|
-
dependencies:
|
11
|
+
date: 2023-07-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: drawille
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.3
|
13
27
|
description: Reverse-Polish-Lisp inspired language in ruby
|
14
28
|
email: gwenhael@le-moine.org
|
15
29
|
executables:
|
@@ -27,6 +41,7 @@ files:
|
|
27
41
|
- lib/rpl/types.rb
|
28
42
|
- lib/rpl/types/boolean.rb
|
29
43
|
- lib/rpl/types/complex.rb
|
44
|
+
- lib/rpl/types/grob.rb
|
30
45
|
- lib/rpl/types/list.rb
|
31
46
|
- lib/rpl/types/name.rb
|
32
47
|
- lib/rpl/types/numeric.rb
|
@@ -34,9 +49,9 @@ files:
|
|
34
49
|
- lib/rpl/types/string.rb
|
35
50
|
- lib/rpl/words.rb
|
36
51
|
- lib/rpl/words/branch.rb
|
37
|
-
- lib/rpl/words/display.rb
|
38
52
|
- lib/rpl/words/filesystem.rb
|
39
53
|
- lib/rpl/words/general.rb
|
54
|
+
- lib/rpl/words/graphics.rb
|
40
55
|
- lib/rpl/words/list.rb
|
41
56
|
- lib/rpl/words/logarithm.rb
|
42
57
|
- lib/rpl/words/mode.rb
|
@@ -72,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
87
|
- !ruby/object:Gem::Version
|
73
88
|
version: '0'
|
74
89
|
requirements: []
|
75
|
-
rubygems_version: 3.4.
|
90
|
+
rubygems_version: 3.4.17
|
76
91
|
signing_key:
|
77
92
|
specification_version: 4
|
78
93
|
summary: Functional Stack Language
|
data/lib/rpl/words/display.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RplLang
|
4
|
-
module Words
|
5
|
-
module Display
|
6
|
-
include Types
|
7
|
-
|
8
|
-
def populate_dictionary
|
9
|
-
super
|
10
|
-
|
11
|
-
category = 'Display'
|
12
|
-
|
13
|
-
@dictionary.add_word!( ['erase'],
|
14
|
-
category,
|
15
|
-
'( -- ) erase display',
|
16
|
-
proc do
|
17
|
-
initialize_frame_buffer
|
18
|
-
end )
|
19
|
-
|
20
|
-
@dictionary.add_word!( ['display→', 'display->'],
|
21
|
-
category,
|
22
|
-
'( -- pict ) put current display state on stack',
|
23
|
-
proc do
|
24
|
-
@stack << @frame_buffer # FIXME: RplPict type
|
25
|
-
end )
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|