Skip to content

Instantly share code, notes, and snippets.

@kamilchm
Created February 4, 2019 17:43
Show Gist options
  • Save kamilchm/702251e49892ca3302e917bd528c2657 to your computer and use it in GitHub Desktop.
Save kamilchm/702251e49892ca3302e917bd528c2657 to your computer and use it in GitHub Desktop.
Definitions.
WHITESPACE = [\s\t\n\r]
NAME = [_A-Za-z0-9]
QUOTED = \"[^\"]*\"
KEYWORD = query|mutation|fragment|on
ASSIGN = :
COMMA = ,
SPREAD = \.\.\.
Rules.
{KEYWORD} : {token, {list_to_atom(TokenChars), TokenLine}}.
\{ : {token, {'{', TokenLine}}.
\} : {token, {'}', TokenLine}}.
\( : {token, {'(', TokenLine}}.
\) : {token, {')', TokenLine}}.
\" : {token, {'"', TokenLine}}.
{ASSIGN} : {token, {assign, TokenLine}}.
{COMMA} : {token, {comma, TokenLine}}.
{SPREAD} : {token, {spread, TokenLine}}.
{NAME}+ : {token, {word, TokenLine, TokenChars}}.
{QUOTED} : {token, {quoted, TokenLine, TokenChars}}.
{WHITESPACE}+ : skip_token.
Erlang code.
Nonterminals
queryDef operationType operations queryType fragmentType fragments mutationType
field fields args arg name.
Terminals
'{' '}' '(' ')' '"' word quoted 'query' 'mutation' 'fragment' 'on' assign comma spread.
Rootsymbol queryDef.
name -> word : '$1'.
queryDef -> operations : #{operations => '$1'}.
queryDef -> operations fragments : #{operations => '$1', fragments => '$2'}.
operations -> operationType : ['$1'].
operations -> operationType operations : ['$1'|'$2'].
operationType -> queryType : '$1'.
operationType -> mutationType : '$1'.
fragments -> fragmentType : ['$1'].
fragments -> fragmentType fragments : ['$1'|'$2'].
queryType -> 'query' name '{' field '}' : #{name => extract_token('$2'), query => '$4'}.
fragmentType -> 'fragment' name 'on' name '{' fields '}' :
#{name => extract_token('$2'),
fragment => #{fields => '$6', on => extract_token('$4')}
}.
mutationType -> 'mutation' name '{' field '}' :
#{name => extract_token('$2'), mutation => '$4'}.
field -> name : build_field('$1').
field -> name '(' args ')' : maps:merge(build_field('$1'), #{args => '$3'}).
field -> spread name : build_fragment('$2').
field -> field '{' fields '}' : maps:merge('$1', #{fields => '$3'}).
fields -> field : ['$1'].
fields -> field fields : ['$1'|'$2'].
arg -> name assign word :
#{extract_token('$1') => extract_token('$3')}.
arg -> name assign quoted :
#{extract_token('$1') => extract_quoted('$3')}.
arg -> name assign '{' args '}' :
#{extract_token('$1') => '$4'}.
args -> arg : '$1'.
args -> arg comma args : maps:merge('$1', '$3').
Erlang code.
extract_token({_Token, _Line, Value}) -> list_to_binary(Value).
extract_quoted({_Token, _Line, Value}) ->
list_to_binary(lists:sublist(Value, 2, length(Value) - 2)).
build_field({_Token, _Line, Name}) -> #{name => list_to_binary(Name)}.
build_fragment({_Token, _Line, Name}) -> #{fragment => list_to_binary(Name)}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment