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.



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

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



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

def body
  @body
end

#commentsObject (readonly)

Array[ Comment | EmbDoc ]

the comments attached to this node



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

def comments
  @comments
end

Instance Method Details

#===(other) ⇒ Object



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

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

#accept(visitor) ⇒ Object



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

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

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



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
9923
# File 'lib/syntax_tree/node.rb', line 9896

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



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

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



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

def child_nodes
  body
end

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



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

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



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

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

#empty?Boolean

Returns:

  • (Boolean)


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

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

#format(q) ⇒ Object



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
10014
# File 'lib/syntax_tree/node.rb', line 9968

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