oppen 0.9.0 → 0.9.2

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: 7a496d964de133aa177270080b9444d8e9ef865ce1b355bef4a6c4a43462d48c
4
- data.tar.gz: d2955b0983ef133fd374c1c46fc3424d9cff05c4ec910a6ca5ad94ec3f2db78d
3
+ metadata.gz: fdf36c265fd8c6c3d7335fe79b016ac1e6d8014a23f1b027fc4d956d05b442ab
4
+ data.tar.gz: d75772336cb34c8af929e95d5c4520f0388718739f7d6df722496f6f2f96a82a
5
5
  SHA512:
6
- metadata.gz: d4319e6b5be2d8fa394cf8d6cd593c4e8ab0b5c1c0a313cc42e287a93b46e23a95d844b8bddd01e5547ac67faa4b04395d5edb5ae911380572a0df1b7acf0c95
7
- data.tar.gz: 680e57e6f38f4cda980b57d04e787b4b33becc7b45de4c73810b243e82169411d62cd0d34b56a67df3e96debcc6d8a2ad777046aedec342429792fc91f3b3346
6
+ metadata.gz: 1d745467bc343f1262dbf36f1206a1a37336840014b6785badab602712fe167457b45598b4d2f10e4d438cb49935472c8fe9aea1e21109f349c6f52524831e8e
7
+ data.tar.gz: ad6279e7c29f9b6764fd19ddcdfc8fe006272eb481632d0a3f4f7fa9aad7a5b873e624ea5e829b89ee97401c474779034cfa956ff202e438a27afa22e6bd9151
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Oppen
4
+ # Mixins.
5
+ module Mixins
6
+ # Rotates circular array and triples its size.
7
+ # This method is not for public use.
8
+ #
9
+ # @param arr [Array]
10
+ # @param offset [Integer] Rotation amount
11
+ #
12
+ # @return [Array<Array, Integer, Integer>] upsized array, lhs, rhs
13
+ def upsize_circular_array(arr, offset)
14
+ size = arr.size
15
+ arr = arr.rotate(offset)
16
+ arr.fill(nil, size, 2 * size)
17
+ [arr, 0, size]
18
+ end
19
+
20
+ # Convert a list of tokens to its wadler representation.
21
+ #
22
+ # @param tokens [Array[Token]]
23
+ # @param base_indent [Integer]
24
+ #
25
+ # @return [String]
26
+ def tokens_to_wadler(tokens, base_indent = 4)
27
+ out = StringIO.new
28
+ write = ->(txt, nb_spaces) {
29
+ out.write("#{' ' * nb_spaces}#{txt}\n")
30
+ }
31
+ nb_spaces = base_indent
32
+ tokens.each do |token|
33
+ case token
34
+ in Token::String
35
+ write.call("out.text '#{token}'", nb_spaces)
36
+ in Token::LineBreak
37
+ write.call('out.break', nb_spaces)
38
+ in Token::Break
39
+ write.call('out.breakable', nb_spaces)
40
+ in Token::Begin
41
+ write.call('out.group {', nb_spaces)
42
+ nb_spaces += 2
43
+ in Token::End
44
+ nb_spaces -= 2
45
+ write.call('}', nb_spaces)
46
+ in Token::EOF
47
+ write.call('', nb_spaces) # new line
48
+ end
49
+ end
50
+ out.string
51
+ end
52
+ end
53
+ end
@@ -33,15 +33,15 @@ module Oppen
33
33
  # Delimiter between lines in output
34
34
  attr_reader :new_line
35
35
 
36
- # Page margin (Called length in the original paper).
37
- attr_reader :margin
36
+ # Maximum allowed width for printing (Called length in the original paper).
37
+ attr_reader :width
38
38
 
39
39
  # Current available space (Called index in the original paper).
40
40
  #
41
41
  # @return [Integer] Current available space (Called index in the original paper).
42
42
  attr_reader :space
43
43
 
44
- def initialize(margin, new_line, config, space, out)
44
+ def initialize(width, new_line, config, space, out)
45
45
  @buffer = out
46
46
  @config = config
47
47
  @genspace =
