img_to_script 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +25 -0
  3. data/.vscode/launch.json +21 -0
  4. data/CHANGELOG.md +7 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +271 -0
  7. data/Rakefile +16 -0
  8. data/img_to_script.gemspec +41 -0
  9. data/lib/img_to_script/abs_token_type.rb +33 -0
  10. data/lib/img_to_script/abstract_token/abs_func.rb +19 -0
  11. data/lib/img_to_script/abstract_token/abstract_token.rb +23 -0
  12. data/lib/img_to_script/abstract_token/assign_value.rb +20 -0
  13. data/lib/img_to_script/abstract_token/clear_screen.rb +16 -0
  14. data/lib/img_to_script/abstract_token/data_read.rb +19 -0
  15. data/lib/img_to_script/abstract_token/data_store.rb +19 -0
  16. data/lib/img_to_script/abstract_token/draw_chunk_by_hex_value.rb +19 -0
  17. data/lib/img_to_script/abstract_token/draw_line_by_abs_coords.rb +22 -0
  18. data/lib/img_to_script/abstract_token/draw_pixel_by_abs_coords.rb +20 -0
  19. data/lib/img_to_script/abstract_token/go_to.rb +19 -0
  20. data/lib/img_to_script/abstract_token/if_condition.rb +20 -0
  21. data/lib/img_to_script/abstract_token/loop_begin.rb +21 -0
  22. data/lib/img_to_script/abstract_token/loop_end.rb +19 -0
  23. data/lib/img_to_script/abstract_token/math_add.rb +20 -0
  24. data/lib/img_to_script/abstract_token/math_greater_than.rb +20 -0
  25. data/lib/img_to_script/abstract_token/math_mult.rb +20 -0
  26. data/lib/img_to_script/abstract_token/math_sub.rb +20 -0
  27. data/lib/img_to_script/abstract_token/move_point_to_abs_coords.rb +20 -0
  28. data/lib/img_to_script/abstract_token/parentheses.rb +19 -0
  29. data/lib/img_to_script/abstract_token/program_begin.rb +16 -0
  30. data/lib/img_to_script/abstract_token/program_end.rb +16 -0
  31. data/lib/img_to_script/abstract_token/remark.rb +19 -0
  32. data/lib/img_to_script/abstract_token/sign_func.rb +19 -0
  33. data/lib/img_to_script/abstract_token/wait.rb +19 -0
  34. data/lib/img_to_script/abstract_token.rb +8 -0
  35. data/lib/img_to_script/container.rb +26 -0
  36. data/lib/img_to_script/current_line_placeholder.rb +40 -0
  37. data/lib/img_to_script/formatter.rb +34 -0
  38. data/lib/img_to_script/generators/generator.rb +134 -0
  39. data/lib/img_to_script/generators/hex_mask/default.rb +24 -0
  40. data/lib/img_to_script/generators/hex_mask/enhanced.rb +220 -0
  41. data/lib/img_to_script/generators/hex_mask/hex_mask.rb +100 -0
  42. data/lib/img_to_script/generators/hex_mask.rb +13 -0
  43. data/lib/img_to_script/generators/run_length_encoding/horizontal.rb +78 -0
  44. data/lib/img_to_script/generators/run_length_encoding/run_length_encoding.rb +304 -0
  45. data/lib/img_to_script/generators/run_length_encoding/vertical.rb +79 -0
  46. data/lib/img_to_script/generators/run_length_encoding.rb +10 -0
  47. data/lib/img_to_script/generators/segmental/data_read_draw/data_read_draw.rb +70 -0
  48. data/lib/img_to_script/generators/segmental/data_read_draw/horizontal.rb +54 -0
  49. data/lib/img_to_script/generators/segmental/data_read_draw/vertical.rb +54 -0
  50. data/lib/img_to_script/generators/segmental/data_read_draw.rb +18 -0
  51. data/lib/img_to_script/generators/segmental/direct_draw/direct_draw.rb +62 -0
  52. data/lib/img_to_script/generators/segmental/direct_draw/horizontal.rb +16 -0
  53. data/lib/img_to_script/generators/segmental/direct_draw/vertical.rb +16 -0
  54. data/lib/img_to_script/generators/segmental/direct_draw.rb +12 -0
  55. data/lib/img_to_script/generators/segmental/horizontal_mixin.rb +32 -0
  56. data/lib/img_to_script/generators/segmental/segmental.rb +101 -0
  57. data/lib/img_to_script/generators/segmental/vertical_mixin.rb +38 -0
  58. data/lib/img_to_script/generators/segmental.rb +10 -0
  59. data/lib/img_to_script/generators.rb +27 -0
  60. data/lib/img_to_script/import.rb +5 -0
  61. data/lib/img_to_script/language_token.rb +8 -0
  62. data/lib/img_to_script/languages/mk90_basic/formatters/formatter.rb +49 -0
  63. data/lib/img_to_script/languages/mk90_basic/formatters/minificator.rb +316 -0
  64. data/lib/img_to_script/languages/mk90_basic/formatters/sliceable_tokens_mixin.rb +15 -0
  65. data/lib/img_to_script/languages/mk90_basic/formatters.rb +13 -0
  66. data/lib/img_to_script/languages/mk90_basic/mk90_basic_token.rb +59 -0
  67. data/lib/img_to_script/languages/mk90_basic/translators/mixin.rb +205 -0
  68. data/lib/img_to_script/languages/mk90_basic/translators/mk90_basic_10.rb +27 -0
  69. data/lib/img_to_script/languages/mk90_basic/translators/mk90_basic_20.rb +27 -0
  70. data/lib/img_to_script/languages/mk90_basic/translators/translator.rb +205 -0
  71. data/lib/img_to_script/languages/mk90_basic/translators.rb +13 -0
  72. data/lib/img_to_script/languages/mk90_basic.rb +17 -0
  73. data/lib/img_to_script/languages.rb +10 -0
  74. data/lib/img_to_script/task.rb +26 -0
  75. data/lib/img_to_script/translator.rb +31 -0
  76. data/lib/img_to_script/version.rb +5 -0
  77. data/lib/img_to_script.rb +19 -0
  78. data/sig/img_to_script.rbs +4 -0
  79. metadata +204 -0
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImgToScript
4
+ module Generators
5
+ module HexMask
6
+ #
7
+ # Generates image rendering script using the DRAW/M statement with
8
+ # the 'enhancements'.
9
+ #
10
+ # To save space at the MPO-10 cart, it's possible to replacelong
11
+ # sequences of repeating chunks with a shorter
12
+ # (in terms of number of chars required to store the statement) code,
13
+ # e.g.:
14
+ #
15
+ # xxDRAWMFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFF
16
+ # // 43 bytes -- 16 x 'AA'.
17
+ # xxDRAWMFF:FORI=1TO16:DRAWMAA:NEXTI:DRAWMFF
18
+ # // 42 bytes -- repeating chunks were replaced with a loop.
19
+ #
20
+ # Same principle could be applied to eliminate long sequences of white
21
+ # pixels, e.g.:
22
+ # xxDRAWMFF00000000000000000000FF
23
+ # // 31 bytes -- 10 x '00'.
24
+ # xxDRAWMFF:DRAWOxxx,yy:DRAWMFF
25
+ # // 29 bytes -- replaced with a manual shift.
26
+ #
27
+ # The algorithm is:
28
+ # 1. apply RLE to the array of hex chunks (DRAW/M arguments);
29
+ # 2. loop through the array of run-lengths: take an element (a 'chunk') and
30
+ # heck if it's run-length is larger than an estimated value (MIN_REP_CHUNKS
31
+ # or MIN_REP_WH_CHUNKS);
32
+ # 3. if true: add pending chunks to the BASIC code; then append a FOR-NEXT loop or
33
+ # DRAW/O. Clear pending chunks array and continue to loop through the array of
34
+ # run-lengths.
35
+ # 4. otherwise: add current chunk to the array of pending chunks;
36
+ # 5. after the loop: add pending chunks.
37
+ #
38
+ class Enhanced < HexMask
39
+ MIN_REP_CHUNKS = 16
40
+ MIN_REP_WH_CHUNKS = 9
41
+
42
+ private
43
+
44
+ def _generate
45
+ _init_instant_vars
46
+ _process_rle_image
47
+ _append_pending_chunks
48
+ end
49
+
50
+ #
51
+ # Set up initional values for the instant variables.
52
+ #
53
+ def _init_instant_vars
54
+ @x = 0 # It is always = 0, not the x/y_offset. The reason is that
55
+ @y = 0 # we've already applied offset in the #_prepare_image method.
56
+
57
+ @hex_img = _encode_img
58
+ @rle_hex_img = _encode_hex_img
59
+
60
+ @pending_chunks = []
61
+ @run_length_index = 0
62
+ end
63
+
64
+ #
65
+ # Loop through the RLE-encoded hex-image.
66
+ #
67
+ def _process_rle_image
68
+ @rle_hex_img.each_with_index do |rle_item, idx|
69
+ @chunk_count = rle_item.run_length
70
+ @chunk = rle_item.chunk
71
+
72
+ _calc_current_pos
73
+ _process_chunk(idx)
74
+ end
75
+ end
76
+
77
+ #
78
+ # Choose action for a current chunk depending on its run-length
79
+ # and its color hex value (white or non-white).
80
+ #
81
+ # @param [Integer] idx
82
+ # Index of the element in the RLE array.
83
+ #
84
+ def _process_chunk(idx)
85
+ if @chunk_count >= MIN_REP_WH_CHUNKS && @chunk == "00"
86
+ _process_white_segments(idx)
87
+ elsif @chunk_count >= MIN_REP_CHUNKS && @chunk != "00"
88
+ _process_non_white_segments
89
+ else
90
+ _upd_pending_chunks
91
+ _upd_rle_index
92
+ end
93
+ end
94
+
95
+ #
96
+ # Run-length encoding of the @hex_img.
97
+ #
98
+ # @return [Array<RunLengthEncodingRb::RLEElement>]
99
+ #
100
+ def _encode_hex_img
101
+ RunLengthEncodingRb.encode(@hex_img)
102
+ end
103
+
104
+ #
105
+ # Calculate current (X, Y) position.
106
+ #
107
+ def _calc_current_pos
108
+ @y += @chunk_count
109
+ return unless @y > @scr_height - 1
110
+
111
+ # Reached the vertical end of the screen - re-calculate position:
112
+ div_res = @y.div(@scr_height)
113
+ @x += CHUNK_WIDTH * div_res
114
+ @y = @y.remainder(@scr_height)
115
+ end
116
+
117
+ def _upd_rle_index
118
+ @run_length_index += @chunk_count
119
+ end
120
+
121
+ def _clr_pending_chunks
122
+ @pending_chunks = []
123
+ end
124
+
125
+ #
126
+ # Replace long sequences of repeating non-white chunks with a shorter FOR-NEXT loop.
127
+ #
128
+ def _process_non_white_segments
129
+ _append_pending_chunks
130
+ _clr_pending_chunks
131
+
132
+ _append_start_loop(@chunk_count)
133
+ _append_hex_values(Array(@chunk))
134
+ _append_end_loop
135
+
136
+ _upd_rle_index
137
+ end
138
+
139
+ def _append_hex_values(hex_values)
140
+ @tokens.append(
141
+ AbstractToken::DrawChunkByHexValue.new(
142
+ hex_values: hex_values
143
+ )
144
+ )
145
+ end
146
+
147
+ def _append_start_loop(end_value)
148
+ @tokens.append(
149
+ AbstractToken::LoopBegin.new(
150
+ var_name: LOOP_VAR,
151
+ start_value: 1,
152
+ end_value: end_value
153
+ )
154
+ )
155
+ end
156
+
157
+ def _append_end_loop
158
+ @tokens.append(
159
+ AbstractToken::LoopEnd.new(
160
+ var_name: LOOP_VAR
161
+ )
162
+ )
163
+ end
164
+
165
+ def _append_move_point(x, y)
166
+ @tokens.append(
167
+ AbstractToken::MovePointToAbsCoords.new(
168
+ x: x,
169
+ y: y
170
+ )
171
+ )
172
+ end
173
+
174
+ #
175
+ # Replace long sequences of white chunks (0x00) with a shorter manual shift of the (X, Y) point.
176
+ #
177
+ # @param [Integer] idx
178
+ # Index of the element in the RLE array.
179
+ #
180
+ def _process_white_segments(idx)
181
+ # If white segments are the last part of the image,
182
+ # we don't need to store them in the BASIC script at all
183
+ return if idx == @rle_hex_img.length - 1
184
+
185
+ _append_pending_chunks
186
+ _clr_pending_chunks
187
+
188
+ _append_move_point(@x, @y)
189
+
190
+ _upd_rle_index
191
+ end
192
+
193
+ #
194
+ # Append accumulated pending chunks to the tokens array.
195
+ #
196
+ def _append_pending_chunks
197
+ return if @pending_chunks == []
198
+
199
+ _append_hex_values(@pending_chunks)
200
+ end
201
+
202
+ #
203
+ # Update array of the pending chunks.
204
+ #
205
+ def _upd_pending_chunks
206
+ @pending_chunks.concat _current_pending_chunks
207
+ end
208
+
209
+ #
210
+ # Retun chunks that are pending at the current itteration.
211
+ #
212
+ # @return [Array<String>]
213
+ #
214
+ def _current_pending_chunks
215
+ @hex_img.slice(@run_length_index, @chunk_count)
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImgToScript
4
+ module Generators
5
+ module HexMask
6
+ #
7
+ # Base class for the hex-mask-based generators.
8
+ #
9
+ class HexMask < Generator
10
+ CHUNK_WIDTH = 8
11
+
12
+ private
13
+
14
+ #
15
+ # Encode a binary image to a hex-mask encoded image.
16
+ #
17
+ # @return [Array<String>] hex_img
18
+ # An encoded image, represented as an array of hex-chunks.
19
+ #
20
+ def _encode_img
21
+ image = _prepare_image
22
+
23
+ hex_img = []
24
+
25
+ (0...image.width).step(CHUNK_WIDTH).each do |x|
26
+ (0...image.height).each do |y|
27
+ chunk = _grab_chunk(image, x, y)
28
+ hex_img.push(_bin_to_hex(chunk))
29
+ end
30
+ end
31
+
32
+ hex_img
33
+ end
34
+
35
+ #
36
+ # Prepare the image:
37
+ # 1. ensure that image width is divisible by 8 (CHUNK_WIDTH);
38
+ # 2. ensure that image height is equal to @scr_height;
39
+ # 3. offset the image according to the provided @x_offset / @y_offset.
40
+ #
41
+ # Steps 1 & 2 are required by the DRAW/M statement's algorithm.
42
+ #
43
+ def _prepare_image
44
+ @image.extent(_new_width,
45
+ @scr_height,
46
+ @x_offset * -1,
47
+ @y_offset * -1)
48
+ end
49
+
50
+ #
51
+ # Calculate new width for the image.
52
+ #
53
+ # The algorithm of the DRAW/M statement requires that image width should
54
+ # be divisible by 8 (CHUNK_WIDTH). If the image doesn't comply with this
55
+ # condition, it is required to extend the image width to a nearlest number
56
+ # n: n.remainder(CHUNK_WIDTH) == 0.
57
+ #
58
+ # @return [Integer]
59
+ # New width.
60
+ #
61
+ def _new_width
62
+ width = ((@image.width + @x_offset) / CHUNK_WIDTH.to_f).ceil * CHUNK_WIDTH
63
+ width.clamp(CHUNK_WIDTH, @scr_width)
64
+ end
65
+
66
+ #
67
+ # Grab a 8 x 1 rectangle from the image and convert its pixels to a binary string representation.
68
+ #
69
+ # @param [Magick::Image, Magick::BinMagick::Image] image
70
+ #
71
+ # @param [Integer] x, y
72
+ # A current X, Y position at the image.
73
+ #
74
+ # @return [String]
75
+ # An 8-character string of 0's and 1's. Example: "11110011"
76
+ #
77
+ def _grab_chunk(image, x, y)
78
+ chunk_width = CHUNK_WIDTH
79
+ chunk_heigth = 1
80
+ pixels = image.get_pixels(x, y, chunk_width, chunk_heigth)
81
+
82
+ pixels.map { |pixel| pixel.to_color == "black" ? 1 : 0 }.join("")
83
+ end
84
+
85
+ #
86
+ # Convert a string of binary values to a two-digit hex representation.
87
+ #
88
+ # Example: "11110011" => "F3"
89
+ #
90
+ # @param [String] str
91
+ #
92
+ # @return [String]
93
+ #
94
+ def _bin_to_hex(str)
95
+ format("%02x", str.to_i(2)).upcase
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImgToScript
4
+ module Generators
5
+ #
6
+ # Each 8x1 pixels block of a binary image gets encoded as a hex value.
7
+ #
8
+ # The method natively supported only by the Elektronika MK90 BASIC with its
9
+ # DRAWM statement.
10
+ #
11
+ module HexMask; end
12
+ end
13
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImgToScript
4
+ module Generators
5
+ module RunLengthEncoding
6
+ #
7
+ # RLE - horizontal scanlines.
8
+ #
9
+ class Horizontal < RunLengthEncoding
10
+ private
11
+
12
+ def _generate
13
+ @pixels = @image.get_pixels(0, 0, @image.width, @image.height)
14
+ _encode_pixels
15
+ _append_decoder
16
+ end
17
+
18
+ def _append_decoder
19
+ @image_size = @image.width + @x_offset
20
+ @segment_size = @image_size - 1
21
+
22
+ @major_axis_symbol = X_LBL
23
+ @minor_axis_symbol = Y_LBL
24
+
25
+ @major_axis_value = @x_offset
26
+
27
+ @part_line_pattern = _part_line_pattern
28
+ @full_line_pattern = _full_line_pattern
29
+
30
+ super
31
+ end
32
+
33
+ #
34
+ # Part-length line, i.e. a line that fills only
35
+ # a part of the scan line.
36
+ #
37
+ # Formatted for the horizontal scan lines.
38
+ #
39
+ def _part_line_pattern
40
+ AbstractToken::DrawLineByAbsCoords.new(
41
+ x0: X_LBL,
42
+ y0: Y_LBL,
43
+ x1: _x1_expression,
44
+ y1: Y_LBL
45
+ )
46
+ end
47
+
48
+ #
49
+ # Expression to evaluate x1 point.
50
+ #
51
+ def _x1_expression
52
+ AbstractToken::MathSub.new(
53
+ left: AbstractToken::MathAdd.new(
54
+ left: X_LBL,
55
+ right: READ_VAR
56
+ ),
57
+ right: 1
58
+ )
59
+ end
60
+
61
+ #
62
+ # Full-length line pattern, i.e. a line that fills
63
+ # the whole scan line.
64
+ #
65
+ # Formatted for the horizontal scan lines.
66
+ #
67
+ def _full_line_pattern
68
+ AbstractToken::DrawLineByAbsCoords.new(
69
+ x0: X_LBL,
70
+ y0: Y_LBL,
71
+ x1: @segment_size,
72
+ y1: Y_LBL
73
+ )
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,304 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImgToScript
4
+ module Generators
5
+ module RunLengthEncoding
6
+ #
7
+ # Base class for the RLE-based script generators.
8
+ #
9
+ class RunLengthEncoding < Generator
10
+ private
11
+
12
+ #
13
+ # Encode pixels into the RLE data.
14
+ #
15
+ def _encode_pixels
16
+ @run_length_data = RunLengthEncodingRb.encode(@pixels)
17
+ run_lengths = []
18
+
19
+ encode = lambda { |count:, pixel:|
20
+ count = -count if pixel.to_color == "white"
21
+ run_lengths.push(count.to_s)
22
+ }
23
+
24
+ @run_length_data.each { |e| encode.call(pixel: e.chunk, count: e.run_length) }
25
+
26
+ _append_data(run_lengths)
27
+ end
28
+
29
+ def _append_data(arr)
30
+ @tokens.append(
31
+ AbstractToken::DataStore.new(
32
+ data: arr,
33
+ require_nl: true
34
+ )
35
+ )
36
+ end
37
+
38
+ #
39
+ # Append RLE decoder procedure afther the DATA sequence.
40
+ #
41
+ def _append_decoder
42
+ _dec_line01
43
+ _dec_line02
44
+ _dec_line03
45
+ _dec_line04
46
+ _dec_line05
47
+ _dec_line06
48
+ end
49
+
50
+ #
51
+ # 1-st line of the decoder procedure.
52
+ #
53
+ # In this line the X & Y variables are defined. The X and Y variables
54
+ # are used to keep track of the current position on the screen.
55
+ #
56
+ # Then the main loop starts. The loop iterates over each pixel value
57
+ # (represented by the variable READ_VAR) in the input data and translates
58
+ # the RLE-encoded values into the "draw a line" commands that draw lines
59
+ # on the screen.
60
+ #
61
+ def _dec_line01
62
+ _init_x
63
+ _init_y
64
+ _start_loop
65
+ _read_value
66
+ end
67
+
68
+ #
69
+ # 2-nd line of the decoder procedure.
70
+ #
71
+ # The IF statement is used to check cases where the line would extend
72
+ # beyond the bounds of the image/screen. In this case the program jumps
73
+ # to the 5-th line (3 lines down from the current line) of the decoder,
74
+ # that handles this edge case.
75
+ #
76
+ def _dec_line02
77
+ expression = AbstractToken::MathGreaterThan.new(
78
+ left: _sum_of_current_point_and_length,
79
+ right: @segment_size
80
+ )
81
+
82
+ @tokens.append(
83
+ AbstractToken::IfCondition.new(
84
+ expression: expression,
85
+ consequent: CurrentLinePlaceholder.new(3),
86
+ require_nl: true
87
+ )
88
+ )
89
+ end
90
+
91
+ #
92
+ # 3-rd line of the decoder procedure.
93
+ #
94
+ # Draws a line if S is a positive number. Positive numbers represent
95
+ # black pixels. Negative numbers represent white pixels.
96
+ #
97
+ def _dec_line03
98
+ @tokens.append(
99
+ AbstractToken::IfCondition.new(
100
+ expression: _read_var_positive,
101
+ consequent: @part_line_pattern,
102
+ require_nl: true
103
+ )
104
+ )
105
+ end
106
+
107
+ #
108
+ # 4-th line of the decoder procedure.
109
+ #
110
+ # Updates major axis position. Ends the main loop. Jumps to the end
111
+ # of the program.
112
+ #
113
+ def _dec_line04
114
+ _update_current_point
115
+ _end_loop
116
+ _jump_to_the_end
117
+ end
118
+
119
+ #
120
+ # 5-th line of the decoder procedure.
121
+ #
122
+ # This part handles cases where the line would extend beyond the
123
+ # bounds of the image/screen. It draws a line from the current
124
+ # position up to the end of the image/screen.
125
+ #
126
+ def _dec_line05
127
+ @tokens.append(
128
+ AbstractToken::IfCondition.new(
129
+ expression: _read_var_positive,
130
+ consequent: @full_line_pattern,
131
+ require_nl: true
132
+ )
133
+ )
134
+ end
135
+
136
+ #
137
+ # 6-th line of the decoder procedure.
138
+ #
139
+ # This part handles cases where the line would extend beyond the
140
+ # bounds of the image/screen. It updates the current position on
141
+ # the screen and the run-length value. When it jumps back to the
142
+ # line length check (2nd line of the decoder).
143
+ #
144
+ def _dec_line06
145
+ _increment_minor_axis
146
+ _update_read_variable
147
+ _reset_major_axis
148
+ _jump_to_length_check
149
+ end
150
+
151
+ def _read_var_positive
152
+ AbstractToken::MathGreaterThan.new(
153
+ left: READ_VAR,
154
+ right: 0
155
+ )
156
+ end
157
+
158
+ def _init_x
159
+ @tokens.append(
160
+ AbstractToken::AssignValue.new(
161
+ left: X_LBL,
162
+ right: @x_offset,
163
+ require_nl: true
164
+ )
165
+ )
166
+ end
167
+
168
+ def _init_y
169
+ @tokens.append(
170
+ AbstractToken::AssignValue.new(
171
+ left: Y_LBL,
172
+ right: @y_offset
173
+ )
174
+ )
175
+ end
176
+
177
+ def _start_loop
178
+ @tokens.append(
179
+ AbstractToken::LoopBegin.new(
180
+ var_name: LOOP_VAR,
181
+ start_value: 1,
182
+ end_value: @run_length_data.length
183
+ )
184
+ )
185
+ end
186
+
187
+ def _read_value
188
+ @tokens.append(
189
+ AbstractToken::DataRead.new(
190
+ var_list: READ_VAR
191
+ )
192
+ )
193
+ end
194
+
195
+ def _abs_length_value
196
+ AbstractToken::AbsFunc.new(
197
+ expression: READ_VAR
198
+ )
199
+ end
200
+
201
+ def _sum_of_current_point_and_length
202
+ AbstractToken::MathAdd.new(
203
+ left: _abs_length_value,
204
+ right: @major_axis_symbol
205
+ )
206
+ end
207
+
208
+ def _update_current_point
209
+ @tokens.append(
210
+ AbstractToken::AssignValue.new(
211
+ left: @major_axis_symbol,
212
+ right: _sum_of_current_point_and_length,
213
+ require_nl: true
214
+ )
215
+ )
216
+ end
217
+
218
+ def _end_loop
219
+ @tokens.append(
220
+ AbstractToken::LoopEnd.new(
221
+ var_name: LOOP_VAR
222
+ )
223
+ )
224
+ end
225
+
226
+ def _jump_to_the_end
227
+ @tokens.append(
228
+ AbstractToken::GoTo.new(
229
+ line: CurrentLinePlaceholder.new(3)
230
+ )
231
+ )
232
+ end
233
+
234
+ def _sign_func
235
+ AbstractToken::SignFunc.new(
236
+ expression: READ_VAR
237
+ )
238
+ end
239
+
240
+ def _increment_minor_axis
241
+ @tokens.append(
242
+ AbstractToken::AssignValue.new(
243
+ left: @minor_axis_symbol,
244
+ right: AbstractToken::MathAdd.new(
245
+ left: @minor_axis_symbol,
246
+ right: 1
247
+ ),
248
+ require_nl: true
249
+ )
250
+ )
251
+ end
252
+
253
+ def _reset_major_axis
254
+ @tokens.append(
255
+ AbstractToken::AssignValue.new(
256
+ left: @major_axis_symbol,
257
+ right: @major_axis_value
258
+ )
259
+ )
260
+ end
261
+
262
+ def _jump_to_length_check
263
+ @tokens.append(
264
+ AbstractToken::GoTo.new(
265
+ line: CurrentLinePlaceholder.new(-4)
266
+ )
267
+ )
268
+ end
269
+
270
+ def _sum_token
271
+ AbstractToken::MathAdd.new(
272
+ left: _abs_length_value,
273
+ right: @major_axis_symbol
274
+ )
275
+ end
276
+
277
+ def _sub_token
278
+ AbstractToken::MathSub.new(
279
+ left: _sum_token,
280
+ right: @image_size
281
+ )
282
+ end
283
+
284
+ def _mult_token
285
+ AbstractToken::MathMult.new(
286
+ left: AbstractToken::Parentheses.new(
287
+ expression: _sub_token
288
+ ),
289
+ right: _sign_func
290
+ )
291
+ end
292
+
293
+ def _update_read_variable
294
+ @tokens.append(
295
+ AbstractToken::AssignValue.new(
296
+ left: READ_VAR,
297
+ right: _mult_token
298
+ )
299
+ )
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end