Repository URL to install this package:
|
Version:
1.8.2 ▾
|
class GraphQL::Language::Parser
rule
target: document
document: definitions_list { return make_node(:Document, definitions: val[0])}
definitions_list:
definition { return [val[0]]}
| definitions_list definition { val[0] << val[1] }
definition:
operation_definition
| fragment_definition
| type_system_definition
operation_definition:
operation_type operation_name_opt variable_definitions_opt directives_list_opt selection_set {
return make_node(
:OperationDefinition, {
operation_type: val[0],
name: val[1],
variables: val[2],
directives: val[3],
selections: val[4],
position_source: val[0],
}
)
}
| LCURLY selection_list RCURLY {
return make_node(
:OperationDefinition, {
operation_type: "query",
selections: val[1],
position_source: val[0],
}
)
}
| LCURLY RCURLY {
return make_node(
:OperationDefinition, {
operation_type: "query",
selections: [],
position_source: val[0],
}
)
}
operation_type:
QUERY
| MUTATION
| SUBSCRIPTION
operation_name_opt:
/* none */ { return nil }
| name
variable_definitions_opt:
/* none */ { return [] }
| LPAREN variable_definitions_list RPAREN { return val[1] }
variable_definitions_list:
variable_definition { return [val[0]] }
| variable_definitions_list variable_definition { val[0] << val[1] }
variable_definition:
VAR_SIGN name COLON type default_value_opt {
return make_node(:VariableDefinition, {
name: val[1],
type: val[3],
default_value: val[4],
position_source: val[0],
})
}
type:
name { return make_node(:TypeName, name: val[0])}
| type BANG { return make_node(:NonNullType, of_type: val[0]) }
| LBRACKET type RBRACKET { return make_node(:ListType, of_type: val[1]) }
default_value_opt:
/* none */ { return nil }
| EQUALS literal_value { return val[1] }
selection_set:
LCURLY selection_list RCURLY { return val[1] }
selection_set_opt:
/* none */ { return [] }
| selection_set { return val[0] }
selection_list:
selection { return [result] }
| selection_list selection { val[0] << val[1] }
selection:
field
| fragment_spread
| inline_fragment
field:
name arguments_opt directives_list_opt selection_set_opt {
return make_node(
:Field, {
name: val[0],
arguments: val[1],
directives: val[2],
selections: val[3],
position_source: val[0],
}
)
}
| name COLON name arguments_opt directives_list_opt selection_set_opt {
return make_node(
:Field, {
alias: val[0],
name: val[2],
arguments: val[3],
directives: val[4],
selections: val[5],
position_source: val[0],
}
)
}
name:
name_without_on
| ON
schema_keyword:
SCHEMA
| SCALAR
| TYPE
| IMPLEMENTS
| INTERFACE
| UNION
| ENUM
| INPUT
| DIRECTIVE
name_without_on:
IDENTIFIER
| FRAGMENT
| TRUE
| FALSE
| operation_type
| schema_keyword
enum_name: /* any identifier, but not "true", "false" or "null" */
IDENTIFIER
| FRAGMENT
| ON
| operation_type
| schema_keyword
enum_value_definition:
enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0]), position_source: val[0]) }
enum_value_definitions:
enum_value_definition { return [val[0]] }
| enum_value_definitions enum_value_definition { return val[0] << val[1] }
arguments_opt:
/* none */ { return [] }
| LPAREN RPAREN { return [] }
| LPAREN arguments_list RPAREN { return val[1] }
arguments_list:
argument { return [val[0]] }
| arguments_list argument { val[0] << val[1] }
argument:
name COLON input_value { return make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
literal_value:
FLOAT { return val[0].to_f }
| INT { return val[0].to_i }
| STRING { return val[0].to_s }
| TRUE { return true }
| FALSE { return false }
| null_value
| enum_value
| list_value
| object_literal_value
input_value:
| literal_value
| variable
| object_value
null_value: NULL { return make_node(:NullValue, name: val[0], position_source: val[0]) }
variable: VAR_SIGN name { return make_node(:VariableIdentifier, name: val[1], position_source: val[0]) }
list_value:
LBRACKET RBRACKET { return [] }
| LBRACKET list_value_list RBRACKET { return val[1] }
list_value_list:
input_value { return [val[0]] }
| list_value_list input_value { val[0] << val[1] }
object_value:
LCURLY RCURLY { return make_node(:InputObject, arguments: [], position_source: val[0])}
| LCURLY object_value_list RCURLY { return make_node(:InputObject, arguments: val[1], position_source: val[0])}
object_value_list:
object_value_field { return [val[0]] }
| object_value_list object_value_field { val[0] << val[1] }
object_value_field:
name COLON input_value { return make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
/* like the previous, but with literals only: */
object_literal_value:
LCURLY RCURLY { return make_node(:InputObject, arguments: [], position_source: val[0])}
| LCURLY object_literal_value_list RCURLY { return make_node(:InputObject, arguments: val[1], position_source: val[0])}
object_literal_value_list:
object_literal_value_field { return [val[0]] }
| object_literal_value_list object_literal_value_field { val[0] << val[1] }
object_literal_value_field:
name COLON literal_value { return make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
enum_value: enum_name { return make_node(:Enum, name: val[0], position_source: val[0]) }
directives_list_opt:
/* none */ { return [] }
| directives_list
directives_list:
directive { return [val[0]] }
| directives_list directive { val[0] << val[1] }
directive: DIR_SIGN name arguments_opt { return make_node(:Directive, name: val[1], arguments: val[2], position_source: val[0]) }
fragment_spread:
ELLIPSIS name_without_on directives_list_opt { return make_node(:FragmentSpread, name: val[1], directives: val[2], position_source: val[0]) }
inline_fragment:
ELLIPSIS ON type directives_list_opt selection_set {
return make_node(:InlineFragment, {
type: val[2],
directives: val[3],
selections: val[4],
position_source: val[0]
})
}
| ELLIPSIS directives_list_opt selection_set {
return make_node(:InlineFragment, {
type: nil,
directives: val[1],
selections: val[2],
position_source: val[0]
})
}
fragment_definition:
FRAGMENT fragment_name_opt ON type directives_list_opt selection_set {
return make_node(:FragmentDefinition, {
name: val[1],
type: val[3],
directives: val[4],
selections: val[5],
position_source: val[0],
}
)
}
fragment_name_opt:
/* none */ { return nil }
| name_without_on
type_system_definition:
schema_definition
| type_definition
| directive_definition
schema_definition:
SCHEMA directives_list_opt LCURLY operation_type_definition_list RCURLY { return make_node(:SchemaDefinition, position_source: val[0], directives: val[1], **val[3]) }
operation_type_definition_list:
operation_type_definition
| operation_type_definition_list operation_type_definition { return val[0].merge(val[1]) }
operation_type_definition:
operation_type COLON name { return { val[0].to_s.to_sym => val[2] } }
type_definition:
scalar_type_definition
| object_type_definition
| interface_type_definition
| union_type_definition
| enum_type_definition
| input_object_type_definition
scalar_type_definition: SCALAR name directives_list_opt { return make_node(:ScalarTypeDefinition, name: val[1], directives: val[2], description: get_description(val[0]), position_source: val[0]) }
object_type_definition:
TYPE name implements_opt directives_list_opt LCURLY field_definition_list RCURLY {
return make_node(:ObjectTypeDefinition, name: val[1], interfaces: val[2], directives: val[3], fields: val[5], description: get_description(val[0]), position_source: val[0])
}
implements_opt:
/* none */ { return [] }
| IMPLEMENTS AMP interfaces_list { return val[2] }
| IMPLEMENTS interfaces_list { return val[1] }
| IMPLEMENTS legacy_interfaces_list { return val[1] }
interfaces_list:
name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
| interfaces_list AMP name { val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) }
legacy_interfaces_list:
name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
| legacy_interfaces_list name { val[0] << make_node(:TypeName, name: val[1], position_source: val[1]) }
input_value_definition:
name COLON type default_value_opt directives_list_opt {
return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
}
input_value_definition_list:
input_value_definition { return [val[0]] }
| input_value_definition_list input_value_definition { val[0] << val[1] }
arguments_definitions_opt:
/* none */ { return [] }
| LPAREN input_value_definition_list RPAREN { return val[1] }
field_definition:
name arguments_definitions_opt COLON type directives_list_opt {
return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
}
field_definition_list:
/* none */ { return [] }
| field_definition { return [val[0]] }
| field_definition_list field_definition { val[0] << val[1] }
interface_type_definition:
INTERFACE name directives_list_opt LCURLY field_definition_list RCURLY {
return make_node(:InterfaceTypeDefinition, name: val[1], directives: val[2], fields: val[4], description: get_description(val[0]), position_source: val[0])
}
union_members:
name { return [make_node(:TypeName, name: val[0], position_source: val[0])]}
| union_members PIPE name { val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) }
union_type_definition:
UNION name directives_list_opt EQUALS union_members {
return make_node(:UnionTypeDefinition, name: val[1], directives: val[2], types: val[4], description: get_description(val[0]), position_source: val[0])
}
enum_type_definition:
ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY {
return make_node(:EnumTypeDefinition, name: val[1], directives: val[2], values: val[4], description: get_description(val[0]), position_source: val[0])
}
input_object_type_definition:
INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY {
return make_node(:InputObjectTypeDefinition, name: val[1], directives: val[2], fields: val[4], description: get_description(val[0]), position_source: val[0])
}
directive_definition:
DIRECTIVE DIR_SIGN name arguments_definitions_opt ON directive_locations {
return make_node(:DirectiveDefinition, name: val[2], arguments: val[3], locations: val[5], description: get_description(val[0]), position_source: val[0])
}
directive_locations:
name { return [val[0].to_s] }
| directive_locations PIPE name { val[0] << val[2].to_s }
end
---- header ----
---- inner ----
def initialize(query_string, filename:, tracer: Tracing::NullTracer)
@query_string = query_string
@filename = filename
@tracer = tracer
end
def parse_document
@document ||= begin
# Break the string into tokens
@tracer.trace("lex", {query_string: @query_string}) do
@tokens ||= GraphQL.scan(@query_string)
end
# From the tokens, build an AST
@tracer.trace("parse", {query_string: @query_string}) do
if @tokens.none?
make_node(:Document, definitions: [], filename: @filename)
else
do_parse
end
end
end
end
def self.parse(query_string, filename: nil, tracer: GraphQL::Tracing::NullTracer)
self.new(query_string, filename: filename, tracer: tracer).parse_document
end
private
def next_token
lexer_token = @tokens.shift
if lexer_token.nil?
nil
else
[lexer_token.name, lexer_token]
end
end
def get_description(token)
comments = []
loop do
prev_token = token
token = token.prev_token
break if token.nil?
break if token.name != :COMMENT
break if prev_token.line != token.line + 1
comments.unshift(token.to_s.sub(/^#\s*/, ""))
end
return nil if comments.empty?
comments.join("\n")
end
def on_error(parser_token_id, lexer_token, vstack)
if lexer_token == "$" || lexer_token == nil
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @query_string, filename: @filename)
else
parser_token_name = token_to_str(parser_token_id)
if parser_token_name.nil?
raise GraphQL::ParseError.new("Parse Error on unknown token: {token_id: #{parser_token_id}, lexer_token: #{lexer_token}} from #{@query_string}", nil, nil, @query_string, filename: @filename)
else
line, col = lexer_token.line_and_column
if lexer_token.name == :BAD_UNICODE_ESCAPE
raise GraphQL::ParseError.new("Parse error on bad Unicode escape sequence: #{lexer_token.to_s.inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
else
raise GraphQL::ParseError.new("Parse error on #{lexer_token.to_s.inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
end
end
end
end
def make_node(node_name, assigns)
assigns.each do |key, value|
if key != :position_source && value.is_a?(GraphQL::Language::Token)
assigns[key] = value.to_s
end
end
assigns[:filename] = @filename
GraphQL::Language::Nodes.const_get(node_name).new(assigns)
end