@@ -55,8 +55,8 @@ module Oppen
55
55
  end
56
56
  @items = []
57
57
  @new_line = new_line
58
- @margin = margin
59
- @space = margin
58
+ @width = width
59
+ @space = width
60
60
  end
61
61
 
62
62
  # Returns the output of the print stack
@@ -71,32 +71,32 @@ module Oppen
71
71
  # @note Called Print in the original paper.
72
72
  #
73
73
  # @param token [Token]
74
- # @param token_length [Integer]
74
+ # @param token_width [Integer]
75
75
  #
76
76
  # @return [Nil]
77
- def print(token, token_length)
77
+ def print(token, token_width)
78
78
  case token
79
79
  in Token::Begin
80
- handle_begin token, token_length
80
+ handle_begin token, token_width
81
81
  in Token::End
82
82
  handle_end
83
83
  in Token::Break
84
- handle_break token, token_length
84
+ handle_break token, token_width
85
85
  in Token::String
86
- handle_string token, token_length
86
+ handle_string token, token_width
87
87
  end
88
88
  end
89
89
 
90
90
  # Handle Begin Token.
91
91
  #
92
92
  # @param token [Token]
93
- # @param token_length [Integer]
93
+ # @param token_width [Integer]
94
94
  #
95
95
  # @return [Nil]
96
96
  #
97
97
  # @see Token::Begin
98
- def handle_begin(token, token_length)
99
- if token_length > space
98
+ def handle_begin(token, token_width)
99
+ if token_width > space
100
100
  type =
101
101
  if token.break_type == Token::BreakType::CONSISTENT
102
102
  Token::BreakType::CONSISTENT
@@ -129,16 +129,16 @@ module Oppen
129
129
  # Handle Break Token.
130
130
  #
131
131
  # @param token [Token]
132
- # @param token_length [Integer]
132
+ # @param token_width [Integer]
133
133
  #
134
134
  # @return [Nil]
135
135
  #
136
136
  # @see Token::Break
137
- def handle_break(token, token_length)
137
+ def handle_break(token, token_width)
138
138
  block = top
139
139
  case block.break_type
140
140
  in Token::BreakType::FITS
141
- @space -= token.length
141
+ @space -= token.width
142
142
  write token
143
143
  in Token::BreakType::CONSISTENT
144
144
  @space = block.offset - token.offset
@@ -146,23 +146,23 @@ module Oppen
146
146
  if config&.indent_anchor == Config::IndentAnchor::ON_BEGIN
147
147
  token.offset
148
148
  else
149
- margin - space
149
+ width - space
150
150
  end
151
151
  write token.line_continuation
152
152
  print_new_line indent
153
153
  in Token::BreakType::INCONSISTENT
154
- if token_length > space
154
+ if token_width > space
155
155
  @space = block.offset - token.offset
156
156
  indent =
157
157
  if config&.indent_anchor == Config::IndentAnchor::ON_BEGIN
158
158
  token.offset
159
159
  else
160
- margin - space
160
+ width - space
161
161
  end
162
162
  write token.line_continuation
163
163
  print_new_line indent
164
164
  else
165
- @space -= token.length
165
+ @space -= token.width
166
166
  write token
167
167
  end
168
168
  end
@@ -171,13 +171,13 @@ module Oppen
171
171
  # Handle String Token.
172
172
  #
173
173
  # @param token [Token]
174
- # @param token_length [Integer]
174
+ # @param token_width [Integer]
175
175
  #
176
176
  # @return [Nil]
177
177
  #
178
178
  # @see Token::String
179
- def handle_string(token, token_length)
180
- @space = [0, space - token_length].max
179
+ def handle_string(token, token_width)
180
+ @space = [0, space - token_width].max
181
181
  write token
182
182
  end
183
183
 
@@ -222,8 +222,8 @@ module Oppen
222
222
  def print_new_line(amount)
223
223
  write new_line
224
224
  if config&.indent_anchor == Config::IndentAnchor::ON_BEGIN
225
- @space = margin - top.offset - amount
226
- indent margin - space
225
+ @space = width - top.offset - amount
226
+ indent width - space
227
227
  else
