Class: Oppen::PrintStack

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

Overview

A stack of Tokens.

Defined Under Namespace

Classes: PrintStackEntry

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(width, new_line, config, space, out) ⇒ PrintStack

Returns a new instance of PrintStack.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/oppen/print_stack.rb', line 37

def initialize(width, new_line, config, space, out)
  @buffer = out
  @config = config
  @genspace =
    if space.respond_to? :call
      raise ArgumentError, 'space argument must be a Proc of arity 1' \
        if space.to_proc.arity != 1

      space
    else
      ->(n) { space * n }
    end
  @indent = 0 # the amount of indentation to display on the next non empty new line.
  @items = []
  @new_line = new_line
  @width = width
  @space = width
end

Instance Attribute Details

#bufferObject (readonly)

IO sink for the output.



23
24
25
# File 'lib/oppen/print_stack.rb', line 23

def buffer
  @buffer
end

#configObject (readonly)

The printer's configuration, altering its behavior.



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

def config
  @config
end

#genspaceObject (readonly)

Space generator, a callable.



27
28
29
# File 'lib/oppen/print_stack.rb', line 27

def genspace
  @genspace
end

#itemsObject (readonly)

The stack of PrintStackEntries.



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

def items
  @items
end

#new_lineObject (readonly)

Delimiter between lines.



31
32
33
# File 'lib/oppen/print_stack.rb', line 31

def new_line
  @new_line
end

#spaceObject (readonly)

Current available space (index in the original paper).



33
34
35
# File 'lib/oppen/print_stack.rb', line 33

def space
  @space
end

#widthObject (readonly)

Maximum allowed width for printing (length in the original paper).



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

def width
  @width
end

Instance Method Details

#erase(count = 0) ⇒ Nil

Erase the last count characters.

Parameters:

  • count (Integer) (defaults to: 0)

Returns:

  • (Nil)

Raises:

  • (ArgumentError)


251
252
253
254
255
256
# File 'lib/oppen/print_stack.rb', line 251

def erase(count = 0)
  raise ArgumentError, "count = #{count} must be non-negative" if count.negative?

  buffer.seek(-count, IO::SEEK_CUR)
  @space += count
end

#handle_begin(token, token_width) ⇒ Nil

Handle Token::Begin.

Parameters:

  • token (Token)
  • token_width (Integer)

Returns:

  • (Nil)


96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/oppen/print_stack.rb', line 96

def handle_begin(token, token_width)
  if token_width > space
    type =
      if token.break_type == :consistent
        :consistent
      else
        :inconsistent
      end
    if config&.indent_anchor == :current_offset
      indent = token.offset
      if !items.empty?
        indent += top.offset
      end
    else
      indent = space - token.offset
    end
    push PrintStackEntry.new indent, type
  else
    push PrintStackEntry.new 0, :fits
  end
end

#handle_break(token, token_width, trim_on_break: 0) ⇒ Nil

Handle Token::Break.

Parameters:

  • token (Token::Break)
  • token_width (Integer)
  • trim_on_break (Integer) (defaults to: 0)

    number of trailing whitespace characters to trim. 0 = none.

Returns:

  • (Nil)


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/oppen/print_stack.rb', line 134

def handle_break(token, token_width, trim_on_break: 0)
  block = top
  case block.break_type
  in :fits
    # No new line is needed (the block fits on the line).
    @space -= token.width
    write token
  in :consistent
    @space = block.offset - token.offset
    indent =
      if config&.indent_anchor == :current_offset
        token.offset
      else
        width - space
      end
    erase trim_on_break
    write token.line_continuation
    print_new_line indent
  in :inconsistent
    if token_width > space
      @space = block.offset - token.offset
      indent =
        if config&.indent_anchor == :current_offset
          token.offset
        else
          width - space
        end
      erase trim_on_break
      write token.line_continuation
      print_new_line indent
    else
      @space -= token.width
      write token
    end
  end
end

#handle_endNil

Handle Token::End.

Returns:

  • (Nil)


121
122
123
# File 'lib/oppen/print_stack.rb', line 121

def handle_end
  pop
end

#handle_string(token, token_width) ⇒ Nil

Handle Token::String.

Parameters:

Returns:

  • (Nil)


177
178
179
180
181
182
183
184
185
186
# File 'lib/oppen/print_stack.rb', line 177

def handle_string(token, token_width)
  return if token.value.empty?

  @space = [0, space - token_width].max
  if @indent.positive?
    indent @indent
    @indent = 0
  end
  write token
end

#indent(amount) ⇒ Nil

Note:

Called Indent as well in the original paper.

Add indentation by amount.

Parameters:

  • amount (Integer)

Returns:

  • (Nil)


265
266
267
268
269
# File 'lib/oppen/print_stack.rb', line 265

def indent(amount)
  raise ArgumentError 'Indenting using negative amount' if amount.negative?

  write genspace.(amount) if amount.positive?
end

#outputString

The final pretty-printed output.

Returns:

  • (String)

    The output of the print stack.



60
61
62
63
# File 'lib/oppen/print_stack.rb', line 60

def output
  buffer.truncate buffer.pos
  buffer.string
end

#popPrintStackEntry

Pop a PrintStackEntry from the stack.

Returns:



200
201
202
203
204
205
206
# File 'lib/oppen/print_stack.rb', line 200

def pop
  if items.empty?
    raise 'Popping empty stack'
  end

  items.pop
end
Note:

Called Print in the original paper.

Core method responsible for building the print stack and the output string.

Parameters:

  • token (Token)
  • token_width (Integer)
  • trim_on_break (Integer) (defaults to: 0)

    number of trailing whitespace characters to trim. If zero, no character will be trimmed.

Returns:

  • (Nil)


77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/oppen/print_stack.rb', line 77

def print(token, token_width, trim_on_break: 0)
  case token
  in Token::Begin
    handle_begin token, token_width
  in Token::End
    handle_end
  in Token::Break
    handle_break token, token_width, trim_on_break:
  in Token::String
    handle_string token, token_width
  end
end
Note:

Called PrintNewLine as well in the original paper.

Add a new line to the output.

Parameters:

  • amount (Integer)

    indentation amount.

Returns:

  • (Nil)


227
228
229
230
231
232
233
234
235
# File 'lib/oppen/print_stack.rb', line 227

def print_new_line(amount)
  write new_line
  if config&.indent_anchor == :current_offset
    @space = width - top.offset - amount
    @indent = width - space
  else
    @indent = amount
  end
end

#push(print_stack_entry) ⇒ Nil

Push a PrintStackEntry into the stack.

Parameters:

Returns:

  • (Nil)


193
194
195
# File 'lib/oppen/print_stack.rb', line 193

def push(print_stack_entry)
  items.append print_stack_entry
end

#topPrintStackEntry

Get the element at the top of the stack.

Returns:



211
212
213
214
215
216
217
# File 'lib/oppen/print_stack.rb', line 211

def top
  if items.empty?
    raise 'Accessing empty stack'
  end

  items.last
end

#write(obj) ⇒ Nil

Write a string to the output.

Parameters:

  • obj (Object)

Returns:

  • (Nil)


242
243
244
# File 'lib/oppen/print_stack.rb', line 242

def write(obj)
  buffer.write obj.to_s
end