oppen 0.9.7 → 1.0.0

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.
data/lib/oppen/printer.rb CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'stringio'
4
4
 
5
- require_relative 'scan_stack'
6
- require_relative 'print_stack'
7
5
  require_relative 'mixins'
6
+ require_relative 'print_stack'
7
+ require_relative 'scan_stack'
8
8
 
9
9
  # Oppen.
10
10
  module Oppen
@@ -12,73 +12,82 @@ module Oppen
12
12
  class Printer
13
13
  extend Mixins
14
14
 
15
+ # The printer's configuration, altering its behavior.
16
+ #
17
+ # @return [Config]
15
18
  attr_reader :config
16
- # Ring buffer left index.
19
+ # Ring buffer's left index.
17
20
  #
18
- # @note Called left as well in the original paper.
21
+ # @note Called `left` as well in the original paper.
22
+ #
23
+ # @return [Integer]
19
24
  attr_reader :left
20
-
21
- # Total number of spaces needed to print from start of buffer to the left.
25
+ # Number of spaces needed to print from start of buffer to left.
22
26
  #
23
- # @note Called leftTotal as well in the original paper.
27
+ # @note Called `leftTotal` as well in the original paper.
28
+ #
29
+ # @return [Integer]
24
30
  attr_reader :left_total
25
-
26
- # @note Called printStack as well in the original paper.
31
+ # A stack of {Token}s; builds the the final output.
32
+ #
33
+ # @note Called `printStack` as well in the original paper.
34
+ #
35
+ # @return [PrintStack]
27
36
  attr_reader :print_stack
28
-
29
- # Ring buffer right index.
37
+ # Ring buffer's right index.
30
38
  #
31
- # @note Called right as well in the original paper.
39
+ # @note Called `right` as well in the original paper.
40
+ #
41
+ # @return [Integer]
32
42
  attr_reader :right
33
-
34
- # Total number of spaces needed to print from start of buffer to the right.
43
+ # Number of spaces needed to print from start of buffer to right.
35
44
  #
36
- # @note Called leftTotal as well in the original paper.
45
+ # @note Called `leftTotal` as well in the original paper.
46
+ #
47
+ # @return [Integer]
37
48
  attr_reader :right_total
38
-
39
49
  # Potential breaking positions.
40
50
  #
41
- # @note Called scanStack as well in the original paper.
51
+ # @note Called `scanStack` as well in the original paper.
52
+ #
53
+ # @return [ScanStack]
42
54
  attr_reader :scan_stack
43
-
44
55
  # Size buffer, initially filled with nil.
45
56
  #
46
- # @note Called size as well in the original paper.
57
+ # @note Called `size` as well in the original paper.
58
+ #
59
+ # @return [Integer]
47
60
  attr_reader :size
48
-
49
61
  # Token buffer, initially filled with nil.
50
62
  #
51
- # @note Called token in the original paper.
63
+ # @note Called `token` in the original paper.
64
+ #
65
+ # @return [Array<Tokens>]
52
66
  attr_reader :tokens
53
67
 
54
- # Some description
55
- #
56
- # @example
57
- # "This is a string" # => and this is a comment
58
- # out = Oppen::Wadler.new (margin: 13) # Hawn
59
- # # Baliz
60
- #
61
- # @example
62
- # "This is a string" # => and this is a comment
63
- # # var = 12
64
- #
65
- # @param width [Integer] maximum line width desired.
66
- # @param new_line [String] the delimiter between lines.
67
- # @param config [Config]
68
- # @param space [String, Proc] could be a String or a callable.
69
- # If it's a string, spaces will be generated with the the
70
- # lambda `->(n){ n * space }`, where `n` is the number of columns
71
- # to indent.
72
- # If it's a callable, it will receive `n` and it needs to return
73
- # a string.
74
- # @param out [Object] should have a write and string method
68
+ # @note Called `PrettyPrintInit` in the original paper.
69
+ #
70
+ # @param config [Config]
71
+ # to customize the printer's behavior.
72
+ # @param new_line [String]
73
+ # the delimiter between lines.
74
+ # @param space [String, Proc]
75
+ # indentation string or a string generator.
76
+ # - If a `String`, spaces will be generated with the the lambda
77
+ # `->(n){ space * n }`, where `n` is the number of columns to indent.
78
+ # - If a `Proc`, it will receive `n` and it needs to return a `String`.
79
+ # @param width [Integer]
80
+ # maximum line width desired.
81
+ # @param out [Object]
82
+ # the output string buffer. It should have both `write` and `string`
83
+ # methods.
75
84
  def initialize(width, new_line, config = Config.oppen,
76
85
  space = ' ', out = StringIO.new)
