Class: Oppen::PrintStack

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

Overview

Class that represents a stack that builds an output string using the values of the tokens that were pushed into it.

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.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/oppen/print_stack.rb', line 44

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
  @items = []
  @new_line = new_line
  @width = width
  @space = width
end

Instance Attribute Details

#bufferObject (readonly)

IO element that builds the output.



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

def buffer
  @buffer
end

#configObject (readonly)

Config containing customization flags



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

def config
  @config
end

#genspaceObject (readonly)

Callable that generate spaces



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

def genspace
  @genspace
end

#itemsObject (readonly)

Array representing the stack of PrintStackEntries.



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

def items
  @items
end

#new_lineObject (readonly)

Delimiter between lines in output



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

def new_line
  @new_line
end

#spaceInteger (readonly)

Current available space (Called index in the original paper).

Returns:

  • (Integer)

    Current available space (Called index in the original paper).



42
43
44
# File 'lib/oppen/print_stack.rb', line 42

def space
  @space
end

#widthObject (readonly)

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



37
38
39
# File 'lib/oppen/print_stack.rb', line 37

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)


258
259
260
261
262
263
# File 'lib/oppen/print_stack.rb', line 258

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 Begin Token.

Parameters:

  • token (Token)
  • token_width (Integer)

Returns:

  • (Nil)

See Also:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/oppen/print_stack.rb', line 101

def handle_begin(token, token_width)
  if token_width > space
    type =
      if token.break_type == Token::BreakType::CONSISTENT
        Token::BreakType::CONSISTENT
      else
        Token::BreakType::INCONSISTENT
      end
    if config&.indent_anchor == Config::IndentAnchor::ON_BEGIN
      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, Token::BreakType::FITS
  end
end

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

Handle Break Token.

Parameters:

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

    Number of trailing whitespace characters to trim.

Returns:

  • (Nil)

See Also:



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
170
171
172
173
174
175
# File 'lib/oppen/print_stack.rb', line 141

def handle_break(token, token_width, trim_on_break: 0)
  block = top
  case block.break_type
  in Token::BreakType::FITS
    @space -= token.width
    write token
  in Token::BreakType::CONSISTENT
    @space = block.offset - token.offset
    indent =
      if config&.indent_anchor == Config::IndentAnchor::ON_BEGIN
        token.offset
      else
        width - space
      end
    erase(trim_on_break)
    write token.line_continuation
    print_new_line indent
  in Token::BreakType::INCONSISTENT
    if token_width > space
      @space = block.offset - token.offset
      indent =
        if config&.indent_anchor == Config::IndentAnchor::ON_BEGIN
          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 End Token.

Returns:

  • (Nil)

See Also:



128
129
130
# File 'lib/oppen/print_stack.rb', line 128

def handle_end
  pop
end

#handle_string(token, token_width) ⇒ Nil

Handle String Token.

Parameters:

  • token (Token)
  • token_width (Integer)

Returns:

  • (Nil)

See Also:



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

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)


272
273
274
275
276
# File 'lib/oppen/print_stack.rb', line 272

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

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

#outputString

Returns the output of the print stack

Returns:

  • (String)


66
67
68
69
# File 'lib/oppen/print_stack.rb', line 66

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

#popPrintStackEntry

Pop a PrintStackEntry from the stack.

Returns:



208
209
210
211
212
213
214
# File 'lib/oppen/print_stack.rb', line 208

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.

Returns:

  • (Nil)


80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/oppen/print_stack.rb', line 80

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)


234
235
236
237
238
239
240
241
242
# File 'lib/oppen/print_stack.rb', line 234

def print_new_line(amount)
  write new_line
  if config&.indent_anchor == Config::IndentAnchor::ON_BEGIN
    @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)


201
202
203
# File 'lib/oppen/print_stack.rb', line 201

def push(print_stack_entry)
  items.append(print_stack_entry)
end

#topPrintStackEntry

Get the element at the top of the stack.

Returns:



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

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)


249
250
251
# File 'lib/oppen/print_stack.rb', line 249

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