oppen 0.9.6 → 0.9.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|