77
86
  # Maximum size if the stacks
78
87
  n = 3 * width
79
88
 
80
89
  @config = config
81
- @last_whitespaces_width = 0
90
+ @last_whitespaces_width = 0 # Accumulates the width of the last Whitespace tokens encountered.
82
91
  @left = 0
83
92
  @left_total = 1
84
93
  @print_stack = PrintStack.new width, new_line, config, space, out
@@ -89,14 +98,16 @@ module Oppen
89
98
  @tokens = Array.new n
90
99
  end
91
100
 
101
+ # The final pretty-printed output.
102
+ #
92
103
  # @return [String]
93
- def output
94
- print_stack.output
95
- end
104
+ # the output of the print stack.
105
+ def output = print_stack.output
96
106
 
97
- # Core function of the algorithm responsible for populating the scan and print stack.
107
+ # Core function of the algorithm responsible for populating the {ScanStack}
108
+ # and {PrintStack}.
98
109
  #
99
- # @note Called PrettyPrint as well in the original paper.
110
+ # @note Called `PrettyPrint` as well in the original paper.
100
111
  #
101
112
  # @param token [Token]
102
113
  #
@@ -120,11 +131,9 @@ module Oppen
120
131
  end
121
132
  end
122
133
 
123
- # Handle EOF Token.
134
+ # Handle {Token::EOF}.
124
135
  #
125
136
  # @return [Nil]
126
- #
127
- # @see Token::EOF
128
137
  def handle_eof
129
138
  if !scan_stack.empty?
130
139
  check_stack 0
@@ -133,11 +142,11 @@ module Oppen
133
142
  print_stack.indent 0
134
143
  end
135
144
 
136
- # Handle Begin Token.
145
+ # Handle {Token::Begin}.
137
146
  #
138
- # @return [Nil]
147
+ # @param token [Token::Begin]
139
148
  #
140
- # @see Token::Begin
149
+ # @return [Nil]
141
150
  def handle_begin(token)
142
151
  if scan_stack.empty?
143
152
  @left = 0
@@ -145,7 +154,7 @@ module Oppen
145
154
  @right = 0
146
155
  @right_total = 1
147
156
 
148
- # config.trim_trailing_whitespaces
157
+ # config.trim_trailing_whitespaces.
149
158
  @tokens[-1] = nil
150
159
  else
151
160
  advance_right
@@ -155,11 +164,11 @@ module Oppen
155
164
  scan_stack.push right
156
165
  end
157
166
 
158
- # Handle End Token.
167
+ # Handle {Token::End}.
159
168
  #
160
- # @return [Nil]
169
+ # @param token [Token::End]
161
170
  #
162
- # @see Token::End
171
+ # @return [Nil]
163
172
  def handle_end(token)
164
173
  if scan_stack.empty?
165
174
  print_stack.print token, 0
@@ -176,11 +185,11 @@ module Oppen
176
185
  end
177
186
  end
178
187
 
179
- # Handle Break Token.
188
+ # Handle {Token::Break}.
180
189
  #
181
- # @return [Nil]
190
+ # @param token [Token::Break]
182
191
  #
183
- # @see Token::Break
192
+ # @return [Nil]
184
193
  def handle_break(token)
185
194
  if scan_stack.empty?
186
195
  @left = 0
@@ -188,7 +197,7 @@ module Oppen
188
197
  @right = 0
189
198
  @right_total = 1
190
199
 
191
- # config.trim_trailing_whitespaces
200
+ # config.trim_trailing_whitespaces.
192
201
  tokens[-1] = nil
193
202
  print_stack.erase @last_whitespaces_width
194
203
  @last_whitespaces_width = 0
@@ -202,11 +211,11 @@ module Oppen
202
211
  @right_total += token.width
203
212
  end
204
213
 
