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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92ffc36b2560d0b7a6396c32d769c95a9d108fea01b9c58b32e2e7f401f2265f
4
- data.tar.gz: ba04b5b645003dff6bb73b9d561c0b3818aff12e12756a30958c3a72c4639a50
3
+ metadata.gz: 9503bcb52c319c657b082e69d395d55afc2bd2d0426d6fd58a488296dfb401fe
4
+ data.tar.gz: 01cf9eece63336abf8ce25c27faae3bffc67e678cc2267eaf6c91e9ba4302053
5
5
  SHA512:
6
- metadata.gz: 63fa59fa82bc0cb40d4dd3d17965721491c586e4a81ab775f78156c266603f231c26472bba75242a4314c551158c614cff1bebd94fa50e478a6f63e5fd9a44c0
7
- data.tar.gz: 7212eb69e7631bd4ff6ce27b7e4833a98c1a8c33bb14a712773c39b46533aee71fb7a59b3915ceff8dce733ba8a44db9a6109acac82b6be944beb1b84927ad6a
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
 
@@ -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
- :frame_buffer,
15
+ :lcd_grob,
34
16
  :dictionary,
35
17
  :version
36
18
 
37
- attr_accessor :precision
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
- initialize_frame_buffer
44
- end
25
+ @show_lcd = false
45
26
 
46
- def initialize_frame_buffer
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
@@ -7,6 +7,7 @@ require 'rpl/types/string'
7
7
  require 'rpl/types/program'
8
8
  require 'rpl/types/numeric'
9
9
  require 'rpl/types/complex'
10
+ require 'rpl/types/grob'
10
11
 
11
12
  module Types
12
13
  module_function
@@ -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
@@ -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.16.2'
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.16.2
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-04-06 00:00:00.000000000 Z
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.10
90
+ rubygems_version: 3.4.17
76
91
  signing_key:
77
92
  specification_version: 4
78
93
  summary: Functional Stack Language
@@ -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