# frozen_string_literal: true
=begin
This file is generated by the bin/template script and should not be
modified manually. See templates/lib/yarp/serialize.rb.erb
if you are looking to modify the template
=end

require "stringio"

# Polyfill for String#unpack1 with the offset parameter.
if String.instance_method(:unpack1).parameters.none? { |_, name| name == :offset }
  String.prepend(
    Module.new {
      def unpack1(format, offset: 0)
        offset == 0 ? super(format) : self[offset..].unpack1(format)
      end
    }
  )
end

module YARP
  module Serialize
    MAJOR_VERSION = 0
    MINOR_VERSION = 7
    PATCH_VERSION = 0

    def self.load(input, serialized)
      Loader.new(Source.new(input), serialized).load
    end

    def self.load_tokens(source, serialized)
      Loader.new(source, serialized).load_tokens
    end

    class Loader
      attr_reader :encoding, :input, :serialized, :io
      attr_reader :constant_pool_offset, :constant_pool, :source

      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
      end

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

        comments = load_varint.times.map { Comment.new(Comment::TYPES.fetch(load_varint), load_location) }
        errors = load_varint.times.map { ParseError.new(load_string, load_location) }
        warnings = load_varint.times.map { ParseWarning.new(load_string, load_location) }

        raise "Expected to consume all bytes while deserializing" unless @io.eof?

        YARP::ParseResult.new(tokens, comments, errors, warnings, @source)
      end

      def load
        raise "Invalid serialization" if io.read(4) != "YARP"
        raise "Invalid serialization" if io.read(3).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]

        @encoding = Encoding.find(io.read(load_varint))
        @input = input.force_encoding(@encoding).freeze

        comments = load_varint.times.map { Comment.new(Comment::TYPES.fetch(io.getbyte), load_location) }
        errors = load_varint.times.map { ParseError.new(load_string, load_location) }
        warnings = load_varint.times.map { ParseWarning.new(load_string, load_location) }

        @constant_pool_offset = io.read(4).unpack1("L")
        @constant_pool = Array.new(load_varint, nil)

        ast = load_node

        YARP::ParseResult.new(ast, comments, errors, warnings, @source)
      end

      private

      # variable-length integer using https://en.wikipedia.org/wiki/LEB128
      # This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints
      def load_varint
        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_serialized_length
        io.read(4).unpack1("L")
      end

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

      def load_string
        io.read(load_varint).force_encoding(encoding)
      end

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

      def load_optional_location
        load_location if io.getbyte != 0
      end

      def load_constant
        index = load_varint - 1
        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 = input.byteslice(start, length).to_sym
          constant_pool[index] = constant
        end

        constant
      end

      def load_node
        type = io.getbyte
        location = load_location

        case type
        when 1 then
          AliasNode.new(load_node, load_node, load_location, location)
        when 2 then
          AlternationPatternNode.new(load_node, load_node, load_location, location)
        when 3 then
          AndNode.new(load_node, load_node, load_location, location)
        when 4 then
          ArgumentsNode.new(Array.new(load_varint) { load_node }, location)
        when 5 then
          ArrayNode.new(Array.new(load_varint) { load_node }, load_optional_location, load_optional_location, location)
        when 6 then
          ArrayPatternNode.new(load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, Array.new(load_varint) { load_node }, load_optional_location, load_optional_location, location)
        when 7 then
          AssocNode.new(load_node, load_optional_node, load_optional_location, location)
        when 8 then
          AssocSplatNode.new(load_optional_node, load_location, location)
        when 9 then
          BackReferenceReadNode.new(location)
        when 10 then
          BeginNode.new(load_optional_location, load_optional_node, load_optional_node, load_optional_node, load_optional_node, load_optional_location, location)
        when 11 then
          BlockArgumentNode.new(load_optional_node, load_location, location)
        when 12 then
          BlockNode.new(Array.new(load_varint) { load_constant }, load_optional_node, load_optional_node, load_location, load_location, location)
        when 13 then
          BlockParameterNode.new(load_optional_location, load_location, location)
        when 14 then
          BlockParametersNode.new(load_optional_node, Array.new(load_varint) { load_location }, load_optional_location, load_optional_location, location)
        when 15 then
          BreakNode.new(load_optional_node, load_location, location)
        when 16 then
          CallNode.new(load_optional_node, load_optional_location, load_optional_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, load_varint, load_string, location)
        when 17 then
          CallOperatorAndWriteNode.new(load_node, load_location, load_node, location)
        when 18 then
          CallOperatorOrWriteNode.new(load_node, load_node, load_location, location)
        when 19 then
          CallOperatorWriteNode.new(load_node, load_location, load_node, load_constant, location)
        when 20 then
          CapturePatternNode.new(load_node, load_node, load_location, location)
        when 21 then
          CaseNode.new(load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, load_location, load_location, location)
        when 22 then
          ClassNode.new(Array.new(load_varint) { load_constant }, load_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_location, location)
        when 23 then
          ClassVariableOperatorAndWriteNode.new(load_location, load_location, load_node, location)
        when 24 then
          ClassVariableOperatorOrWriteNode.new(load_location, load_location, load_node, location)
        when 25 then
          ClassVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, location)
        when 26 then
          ClassVariableReadNode.new(location)
        when 27 then
          ClassVariableWriteNode.new(load_location, load_optional_node, load_optional_location, location)
        when 28 then
          ConstantOperatorAndWriteNode.new(load_location, load_location, load_node, location)
        when 29 then
          ConstantOperatorOrWriteNode.new(load_location, load_location, load_node, location)
        when 30 then
          ConstantOperatorWriteNode.new(load_location, load_location, load_node, load_constant, location)
        when 31 then
          ConstantPathNode.new(load_optional_node, load_node, load_location, location)
        when 32 then
          ConstantPathOperatorAndWriteNode.new(load_node, load_location, load_node, location)
        when 33 then
          ConstantPathOperatorOrWriteNode.new(load_node, load_location, load_node, location)
        when 34 then
          ConstantPathOperatorWriteNode.new(load_node, load_location, load_node, load_constant, location)
        when 35 then
          ConstantPathWriteNode.new(load_node, load_optional_location, load_optional_node, location)
        when 36 then
          ConstantReadNode.new(location)
        when 37 then
          ConstantWriteNode.new(load_location, load_optional_node, load_optional_location, location)
        when 38 then
          load_serialized_length
          DefNode.new(load_location, load_optional_node, load_optional_node, load_optional_node, Array.new(load_varint) { load_constant }, load_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, location)
        when 39 then
          DefinedNode.new(load_optional_location, load_node, load_optional_location, load_location, location)
        when 40 then
          ElseNode.new(load_location, load_optional_node, load_optional_location, location)
        when 41 then
          EmbeddedStatementsNode.new(load_location, load_optional_node, load_location, location)
        when 42 then
          EmbeddedVariableNode.new(load_location, load_node, location)
        when 43 then
          EnsureNode.new(load_location, load_optional_node, load_location, location)
        when 44 then
          FalseNode.new(location)
        when 45 then
          FindPatternNode.new(load_optional_node, load_node, Array.new(load_varint) { load_node }, load_node, load_optional_location, load_optional_location, location)
        when 46 then
          FlipFlopNode.new(load_optional_node, load_optional_node, load_location, load_varint, location)
        when 47 then
          FloatNode.new(location)
        when 48 then
          ForNode.new(load_node, load_node, load_optional_node, load_location, load_location, load_optional_location, load_location, location)
        when 49 then
          ForwardingArgumentsNode.new(location)
        when 50 then
          ForwardingParameterNode.new(location)
        when 51 then
          ForwardingSuperNode.new(load_optional_node, location)
        when 52 then
          GlobalVariableOperatorAndWriteNode.new(load_location, load_location, load_node, location)
        when 53 then
          GlobalVariableOperatorOrWriteNode.new(load_location, load_location, load_node, location)
        when 54 then
          GlobalVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, location)
        when 55 then
          GlobalVariableReadNode.new(location)
        when 56 then
          GlobalVariableWriteNode.new(load_location, load_optional_location, load_optional_node, location)
        when 57 then
          HashNode.new(load_location, Array.new(load_varint) { load_node }, load_location, location)
        when 58 then
          HashPatternNode.new(load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, load_optional_location, load_optional_location, location)
        when 59 then
          IfNode.new(load_optional_location, load_node, load_optional_node, load_optional_node, load_optional_location, location)
        when 60 then
          ImaginaryNode.new(load_node, location)
        when 61 then
          InNode.new(load_node, load_optional_node, load_location, load_optional_location, location)
        when 62 then
          InstanceVariableOperatorAndWriteNode.new(load_location, load_location, load_node, location)
        when 63 then
          InstanceVariableOperatorOrWriteNode.new(load_location, load_location, load_node, location)
        when 64 then
          InstanceVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, location)
        when 65 then
          InstanceVariableReadNode.new(location)
        when 66 then
          InstanceVariableWriteNode.new(load_location, load_optional_node, load_optional_location, location)
        when 67 then
          IntegerNode.new(location)
        when 68 then
          InterpolatedRegularExpressionNode.new(load_location, Array.new(load_varint) { load_node }, load_location, load_varint, location)
        when 69 then
          InterpolatedStringNode.new(load_optional_location, Array.new(load_varint) { load_node }, load_optional_location, location)
        when 70 then
          InterpolatedSymbolNode.new(load_optional_location, Array.new(load_varint) { load_node }, load_optional_location, location)
        when 71 then
          InterpolatedXStringNode.new(load_location, Array.new(load_varint) { load_node }, load_location, location)
        when 72 then
          KeywordHashNode.new(Array.new(load_varint) { load_node }, location)
        when 73 then
          KeywordParameterNode.new(load_location, load_optional_node, location)
        when 74 then
          KeywordRestParameterNode.new(load_location, load_optional_location, location)
        when 75 then
          LambdaNode.new(Array.new(load_varint) { load_constant }, load_location, load_optional_node, load_optional_node, location)
        when 76 then
          LocalVariableOperatorAndWriteNode.new(load_location, load_location, load_node, load_constant, location)
        when 77 then
          LocalVariableOperatorOrWriteNode.new(load_location, load_location, load_node, load_constant, location)
        when 78 then
          LocalVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, load_constant, location)
        when 79 then
          LocalVariableReadNode.new(load_constant, load_varint, location)
        when 80 then
          LocalVariableWriteNode.new(load_constant, load_varint, load_optional_node, load_location, load_optional_location, location)
        when 81 then
          MatchPredicateNode.new(load_node, load_node, load_location, location)
        when 82 then
          MatchRequiredNode.new(load_node, load_node, load_location, location)
        when 83 then
          MissingNode.new(location)
        when 84 then
          ModuleNode.new(Array.new(load_varint) { load_constant }, load_location, load_node, load_optional_node, load_location, location)
        when 85 then
          MultiWriteNode.new(Array.new(load_varint) { load_node }, load_optional_location, load_optional_node, load_optional_location, load_optional_location, location)
        when 86 then
          NextNode.new(load_optional_node, load_location, location)
        when 87 then
          NilNode.new(location)
        when 88 then
          NoKeywordsParameterNode.new(load_location, load_location, location)
        when 89 then
          NumberedReferenceReadNode.new(location)
        when 90 then
          OptionalParameterNode.new(load_constant, load_location, load_location, load_node, location)
        when 91 then
          OrNode.new(load_node, load_node, load_location, location)
        when 92 then
          ParametersNode.new(Array.new(load_varint) { load_node }, Array.new(load_varint) { load_node }, Array.new(load_varint) { load_node }, load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, load_optional_node, location)
        when 93 then
          ParenthesesNode.new(load_optional_node, load_location, load_location, location)
        when 94 then
          PinnedExpressionNode.new(load_node, load_location, load_location, load_location, location)
        when 95 then
          PinnedVariableNode.new(load_node, load_location, location)
        when 96 then
          PostExecutionNode.new(load_optional_node, load_location, load_location, load_location, location)
        when 97 then
          PreExecutionNode.new(load_optional_node, load_location, load_location, load_location, location)
        when 98 then
          ProgramNode.new(Array.new(load_varint) { load_constant }, load_node, location)
        when 99 then
          RangeNode.new(load_optional_node, load_optional_node, load_location, load_varint, location)
        when 100 then
          RationalNode.new(load_node, location)
        when 101 then
          RedoNode.new(location)
        when 102 then
          RegularExpressionNode.new(load_location, load_location, load_location, load_string, load_varint, location)
        when 103 then
          RequiredDestructuredParameterNode.new(Array.new(load_varint) { load_node }, load_location, load_location, location)
        when 104 then
          RequiredParameterNode.new(load_constant, location)
        when 105 then
          RescueModifierNode.new(load_node, load_location, load_node, location)
        when 106 then
          RescueNode.new(load_location, Array.new(load_varint) { load_node }, load_optional_location, load_optional_node, load_optional_node, load_optional_node, location)
        when 107 then
          RestParameterNode.new(load_location, load_optional_location, location)
        when 108 then
          RetryNode.new(location)
        when 109 then
          ReturnNode.new(load_location, load_optional_node, location)
        when 110 then
          SelfNode.new(location)
        when 111 then
          SingletonClassNode.new(Array.new(load_varint) { load_constant }, load_location, load_location, load_node, load_optional_node, load_location, location)
        when 112 then
          SourceEncodingNode.new(location)
        when 113 then
          SourceFileNode.new(load_string, location)
        when 114 then
          SourceLineNode.new(location)
        when 115 then
          SplatNode.new(load_location, load_optional_node, location)
        when 116 then
          StatementsNode.new(Array.new(load_varint) { load_node }, location)
        when 117 then
          StringConcatNode.new(load_node, load_node, location)
        when 118 then
          StringNode.new(load_optional_location, load_location, load_optional_location, load_string, location)
        when 119 then
          SuperNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, location)
        when 120 then
          SymbolNode.new(load_optional_location, load_location, load_optional_location, load_string, location)
        when 121 then
          TrueNode.new(location)
        when 122 then
          UndefNode.new(Array.new(load_varint) { load_node }, load_location, location)
        when 123 then
          UnlessNode.new(load_location, load_node, load_optional_node, load_optional_node, load_optional_location, location)
        when 124 then
          UntilNode.new(load_location, load_node, load_optional_node, load_varint, location)
        when 125 then
          WhenNode.new(load_location, Array.new(load_varint) { load_node }, load_optional_node, location)
        when 126 then
          WhileNode.new(load_location, load_node, load_optional_node, load_varint, location)
        when 127 then
          XStringNode.new(load_location, load_location, load_location, load_string, location)
        when 128 then
          YieldNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, location)
        end
      end
    end

    TOKEN_TYPES = [
      nil,
      :EOF,
      :MISSING,
      :NOT_PROVIDED,
      :AMPERSAND,
      :AMPERSAND_AMPERSAND,
      :AMPERSAND_AMPERSAND_EQUAL,
      :AMPERSAND_DOT,
      :AMPERSAND_EQUAL,
      :BACKTICK,
      :BACK_REFERENCE,
      :BANG,
      :BANG_EQUAL,
      :BANG_TILDE,
      :BRACE_LEFT,
      :BRACE_RIGHT,
      :BRACKET_LEFT,
      :BRACKET_LEFT_ARRAY,
      :BRACKET_LEFT_RIGHT,
      :BRACKET_LEFT_RIGHT_EQUAL,
      :BRACKET_RIGHT,
      :CARET,
      :CARET_EQUAL,
      :CHARACTER_LITERAL,
      :CLASS_VARIABLE,
      :COLON,
      :COLON_COLON,
      :COMMA,
      :COMMENT,
      :CONSTANT,
      :DOT,
      :DOT_DOT,
      :DOT_DOT_DOT,
      :EMBDOC_BEGIN,
      :EMBDOC_END,
      :EMBDOC_LINE,
      :EMBEXPR_BEGIN,
      :EMBEXPR_END,
      :EMBVAR,
      :EQUAL,
      :EQUAL_EQUAL,
      :EQUAL_EQUAL_EQUAL,
      :EQUAL_GREATER,
      :EQUAL_TILDE,
      :FLOAT,
      :FLOAT_IMAGINARY,
      :FLOAT_RATIONAL,
      :FLOAT_RATIONAL_IMAGINARY,
      :GLOBAL_VARIABLE,
      :GREATER,
      :GREATER_EQUAL,
      :GREATER_GREATER,
      :GREATER_GREATER_EQUAL,
      :HEREDOC_END,
      :HEREDOC_START,
      :IDENTIFIER,
      :IGNORED_NEWLINE,
      :INSTANCE_VARIABLE,
      :INTEGER,
      :INTEGER_IMAGINARY,
      :INTEGER_RATIONAL,
      :INTEGER_RATIONAL_IMAGINARY,
      :KEYWORD_ALIAS,
      :KEYWORD_AND,
      :KEYWORD_BEGIN,
      :KEYWORD_BEGIN_UPCASE,
      :KEYWORD_BREAK,
      :KEYWORD_CASE,
      :KEYWORD_CLASS,
      :KEYWORD_DEF,
      :KEYWORD_DEFINED,
      :KEYWORD_DO,
      :KEYWORD_DO_LOOP,
      :KEYWORD_ELSE,
      :KEYWORD_ELSIF,
      :KEYWORD_END,
      :KEYWORD_END_UPCASE,
      :KEYWORD_ENSURE,
      :KEYWORD_FALSE,
      :KEYWORD_FOR,
      :KEYWORD_IF,
      :KEYWORD_IF_MODIFIER,
      :KEYWORD_IN,
      :KEYWORD_MODULE,
      :KEYWORD_NEXT,
      :KEYWORD_NIL,
      :KEYWORD_NOT,
      :KEYWORD_OR,
      :KEYWORD_REDO,
      :KEYWORD_RESCUE,
      :KEYWORD_RESCUE_MODIFIER,
      :KEYWORD_RETRY,
      :KEYWORD_RETURN,
      :KEYWORD_SELF,
      :KEYWORD_SUPER,
      :KEYWORD_THEN,
      :KEYWORD_TRUE,
      :KEYWORD_UNDEF,
      :KEYWORD_UNLESS,
      :KEYWORD_UNLESS_MODIFIER,
      :KEYWORD_UNTIL,
      :KEYWORD_UNTIL_MODIFIER,
      :KEYWORD_WHEN,
      :KEYWORD_WHILE,
      :KEYWORD_WHILE_MODIFIER,
      :KEYWORD_YIELD,
      :KEYWORD___ENCODING__,
      :KEYWORD___FILE__,
      :KEYWORD___LINE__,
      :LABEL,
      :LABEL_END,
      :LAMBDA_BEGIN,
      :LESS,
      :LESS_EQUAL,
      :LESS_EQUAL_GREATER,
      :LESS_LESS,
      :LESS_LESS_EQUAL,
      :MINUS,
      :MINUS_EQUAL,
      :MINUS_GREATER,
      :NEWLINE,
      :NUMBERED_REFERENCE,
      :PARENTHESIS_LEFT,
      :PARENTHESIS_LEFT_PARENTHESES,
      :PARENTHESIS_RIGHT,
      :PERCENT,
      :PERCENT_EQUAL,
      :PERCENT_LOWER_I,
      :PERCENT_LOWER_W,
      :PERCENT_LOWER_X,
      :PERCENT_UPPER_I,
      :PERCENT_UPPER_W,
      :PIPE,
      :PIPE_EQUAL,
      :PIPE_PIPE,
      :PIPE_PIPE_EQUAL,
      :PLUS,
      :PLUS_EQUAL,
      :QUESTION_MARK,
      :REGEXP_BEGIN,
      :REGEXP_END,
      :SEMICOLON,
      :SLASH,
      :SLASH_EQUAL,
      :STAR,
      :STAR_EQUAL,
      :STAR_STAR,
      :STAR_STAR_EQUAL,
      :STRING_BEGIN,
      :STRING_CONTENT,
      :STRING_END,
      :SYMBOL_BEGIN,
      :TILDE,
      :UAMPERSAND,
      :UCOLON_COLON,
      :UDOT_DOT,
      :UDOT_DOT_DOT,
      :UMINUS,
      :UMINUS_NUM,
      :UPLUS,
      :USTAR,
      :USTAR_STAR,
      :WORDS_SEP,
      :__END__,
    ]
  end
end