205
- # Handle String Token.
214
+ # Handle {Token::String}.
206
215
  #
207
- # @return [Nil]
216
+ # @param token [Token::String]
208
217
  #
209
- # @see Token::String
218
+ # @return [Nil]
210
219
  def handle_string(token)
211
220
  if scan_stack.empty?
212
221
  print_stack.print token, token.width
@@ -221,7 +230,7 @@ module Oppen
221
230
 
222
231
  # Flushes the input if possible.
223
232
  #
224
- # @note Called CheckStream as well in the original paper.
233
+ # @note Called `CheckStream` as well in the original paper.
225
234
  #
226
235
  # @return [Nil]
227
236
  def check_stream
@@ -236,9 +245,9 @@ module Oppen
236
245
  check_stream
237
246
  end
238
247
 
239
- # Advances the `right` pointer.
248
+ # Advances the {#right} pointer.
240
249
  #
241
- # @note Called AdvanceRight as well in the original paper.
250
+ # @note Called `AdvanceRight` as well in the original paper.
242
251
  #
243
252
  # @return [Nil]
244
253
  def advance_right
@@ -253,10 +262,13 @@ module Oppen
253
262
  @tokens, @left, @right = ScanStack.upsize_circular_array(@tokens, @left)
254
263
  end
255
264
 
256
- # Advances the `left` pointer and lets the print stack
257
- # print some of the tokens it contains.
265
+ # Advances the {#left} pointer and lets the print stack print some of the
266
+ # tokens it contains.
267
+ #
268
+ # @note Called `AdvanceLeft` as well in the original paper.
258
269
  #
259
- # @note Called AdvanceLeft as well in the original paper.
270
+ # @param token [Token]
271
+ # @param token_width [Integer]
260
272
  #
261
273
  # @return [Nil]
262
274
  def advance_left(token, token_width)
@@ -296,12 +308,13 @@ module Oppen
296
308
  advance_left tokens[left], size[left]
297
309
  end
298
310
 
299
- # Updates the size buffer taking into
300
- # account the length of the current group.
311
+ # Updates the {#size} buffer taking into account the length of the current
312
+ # group.
301
313
  #
302
- # @note Called CheckStack as well in the original paper.
314
+ # @note Called `CheckStack` as well in the original paper.
303
315
  #
304
- # @param depth [Integer] depth of the group
316
+ # @param depth [Integer]
317
+ # depth of the group.
305
318
  #
306
319
  # @return [Nil]
307
320
  def check_stack(depth)
@@ -309,12 +322,12 @@ module Oppen
309
322
 
310
323
  x = scan_stack.top
311
324
  case tokens[x]
312
- when Token::Begin
325
+ in Token::Begin
313
326
  if depth.positive?
314
327
  size[scan_stack.pop] = size[x] + right_total
315
328
  check_stack depth - 1
316
329
  end
317
- when Token::End
330
+ in Token::End
318
331
  size[scan_stack.pop] = 1
319
332
  check_stack depth + 1
320
333
  else
@@ -9,23 +9,28 @@ module Oppen
9
9
  extend Mixins
10
10
 
11
11
  def initialize(size, config)
12
- @bottom = 0
13
- @config = config
14
- @empty = true
15
- @stack = Array.new(size)
16
- @top = 0
12
+ @bottom = 0 # Points to the bottom of the stack.
13
+ @config = config # Printing config.
14
+ @empty = true # Emptiness flag.
15
+ @stack = Array.new size # The fixed sized stack.
16
+ @top = 0 # Points to the top of the stack.
17
17
  end
18
18
 
19
+ # Whether the stack is empty.
20
+ #
19
21
  # @return [Boolean]
20
- def empty?
21
- @empty
22
- end
22
+ def empty? = @empty
23
23
 
24
+ # The current length of the stack.
25
+ #
24
26
  # @return [Integer]
25
- def length
26
- @stack.length
27
- end
27
+ def length = @stack.length
28
28
 
29
+ # The top element of the stack.
30
+ #
31
+ # @raise [RuntimeError]
32
+ # when accessing empty stack.
33
+ #
29
34
  # @return [Object]
30
35
  def top
31
36
  if empty?
@@ -35,6 +40,11 @@ module Oppen
35
40
  @stack[@top]
