oppen 0.9.6 → 0.9.8
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 +4 -4
- data/README.md +1 -2
- data/lib/oppen/mixins.rb +50 -27
- data/lib/oppen/print_stack.rb +77 -67
- data/lib/oppen/printer.rb +122 -77
- data/lib/oppen/scan_stack.rb +36 -16
- data/lib/oppen/token.rb +54 -22
- data/lib/oppen/version.rb +3 -2
- data/lib/oppen.rb +186 -75
- data/lib/wadler/print.rb +248 -45
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '008545ae6d86a7415e434ef51a19872fbf5b768db232d70bbac025667e002604'
|
4
|
+
data.tar.gz: a989a6e8d422c363e7ebca36fc10dac4ad030f145afc2b4bc152c9cff5bdfe49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a3e32d3a05c638bd26a9e170d737186c9635eeb3c54844869b108c8252fdafa942a05a76a1e3d3d25d5e93a47d076c280f7346c1c313b5c7159a8f3d1166ef6
|
7
|
+
data.tar.gz: 1f3c076ea8b298f5a772d9c209c4bc64087f6093576e41e2ffb6289b5d0aba08c1b3ed9d3022ebb14b7d7fe4c083804e60219735bce5c00f96785e9dede2bb69
|
data/README.md
CHANGED
data/lib/oppen/mixins.rb
CHANGED
@@ -4,50 +4,73 @@ module Oppen
|
|
4
4
|
# Mixins.
|
5
5
|
module Mixins
|
6
6
|
# Rotates circular array and triples its size.
|
7
|
-
# This method is not for public use.
|
8
7
|
#
|
9
|
-
#
|
10
|
-
# @
|
8
|
+
# @!visibility private
|
9
|
+
# @note This method is not for public use.
|
11
10
|
#
|
12
|
-
# @
|
11
|
+
# @param arr [Array]
|
12
|
+
# the circular array.
|
13
|
+
# @param offset [Integer]
|
14
|
+
# rotation amount.
|
15
|
+
#
|
16
|
+
# @return [Array<Array, Integer, Integer>]
|
17
|
+
# upsized array, lhs, rhs.
|
13
18
|
def upsize_circular_array(arr, offset)
|
14
19
|
size = arr.size
|
15
|
-
arr = arr.rotate
|
16
|
-
arr.fill
|
20
|
+
arr = arr.rotate offset
|
21
|
+
arr.fill nil, size, 2 * size
|
17
22
|
[arr, 0, size]
|
18
23
|
end
|
19
24
|
|
20
|
-
# Convert a list of tokens to its wadler representation.
|
21
|
-
#
|
22
|
-
# @param tokens [Array[Token]]
|
23
|
-
# @param base_indent [Integer]
|
24
|
-
#
|
25
25
|
# @return [String]
|
26
|
-
def tokens_to_wadler(tokens, base_indent
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
def tokens_to_wadler(tokens, base_indent: 0, printer_name: 'out', width: tokens.length * 3)
|
27
|
+
printer = Oppen::Wadler.new(width: width)
|
28
|
+
printer.base_indent(base_indent)
|
29
|
+
indent = 2
|
30
|
+
|
31
|
+
handle_break_token = ->(token) {
|
32
|
+
if token.offset.positive?
|
33
|
+
printer.text "#{printer_name}.nest(#{token.offset}, '', '') {"
|
34
|
+
printer.nest_open indent
|
35
|
+
printer.break
|
36
|
+
end
|
37
|
+
|
38
|
+
printer.text(
|
39
|
+
case token
|
40
|
+
in Token::LineBreak
|
41
|
+
"#{printer_name}.break(line_continuation: #{token.line_continuation.inspect})"
|
42
|
+
in Token::Break
|
43
|
+
"#{printer_name}.breakable(#{token.str.inspect}, width: #{token.width}, " \
|
44
|
+
"line_continuation: #{token.line_continuation.inspect})"
|
45
|
+
end,
|
46
|
+
)
|
47
|
+
|
48
|
+
if token.offset.positive?
|
49
|
+
printer.nest_close indent
|
50
|
+
printer.break
|
51
|
+
printer.text '}'
|
52
|
+
end
|
30
53
|
}
|
31
|
-
|
32
|
-
tokens.
|
54
|
+
|
55
|
+
tokens.each_with_index do |token, idx|
|
33
56
|
case token
|
34
57
|
in Token::String
|
35
|
-
|
36
|
-
in Token::LineBreak
|
37
|
-
write.call('out.break', nb_spaces)
|
58
|
+
printer.text "#{printer_name}.text(#{token.value.inspect}, width: #{token.width})"
|
38
59
|
in Token::Break
|
39
|
-
|
60
|
+
handle_break_token.(token)
|
40
61
|
in Token::Begin
|
41
|
-
|
42
|
-
|
62
|
+
printer.text "#{printer_name}.group(#{token.offset}, '', '', #{token.break_type.inspect}) {"
|
63
|
+
printer.nest_open indent
|
43
64
|
in Token::End
|
44
|
-
|
45
|
-
|
65
|
+
printer.nest_close indent
|
66
|
+
printer.break
|
67
|
+
printer.text '}'
|
46
68
|
in Token::EOF
|
47
|
-
|
69
|
+
nil
|
48
70
|
end
|
71
|
+
printer.break if !tokens[idx + 1].is_a?(Token::End)
|
49
72
|
end
|
50
|
-
|
73
|
+
printer.output
|
51
74
|
end
|
52
75
|
end
|
53
76
|
end
|
data/lib/oppen/print_stack.rb
CHANGED
@@ -2,15 +2,16 @@
|
|
2
2
|
|
3
3
|
# Oppen.
|
4
4
|
module Oppen
|
5
|
-
#
|
6
|
-
# using the values of the tokens that were pushed into it.
|
5
|
+
# A stack of {Token}s.
|
7
6
|
class PrintStack
|
8
|
-
#
|
7
|
+
# An item in the print stack.
|
9
8
|
class PrintStackEntry
|
10
|
-
# @return [
|
11
|
-
|
12
|
-
# @return [Token::BreakType] (Called break in the original paper).
|
9
|
+
# @return [Token::BreakType]
|
10
|
+
# Called `break` in the original paper.
|
13
11
|
attr_reader :break_type
|
12
|
+
# @return [Integer]
|
13
|
+
# Indentation level.
|
14
|
+
attr_reader :offset
|
14
15
|
|
15
16
|
def initialize(offset, break_type)
|
16
17
|
@offset = offset
|
@@ -18,34 +19,26 @@ module Oppen
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
# IO
|
22
|
+
# IO sink for the output.
|
22
23
|
attr_reader :buffer
|
23
|
-
|
24
|
-
# Config containing customization flags
|
24
|
+
# The printer's configuration, altering its behavior.
|
25
25
|
attr_reader :config
|
26
|
-
|
27
|
-
# Callable that generate spaces
|
26
|
+
# Space generator, a callable.
|
28
27
|
attr_reader :genspace
|
29
|
-
|
30
|
-
# Array representing the stack of PrintStackEntries.
|
28
|
+
# The stack of PrintStackEntries.
|
31
29
|
attr_reader :items
|
32
|
-
|
33
|
-
# Delimiter between lines in output
|
30
|
+
# Delimiter between lines.
|
34
31
|
attr_reader :new_line
|
35
|
-
|
36
|
-
# Maximum allowed width for printing (Called length in the original paper).
|
37
|
-
attr_reader :width
|
38
|
-
|
39
|
-
# Current available space (Called index in the original paper).
|
40
|
-
#
|
41
|
-
# @return [Integer] Current available space (Called index in the original paper).
|
32
|
+
# Current available space (`index` in the original paper).
|
42
33
|
attr_reader :space
|
34
|
+
# Maximum allowed width for printing (`length` in the original paper).
|
35
|
+
attr_reader :width
|
43
36
|
|
44
37
|
def initialize(width, new_line, config, space, out)
|
45
38
|
@buffer = out
|
46
39
|
@config = config
|
47
40
|
@genspace =
|
48
|
-
if space.respond_to?
|
41
|
+
if space.respond_to? :call
|
49
42
|
raise ArgumentError, 'space argument must be a Proc of arity 1' \
|
50
43
|
if space.to_proc.arity != 1
|
51
44
|
|
@@ -53,58 +46,62 @@ module Oppen
|
|
53
46
|
else
|
54
47
|
->(n) { space * n }
|
55
48
|
end
|
56
|
-
@indent = 0
|
49
|
+
@indent = 0 # the amount of indentation to display on the next non empty new line.
|
57
50
|
@items = []
|
58
51
|
@new_line = new_line
|
59
52
|
@width = width
|
60
53
|
@space = width
|
61
54
|
end
|
62
55
|
|
63
|
-
#
|
56
|
+
# The final pretty-printed output.
|
64
57
|
#
|
65
58
|
# @return [String]
|
59
|
+
# The output of the print stack.
|
66
60
|
def output
|
61
|
+
buffer.truncate buffer.pos
|
67
62
|
buffer.string
|
68
63
|
end
|
69
64
|
|
70
|
-
# Core method responsible for building the print stack and the output
|
65
|
+
# Core method responsible for building the print stack and the output
|
66
|
+
# string.
|
71
67
|
#
|
72
|
-
# @note Called Print in the original paper.
|
68
|
+
# @note Called `Print` in the original paper.
|
73
69
|
#
|
74
|
-
# @param token
|
75
|
-
# @param token_width
|
70
|
+
# @param token [Token]
|
71
|
+
# @param token_width [Integer]
|
72
|
+
# @param trim_on_break [Integer]
|
73
|
+
# number of trailing whitespace characters to trim. If zero, no
|
74
|
+
# character will be trimmed.
|
76
75
|
#
|
77
76
|
# @return [Nil]
|
78
|
-
def print(token, token_width)
|
77
|
+
def print(token, token_width, trim_on_break: 0)
|
79
78
|
case token
|
80
79
|
in Token::Begin
|
81
80
|
handle_begin token, token_width
|
82
81
|
in Token::End
|
83
82
|
handle_end
|
84
83
|
in Token::Break
|
85
|
-
handle_break token, token_width
|
84
|
+
handle_break token, token_width, trim_on_break: trim_on_break
|
86
85
|
in Token::String
|
87
86
|
handle_string token, token_width
|
88
87
|
end
|
89
88
|
end
|
90
89
|
|
91
|
-
# Handle Begin
|
90
|
+
# Handle {Token::Begin}.
|
92
91
|
#
|
93
|
-
# @param token
|
92
|
+
# @param token [Token]
|
94
93
|
# @param token_width [Integer]
|
95
94
|
#
|
96
95
|
# @return [Nil]
|
97
|
-
#
|
98
|
-
# @see Token::Begin
|
99
96
|
def handle_begin(token, token_width)
|
100
97
|
if token_width > space
|
101
98
|
type =
|
102
|
-
if token.break_type ==
|
103
|
-
|
99
|
+
if token.break_type == :consistent
|
100
|
+
:consistent
|
104
101
|
else
|
105
|
-
|
102
|
+
:inconsistent
|
106
103
|
end
|
107
|
-
if config&.indent_anchor ==
|
104
|
+
if config&.indent_anchor == :current_offset
|
108
105
|
indent = token.offset
|
109
106
|
if !items.empty?
|
110
107
|
indent += top.offset
|
@@ -114,52 +111,54 @@ module Oppen
|
|
114
111
|
end
|
115
112
|
push PrintStackEntry.new indent, type
|
116
113
|
else
|
117
|
-
push PrintStackEntry.new 0,
|
114
|
+
push PrintStackEntry.new 0, :fits
|
118
115
|
end
|
119
116
|
end
|
120
117
|
|
121
|
-
# Handle End
|
118
|
+
# Handle {Token::End}.
|
122
119
|
#
|
123
120
|
# @return [Nil]
|
124
|
-
#
|
125
|
-
# @see Token::End
|
126
121
|
def handle_end
|
127
122
|
pop
|
128
123
|
end
|
129
124
|
|
130
|
-
# Handle Break
|
125
|
+
# Handle {Token::Break}.
|
131
126
|
#
|
132
|
-
# @param token
|
133
|
-
# @param token_width
|
127
|
+
# @param token [Token::Break]
|
128
|
+
# @param token_width [Integer]
|
129
|
+
# @param trim_on_break [Integer]
|
130
|
+
# number of trailing whitespace characters to trim.
|
131
|
+
# 0 = none.
|
134
132
|
#
|
135
133
|
# @return [Nil]
|
136
|
-
|
137
|
-
# @see Token::Break
|
138
|
-
def handle_break(token, token_width)
|
134
|
+
def handle_break(token, token_width, trim_on_break: 0)
|
139
135
|
block = top
|
140
136
|
case block.break_type
|
141
|
-
in
|
137
|
+
in :fits
|
138
|
+
# No new line is needed (the block fits on the line).
|
142
139
|
@space -= token.width
|
143
140
|
write token
|
144
|
-
in
|
141
|
+
in :consistent
|
145
142
|
@space = block.offset - token.offset
|
146
143
|
indent =
|
147
|
-
if config&.indent_anchor ==
|
144
|
+
if config&.indent_anchor == :current_offset
|
148
145
|
token.offset
|
149
146
|
else
|
150
147
|
width - space
|
151
148
|
end
|
149
|
+
erase trim_on_break
|
152
150
|
write token.line_continuation
|
153
151
|
print_new_line indent
|
154
|
-
in
|
152
|
+
in :inconsistent
|
155
153
|
if token_width > space
|
156
154
|
@space = block.offset - token.offset
|
157
155
|
indent =
|
158
|
-
if config&.indent_anchor ==
|
156
|
+
if config&.indent_anchor == :current_offset
|
159
157
|
token.offset
|
160
158
|
else
|
161
159
|
width - space
|
162
160
|
end
|
161
|
+
erase trim_on_break
|
163
162
|
write token.line_continuation
|
164
163
|
print_new_line indent
|
165
164
|
else
|
@@ -169,14 +168,12 @@ module Oppen
|
|
169
168
|
end
|
170
169
|
end
|
171
170
|
|
172
|
-
# Handle String
|
171
|
+
# Handle {Token::String}.
|
173
172
|
#
|
174
|
-
# @param token
|
173
|
+
# @param token [Token::String]
|
175
174
|
# @param token_width [Integer]
|
176
175
|
#
|
177
176
|
# @return [Nil]
|
178
|
-
#
|
179
|
-
# @see Token::String
|
180
177
|
def handle_string(token, token_width)
|
181
178
|
return if token.value.empty?
|
182
179
|
|
@@ -188,16 +185,16 @@ module Oppen
|
|
188
185
|
write token
|
189
186
|
end
|
190
187
|
|
191
|
-
# Push a PrintStackEntry into the stack.
|
188
|
+
# Push a {PrintStackEntry} into the stack.
|
192
189
|
#
|
193
190
|
# @param print_stack_entry [PrintStackEntry]
|
194
191
|
#
|
195
192
|
# @return [Nil]
|
196
193
|
def push(print_stack_entry)
|
197
|
-
items.append
|
194
|
+
items.append print_stack_entry
|
198
195
|
end
|
199
196
|
|
200
|
-
# Pop a PrintStackEntry from the stack.
|
197
|
+
# Pop a {PrintStackEntry} from the stack.
|
201
198
|
#
|
202
199
|
# @return [PrintStackEntry]
|
203
200
|
def pop
|
@@ -221,14 +218,15 @@ module Oppen
|
|
221
218
|
|
222
219
|
# Add a new line to the output.
|
223
220
|
#
|
224
|
-
# @note Called PrintNewLine as well in the original paper.
|
221
|
+
# @note Called `PrintNewLine` as well in the original paper.
|
225
222
|
#
|
226
|
-
# @param amount [Integer]
|
223
|
+
# @param amount [Integer]
|
224
|
+
# indentation amount.
|
227
225
|
#
|
228
226
|
# @return [Nil]
|
229
227
|
def print_new_line(amount)
|
230
228
|
write new_line
|
231
|
-
if config&.indent_anchor ==
|
229
|
+
if config&.indent_anchor == :current_offset
|
232
230
|
@space = width - top.offset - amount
|
233
231
|
@indent = width - space
|
234
232
|
else
|
@@ -242,12 +240,24 @@ module Oppen
|
|
242
240
|
#
|
243
241
|
# @return [Nil]
|
244
242
|
def write(obj)
|
245
|
-
buffer.write
|
243
|
+
buffer.write obj.to_s
|
244
|
+
end
|
245
|
+
|
246
|
+
# Erase the last `count` characters.
|
247
|
+
#
|
248
|
+
# @param count [Integer]
|
249
|
+
#
|
250
|
+
# @return [Nil]
|
251
|
+
def erase(count = 0)
|
252
|
+
raise ArgumentError, "count = #{count} must be non-negative" if count.negative?
|
253
|
+
|
254
|
+
buffer.seek(-count, IO::SEEK_CUR)
|
255
|
+
@space += count
|
246
256
|
end
|
247
257
|
|
248
258
|
# Add indentation by `amount`.
|
249
259
|
#
|
250
|
-
# @note Called Indent as well in the original paper.
|
260
|
+
# @note Called `Indent` as well in the original paper.
|
251
261
|
#
|
252
262
|
# @param amount [Integer]
|
253
263
|
#
|
@@ -255,7 +265,7 @@ module Oppen
|
|
255
265
|
def indent(amount)
|
256
266
|
raise ArgumentError 'Indenting using negative amount' if amount.negative?
|
257
267
|
|
258
|
-
write genspace.
|
268
|
+
write genspace.(amount) if amount.positive?
|
259
269
|
end
|
260
270
|
end
|
261
271
|
end
|