228
228
  indent amount
229
229
  end
data/lib/oppen/printer.rb CHANGED
@@ -4,11 +4,14 @@ require 'stringio'
4
4
 
5
5
  require_relative 'scan_stack'
6
6
  require_relative 'print_stack'
7
+ require_relative 'mixins'
7
8
 
8
9
  # Oppen.
9
10
  module Oppen
10
11
  # Oppen pretty-printer.
11
12
  class Printer
13
+ extend Mixins
14
+
12
15
  attr_reader :config
13
16
  # Ring buffer left index.
14
17
  #
@@ -48,9 +51,18 @@ module Oppen
48
51
  # @note Called token in the original paper.
49
52
  attr_reader :tokens
50
53
 
51
- # @note Called PrettyPrintInit in the original paper.
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
52
64
  #
53
- # @param margin [Integer] maximum line width desired.
65
+ # @param width [Integer] maximum line width desired.
54
66
  # @param new_line [String] the delimiter between lines.
55
67
  # @param config [Config]
56
68
  # @param space [String, Proc] could be a String or a callable.
@@ -60,18 +72,18 @@ module Oppen
60
72
  # If it's a callable, it will receive `n` and it needs to return
61
73
  # a string.
62
74
  # @param out [Object] should have a write and string method
63
- def initialize(margin, new_line, config = Config.oppen,
75
+ def initialize(width, new_line, config = Config.oppen,
64
76
  space = ' ', out = StringIO.new)
65
77
  # Maximum size if the stacks
66
- n = 3 * margin
78
+ n = 3 * width
67
79
 
68
80
  @config = config
69
81
  @left = 0
70
82
  @left_total = 1
71
- @print_stack = PrintStack.new margin, new_line, config, space, out
83
+ @print_stack = PrintStack.new width, new_line, config, space, out
72
84
  @right = 0
73
85
  @right_total = 1
74
- @scan_stack = ScanStack.new n
86
+ @scan_stack = ScanStack.new n, config
75
87
  @size = Array.new n
76
88
  @tokens = Array.new n
77
89
  end
@@ -148,7 +160,7 @@ module Oppen
148
160
  tokens[right] = token
149
161
  size[right] = -1
150
162
  scan_stack.push right
151
- if config&.eager_print &&
163
+ if config&.eager_print? &&
152
164
  (!scan_stack.empty? && right_total - left_total < print_stack.space)
153
165
  check_stack 0
154
166
  advance_left tokens[left], size[left]
@@ -174,7 +186,7 @@ module Oppen
174
186
  scan_stack.push right
175
187
  tokens[right] = token
176
188
  size[right] = -right_total
177
- @right_total += token.length
189
+ @right_total += token.width
178
190
  end
179
191
 
180
192
  # Handle String Token.
@@ -184,12 +196,12 @@ module Oppen
184
196
  # @see Token::String
185
197
  def handle_string(token)
186
198
  if scan_stack.empty?
187
- print_stack.print token, token.length
199
+ print_stack.print token, token.width
188
200
  else
189
201
  advance_right
190
202
  tokens[right] = token
191
- size[right] = token.length
192
- @right_total += token.length
203
+ size[right] = token.width
204
+ @right_total += token.width
193
205
  check_stream
194
206
  end
195
207
  end
@@ -217,10 +229,15 @@ module Oppen
217
229
  #
218
230
  # @return [Nil]
219
231
  def advance_right
220
- @right = (right + 1) % scan_stack.length
232
+ @right = (right + 1) % @size.length
233
+
221
234
  return if right != left
222
235
 
223
- raise 'Token queue full'
236
+ raise 'Token queue full' if !config.upsize_stack?
237
+
238
+ @scan_stack.update_indexes(-@left)
239
+ @size, _left, _right = ScanStack.upsize_circular_array(@size, @left)
240
+ @tokens, @left, @right = ScanStack.upsize_circular_array(@tokens, @left)
224
241
  end
225
242
 
226
243
  # Advances the `left` pointer and lets the print stack
@@ -229,16 +246,16 @@ module Oppen
229
246
  # @note Called AdvanceLeft as well in the original paper.
230
247
  #
231
248
  # @return [Nil]
232
- def advance_left(token, token_length)
233
- return if token_length.negative?
249
+ def advance_left(token, token_width)
250
+ return if token_width.negative?
234
251
 
235
- print_stack.print token, token_length
252
+ print_stack.print token, token_width
236
253
 
237
254
  case token
238
255
  when Token::Break
239
- @left_total += token.length
256
+ @left_total += token.width
240
257
  when Token::String
241
- @left_total += token_length
258
+ @left_total += token_width
242
259
  end
243
260
 
244
261
  return if left == right
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'mixins'
4
+
3
5
  # Oppen.
4
6
  module Oppen
5
7
  # A fixed-size stack that can be popped from top and bottom.
6
8
  class ScanStack
7
- def initialize(size)
9
+ extend Mixins
10
+
11
+ def initialize(size, config)
8
12
  @bottom = 0
13
+ @config = config
9
14
  @empty = true
10
15
  @stack = Array.new(size)
11
16
  @top = 0
@@ -68,7 +73,9 @@ module Oppen
68
73
  else
69
74
  @top = increment(@top)
70
75
  if @top == @bottom
71
- raise 'Stack full'
76
+ raise 'Stack full' if !@config.upsize_stack?
77
+
78
+ @stack, @bottom, @top = ScanStack.upsize_circular_array(@stack, @bottom)
72
79
  end
73
80
  end
74
81
  @stack[@top] = value
@@ -107,5 +114,16 @@ module Oppen
107
114
  end
108
115
  res
109
116
  end
117
+
118
+ # Offset the values of the stack.
119
+ #
120
+ # @param offset [Integer]
121
+ #
122
+ # @return [Array[Integer]]
123
+ def update_indexes(offset)
124
+ @stack = @stack.map { |val|
125
+ (val + offset) % length if val
126
+ }
127
+ end
110
128
  end
111
129
  end
data/lib/oppen/token.rb CHANGED
@@ -18,60 +18,50 @@ module Oppen
18
18
  CONSISTENT = 2
19
19
  end
20
20
 
21
- # Default token length
21
+ # Default token width
22
22
  # @return [Integer]
23
- def length
24
- 0
25
- end
23
+ def width = 0
26
24
 
27
25
  # String Token.
28
26
  class String < Token
29
27
  # @return [String] String value.
30
28
  attr_reader :value
29
+ # @return [Integer]
30
+ attr_reader :width
31
31
 
32
- def initialize(value)
32
+ def initialize(value, width: value.length)
33
33
  @value = value
34
+ @width = width
34
35
  super()
35
36
  end
36
37
 
37
- # @return [Integer]
38
- def length
39
- value.length
40
- end
41
-
42
38
  # @return [String]
43
- def to_s
44
- value
45
- end
39
+ def to_s = value
46
40
  end
47
41
 
48
42
  # Break Token.
49
43
  class Break < Token
50
- # @return [String] Break strings.
51
- attr_reader :str
52
44
  # @return [String] If a new line is needed display this string before the new line
53
45
  attr_reader :line_continuation
54
46
  # @return [Integer] Indentation.
55
47
  attr_reader :offset
48
+ # @return [String] Break strings.
49
+ attr_reader :str
50
+ # @return [Integer]
51
+ attr_reader :width
56
52
 
57
- def initialize(str = ' ', line_continuation: '', offset: 0)
53
+ def initialize(str = ' ', width: str.length, line_continuation: '', offset: 0)
58
54
  raise ArgumentError, 'line_continuation cannot be nil' if line_continuation.nil?
59
55
 
60
56
  @line_continuation = line_continuation
61
57
  @offset = offset
62
58
  @str = str
59
+ @width = width
63
60
  super()
64
61
  end
65
62
 
66
- # @return [Integer]
67
- def length
68
- str.length
69
- end
70
-
71
63
  # @return [String]
72
- def to_s
73
- str
74
- end
64
+ def to_s = str
75
65
  end
76
66
 
77
67
  # Distinguished instance of Break which forces a line break.
@@ -79,9 +69,7 @@ module Oppen
79
69
  # Mock string that represents an infinite string to force new line.
80
70
  class LineBreakString
81
71
  # @return [Integer]
82
- def length
83
- 999_999
84
- end
72
+ def length = 999_999
85
73
  end
86
74
 
87
75
  def initialize(line_continuation: '', offset: 0)
data/lib/oppen/version.rb CHANGED
@@ -5,5 +5,5 @@ module Oppen
5
5
  # Oppen version
6
6
  #
7
7
  # @return [String] current version
8
- VERSION = '0.9.0' # managed by release.sh
8
+ VERSION = '0.9.2' # managed by release.sh
9
9
  end
data/lib/oppen.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'oppen/mixins'
3
4
  require_relative 'oppen/printer'
4
5
  require_relative 'oppen/print_stack'
5
6
  require_relative 'oppen/scan_stack'
@@ -9,6 +10,8 @@ require_relative 'wadler/print'
9
10
 
10
11
  # Oppen.
11
12
  module Oppen
13
+ extend Mixins
14
+
12
15
  # Entry point of the pretty printer.
13
16
  #
14
17
  # @param config [Config]
@@ -18,15 +21,15 @@ module Oppen
18
21
  # to indent.
19
22
  # If it's a callable, it will receive `n` and it needs to return
20
23
  # a string.
21
- # @param margin [Integer] maximum line width desired
22
24
  # @param new_line [String] the delimiter between lines
23
25
  # @param out [Object] should have a write and string method
24
26
  # @param tokens [Array[Token]] the list of tokens to be printed
27
+ # @param width [Integer] maximum line width desired
25
28
  #
26
29
  # @return [String] output of the pretty printer
27
30
  def self.print(config: Config.oppen, space: ' ',
28
- margin: 80, new_line: "\n", out: StringIO.new, tokens: [])
29
- printer = Printer.new margin, new_line, config, space, out
31
+ new_line: "\n", out: StringIO.new, tokens: [], width: 80)
32
+ printer = Printer.new width, new_line, config, space, out
30
33
  tokens.each do |token|
