class Prism::Serialize::Loader

:nodoc:

def define_load_node_lambdas

def define_load_node_lambdas
  @load_node_lambdas = [
    nil,
    -> {
      location = load_location
      AliasGlobalVariableNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      AliasMethodNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      AlternationPatternNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      AndNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      ArgumentsNode.new(load_varuint, Array.new(load_varuint) { load_node }, location)
    },
    -> {
      location = load_location
      ArrayNode.new(load_varuint, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
    },
    -> {
      location = load_location
      ArrayPatternNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
    },
    -> {
      location = load_location
      AssocNode.new(load_node, load_node, load_optional_location, location)
    },
    -> {
      location = load_location
      AssocSplatNode.new(load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      BackReferenceReadNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      BeginNode.new(load_optional_location, load_optional_node, load_optional_node, load_optional_node, load_optional_node, load_optional_location, location)
    },
    -> {
      location = load_location
      BlockArgumentNode.new(load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      BlockLocalVariableNode.new(load_varuint, load_required_constant, location)
    },
    -> {
      location = load_location
      BlockNode.new(Array.new(load_varuint) { load_required_constant }, load_optional_node, load_optional_node, load_location, load_location, location)
    },
    -> {
      location = load_location
      BlockParameterNode.new(load_varuint, load_optional_constant, load_optional_location, load_location, location)
    },
    -> {
      location = load_location
      BlockParametersNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
    },
    -> {
      location = load_location
      BreakNode.new(load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      CallAndWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_optional_location, load_required_constant, load_required_constant, load_location, load_node, location)
    },
    -> {
      location = load_location
      CallNode.new(load_varuint, load_optional_node, load_optional_location, load_required_constant, load_optional_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, location)
    },
    -> {
      location = load_location
      CallOperatorWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_optional_location, load_required_constant, load_required_constant, load_required_constant, load_location, load_node, location)
    },
    -> {
      location = load_location
      CallOrWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_optional_location, load_required_constant, load_required_constant, load_location, load_node, location)
    },
    -> {
      location = load_location
      CallTargetNode.new(load_varuint, load_node, load_location, load_required_constant, load_location, location)
    },
    -> {
      location = load_location
      CapturePatternNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      CaseMatchNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, load_location, load_location, location)
    },
    -> {
      location = load_location
      CaseNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, load_location, load_location, location)
    },
    -> {
      location = load_location
      ClassNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_location, load_required_constant, location)
    },
    -> {
      location = load_location
      ClassVariableAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      ClassVariableOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
    },
    -> {
      location = load_location
      ClassVariableOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      ClassVariableReadNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      ClassVariableTargetNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      ClassVariableWriteNode.new(load_required_constant, load_location, load_node, load_optional_location, location)
    },
    -> {
      location = load_location
      ConstantAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      ConstantOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
    },
    -> {
      location = load_location
      ConstantOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      ConstantPathAndWriteNode.new(load_node, load_location, load_node, location)
    },
    -> {
      location = load_location
      ConstantPathNode.new(load_optional_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      ConstantPathOperatorWriteNode.new(load_node, load_location, load_node, load_required_constant, location)
    },
    -> {
      location = load_location
      ConstantPathOrWriteNode.new(load_node, load_location, load_node, location)
    },
    -> {
      location = load_location
      ConstantPathTargetNode.new(load_optional_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      ConstantPathWriteNode.new(load_node, load_location, load_node, location)
    },
    -> {
      location = load_location
      ConstantReadNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      ConstantTargetNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      ConstantWriteNode.new(load_required_constant, load_location, load_node, load_location, location)
    },
    -> {
      location = load_location
      load_serialized_length
      DefNode.new(load_required_constant, load_location, load_optional_node, load_optional_node, load_optional_node, Array.new(load_varuint) { load_required_constant }, load_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, location)
    },
    -> {
      location = load_location
      DefinedNode.new(load_optional_location, load_node, load_optional_location, load_location, location)
    },
    -> {
      location = load_location
      ElseNode.new(load_location, load_optional_node, load_optional_location, location)
    },
    -> {
      location = load_location
      EmbeddedStatementsNode.new(load_location, load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      EmbeddedVariableNode.new(load_location, load_node, location)
    },
    -> {
      location = load_location
      EnsureNode.new(load_location, load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      FalseNode.new(location)
    },
    -> {
      location = load_location
      FindPatternNode.new(load_optional_node, load_node, Array.new(load_varuint) { load_node }, load_node, load_optional_location, load_optional_location, location)
    },
    -> {
      location = load_location
      FlipFlopNode.new(load_varuint, load_optional_node, load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      FloatNode.new(location)
    },
    -> {
      location = load_location
      ForNode.new(load_node, load_node, load_optional_node, load_location, load_location, load_optional_location, load_location, location)
    },
    -> {
      location = load_location
      ForwardingArgumentsNode.new(location)
    },
    -> {
      location = load_location
      ForwardingParameterNode.new(location)
    },
    -> {
      location = load_location
      ForwardingSuperNode.new(load_optional_node, location)
    },
    -> {
      location = load_location
      GlobalVariableAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      GlobalVariableOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
    },
    -> {
      location = load_location
      GlobalVariableOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      GlobalVariableReadNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      GlobalVariableTargetNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      GlobalVariableWriteNode.new(load_required_constant, load_location, load_node, load_location, location)
    },
    -> {
      location = load_location
      HashNode.new(load_location, Array.new(load_varuint) { load_node }, load_location, location)
    },
    -> {
      location = load_location
      HashPatternNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, load_optional_location, load_optional_location, location)
    },
    -> {
      location = load_location
      IfNode.new(load_optional_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_optional_location, location)
    },
    -> {
      location = load_location
      ImaginaryNode.new(load_node, location)
    },
    -> {
      location = load_location
      ImplicitNode.new(load_node, location)
    },
    -> {
      location = load_location
      ImplicitRestNode.new(location)
    },
    -> {
      location = load_location
      InNode.new(load_node, load_optional_node, load_location, load_optional_location, location)
    },
    -> {
      location = load_location
      IndexAndWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_location, load_optional_node, load_location, load_optional_node, load_location, load_node, location)
    },
    -> {
      location = load_location
      IndexOperatorWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_location, load_optional_node, load_location, load_optional_node, load_required_constant, load_location, load_node, location)
    },
    -> {
      location = load_location
      IndexOrWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_location, load_optional_node, load_location, load_optional_node, load_location, load_node, location)
    },
    -> {
      location = load_location
      IndexTargetNode.new(load_varuint, load_node, load_location, load_optional_node, load_location, load_optional_node, location)
    },
    -> {
      location = load_location
      InstanceVariableAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      InstanceVariableOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
    },
    -> {
      location = load_location
      InstanceVariableOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      InstanceVariableReadNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      InstanceVariableTargetNode.new(load_required_constant, location)
    },
    -> {
      location = load_location
      InstanceVariableWriteNode.new(load_required_constant, load_location, load_node, load_location, location)
    },
    -> {
      location = load_location
      IntegerNode.new(load_varuint, location)
    },
    -> {
      location = load_location
      InterpolatedMatchLastLineNode.new(load_varuint, load_location, Array.new(load_varuint) { load_node }, load_location, location)
    },
    -> {
      location = load_location
      InterpolatedRegularExpressionNode.new(load_varuint, load_location, Array.new(load_varuint) { load_node }, load_location, location)
    },
    -> {
      location = load_location
      InterpolatedStringNode.new(load_optional_location, Array.new(load_varuint) { load_node }, load_optional_location, location)
    },
    -> {
      location = load_location
      InterpolatedSymbolNode.new(load_optional_location, Array.new(load_varuint) { load_node }, load_optional_location, location)
    },
    -> {
      location = load_location
      InterpolatedXStringNode.new(load_location, Array.new(load_varuint) { load_node }, load_location, location)
    },
    -> {
      location = load_location
      KeywordHashNode.new(load_varuint, Array.new(load_varuint) { load_node }, location)
    },
    -> {
      location = load_location
      KeywordRestParameterNode.new(load_varuint, load_optional_constant, load_optional_location, load_location, location)
    },
    -> {
      location = load_location
      LambdaNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_location, load_location, load_optional_node, load_optional_node, location)
    },
    -> {
      location = load_location
      LocalVariableAndWriteNode.new(load_location, load_location, load_node, load_required_constant, load_varuint, location)
    },
    -> {
      location = load_location
      LocalVariableOperatorWriteNode.new(load_location, load_location, load_node, load_required_constant, load_required_constant, load_varuint, location)
    },
    -> {
      location = load_location
      LocalVariableOrWriteNode.new(load_location, load_location, load_node, load_required_constant, load_varuint, location)
    },
    -> {
      location = load_location
      LocalVariableReadNode.new(load_required_constant, load_varuint, location)
    },
    -> {
      location = load_location
      LocalVariableTargetNode.new(load_required_constant, load_varuint, location)
    },
    -> {
      location = load_location
      LocalVariableWriteNode.new(load_required_constant, load_varuint, load_location, load_node, load_location, location)
    },
    -> {
      location = load_location
      MatchLastLineNode.new(load_varuint, load_location, load_location, load_location, load_string, location)
    },
    -> {
      location = load_location
      MatchPredicateNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      MatchRequiredNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      MatchWriteNode.new(load_node, Array.new(load_varuint) { load_node }, location)
    },
    -> {
      location = load_location
      MissingNode.new(location)
    },
    -> {
      location = load_location
      ModuleNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_node, load_optional_node, load_location, load_required_constant, location)
    },
    -> {
      location = load_location
      MultiTargetNode.new(Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
    },
    -> {
      location = load_location
      MultiWriteNode.new(Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      NextNode.new(load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      NilNode.new(location)
    },
    -> {
      location = load_location
      NoKeywordsParameterNode.new(load_location, load_location, location)
    },
    -> {
      location = load_location
      NumberedParametersNode.new(io.getbyte, location)
    },
    -> {
      location = load_location
      NumberedReferenceReadNode.new(load_varuint, location)
    },
    -> {
      location = load_location
      OptionalKeywordParameterNode.new(load_varuint, load_required_constant, load_location, load_node, location)
    },
    -> {
      location = load_location
      OptionalParameterNode.new(load_varuint, load_required_constant, load_location, load_location, load_node, location)
    },
    -> {
      location = load_location
      OrNode.new(load_node, load_node, load_location, location)
    },
    -> {
      location = load_location
      ParametersNode.new(Array.new(load_varuint) { load_node }, Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, Array.new(load_varuint) { load_node }, load_optional_node, load_optional_node, location)
    },
    -> {
      location = load_location
      ParenthesesNode.new(load_optional_node, load_location, load_location, location)
    },
    -> {
      location = load_location
      PinnedExpressionNode.new(load_node, load_location, load_location, load_location, location)
    },
    -> {
      location = load_location
      PinnedVariableNode.new(load_node, load_location, location)
    },
    -> {
      location = load_location
      PostExecutionNode.new(load_optional_node, load_location, load_location, load_location, location)
    },
    -> {
      location = load_location
      PreExecutionNode.new(load_optional_node, load_location, load_location, load_location, location)
    },
    -> {
      location = load_location
      ProgramNode.new(Array.new(load_varuint) { load_required_constant }, load_node, location)
    },
    -> {
      location = load_location
      RangeNode.new(load_varuint, load_optional_node, load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      RationalNode.new(load_node, location)
    },
    -> {
      location = load_location
      RedoNode.new(location)
    },
    -> {
      location = load_location
      RegularExpressionNode.new(load_varuint, load_location, load_location, load_location, load_string, location)
    },
    -> {
      location = load_location
      RequiredKeywordParameterNode.new(load_varuint, load_required_constant, load_location, location)
    },
    -> {
      location = load_location
      RequiredParameterNode.new(load_varuint, load_required_constant, location)
    },
    -> {
      location = load_location
      RescueModifierNode.new(load_node, load_location, load_node, location)
    },
    -> {
      location = load_location
      RescueNode.new(load_location, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_node, load_optional_node, load_optional_node, location)
    },
    -> {
      location = load_location
      RestParameterNode.new(load_varuint, load_optional_constant, load_optional_location, load_location, location)
    },
    -> {
      location = load_location
      RetryNode.new(location)
    },
    -> {
      location = load_location
      ReturnNode.new(load_location, load_optional_node, location)
    },
    -> {
      location = load_location
      SelfNode.new(location)
    },
    -> {
      location = load_location
      SingletonClassNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_location, load_node, load_optional_node, load_location, location)
    },
    -> {
      location = load_location
      SourceEncodingNode.new(location)
    },
    -> {
      location = load_location
      SourceFileNode.new(load_string, location)
    },
    -> {
      location = load_location
      SourceLineNode.new(location)
    },
    -> {
      location = load_location
      SplatNode.new(load_location, load_optional_node, location)
    },
    -> {
      location = load_location
      StatementsNode.new(Array.new(load_varuint) { load_node }, location)
    },
    -> {
      location = load_location
      StringNode.new(load_varuint, load_optional_location, load_location, load_optional_location, load_string, location)
    },
    -> {
      location = load_location
      SuperNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, location)
    },
    -> {
      location = load_location
      SymbolNode.new(load_varuint, load_optional_location, load_optional_location, load_optional_location, load_string, location)
    },
    -> {
      location = load_location
      TrueNode.new(location)
    },
    -> {
      location = load_location
      UndefNode.new(Array.new(load_varuint) { load_node }, load_location, location)
    },
    -> {
      location = load_location
      UnlessNode.new(load_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_optional_location, location)
    },
    -> {
      location = load_location
      UntilNode.new(load_varuint, load_location, load_optional_location, load_node, load_optional_node, location)
    },
    -> {
      location = load_location
      WhenNode.new(load_location, Array.new(load_varuint) { load_node }, load_optional_node, location)
    },
    -> {
      location = load_location
      WhileNode.new(load_varuint, load_location, load_optional_location, load_node, load_optional_node, location)
    },
    -> {
      location = load_location
      XStringNode.new(load_varuint, load_location, load_location, load_location, load_string, location)
    },
    -> {
      location = load_location
      YieldNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, location)
    },
  ]
