Class: Oppen::Printer

Inherits:
Object
  • Object
show all
Defined in:
lib/oppen/printer.rb

Overview

Oppen pretty-printer.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(width, new_line, config = Config.oppen, space = ' ', out = StringIO.new) ⇒ Printer

Some description

Examples:

"This is a string" # => and this is a comment
out = Oppen::Wadler.new (margin: 13) # Hawn
# Baliz
"This is a string" # => and this is a comment
# var = 12

Parameters:

  • width (Integer)

    maximum line width desired.

  • new_line (String)

    the delimiter between lines.

  • config (Config) (defaults to: Config.oppen)
  • space (String, Proc) (defaults to: ' ')

    could be a String or a callable. If it's a string, spaces will be generated with the the lambda ->(n){ n * space }, where n is the number of columns to indent. If it's a callable, it will receive n and it needs to return a string.

  • out (Object) (defaults to: StringIO.new)

    should have a write and string method



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/oppen/printer.rb', line 73

def initialize(width, new_line, config = Config.oppen,
               space = ' ', out = StringIO.new)
  # Maximum size if the stacks
  n = 3 * width

  @config = config
  @left = 0
  @left_total = 1
  @print_stack = PrintStack.new width, new_line, config, space, out
  @right = 0
  @right_total = 1
  @scan_stack = ScanStack.new n, config
  @size = Array.new n
  @tokens = Array.new n
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



13
14
15
# File 'lib/oppen/printer.rb', line 13

def config
  @config
end

#leftObject (readonly)

Note:

Called left as well in the original paper.

Ring buffer left index.



17
18
19
# File 'lib/oppen/printer.rb', line 17

def left
  @left
end

#left_totalObject (readonly)

Note:

Called leftTotal as well in the original paper.

Total number of spaces needed to print from start of buffer to the left.



22
23
24
# File 'lib/oppen/printer.rb', line 22

def left_total
  @left_total
end
Note:

Called printStack as well in the original paper.



25
26
27
# File 'lib/oppen/printer.rb', line 25

def print_stack
  @print_stack
end

#rightObject (readonly)

Note:

Called right as well in the original paper.

Ring buffer right index.



30
31
32
# File 'lib/oppen/printer.rb', line 30

def right
  @right
end

#right_totalObject (readonly)

Note:

Called leftTotal as well in the original paper.

Total number of spaces needed to print from start of buffer to the right.



35
36
37
# File 'lib/oppen/printer.rb', line 35

def right_total
  @right_total
end

#scan_stackObject (readonly)

Note:

Called scanStack as well in the original paper.

Potential breaking positions.



40
41
42
# File 'lib/oppen/printer.rb', line 40

def scan_stack
  @scan_stack
end

#sizeObject (readonly)

Note:

Called size as well in the original paper.

Size buffer, initially filled with nil.



45
46
47
# File 'lib/oppen/printer.rb', line 45

def size
  @size
end

#tokensObject (readonly)

Note:

Called token in the original paper.

Token buffer, initially filled with nil.



50
51
52
# File 'lib/oppen/printer.rb', line 50

def tokens
  @tokens
end

Instance Method Details

#advance_left(token, token_width) ⇒ Nil

Note:

Called AdvanceLeft as well in the original paper.

Advances the left pointer and lets the print stack print some of the tokens it contains.

Returns:

  • (Nil)


245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/oppen/printer.rb', line 245

def advance_left(token, token_width)
  return if token_width.negative?

  print_stack.print token, token_width

  case token
  when Token::Break
    @left_total += token.width
  when Token::String
    @left_total += token_width
  end

  return if left == right

  @left = (left + 1) % scan_stack.length
  advance_left tokens[left], size[left]
end

#advance_rightNil

Note:

Called AdvanceRight as well in the original paper.

Advances the right pointer.

Returns:

  • (Nil)


229
230
231
232
233
234
235
236
237
# File 'lib/oppen/printer.rb', line 229

def advance_right
  @right = (right + 1) % scan_stack.length
  return if right != left

  raise 'Token queue full' if !config.upsize_stack?

  @size, = Utils.upsize_circular_array(@size, @left)
  @tokens, @left, @right = Utils.upsize_circular_array(@tokens, @left)
