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
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,72 +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
|
-
#
|
25
|
+
# Number of spaces needed to print from start of buffer to left.
|
26
|
+
#
|
27
|
+
# @note Called `leftTotal` as well in the original paper.
|
22
28
|
#
|
23
|
-
# @
|
29
|
+
# @return [Integer]
|
24
30
|
attr_reader :left_total
|
25
|
-
|
26
|
-
#
|
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
|
-
#
|
37
|
+
# Ring buffer's right index.
|
38
|
+
#
|
39
|
+
# @note Called `right` as well in the original paper.
|
30
40
|
#
|
31
|
-
# @
|
41
|
+
# @return [Integer]
|
32
42
|
attr_reader :right
|
33
|
-
|
34
|
-
#
|
43
|
+
# Number of spaces needed to print from start of buffer to right.
|
44
|
+
#
|
45
|
+
# @note Called `leftTotal` as well in the original paper.
|
35
46
|
#
|
36
|
-
# @
|
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
|
-
#
|
55
|
-
#
|
56
|
-
# @
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
# @param width
|
66
|
-
#
|
67
|
-
# @param
|
68
|
-
#
|
69
|
-
#
|
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
|
90
|
+
@last_whitespaces_width = 0 # Accumulates the width of the last Whitespace tokens encountered.
|
81
91
|
@left = 0
|
82
92
|
@left_total = 1
|
83
93
|
@print_stack = PrintStack.new width, new_line, config, space, out
|
@@ -88,14 +98,16 @@ module Oppen
|
|
88
98
|
@tokens = Array.new n
|
89
99
|
end
|
90
100
|
|
101
|
+
# The final pretty-printed output.
|
102
|
+
#
|
91
103
|
# @return [String]
|
92
|
-
|
93
|
-
|
94
|
-
end
|
104
|
+
# the output of the print stack.
|
105
|
+
def output = print_stack.output
|
95
106
|
|
96
|
-
# Core function of the algorithm responsible for populating the
|
107
|
+
# Core function of the algorithm responsible for populating the {ScanStack}
|
108
|
+
# and {PrintStack}.
|
97
109
|
#
|
98
|
-
# @note Called PrettyPrint as well in the original paper.
|
110
|
+
# @note Called `PrettyPrint` as well in the original paper.
|
99
111
|
#
|
100
112
|
# @param token [Token]
|
101
113
|
#
|
@@ -110,16 +122,18 @@ module Oppen
|
|
110
122
|
handle_end token
|
111
123
|
in Token::Break
|
112
124
|
handle_break token
|
125
|
+
in Token::Whitespace
|
126
|
+
@last_whitespaces_width += token.width
|
127
|
+
handle_string token
|
113
128
|
in Token::String
|
129
|
+
@last_whitespaces_width = 0
|
114
130
|
handle_string token
|
115
131
|
end
|
116
132
|
end
|
117
133
|
|
118
|
-
# Handle EOF
|
134
|
+
# Handle {Token::EOF}.
|
119
135
|
#
|
120
136
|
# @return [Nil]
|
121
|
-
#
|
122
|
-
# @see Token::EOF
|
123
137
|
def handle_eof
|
124
138
|
if !scan_stack.empty?
|
125
139
|
check_stack 0
|
@@ -128,17 +142,20 @@ module Oppen
|
|
128
142
|
print_stack.indent 0
|
129
143
|
end
|
130
144
|
|
131
|
-
# Handle Begin
|
145
|
+
# Handle {Token::Begin}.
|
132
146
|
#
|
133
|
-
# @
|
147
|
+
# @param token [Token::Begin]
|
134
148
|
#
|
135
|
-
# @
|
149
|
+
# @return [Nil]
|
136
150
|
def handle_begin(token)
|
137
151
|
if scan_stack.empty?
|
138
152
|
@left = 0
|
139
153
|
@left_total = 1
|
140
154
|
@right = 0
|
141
155
|
@right_total = 1
|
156
|
+
|
157
|
+
# config.trim_trailing_whitespaces.
|
158
|
+
@tokens[-1] = nil
|
142
159
|
else
|
143
160
|
advance_right
|
144
161
|
end
|
@@ -147,11 +164,11 @@ module Oppen
|
|
147
164
|
scan_stack.push right
|
148
165
|
end
|
149
166
|
|
150
|
-
# Handle End
|
167
|
+
# Handle {Token::End}.
|
151
168
|
#
|
152
|
-
# @
|
169
|
+
# @param token [Token::End]
|
153
170
|
#
|
154
|
-
# @
|
171
|
+
# @return [Nil]
|
155
172
|
def handle_end(token)
|
156
173
|
if scan_stack.empty?
|
157
174
|
print_stack.print token, 0
|
@@ -168,17 +185,22 @@ module Oppen
|
|
168
185
|
end
|
169
186
|
end
|
170
187
|
|
171
|
-
# Handle Break
|
188
|
+
# Handle {Token::Break}.
|
172
189
|
#
|
173
|
-
# @
|
190
|
+
# @param token [Token::Break]
|
174
191
|
#
|
175
|
-
# @
|
192
|
+
# @return [Nil]
|
176
193
|
def handle_break(token)
|
177
194
|
if scan_stack.empty?
|
178
195
|
@left = 0
|
179
196
|
@left_total = 1
|
180
197
|
@right = 0
|
181
198
|
@right_total = 1
|
199
|
+
|
200
|
+
# config.trim_trailing_whitespaces.
|
201
|
+
tokens[-1] = nil
|
202
|
+
print_stack.erase @last_whitespaces_width
|
203
|
+
@last_whitespaces_width = 0
|
182
204
|
else
|
183
205
|
advance_right
|
184
206
|
end
|
@@ -189,11 +211,11 @@ module Oppen
|
|
189
211
|
@right_total += token.width
|
190
212
|
end
|
191
213
|
|
192
|
-
# Handle String
|
214
|
+
# Handle {Token::String}.
|
193
215
|
#
|
194
|
-
# @
|
216
|
+
# @param token [Token::String]
|
195
217
|
#
|
196
|
-
# @
|
218
|
+
# @return [Nil]
|
197
219
|
def handle_string(token)
|
198
220
|
if scan_stack.empty?
|
199
221
|
print_stack.print token, token.width
|
@@ -202,13 +224,13 @@ module Oppen
|
|
202
224
|
tokens[right] = token
|
203
225
|
size[right] = token.width
|
204
226
|
@right_total += token.width
|
205
|
-
check_stream
|
227
|
+
check_stream if @last_whitespaces_width.zero?
|
206
228
|
end
|
207
229
|
end
|
208
230
|
|
209
231
|
# Flushes the input if possible.
|
210
232
|
#
|
211
|
-
# @note Called CheckStream as well in the original paper.
|
233
|
+
# @note Called `CheckStream` as well in the original paper.
|
212
234
|
#
|
213
235
|
# @return [Nil]
|
214
236
|
def check_stream
|
@@ -223,9 +245,9 @@ module Oppen
|
|
223
245
|
check_stream
|
224
246
|
end
|
225
247
|
|
226
|
-
# Advances the
|
248
|
+
# Advances the {#right} pointer.
|
227
249
|
#
|
228
|
-
# @note Called AdvanceRight as well in the original paper.
|
250
|
+
# @note Called `AdvanceRight` as well in the original paper.
|
229
251
|
#
|
230
252
|
# @return [Nil]
|
231
253
|
def advance_right
|
@@ -240,16 +262,38 @@ module Oppen
|
|
240
262
|
@tokens, @left, @right = ScanStack.upsize_circular_array(@tokens, @left)
|
241
263
|
end
|
242
264
|
|
243
|
-
# Advances the
|
244
|
-
#
|
265
|
+
# Advances the {#left} pointer and lets the print stack print some of the
|
266
|
+
# tokens it contains.
|
245
267
|
#
|
246
|
-
# @note Called AdvanceLeft as well in the original paper.
|
268
|
+
# @note Called `AdvanceLeft` as well in the original paper.
|
269
|
+
#
|
270
|
+
# @param token [Token]
|
271
|
+
# @param token_width [Integer]
|
247
272
|
#
|
248
273
|
# @return [Nil]
|
249
274
|
def advance_left(token, token_width)
|
250
275
|
return if token_width.negative?
|
251
276
|
|
252
|
-
|
277
|
+
trim_on_break =
|
278
|
+
if token.is_a?(Token::Break)
|
279
|
+
# Find the first previous String token.
|
280
|
+
idx = (left - 1) % tokens.length
|
281
|
+
while idx != right && tokens[idx] && !tokens[idx].is_a?(Token::String) \
|
282
|
+
&& !tokens[idx].is_a?(Token::Break)
|
283
|
+
idx = (idx - 1) % tokens.length
|
284
|
+
end
|
285
|
+
# Sum the widths of the last whitespace tokens.
|
286
|
+
total = 0
|
287
|
+
while tokens[idx].is_a?(Token::Whitespace)
|
288
|
+
total += tokens[idx].width
|
289
|
+
idx = (idx - 1) % tokens.length
|
290
|
+
end
|
291
|
+
@last_whitespaces_width = 0
|
292
|
+
total
|
293
|
+
end
|
294
|
+
trim_on_break ||= 0
|
295
|
+
|
296
|
+
print_stack.print(token, token_width, trim_on_break: trim_on_break)
|
253
297
|
|
254
298
|
case token
|
255
299
|
when Token::Break
|
@@ -260,16 +304,17 @@ module Oppen
|
|
260
304
|
|
261
305
|
return if left == right
|
262
306
|
|
263
|
-
@left = (left + 1) %
|
307
|
+
@left = (left + 1) % tokens.length
|
264
308
|
advance_left tokens[left], size[left]
|
265
309
|
end
|
266
310
|
|
267
|
-
# Updates the size buffer taking into
|
268
|
-
#
|
311
|
+
# Updates the {#size} buffer taking into account the length of the current
|
312
|
+
# group.
|
269
313
|
#
|
270
|
-
# @note Called CheckStack as well in the original paper.
|
314
|
+
# @note Called `CheckStack` as well in the original paper.
|
271
315
|
#
|
272
|
-
# @param depth [Integer]
|
316
|
+
# @param depth [Integer]
|
317
|
+
# depth of the group.
|
273
318
|
#
|
274
319
|
# @return [Nil]
|
275
320
|
def check_stack(depth)
|
@@ -277,12 +322,12 @@ module Oppen
|
|
277
322
|
|
278
323
|
x = scan_stack.top
|
279
324
|
case tokens[x]
|
280
|
-
|
325
|
+
in Token::Begin
|
281
326
|
if depth.positive?
|
282
327
|
size[scan_stack.pop] = size[x] + right_total
|
283
328
|
check_stack depth - 1
|
284
329
|
end
|
285
|
-
|
330
|
+
in Token::End
|
286
331
|
size[scan_stack.pop] = 1
|
287
332
|
check_stack depth + 1
|
288
333
|
else
|
data/lib/oppen/scan_stack.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
#
|
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]
|
14
|
+
# @return [String]
|
28
15
|
attr_reader :value
|
29
16
|
# @return [Integer]
|
30
17
|
attr_reader :width
|
@@ -39,9 +26,21 @@ module Oppen
|
|
39
26
|
def to_s = value
|
40
27
|
end
|
41
28
|
|
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.
|
35
|
+
class Whitespace < ::Oppen::Token::String
|
36
|
+
end
|
37
|
+
|
42
38
|
# Break Token.
|
43
39
|
class Break < Token
|
44
|
-
# @return [String]
|
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`.
|
45
44
|
attr_reader :line_continuation
|
46
45
|
# @return [Integer] Indentation.
|
47
46
|
attr_reader :offset
|
@@ -50,7 +49,7 @@ module Oppen
|
|
50
49
|
# @return [Integer]
|
51
50
|
attr_reader :width
|
52
51
|
|
53
|
-
def initialize(str = ' ',
|
52
|
+
def initialize(str = ' ', line_continuation: '', offset: 0, width: str.length)
|
54
53
|
raise ArgumentError, 'line_continuation cannot be nil' if line_continuation.nil?
|
55
54
|
|
56
55
|
@line_continuation = line_continuation
|
@@ -60,6 +59,8 @@ module Oppen
|
|
60
59
|
super()
|
61
60
|
end
|
62
61
|
|
62
|
+
# Convert token to String.
|
63
|
+
#
|
63
64
|
# @return [String]
|
64
65
|
def to_s = str
|
65
66
|
end
|
@@ -73,7 +74,7 @@ module Oppen
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def initialize(line_continuation: '', offset: 0)
|
76
|
-
super(LineBreakString.new, line_continuation
|
77
|
+
super(LineBreakString.new, line_continuation: line_continuation, offset: offset)
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
@@ -81,22 +82,53 @@ module Oppen
|
|
81
82
|
class Begin < Token
|
82
83
|
# @return [BreakType]
|
83
84
|
attr_reader :break_type
|
84
|
-
# @return [Integer]
|
85
|
+
# @return [Integer]
|
85
86
|
attr_reader :offset
|
86
87
|
|
87
|
-
def initialize(break_type:
|
88
|
+
def initialize(break_type: :inconsistent, offset: 2)
|
88
89
|
@offset = offset
|
89
90
|
@break_type = break_type
|
90
91
|
super()
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
94
|
-
# End Token
|
95
|
+
# End Token.
|
95
96
|
class End < Token
|
96
97
|
nil
|
97
98
|
end
|
98
99
|
|
99
|
-
# EOF
|
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
|
100
132
|
class EOF < Token
|
101
133
|
nil
|
102
134
|
end
|