oppen 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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)
@@ -281,7 +293,7 @@ module Oppen
281
293
  end
282
294
  trim_on_break ||= 0
283
295
 
284
- print_stack.print(token, token_width, trim_on_break:)
296
+ print_stack.print(token, token_width, trim_on_break: trim_on_break)
285
297
 
286
298
  case token
287
299
  when Token::Break
@@ -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
@@ -79,7 +74,7 @@ module Oppen
79
74
  end
80
75
 
81
76
  def initialize(line_continuation: '', offset: 0)
82
- super(LineBreakString.new, line_continuation:, offset:)
77
+ super(LineBreakString.new, line_continuation: line_continuation, offset: offset)
83
78
  end
84
79
  end
85
80
 
@@ -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 = '0.9.8' # managed by release.sh
9
10
  end