36
41
  end
37
42
 
43
+ # The bottom element of the stack.
44
+ #
45
+ # @raise [RuntimeError]
46
+ # when accessing empty stack.
47
+ #
38
48
  # @return [Object]
39
49
  def bottom
40
50
  if empty?
@@ -66,16 +76,20 @@ module Oppen
66
76
  #
67
77
  # @param value [Object]
68
78
  #
79
+ # @raise [RuntimeError]
80
+ # when the stack is full and the `upsize_stack` flag is not activated in
81
+ # {Config}.
82
+ #
69
83
  # @return [Nil]
70
84
  def push(value)
71
85
  if empty?
72
86
  @empty = false
73
87
  else
74
- @top = increment(@top)
88
+ @top = increment @top
75
89
  if @top == @bottom
76
90
  raise 'Stack full' if !@config.upsize_stack?
77
91
 
78
- @stack, @bottom, @top = ScanStack.upsize_circular_array(@stack, @bottom)
92
+ @stack, @bottom, @top = ScanStack.upsize_circular_array @stack, @bottom
79
93
  end
80
94
  end
81
95
  @stack[@top] = value
@@ -83,6 +97,9 @@ module Oppen
83
97
 
84
98
  # Pop a value from the top.
85
99
  #
100
+ # @raise [RuntimeError]
101
+ # when accessing empty stack.
102
+ #
86
103
  # @return [Nil]
87
104
  def pop
88
105
  if empty?
@@ -93,13 +110,16 @@ module Oppen
93
110
  if @top == @bottom
94
111
  @empty = true
95
112
  else
96
- @top = decrement(@top)
113
+ @top = decrement @top
97
114
  end
98
115
  res
99
116
  end
100
117
 
101
118
  # Pop a value from the bottom.
102
119
  #
120
+ # @raise [RuntimeError]
121
+ # when accessing empty stack.
122
+ #
103
123
  # @return [Nil]
104
124
  def pop_bottom
105
125
  if empty?
@@ -110,7 +130,7 @@ module Oppen
110
130
  if @top == @bottom
111
131
  @empty = true
112
132
  else
113
- @bottom = increment(@bottom)
133
+ @bottom = increment @bottom
114
134
  end
115
135
  res
116
136
  end
@@ -119,7 +139,7 @@ module Oppen
119
139
  #
120
140
  # @param offset [Integer]
121
141
  #
122
- # @return [Array[Integer]]
142
+ # @return [Array<Integer>]
123
143
  def update_indexes(offset)