end

def initialize(source, serialized)

def initialize(source, serialized)
  @encoding = Encoding::UTF_8
  @input = source.source.dup
  @serialized = serialized
  @io = StringIO.new(serialized)
  @io.set_encoding(Encoding::BINARY)
  @constant_pool_offset = nil
  @constant_pool = nil
  @source = source
  define_load_node_lambdas unless RUBY_ENGINE == "ruby"
end

def load_comments

def load_comments
  load_varuint.times.map do
    case load_varuint
    when 0 then InlineComment.new(load_location)
    when 1 then EmbDocComment.new(load_location)
    when 2 then DATAComment.new(load_location)
    end
  end
end

def load_constant(index)

def load_constant(index)
  constant = constant_pool[index]
  unless constant
    offset = constant_pool_offset + index * 8
    start = serialized.unpack1("L", offset: offset)
    length = serialized.unpack1("L", offset: offset + 4)
    constant =
      if start.nobits?(1 << 31)
        input.byteslice(start, length).force_encoding(@encoding).to_sym
      else
        serialized.byteslice(start & ((1 << 31) - 1), length).force_encoding(@encoding).to_sym
      end
    constant_pool[index] = constant
  end
  constant
end

def load_embedded_string

def load_embedded_string
  io.read(load_varuint).force_encoding(encoding)
