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.



9889
9890
9891
9892
9893
# File 'lib/syntax_tree/node.rb', line 9889

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



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

def body
  @body
end

#commentsObject (readonly)

Array[ Comment | EmbDoc ]

the comments attached to this node



9887
9888
9889
# File 'lib/syntax_tree/node.rb', line 9887

def comments
  @comments
end

Instance Method Details

#===(other) ⇒ Object



10015
10016
10017
# File 'lib/syntax_tree/node.rb', line 10015

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

#accept(visitor) ⇒ Object



9942
9943
9944
# File 'lib/syntax_tree/node.rb', line 9942

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

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



9895
9896
9897
9898
9899
9900
9901
9902
9903
9904
9905
9906
9907
9908
9909
9910
9911
9912
9913
9914
9915
9916
9917
9918
9919
9920
9921
9922
# File 'lib/syntax_tree/node.rb', line 9895

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 (void_stmt = body[0]).is_a?(VoidStmt)
    location = void_stmt.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



9924
9925
9926
9927
9928
9929
9930
9931
9932
9933
9934
# File 'lib/syntax_tree/node.rb', line 9924

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



9946
9947
9948
# File 'lib/syntax_tree/node.rb', line 9946

def child_nodes
  body
end

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



9950
9951
9952
9953
9954
9955
9956
9957
9958
9959
# File 'lib/syntax_tree/node.rb', line 9950

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



9963
9964
9965
# File 'lib/syntax_tree/node.rb', line 9963

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

#empty?Boolean

Returns:

  • (Boolean)


9936
9937
9938
9939
9940
# File 'lib/syntax_tree/node.rb', line 9936

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

#format(q) ⇒ Object



9967
9968
9969
9970
9971
9972
9973
9974
9975
9976
9977
9978
9979
9980
9981
9982
9983
9984
9985
9986
9987
9988
9989
9990
9991
9992
9993
9994
9995
9996
9997
9998
9999
10000
10001
10002
10003
10004
10005
10006
10007
10008
10009
10010
10011
10012
10013
# File 'lib/syntax_tree/node.rb', line 9967

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