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(margin, new_line, config = Config.oppen, space = ' ', out = StringIO.new) ⇒ Printer

Note:

Called PrettyPrintInit in the original paper.

Returns a new instance of Printer.

Parameters:

  • margin (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



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/oppen/printer.rb', line 63

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

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

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



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

def config
  @config
end

#leftObject (readonly)

Note:

Called left as well in the original paper.

Ring buffer left index.



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

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.



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

def left_total
  @left_total
end
Note:

Called printStack as well in the original paper.



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

def print_stack
  @print_stack
end

#rightObject (readonly)

Note:

Called right as well in the original paper.

Ring buffer right index.



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

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.



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

def right_total
  @right_total
end

#scan_stackObject (readonly)

Note:

Called scanStack as well in the original paper.

Potential breaking positions.



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

def scan_stack
  @scan_stack
end

#sizeObject (readonly)

Note:

Called size as well in the original paper.

Size buffer, initially filled with nil.



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

def size
  @size
end

#tokensObject (readonly)

Note:

Called token in the original paper.

Token buffer, initially filled with nil.



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

def tokens
  @tokens
end

Instance Method Details

#advance_left(token, token_length) ⇒ 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)


232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/oppen/printer.rb', line 232

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

  print_stack.print token, token_length

  case token
  when Token::Break
    @left_total += token.length
  when Token::String
    @left_total += token_length
  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)


219
220
221
222
223
224
# File 'lib/oppen/printer.rb', line 219

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

  raise 'Token queue full'
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)


258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/oppen/printer.rb', line 258

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)


202
203
204
205
206
207
208
209
210
211
212
# File 'lib/oppen/printer.rb', line 202

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:



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/oppen/printer.rb', line 124

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:



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/oppen/printer.rb', line 164

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.length
end

#handle_end(token) ⇒ Nil

Handle End Token.

Returns:

  • (Nil)

See Also:



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/oppen/printer.rb', line 143

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:



111
112
113
114
115
116
117
# File 'lib/oppen/printer.rb', line 111

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:



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/oppen/printer.rb', line 185

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

#outputString

Returns:

  • (String)


80
81
82
# File 'lib/oppen/printer.rb', line 80

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)


91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/oppen/printer.rb', line 91

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