124
144
  @stack = @stack.map { |val|
125
145
  (val + offset) % length if val
data/lib/oppen/token.rb CHANGED
@@ -4,27 +4,14 @@
4
4
  module Oppen
5
5
  # Token.
6
6
  class Token
7
- # BreakType.
7
+ # Default token width.
8
8
  #
9
- # FITS => No break is needed (the block fits on the line).
10
- # INCONSISTENT => New line will be forced only if necessary.
11
- # CONSISTENT => Each subblock of the block will be placed on a new line.
12
- module BreakType
13
- # @return [Integer]
14
- FITS = 0
15
- # @return [Integer]
16
- INCONSISTENT = 1
17
- # @return [Integer]
18
- CONSISTENT = 2
19
- end
20
-
21
- # Default token width
22
9
  # @return [Integer]
23
10
  def width = 0
24
11
 
25
12
  # String Token.
26
13
  class String < Token
27
- # @return [String] String value.
14
+ # @return [String]
28
15
  attr_reader :value
29
16
  # @return [Integer]
30
17
  attr_reader :width
@@ -39,15 +26,21 @@ module Oppen
39
26
  def to_s = value
40
27
  end
41
28
 
42
- # If a [Token::Break] follows [Token::Whitespace], and an actual break
43
- # is issued, and `trim_trailing_whitespaces == true`, then all whitespace
44
- # text will be omitted from the output.
29
+ # This token is not part of Oppen's original work. We introduced it to
30
+ # handle trailing whitespaces.
31
+ #
32
+ # When the config flag `trim_trailing_whitespaces == true`, and a new line
33
+ # is needed, all the {Token::Whitespace} figuring after the last {Token::String}
34
+ # will be be skipped.
45
35
  class Whitespace < ::Oppen::Token::String
46
36
  end
47
37
 
48
38
  # Break Token.
49
39
  class Break < Token
50
- # @return [String] If a new line is needed display this string before the new line
40
+ # @return [String]
41
+ # If a new line is needed, display this string before the new line.
42
+ #
43
+ # @see Wadler#break example on `line_continuation`.
51
44
  attr_reader :line_continuation
52
45
  # @return [Integer] Indentation.
53
46
  attr_reader :offset
@@ -56,7 +49,7 @@ module Oppen
56
49
  # @return [Integer]
57
50
  attr_reader :width
58
51
 
59
- def initialize(str = ' ', width: str.length, line_continuation: '', offset: 0)
52
+ def initialize(str = ' ', line_continuation: '', offset: 0, width: str.length)
60
53
  raise ArgumentError, 'line_continuation cannot be nil' if line_continuation.nil?
61
54
 
62
55
  @line_continuation = line_continuation
@@ -66,6 +59,8 @@ module Oppen
66
59
  super()
67
60
  end
68
61
 
62
+ # Convert token to String.
63
+ #
69
64
  # @return [String]
70
65
  def to_s = str
71
66
  end
@@ -87,33 +82,53 @@ module Oppen
87
82
  class Begin < Token
88
83
  # @return [BreakType]
89
84
  attr_reader :break_type
90
- # @return [Integer] Indentation.
85
+ # @return [Integer]
91
86
  attr_reader :offset
92
87
 
93
- def initialize(break_type: BreakType::INCONSISTENT, offset: 2)
88
+ def initialize(break_type: :inconsistent, offset: 2)
94
89
  @offset = offset
95
90
  @break_type = break_type
96
91
  super()
97
92
  end
98
-
99
- # The break_type name as a String.
100
- #
101
- # @return [String]
102
- def break_type_name
103
- case @break_type
104
- in BreakType::FITS then 'Oppen::Token::BreakType::FITS'
105
- in BreakType::INCONSISTENT then 'Oppen::Token::BreakType::INCONSISTENT'
106
- in BreakType::CONSISTENT then 'Oppen::Token::BreakType::CONSISTENT'
107
- end
108
- end
109
93
  end
110
94
 
111
- # End Token
95
+ # End Token.
112
96
  class End < Token
113
97
  nil
114
98
  end
115
99
 
116
- # EOF Token
100
+ # The EOF token can be interpreted as an output flush operation.
101
+ #
102
+ # @note Multiple {Token::EOF} tokens can be present in the same list of tokens.
103
+ #
104
+ # @example
105
+ # tokens = [
106
+ # Oppen::Token::Begin.new,
107
+ # Oppen::Token::String.new('XXXXXXXXXX'),
108
+ # Oppen::Token::End.new,
109
+ # Oppen::Token::EOF.new,
110
+ # Oppen::Token::Begin.new,
111
+ # Oppen::Token::String.new('YYYYYYYYYY'),
112
+ # Oppen::Token::End.new,
113
+ # ]
114
+ # Oppen.print tokens:
115
+ #
116
+ # # =>
117
+ # # XXXXXXXXXX
118
+ #
119
+ # tokens = [
120
+ # Oppen::Token::Begin.new,
121
+ # Oppen::Token::String.new('XXXXXXXXXX'),
122
+ # Oppen::Token::End.new,
123
+ # Oppen::Token::Begin.new,
124
+ # Oppen::Token::String.new('YYYYYYYYYY'),
125
+ # Oppen::Token::End.new,
126
+ # Oppen::Token::EOF.new,
127
+ # ]
128
+ # Oppen.print tokens:
129
+ #
130
+ # # =>
131
+ # # XXXXXXXXXXYYYYYYYYYY
117
132
  class EOF < Token
118
133
  nil
119
134
  end
data/lib/oppen/version.rb CHANGED
@@ -4,6 +4,7 @@
4
4
  module Oppen
5
5
  # Oppen version
6
6
  #
7
- # @return [String] current version
8
- VERSION = '0.9.7' # managed by release.sh
7
+ # @return [String]
8
+ # current version
9
+ VERSION = '1.0.0' # managed by release.sh
9
10
  end