end

#check_stack(depth) ⇒ Nil

Note:

Called CheckStack as well in the original paper.

Updates the size buffer taking into account the length of the current group.

Parameters:

  • depth (Integer)

    depth of the group

Returns:

  • (Nil)


271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/oppen/printer.rb', line 271

def check_stack(depth)
  return if scan_stack.empty?

  x = scan_stack.top
  case tokens[x]
  when Token::Begin
    if depth.positive?
      size[scan_stack.pop] = size[x] + right_total
      check_stack depth - 1
    end
  when Token::End
    size[scan_stack.pop] = 1
    check_stack depth + 1
  else
    size[scan_stack.pop] = size[x] + right_total
    if depth.positive?
      check_stack depth
    end
  end
end

#check_streamNil

Note:

Called CheckStream as well in the original paper.

Flushes the input if possible.

Returns:

  • (Nil)


212
213
214
215
216
217
218
219
220
221
222
# File 'lib/oppen/printer.rb', line 212

def check_stream
  return if right_total - left_total <= print_stack.space

  if !scan_stack.empty? && left == scan_stack.bottom
    size[scan_stack.pop_bottom] = Float::INFINITY
  end
  advance_left tokens[left], size[left]
  return if left == right

  check_stream
end

#handle_begin(token) ⇒ Nil

Handle Begin Token.

Returns:

  • (Nil)

See Also:



134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/oppen/printer.rb', line 134

def handle_begin(token)
  if scan_stack.empty?
    @left = 0
    @left_total = 1
    @right = 0
    @right_total = 1
  else
    advance_right
  end
  tokens[right] = token
  size[right] = -right_total
  scan_stack.push right
end

#handle_break(token) ⇒ Nil

Handle Break Token.

Returns:

  • (Nil)

See Also:



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/oppen/printer.rb', line 174

def handle_break(token)
  if scan_stack.empty?
    @left = 0
    @left_total = 1
    @right = 0
    @right_total = 1
  else
    advance_right
  end
  check_stack 0
  scan_stack.push right
  tokens[right] = token
  size[right] = -right_total
  @right_total += token.width
end

#handle_end(token) ⇒ Nil

Handle End Token.

Returns:

  • (Nil)

See Also:



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/oppen/printer.rb', line 153

def handle_end(token)
  if scan_stack.empty?
    print_stack.print token, 0
  else
    advance_right
    tokens[right] = token
    size[right] = -1
    scan_stack.push right
    if config&.eager_print? &&
       (!scan_stack.empty? && right_total - left_total < print_stack.space)
      check_stack 0
      advance_left tokens[left], size[left]
    end
  end
end

#handle_eofNil

Handle EOF Token.

Returns:

  • (Nil)

See Also:



121
122
123
124
125
126
127
# File 'lib/oppen/printer.rb', line 121

def handle_eof
  if !scan_stack.empty?
    check_stack 0
    advance_left tokens[left], size[left]
  end
  print_stack.indent 0
end

#handle_string(token) ⇒ Nil

Handle String Token.

Returns:

  • (Nil)

See Also:



195
196
197
198
199
200
201
202
203
204
205
# File 'lib/oppen/printer.rb', line 195

def handle_string(token)
  if scan_stack.empty?
    print_stack.print token, token.width
  else
    advance_right
    tokens[right] = token
    size[right] = token.width
    @right_total += token.width
    check_stream
  end
end

#outputString

Returns:

  • (String)


90
91
92
# File 'lib/oppen/printer.rb', line 90

def output
  print_stack.output
end
Note:

Called PrettyPrint as well in the original paper.

Core function of the algorithm responsible for populating the scan and print stack.

Parameters:

Returns:

  • (Nil)


101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/oppen/printer.rb', line 101

def print(token)
  case token
  in Token::EOF
    handle_eof
  in Token::Begin
    handle_begin token
  in Token::End
    handle_end token
  in Token::Break
    handle_break token
  in Token::String
    handle_string token
  end
end