end

def load_encoding

def load_encoding
  @encoding = Encoding.find(io.read(load_varuint))
  @input = input.force_encoding(@encoding).freeze
  @encoding
end

def load_error_level

def load_error_level
  level = io.getbyte
  case level
  when 0
    :fatal
  when 1
    :argument
  else
    raise "Unknown level: #{level}"
  end
end

def load_header

def load_header
  raise "Invalid serialization" if io.read(5) != "PRISM"
  raise "Invalid serialization" if io.read(3).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
  only_semantic_fields = io.read(1).unpack1("C")
  unless only_semantic_fields == 0
    raise "Invalid serialization (location fields must be included but are not)"
  end
end

def load_location

def load_location
  Location.new(source, load_varuint, load_varuint)
end

def load_metadata

def load_metadata
  comments = load_comments
  magic_comments = load_varuint.times.map { MagicComment.new(load_location, load_location) }
  data_loc = load_optional_location
  errors = load_varuint.times.map { ParseError.new(load_embedded_string, load_location, load_error_level) }
  warnings = load_varuint.times.map { ParseWarning.new(load_embedded_string, load_location, load_warning_level) }
  [comments, magic_comments, data_loc, errors, warnings]
end

def load_node

def load_node
  type = io.getbyte
  location = load_location
  case type
  when 1 then
    AliasGlobalVariableNode.new(load_node, load_node, load_location, location)
  when 2 then
    AliasMethodNode.new(load_node, load_node, load_location, location)
  when 3 then
    AlternationPatternNode.new(load_node, load_node, load_location, location)
  when 4 then
    AndNode.new(load_node, load_node, load_location, location)
  when 5 then
    ArgumentsNode.new(load_varuint, Array.new(load_varuint) { load_node }, location)
  when 6 then
    ArrayNode.new(load_varuint, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
  when 7 then
    ArrayPatternNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
  when 8 then
    AssocNode.new(load_node, load_node, load_optional_location, location)
  when 9 then
    AssocSplatNode.new(load_optional_node, load_location, location)
  when 10 then
    BackReferenceReadNode.new(load_required_constant, location)
  when 11 then
    BeginNode.new(load_optional_location, load_optional_node, load_optional_node, load_optional_node, load_optional_node, load_optional_location, location)
  when 12 then
    BlockArgumentNode.new(load_optional_node, load_location, location)
  when 13 then
    BlockLocalVariableNode.new(load_varuint, load_required_constant, location)
  when 14 then
    BlockNode.new(Array.new(load_varuint) { load_required_constant }, load_optional_node, load_optional_node, load_location, load_location, location)
  when 15 then
    BlockParameterNode.new(load_varuint, load_optional_constant, load_optional_location, load_location, location)
  when 16 then
    BlockParametersNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
  when 17 then
    BreakNode.new(load_optional_node, load_location, location)
  when 18 then
    CallAndWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_optional_location, load_required_constant, load_required_constant, load_location, load_node, location)
  when 19 then
    CallNode.new(load_varuint, load_optional_node, load_optional_location, load_required_constant, load_optional_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, location)
  when 20 then
    CallOperatorWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_optional_location, load_required_constant, load_required_constant, load_required_constant, load_location, load_node, location)
  when 21 then
    CallOrWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_optional_location, load_required_constant, load_required_constant, load_location, load_node, location)
  when 22 then
    CallTargetNode.new(load_varuint, load_node, load_location, load_required_constant, load_location, location)
  when 23 then
    CapturePatternNode.new(load_node, load_node, load_location, location)
  when 24 then
    CaseMatchNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, load_location, load_location, location)
  when 25 then
    CaseNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, load_location, load_location, location)
  when 26 then
    ClassNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_location, load_required_constant, location)
  when 27 then
    ClassVariableAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 28 then
    ClassVariableOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
  when 29 then
    ClassVariableOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 30 then
    ClassVariableReadNode.new(load_required_constant, location)
  when 31 then
    ClassVariableTargetNode.new(load_required_constant, location)
  when 32 then
    ClassVariableWriteNode.new(load_required_constant, load_location, load_node, load_optional_location, location)
  when 33 then
    ConstantAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 34 then
    ConstantOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
  when 35 then
    ConstantOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 36 then
    ConstantPathAndWriteNode.new(load_node, load_location, load_node, location)
  when 37 then
    ConstantPathNode.new(load_optional_node, load_node, load_location, location)
  when 38 then
    ConstantPathOperatorWriteNode.new(load_node, load_location, load_node, load_required_constant, location)
  when 39 then
    ConstantPathOrWriteNode.new(load_node, load_location, load_node, location)
  when 40 then
    ConstantPathTargetNode.new(load_optional_node, load_node, load_location, location)
  when 41 then
    ConstantPathWriteNode.new(load_node, load_location, load_node, location)
  when 42 then
    ConstantReadNode.new(load_required_constant, location)
  when 43 then
    ConstantTargetNode.new(load_required_constant, location)
  when 44 then
    ConstantWriteNode.new(load_required_constant, load_location, load_node, load_location, location)
  when 45 then
    load_serialized_length
    DefNode.new(load_required_constant, load_location, load_optional_node, load_optional_node, load_optional_node, Array.new(load_varuint) { load_required_constant }, load_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, location)
  when 46 then
    DefinedNode.new(load_optional_location, load_node, load_optional_location, load_location, location)
  when 47 then
    ElseNode.new(load_location, load_optional_node, load_optional_location, location)
  when 48 then
    EmbeddedStatementsNode.new(load_location, load_optional_node, load_location, location)
  when 49 then
    EmbeddedVariableNode.new(load_location, load_node, location)
  when 50 then
    EnsureNode.new(load_location, load_optional_node, load_location, location)
  when 51 then
    FalseNode.new(location)
  when 52 then
    FindPatternNode.new(load_optional_node, load_node, Array.new(load_varuint) { load_node }, load_node, load_optional_location, load_optional_location, location)
  when 53 then
    FlipFlopNode.new(load_varuint, load_optional_node, load_optional_node, load_location, location)
  when 54 then
    FloatNode.new(location)
  when 55 then
    ForNode.new(load_node, load_node, load_optional_node, load_location, load_location, load_optional_location, load_location, location)
  when 56 then
    ForwardingArgumentsNode.new(location)
  when 57 then
    ForwardingParameterNode.new(location)
  when 58 then
    ForwardingSuperNode.new(load_optional_node, location)
  when 59 then
    GlobalVariableAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 60 then
    GlobalVariableOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
  when 61 then
    GlobalVariableOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 62 then
    GlobalVariableReadNode.new(load_required_constant, location)
  when 63 then
    GlobalVariableTargetNode.new(load_required_constant, location)
  when 64 then
    GlobalVariableWriteNode.new(load_required_constant, load_location, load_node, load_location, location)
  when 65 then
    HashNode.new(load_location, Array.new(load_varuint) { load_node }, load_location, location)
  when 66 then
    HashPatternNode.new(load_optional_node, Array.new(load_varuint) { load_node }, load_optional_node, load_optional_location, load_optional_location, location)
  when 67 then
    IfNode.new(load_optional_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_optional_location, location)
  when 68 then
    ImaginaryNode.new(load_node, location)
  when 69 then
    ImplicitNode.new(load_node, location)
  when 70 then
    ImplicitRestNode.new(location)
  when 71 then
    InNode.new(load_node, load_optional_node, load_location, load_optional_location, location)
  when 72 then
    IndexAndWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_location, load_optional_node, load_location, load_optional_node, load_location, load_node, location)
  when 73 then
    IndexOperatorWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_location, load_optional_node, load_location, load_optional_node, load_required_constant, load_location, load_node, location)
  when 74 then
    IndexOrWriteNode.new(load_varuint, load_optional_node, load_optional_location, load_location, load_optional_node, load_location, load_optional_node, load_location, load_node, location)
  when 75 then
    IndexTargetNode.new(load_varuint, load_node, load_location, load_optional_node, load_location, load_optional_node, location)
  when 76 then
    InstanceVariableAndWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 77 then
    InstanceVariableOperatorWriteNode.new(load_required_constant, load_location, load_location, load_node, load_required_constant, location)
  when 78 then
    InstanceVariableOrWriteNode.new(load_required_constant, load_location, load_location, load_node, location)
  when 79 then
    InstanceVariableReadNode.new(load_required_constant, location)
  when 80 then
    InstanceVariableTargetNode.new(load_required_constant, location)
  when 81 then
    InstanceVariableWriteNode.new(load_required_constant, load_location, load_node, load_location, location)
  when 82 then
    IntegerNode.new(load_varuint, location)
  when 83 then
    InterpolatedMatchLastLineNode.new(load_varuint, load_location, Array.new(load_varuint) { load_node }, load_location, location)
  when 84 then
    InterpolatedRegularExpressionNode.new(load_varuint, load_location, Array.new(load_varuint) { load_node }, load_location, location)
  when 85 then
    InterpolatedStringNode.new(load_optional_location, Array.new(load_varuint) { load_node }, load_optional_location, location)
  when 86 then
    InterpolatedSymbolNode.new(load_optional_location, Array.new(load_varuint) { load_node }, load_optional_location, location)
  when 87 then
    InterpolatedXStringNode.new(load_location, Array.new(load_varuint) { load_node }, load_location, location)
  when 88 then
    KeywordHashNode.new(load_varuint, Array.new(load_varuint) { load_node }, location)
  when 89 then
    KeywordRestParameterNode.new(load_varuint, load_optional_constant, load_optional_location, load_location, location)
  when 90 then
    LambdaNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_location, load_location, load_optional_node, load_optional_node, location)
  when 91 then
    LocalVariableAndWriteNode.new(load_location, load_location, load_node, load_required_constant, load_varuint, location)
  when 92 then
    LocalVariableOperatorWriteNode.new(load_location, load_location, load_node, load_required_constant, load_required_constant, load_varuint, location)
  when 93 then
    LocalVariableOrWriteNode.new(load_location, load_location, load_node, load_required_constant, load_varuint, location)
  when 94 then
    LocalVariableReadNode.new(load_required_constant, load_varuint, location)
  when 95 then
    LocalVariableTargetNode.new(load_required_constant, load_varuint, location)
  when 96 then
    LocalVariableWriteNode.new(load_required_constant, load_varuint, load_location, load_node, load_location, location)
  when 97 then
    MatchLastLineNode.new(load_varuint, load_location, load_location, load_location, load_string, location)
  when 98 then
    MatchPredicateNode.new(load_node, load_node, load_location, location)
  when 99 then
    MatchRequiredNode.new(load_node, load_node, load_location, location)
  when 100 then
    MatchWriteNode.new(load_node, Array.new(load_varuint) { load_node }, location)
  when 101 then
    MissingNode.new(location)
  when 102 then
    ModuleNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_node, load_optional_node, load_location, load_required_constant, location)
  when 103 then
    MultiTargetNode.new(Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, location)
  when 104 then
    MultiWriteNode.new(Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_location, load_location, load_node, location)
  when 105 then
    NextNode.new(load_optional_node, load_location, location)
  when 106 then
    NilNode.new(location)
  when 107 then
    NoKeywordsParameterNode.new(load_location, load_location, location)
  when 108 then
    NumberedParametersNode.new(io.getbyte, location)
  when 109 then
    NumberedReferenceReadNode.new(load_varuint, location)
  when 110 then
    OptionalKeywordParameterNode.new(load_varuint, load_required_constant, load_location, load_node, location)
  when 111 then
    OptionalParameterNode.new(load_varuint, load_required_constant, load_location, load_location, load_node, location)
  when 112 then
    OrNode.new(load_node, load_node, load_location, location)
  when 113 then
    ParametersNode.new(Array.new(load_varuint) { load_node }, Array.new(load_varuint) { load_node }, load_optional_node, Array.new(load_varuint) { load_node }, Array.new(load_varuint) { load_node }, load_optional_node, load_optional_node, location)
  when 114 then
    ParenthesesNode.new(load_optional_node, load_location, load_location, location)
  when 115 then
    PinnedExpressionNode.new(load_node, load_location, load_location, load_location, location)
  when 116 then
    PinnedVariableNode.new(load_node, load_location, location)
  when 117 then
    PostExecutionNode.new(load_optional_node, load_location, load_location, load_location, location)
  when 118 then
    PreExecutionNode.new(load_optional_node, load_location, load_location, load_location, location)
  when 119 then
    ProgramNode.new(Array.new(load_varuint) { load_required_constant }, load_node, location)
  when 120 then
    RangeNode.new(load_varuint, load_optional_node, load_optional_node, load_location, location)
  when 121 then
    RationalNode.new(load_node, location)
  when 122 then
    RedoNode.new(location)
  when 123 then
    RegularExpressionNode.new(load_varuint, load_location, load_location, load_location, load_string, location)
  when 124 then
    RequiredKeywordParameterNode.new(load_varuint, load_required_constant, load_location, location)
  when 125 then
    RequiredParameterNode.new(load_varuint, load_required_constant, location)
  when 126 then
    RescueModifierNode.new(load_node, load_location, load_node, location)
  when 127 then
    RescueNode.new(load_location, Array.new(load_varuint) { load_node }, load_optional_location, load_optional_node, load_optional_node, load_optional_node, location)
  when 128 then
    RestParameterNode.new(load_varuint, load_optional_constant, load_optional_location, load_location, location)
  when 129 then
    RetryNode.new(location)
  when 130 then
    ReturnNode.new(load_location, load_optional_node, location)
  when 131 then
    SelfNode.new(location)
  when 132 then
    SingletonClassNode.new(Array.new(load_varuint) { load_required_constant }, load_location, load_location, load_node, load_optional_node, load_location, location)
  when 133 then
    SourceEncodingNode.new(location)
  when 134 then
    SourceFileNode.new(load_string, location)
  when 135 then
    SourceLineNode.new(location)
  when 136 then
    SplatNode.new(load_location, load_optional_node, location)
  when 137 then
    StatementsNode.new(Array.new(load_varuint) { load_node }, location)
  when 138 then
    StringNode.new(load_varuint, load_optional_location, load_location, load_optional_location, load_string, location)
  when 139 then
    SuperNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, location)
  when 140 then
    SymbolNode.new(load_varuint, load_optional_location, load_optional_location, load_optional_location, load_string, location)
  when 141 then
    TrueNode.new(location)
  when 142 then
    UndefNode.new(Array.new(load_varuint) { load_node }, load_location, location)
  when 143 then
    UnlessNode.new(load_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_optional_location, location)
  when 144 then
    UntilNode.new(load_varuint, load_location, load_optional_location, load_node, load_optional_node, location)
  when 145 then
    WhenNode.new(load_location, Array.new(load_varuint) { load_node }, load_optional_node, location)
  when 146 then
    WhileNode.new(load_varuint, load_location, load_optional_location, load_node, load_optional_node, location)
  when 147 then
    XStringNode.new(load_varuint, load_location, load_location, load_location, load_string, location)
  when 148 then
    YieldNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, location)
  end