31
34
  printer.print token
32
35
  end
@@ -47,10 +50,17 @@ module Oppen
47
50
  end
48
51
 
49
52
  attr_accessor :indent_anchor
53
+
54
+ def initialize(indent_anchor: IndentAnchor::ON_BREAK, eager_print: false, upsize_stack: false)
55
+ @indent_anchor = indent_anchor
56
+ @eager_print = eager_print
57
+ @upsize_stack = upsize_stack
58
+ end
59
+
50
60
  # Print groups eagerly
51
61
  #
52
62
  # @example
53
- # out = Oppen::Wadler.new (margin: 13)
63
+ # out = Oppen::Wadler.new (width: 13)
54
64
  # out.group {
55
65
  # out.group {
56
66
  # out.text 'abc'
@@ -76,12 +86,9 @@ module Oppen
76
86
  # # jkl
77
87
  #
78
88
  # @return [Boolean]
79
- attr_accessor :eager_print
89
+ def eager_print? = @eager_print
80
90
 
81
- def initialize(indent_anchor: IndentAnchor::ON_BREAK, eager_print: false)
82
- @indent_anchor = indent_anchor
83
- @eager_print = eager_print
84
- end
91
+ def upsize_stack? = @upsize_stack
85
92
 
86
93
  # Default config for Oppen usage
