Class: SyntaxTree::Statements

Inherits:
Node
  • Object
show all
Defined in:
lib/syntax_tree/node.rb

Overview

Everything that has a block of code inside of it has a list of statements. Normally we would just track those as a node that has an array body, but we have some special handling in order to handle empty statement lists. They need to have the right location information, so all of the parent node of stmts nodes will report back down the location information. We then propagate that onto void_stmt nodes inside the stmts in order to make sure all comments get printed appropriately.

Instance Attribute Summary collapse

Attributes inherited from Node

#location

Instance Method Summary collapse

Methods inherited from Node

#construct_keys, #end_char, #pretty_print, #start_char, #to_json, #to_mermaid

Constructor Details

#initialize(body:, location:) ⇒ Statements



9826
9827
9828
9829
9830
# File 'lib/syntax_tree/node.rb', line 9826

def initialize(body:, location:)
  @body = body
  @location = location
  @comments = []
end

Instance Attribute Details

#bodyObject (readonly)

Array[ Node ]

the list of expressions contained within this node



9821
9822
9823
# File 'lib/syntax_tree/node.rb', line 9821

def body
  @body
end

#commentsObject (readonly)

Array[ Comment | EmbDoc ]

the comments attached to this node



9824
9825
9826
# File 'lib/syntax_tree/node.rb', line 9824

def comments
  @comments
end

Instance Method Details

#===(other) ⇒ Object



9952
9953
9954
# File 'lib/syntax_tree/node.rb', line 9952

def ===(other)
  other.is_a?(Statements) && ArrayMatch.call(body, other.body)
end

#accept(visitor) ⇒ Object



9879
9880
9881
# File 'lib/syntax_tree/node.rb', line 9879

def accept(visitor)
  visitor.visit_statements(self)
end

#bind(parser, start_char, start_column, end_char, end_column) ⇒ Object



9832
9833
9834
9835
9836
9837
9838
9839
9840
9841
9842
9843
9844
9845
9846
9847
9848
9849
9850
9851
9852
9853
9854
9855
9856
9857
9858
9859
# File 'lib/syntax_tree/node.rb', line 9832

def bind(parser, start_char, start_column, end_char, end_column)
  @location =
    Location.new(
      start_line: location.start_line,
      start_char: start_char,
      start_column: start_column,
      end_line: location.end_line,
      end_char: end_char,
      end_column: end_column
    )

  if body[0].is_a?(VoidStmt)
    location = body[0].location
    location =
      Location.new(
        start_line: location.start_line,
        start_char: start_char,
        start_column: start_column,
        end_line: location.end_line,
        end_char: start_char,
        end_column: end_column
      )

    body[0] = VoidStmt.new(location: location)
  end

  attach_comments(parser, start_char, end_char)
end

#bind_end(end_char, end_column) ⇒ Object



9861
9862
9863
9864
9865
9866
9867
9868
9869
9870
9871
# File 'lib/syntax_tree/node.rb', line 9861

def bind_end(end_char, end_column)
  @location =
    Location.new(
      start_line: location.start_line,
      start_char: location.start_char,
      start_column: location.start_column,
      end_line: location.end_line,
      end_char: end_char,
      end_column: end_column
    )
end

#child_nodesObject Also known as: deconstruct



9883
9884
9885
# File 'lib/syntax_tree/node.rb', line 9883

def child_nodes
  body
end

#copy(body: nil, location: nil) ⇒ Object



9887
9888
9889
9890
9891
9892
9893
9894
9895
9896
# File 'lib/syntax_tree/node.rb', line 9887

def copy(body: nil, location: nil)
  node =
    Statements.new(
      body: body || self.body,
      location: location || self.location
    )

  node.comments.concat(comments.map(&:copy))
  node
end

#deconstruct_keys(_keys) ⇒ Object



9900
9901
9902
# File 'lib/syntax_tree/node.rb', line 9900

def deconstruct_keys(_keys)
  { body: body, location: location, comments: comments }
end

#empty?Boolean



9873
9874
9875
9876
9877
# File 'lib/syntax_tree/node.rb', line 9873

def empty?
  body.all? do |statement|
    statement.is_a?(VoidStmt) && statement.comments.empty?
  end
end

#format(q) ⇒ Object



9904
9905
9906
9907
9908
9909
9910
9911
9912
9913
9914
9915
9916
9917
9918
9919
9920
9921
9922
9923
9924
9925
9926
9927
9928
9929
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939
9940
9941
9942
9943
9944
9945
9946
9947
9948
9949
9950
# File 'lib/syntax_tree/node.rb', line 9904

def format(q)
  line = nil

  # This handles a special case where you've got a block of statements where
  # the only value is a comment. In that case a lot of nodes like
  # brace_block will attempt to format as a single line, but since that
  # wouldn't work with a comment, we intentionally break the parent group.
  if body.length == 2
    void_stmt, comment = body

    if void_stmt.is_a?(VoidStmt) && comment.is_a?(Comment)
      q.format(comment)
      q.break_parent
      return
    end
  end

  previous = nil
  body.each do |statement|
    next if statement.is_a?(VoidStmt)

    if line.nil?
      q.format(statement)
    elsif (statement.location.start_line - line) > 1
      q.breakable_force
      q.breakable_force
      q.format(statement)
    elsif (statement.is_a?(VCall) && statement.access_control?) ||
          (previous.is_a?(VCall) && previous.access_control?)
      q.breakable_force
      q.breakable_force
      q.format(statement)
    elsif statement.location.start_line != line
      q.breakable_force
      q.format(statement)
    elsif !q.parent.is_a?(StringEmbExpr)
      q.breakable_force
      q.format(statement)
    else
      q.text("; ")
      q.format(statement)
    end

    line = statement.location.end_line
    previous = statement
  end
end