end

def load_node

def load_node
  type = io.getbyte
  @load_node_lambdas[type].call
end

def load_nodes

def load_nodes
  load_header
  load_encoding
  load_start_line
  comments, magic_comments, data_loc, errors, warnings = load_metadata
  @constant_pool_offset = io.read(4).unpack1("L")
  @constant_pool = Array.new(load_varuint, nil)
  [load_node, comments, magic_comments, data_loc, errors, warnings]
end

def load_optional_constant

def load_optional_constant
  index = load_varuint
  load_constant(index - 1) if index != 0
end

def load_optional_location

def load_optional_location
  load_location if io.getbyte != 0
end

def load_optional_node

def load_optional_node
  if io.getbyte != 0
    io.pos -= 1
    load_node
  end
end

def load_required_constant

def load_required_constant
  load_constant(load_varuint - 1)
end

def load_result

def load_result
  node, comments, magic_comments, data_loc, errors, warnings = load_nodes
  Prism::ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, @source)
end

def load_serialized_length

def load_serialized_length
  io.read(4).unpack1("L")
end

def load_start_line

def load_start_line
  source.start_line = load_varsint
end

def load_string

def load_string
  type = io.getbyte
  case type
  when 1
    input.byteslice(load_varuint, load_varuint).force_encoding(encoding)
  when 2
    load_embedded_string
  else
    raise "Unknown serialized string type: #{type}"
  end