87
94
  # @return [Config]
@@ -91,25 +98,27 @@ module Oppen
91
98
 
92
99
  # Default config for Wadler usage
93
100
  # @return [Config]
94
- def self.wadler(eager_print: true)
95
- new(indent_anchor: IndentAnchor::ON_BEGIN, eager_print:)
101
+ def self.wadler(eager_print: true, upsize_stack: true)
102
+ new(indent_anchor: IndentAnchor::ON_BEGIN, eager_print:, upsize_stack:)
96
103
  end
97
104
  end
98
105
 
99
106
  # @param value [String]
107
+ # @param width [Integer] token width that defaults to value.length
100
108
  #
101
109
  # @return [Oppen::Token::String] a new String token
102
- def self.string(value)
103
- Token::String.new(value)
110
+ def self.string(value, width: value.length)
111
+ Token::String.new(value, width:)
104
112
  end
105
113
 
106
114
  # @param str [String]
107
115
  # @param line_continuation [String] If a new line is needed display this string before the new line
108
116
  # @param offset [Integer]
117
+ # @param width [Integer] token width that defaults to str.length
109
118
  #
110
119
  # @return [Oppen::Token::Break] a new Break token
111
- def self.break(str = ' ', line_continuation: '', offset: 0)
112
- Token::Break.new(str, line_continuation:, offset:)
120
+ def self.break(str = ' ', line_continuation: '', offset: 0, width: str.length)
121
+ Token::Break.new(str, width:, line_continuation:, offset:)
113
122
  end
