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

Returns a new instance of Statements.



9857
9858
9859
9860
9861
# File 'lib/syntax_tree/node.rb', line 9857

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



9852
9853
9854
# File 'lib/syntax_tree/node.rb', line 9852

def body
  @body
end

#commentsObject (readonly)

Array[ Comment | EmbDoc ]

the comments attached to this node



9855
9856
9857
# File 'lib/syntax_tree/node.rb', line 9855

def comments
  @comments
end

Instance Method Details

#===(other) ⇒ Object



9983
9984
9985
# File 'lib/syntax_tree/node.rb', line 9983

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

#accept(visitor) ⇒ Object



9910
9911
9912
# File 'lib/syntax_tree/node.rb', line 9910

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

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



9863
9864
9865
9866
9867
9868
9869
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887
9888
9889
9890
# File 'lib/syntax_tree/node.rb', line 9863

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



9892
9893
9894
9895
9896
9897
9898
9899
9900
9901
9902
# File 'lib/syntax_tree/node.rb', line 9892

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



9914
9915
9916
# File 'lib/syntax_tree/node.rb', line 9914

def child_nodes
  body
end

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



9918
9919
9920
9921
9922
9923
9924
9925
9926
9927
# File 'lib/syntax_tree/node.rb', line 9918

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



9931
9932
9933
# File 'lib/syntax_tree/node.rb', line 9931

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

#empty?Boolean

Returns:

  • (Boolean)


9904
9905
9906
9907
9908
# File 'lib/syntax_tree/node.rb', line 9904

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

#format(q) ⇒ Object



9935
9936
9937
9938
9939
9940
9941
9942
9943
9944
9945
9946
9947
9948
9949
9950
9951
9952
9953
9954
9955
9956
9957
9958
9959
9960
9961
9962
9963
9964
9965
9966
9967
9968
9969
9970
9971
9972
9973
9974
9975
9976
9977
9978
9979
9980
9981
# File 'lib/syntax_tree/node.rb', line 9935

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