end

def load_tokens

def load_tokens
  tokens = []
  while type = TOKEN_TYPES.fetch(load_varuint)
    start = load_varuint
    length = load_varuint
    lex_state = load_varuint
    location = Location.new(@source, start, length)
    tokens << [Prism::Token.new(type, location.slice, location), lex_state]
  end
  tokens
end

def load_tokens_result

def load_tokens_result
  tokens = load_tokens
  encoding = load_encoding
  load_start_line
  comments, magic_comments, data_loc, errors, warnings = load_metadata
  tokens.each { |token,| token.value.force_encoding(encoding) }
  raise "Expected to consume all bytes while deserializing" unless @io.eof?
  Prism::ParseResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, @source)
end

def load_varsint

def load_varsint
  n = load_varuint
  (n >> 1) ^ (-(n & 1))
end

def load_varuint

This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints
variable-length integer using https://en.wikipedia.org/wiki/LEB128
def load_varuint
  n = io.getbyte
  if n < 128
    n
  else
    n -= 128
    shift = 0
    while (b = io.getbyte) >= 128
      n += (b - 128) << (shift += 7)
    end
    n + (b << (shift + 7))
  end
end

def load_warning_level

def load_warning_level
  level = io.getbyte
  case level
  when 0
    :default
  when 1
    :verbose
  else
    raise "Unknown level: #{level}"
  end
end