diff --git a/lib/graphql/language/lexer.rb b/lib/graphql/language/lexer.rb index 3ac325a052..87494833f1 100644 --- a/lib/graphql/language/lexer.rb +++ b/lib/graphql/language/lexer.rb @@ -314,7 +314,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:RCURLY, ts, te, meta) + emit(:RCURLY, ts, te, meta, "}") end end @@ -328,7 +328,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:LCURLY, ts, te, meta) + emit(:LCURLY, ts, te, meta, "{") end end @@ -342,7 +342,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:RPAREN, ts, te, meta) + emit(:RPAREN, ts, te, meta, ")") end end @@ -356,7 +356,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:LPAREN, ts, te, meta) + emit(:LPAREN, ts, te, meta, "(") end end @@ -370,7 +370,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:RBRACKET, ts, te, meta) + emit(:RBRACKET, ts, te, meta, "]") end end @@ -384,7 +384,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:LBRACKET, ts, te, meta) + emit(:LBRACKET, ts, te, meta, "[") end end @@ -398,7 +398,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:COLON, ts, te, meta) + emit(:COLON, ts, te, meta, ":") end end @@ -440,7 +440,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:VAR_SIGN, ts, te, meta) + emit(:VAR_SIGN, ts, te, meta, "$") end end @@ -454,7 +454,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:DIR_SIGN, ts, te, meta) + emit(:DIR_SIGN, ts, te, meta, "@") end end @@ -468,7 +468,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:ELLIPSIS, ts, te, meta) + emit(:ELLIPSIS, ts, te, meta, "...") end end @@ -482,7 +482,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:EQUALS, ts, te, meta) + emit(:EQUALS, ts, te, meta, "=") end end @@ -496,7 +496,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:BANG, ts, te, meta) + emit(:BANG, ts, te, meta, "!") end end @@ -510,7 +510,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:PIPE, ts, te, meta) + emit(:PIPE, ts, te, meta, "|") end end @@ -524,7 +524,7 @@ def self.run_lexer(query_string) begin te = p+1; begin - emit(:AMP, ts, te, meta) + emit(:AMP, ts, te, meta, "&") end end @@ -738,7 +738,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:ON, ts, te, meta) + emit(:ON, ts, te, meta, "on") end end @@ -746,7 +746,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:FRAGMENT, ts, te, meta) + emit(:FRAGMENT, ts, te, meta, "fragment") end end @@ -754,7 +754,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:TRUE, ts, te, meta) + emit(:TRUE, ts, te, meta, "true") end end @@ -762,7 +762,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:FALSE, ts, te, meta) + emit(:FALSE, ts, te, meta, "false") end end @@ -770,7 +770,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:NULL, ts, te, meta) + emit(:NULL, ts, te, meta, "null") end end @@ -778,7 +778,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:QUERY, ts, te, meta) + emit(:QUERY, ts, te, meta, "query") end end @@ -786,7 +786,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:MUTATION, ts, te, meta) + emit(:MUTATION, ts, te, meta, "mutation") end end @@ -794,7 +794,7 @@ def self.run_lexer(query_string) begin p = ((te))-1; begin - emit(:SUBSCRIPTION, ts, te, meta) + emit(:SUBSCRIPTION, ts, te, meta, "subscription") end end @@ -1371,11 +1371,11 @@ def self.run_lexer(query_string) def self.record_comment(ts, te, meta) token = GraphQL::Language::Token.new( -name: :COMMENT, -value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING), -line: meta[:line], -col: meta[:col], -prev_token: meta[:previous_token], +:COMMENT, +meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING), +meta[:line], +meta[:col], +meta[:previous_token], ) meta[:previous_token] = token @@ -1383,13 +1383,14 @@ def self.record_comment(ts, te, meta) meta[:col] += te - ts end -def self.emit(token_name, ts, te, meta) +def self.emit(token_name, ts, te, meta, token_value = nil) +token_value ||= meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING) meta[:tokens] << token = GraphQL::Language::Token.new( -name: token_name, -value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING), -line: meta[:line], -col: meta[:col], -prev_token: meta[:previous_token], +token_name, +token_value, +meta[:line], +meta[:col], +meta[:previous_token], ) meta[:previous_token] = token # Bump the column counter for the next token @@ -1428,30 +1429,30 @@ def self.emit_string(ts, te, meta, block:) # (It's faster: https://bugs.ruby-lang.org/issues/8110) if !value.valid_encoding? || value !~ VALID_STRING meta[:tokens] << token = GraphQL::Language::Token.new( -name: :BAD_UNICODE_ESCAPE, -value: value, -line: meta[:line], -col: meta[:col], -prev_token: meta[:previous_token], +:BAD_UNICODE_ESCAPE, +value, +meta[:line], +meta[:col], +meta[:previous_token], ) else replace_escaped_characters_in_place(value) if !value.valid_encoding? meta[:tokens] << token = GraphQL::Language::Token.new( - name: :BAD_UNICODE_ESCAPE, - value: value, - line: meta[:line], - col: meta[:col], - prev_token: meta[:previous_token], + :BAD_UNICODE_ESCAPE, + value, + meta[:line], + meta[:col], + meta[:previous_token], ) else meta[:tokens] << token = GraphQL::Language::Token.new( - name: :STRING, - value: value, - line: meta[:line], - col: meta[:col], - prev_token: meta[:previous_token], + :STRING, + value, + meta[:line], + meta[:col], + meta[:previous_token], ) end end diff --git a/lib/graphql/language/lexer.rl b/lib/graphql/language/lexer.rl index d1431fd20b..d91a5a91df 100644 --- a/lib/graphql/language/lexer.rl +++ b/lib/graphql/language/lexer.rl @@ -67,14 +67,14 @@ main := |* INT => { emit(:INT, ts, te, meta) }; FLOAT => { emit(:FLOAT, ts, te, meta) }; - ON => { emit(:ON, ts, te, meta) }; - FRAGMENT => { emit(:FRAGMENT, ts, te, meta) }; - TRUE => { emit(:TRUE, ts, te, meta) }; - FALSE => { emit(:FALSE, ts, te, meta) }; - NULL => { emit(:NULL, ts, te, meta) }; - QUERY => { emit(:QUERY, ts, te, meta) }; - MUTATION => { emit(:MUTATION, ts, te, meta) }; - SUBSCRIPTION => { emit(:SUBSCRIPTION, ts, te, meta) }; + ON => { emit(:ON, ts, te, meta, "on") }; + FRAGMENT => { emit(:FRAGMENT, ts, te, meta, "fragment") }; + TRUE => { emit(:TRUE, ts, te, meta, "true") }; + FALSE => { emit(:FALSE, ts, te, meta, "false") }; + NULL => { emit(:NULL, ts, te, meta, "null") }; + QUERY => { emit(:QUERY, ts, te, meta, "query") }; + MUTATION => { emit(:MUTATION, ts, te, meta, "mutation") }; + SUBSCRIPTION => { emit(:SUBSCRIPTION, ts, te, meta, "subscription") }; SCHEMA => { emit(:SCHEMA, ts, te, meta) }; SCALAR => { emit(:SCALAR, ts, te, meta) }; TYPE => { emit(:TYPE, ts, te, meta) }; @@ -85,22 +85,22 @@ ENUM => { emit(:ENUM, ts, te, meta) }; INPUT => { emit(:INPUT, ts, te, meta) }; DIRECTIVE => { emit(:DIRECTIVE, ts, te, meta) }; - RCURLY => { emit(:RCURLY, ts, te, meta) }; - LCURLY => { emit(:LCURLY, ts, te, meta) }; - RPAREN => { emit(:RPAREN, ts, te, meta) }; - LPAREN => { emit(:LPAREN, ts, te, meta) }; - RBRACKET => { emit(:RBRACKET, ts, te, meta) }; - LBRACKET => { emit(:LBRACKET, ts, te, meta) }; - COLON => { emit(:COLON, ts, te, meta) }; + RCURLY => { emit(:RCURLY, ts, te, meta, "}") }; + LCURLY => { emit(:LCURLY, ts, te, meta, "{") }; + RPAREN => { emit(:RPAREN, ts, te, meta, ")") }; + LPAREN => { emit(:LPAREN, ts, te, meta, "(")}; + RBRACKET => { emit(:RBRACKET, ts, te, meta, "]") }; + LBRACKET => { emit(:LBRACKET, ts, te, meta, "[") }; + COLON => { emit(:COLON, ts, te, meta, ":") }; QUOTED_STRING => { emit_string(ts, te, meta, block: false) }; BLOCK_STRING => { emit_string(ts, te, meta, block: true) }; - VAR_SIGN => { emit(:VAR_SIGN, ts, te, meta) }; - DIR_SIGN => { emit(:DIR_SIGN, ts, te, meta) }; - ELLIPSIS => { emit(:ELLIPSIS, ts, te, meta) }; - EQUALS => { emit(:EQUALS, ts, te, meta) }; - BANG => { emit(:BANG, ts, te, meta) }; - PIPE => { emit(:PIPE, ts, te, meta) }; - AMP => { emit(:AMP, ts, te, meta) }; + VAR_SIGN => { emit(:VAR_SIGN, ts, te, meta, "$") }; + DIR_SIGN => { emit(:DIR_SIGN, ts, te, meta, "@") }; + ELLIPSIS => { emit(:ELLIPSIS, ts, te, meta, "...") }; + EQUALS => { emit(:EQUALS, ts, te, meta, "=") }; + BANG => { emit(:BANG, ts, te, meta, "!") }; + PIPE => { emit(:PIPE, ts, te, meta, "|") }; + AMP => { emit(:AMP, ts, te, meta, "&") }; IDENTIFIER => { emit(:IDENTIFIER, ts, te, meta) }; COMMENT => { record_comment(ts, te, meta) }; @@ -163,11 +163,11 @@ module GraphQL def self.record_comment(ts, te, meta) token = GraphQL::Language::Token.new( - name: :COMMENT, - value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING), - line: meta[:line], - col: meta[:col], - prev_token: meta[:previous_token], + :COMMENT, + meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING), + meta[:line], + meta[:col], + meta[:previous_token], ) meta[:previous_token] = token @@ -175,13 +175,14 @@ module GraphQL meta[:col] += te - ts end - def self.emit(token_name, ts, te, meta) + def self.emit(token_name, ts, te, meta, token_value = nil) + token_value ||= meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING) meta[:tokens] << token = GraphQL::Language::Token.new( - name: token_name, - value: meta[:data][ts, te - ts].pack(PACK_DIRECTIVE).force_encoding(UTF_8_ENCODING), - line: meta[:line], - col: meta[:col], - prev_token: meta[:previous_token], + token_name, + token_value, + meta[:line], + meta[:col], + meta[:previous_token], ) meta[:previous_token] = token # Bump the column counter for the next token @@ -220,30 +221,30 @@ module GraphQL # (It's faster: https://bugs.ruby-lang.org/issues/8110) if !value.valid_encoding? || value !~ VALID_STRING meta[:tokens] << token = GraphQL::Language::Token.new( - name: :BAD_UNICODE_ESCAPE, - value: value, - line: meta[:line], - col: meta[:col], - prev_token: meta[:previous_token], + :BAD_UNICODE_ESCAPE, + value, + meta[:line], + meta[:col], + meta[:previous_token], ) else replace_escaped_characters_in_place(value) if !value.valid_encoding? meta[:tokens] << token = GraphQL::Language::Token.new( - name: :BAD_UNICODE_ESCAPE, - value: value, - line: meta[:line], - col: meta[:col], - prev_token: meta[:previous_token], + :BAD_UNICODE_ESCAPE, + value, + meta[:line], + meta[:col], + meta[:previous_token], ) else meta[:tokens] << token = GraphQL::Language::Token.new( - name: :STRING, - value: value, - line: meta[:line], - col: meta[:col], - prev_token: meta[:previous_token], + :STRING, + value, + meta[:line], + meta[:col], + meta[:previous_token], ) end end diff --git a/lib/graphql/language/nodes.rb b/lib/graphql/language/nodes.rb index 519aac1a1d..625a4e7135 100644 --- a/lib/graphql/language/nodes.rb +++ b/lib/graphql/language/nodes.rb @@ -28,7 +28,8 @@ def initialize(options = {}) def initialize(options={}) if options.key?(:position_source) position_source = options.delete(:position_source) - @line, @col = position_source.line_and_column + @line = position_source.line + @col = position_source.col end @filename = options.delete(:filename) @@ -350,6 +351,8 @@ class NullValue < NameOnlyNode # A single selection in a GraphQL query. class Field < AbstractNode + NONE = [].freeze + scalar_methods :name, :alias children_methods({ arguments: GraphQL::Language::Nodes::Argument, @@ -360,13 +363,13 @@ class Field < AbstractNode # @!attribute selections # @return [Array] Selections on this object (or empty array if this is a scalar field) - def initialize_node(name: nil, arguments: [], directives: [], selections: [], **kwargs) - @name = name - @arguments = arguments - @directives = directives - @selections = selections + def initialize_node(attributes) + @name = attributes[:name] + @arguments = attributes[:arguments] || NONE + @directives = attributes[:directives] || NONE + @selections = attributes[:selections] || NONE # oops, alias is a keyword: - @alias = kwargs.fetch(:alias, nil) + @alias = attributes[:alias] end # Override this because default is `:fields` diff --git a/lib/graphql/language/parser.rb b/lib/graphql/language/parser.rb index a45b9c83e4..946027ef6f 100644 --- a/lib/graphql/language/parser.rb +++ b/lib/graphql/language/parser.rb @@ -21,6 +21,7 @@ def initialize(query_string, filename:, tracer: Tracing::NullTracer) @query_string = query_string @filename = filename @tracer = tracer + @reused_next_token = [nil, nil] end def parse_document @@ -51,7 +52,9 @@ def next_token if lexer_token.nil? nil else - [lexer_token.name, lexer_token] + @reused_next_token[0] = lexer_token.name + @reused_next_token[1] = lexer_token + @reused_next_token end end diff --git a/lib/graphql/language/parser.y b/lib/graphql/language/parser.y index eaca30f497..4932054971 100644 --- a/lib/graphql/language/parser.y +++ b/lib/graphql/language/parser.y @@ -440,6 +440,7 @@ def initialize(query_string, filename:, tracer: Tracing::NullTracer) @query_string = query_string @filename = filename @tracer = tracer + @reused_next_token = [nil, nil] end def parse_document @@ -470,7 +471,9 @@ def next_token if lexer_token.nil? nil else - [lexer_token.name, lexer_token] + @reused_next_token[0] = lexer_token.name + @reused_next_token[1] = lexer_token + @reused_next_token end end diff --git a/lib/graphql/language/token.rb b/lib/graphql/language/token.rb index 9dae925a8c..923c7e2a45 100644 --- a/lib/graphql/language/token.rb +++ b/lib/graphql/language/token.rb @@ -14,7 +14,7 @@ class Token attr_reader :value attr_reader :prev_token, :line, :col - def initialize(value:, name:, line:, col:, prev_token:) + def initialize(name, value, line, col, prev_token) @name = name @value = -value @line = line