114
123
 
115
124
  # @param line_continuation [String] If a new line is needed display this string before the new line
data/lib/wadler/print.rb CHANGED
@@ -7,10 +7,10 @@ module Oppen
7
7
  attr_reader :config
8
8
  attr_reader :current_indent
9
9
  attr_reader :space
10
- attr_reader :margin
11
10
  attr_reader :new_line
12
11
  attr_reader :out
13
12
  attr_reader :tokens
13
+ attr_reader :width
14
14
 
15
15
  # @param config [Oppen::Config]
16
16
  # @param space [String, Proc] could be a String or a callable.
@@ -19,15 +19,15 @@ module Oppen
19
19
  # to indent.
20
20
  # If it's a callable, it will receive `n` and it needs to return
21
21
  # a string.
22
- # @param margin [Integer]
23
22
  # @param new_line [String]
24
23
  # @param out [Object] should have a write and string method
24
+ # @param width [Integer]
25
25
  def initialize(config: Config.wadler, space: ' ',
26
- margin: 80, new_line: "\n", out: StringIO.new)
26
+ new_line: "\n", out: StringIO.new, width: 80)
27
27
  @config = config
28
28
  @current_indent = 0
29
29
  @space = space
30
- @margin = margin
30
+ @width = width
31
31
  @new_line = new_line
32
32
  @out = out
33
33
  @tokens = []
@@ -38,7 +38,7 @@ module Oppen
38
38
  if !tokens.last.is_a? Oppen::Token::EOF
39
39
  tokens << Oppen.eof
40
40
  end
41
- Oppen.print(tokens:, margin:, new_line:, config:, space:, out:)
41
+ Oppen.print(tokens:, new_line:, config:, space:, out:, width:)
42
42
  end
43
43
 
44
44
  # @param indent [Integer] group indentation
@@ -110,16 +110,16 @@ module Oppen
110
110
  # @param value [String]
111
111
  #
112
112
  # @return [Nil]
113
- def text(value)
114
- tokens << Oppen.string(value)
113
+ def text(value, width: value.length)
114
+ tokens << Oppen.string(value, width:)
115
115
  end
116
116
 
117
117
  # @param str [String]
118
118
  # @param line_continuation [String] If a new line is needed display this string before the new line
119
119
  #
120
120
  # @return [Nil]
121
- def breakable(str = ' ', line_continuation: '')
122
- tokens << Oppen.break(str, line_continuation:, offset: current_indent)
121
+ def breakable(str = ' ', width: str.length, line_continuation: '')
122
+ tokens << Oppen.break(str, width:, line_continuation:, offset: current_indent)
123
123
  end
124
124
 
125
125
  # @param line_continuation [String] If a new line is needed display this string before the new line
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oppen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amine Mike El Maalouf <amine.el-maalouf@epita.fr>
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-09-27 00:00:00.000000000 Z
12
+ date: 2024-10-25 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Implementation of the Oppen's pretty printing algorithm
15
15
  email:
@@ -20,6 +20,7 @@ files:
20
20
  - LICENSE
21
21
  - README.md
22
22
  - lib/oppen.rb
23
+ - lib/oppen/mixins.rb
23
24
  - lib/oppen/print_stack.rb
24
25
  - lib/oppen/printer.rb
25
26
  - lib/oppen/scan_stack.rb