]> git.ozlabs.org Git - ccan/commitdiff
GraphQL lexer and parser (without optional type system)
authorrl-d <robert.lee.dickinson@gmail.com>
Wed, 8 Sep 2021 02:03:07 +0000 (22:03 -0400)
committerrl-d <robert.lee.dickinson@gmail.com>
Wed, 8 Sep 2021 02:03:07 +0000 (22:03 -0400)
ccan/graphql/LICENSE [new symlink]
ccan/graphql/_info [new file with mode: 0644]
ccan/graphql/graphql.c [new file with mode: 0644]
ccan/graphql/graphql.h [new file with mode: 0644]
ccan/graphql/test/run.c [new file with mode: 0644]

diff --git a/ccan/graphql/LICENSE b/ccan/graphql/LICENSE
new file mode 120000 (symlink)
index 0000000..2354d12
--- /dev/null
@@ -0,0 +1 @@
+../../licenses/BSD-MIT
\ No newline at end of file
diff --git a/ccan/graphql/_info b/ccan/graphql/_info
new file mode 100644 (file)
index 0000000..efdb6a1
--- /dev/null
@@ -0,0 +1,68 @@
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * graphql - Routines to lex and parse GraphQL.
+ *
+ * This code contains routines to lex and parse GraphQL code.
+ * This code was written per the spec at:
+ *    https://spec.graphql.org/draft/
+ * ...dated Fri, May 21, 2021 at the time of writing.
+ *    Copyright (c) 2021 WhiteCloudFarm.org <robert.lee.dickinson@gmail.com>
+ *    <https://github.com/rl-d/ccan>
+ * 
+ * Example:
+ *     #include <stdio.h>
+ *     #include "ccan/graphql/graphql.h"
+ *     
+ *     int main(int argc, char *argv[])
+ *     
+ *             const char *input_string = "{ fieldName }";
+ *             struct list_head *output_tokens;
+ *             struct graphql_executable_document *output_document;
+ *     
+ *             const char *errmsg = graphql_lexparse(
+ *                     input_string,
+ *                     NULL, // tal context
+ *                     &output_tokens, // variable to receive tokens
+ *                     &output_document); // variable to receive AST
+ *     
+ *             if (errmsg) {
+ *                     struct graphql_token *last_token;
+ *                     last_token = list_tail(output_tokens, struct graphql_token, list);
+ *                     printf("Line %d, col %d: %s",
+ *                             last_token->source_line,
+ *                             last_token->source_column + last_token->source_len,
+ *                             errmsg);
+ *             } else {
+ *                     // Normally you would check every indirection in the resulting AST for null
+ *                     // pointers, but for simplicity of example:
+ *                     printf("A field from the parsed string: %s\n",
+ *                             output_document->first_def->op_def->sel_set->
+ *                             first->field->name->token_string);
+ *             }
+ *     
+ *             output_tokens = tal_free(output_tokens);
+ *     }
+ *
+ * License: BSD-MIT
+ */
+int main(int argc, char *argv[])
+{
+       /* Expect exactly one argument */
+       if (argc != 2)
+               return 1;
+
+       if (strcmp(argv[1], "depends") == 0) {
+               printf("ccan/list\n");
+               printf("ccan/take\n");
+               printf("ccan/tal\n");
+               printf("ccan/tal/str\n");
+               printf("ccan/utf8\n");
+               return 0;
+       }
+
+       return 1;
+}
+
diff --git a/ccan/graphql/graphql.c b/ccan/graphql/graphql.c
new file mode 100644 (file)
index 0000000..e2b70ef
--- /dev/null
@@ -0,0 +1,1028 @@
+
+#include "graphql.h"
+
+#include "ccan/tal/str/str.h"
+#include "ccan/utf8/utf8.h"
+
+
+// GraphQL character classes
+
+#define SOURCE_CHAR(c) ((c) == 9 || (c) == 10 || (c) == 13 || ((c) >= 32 && (c) <= 65535))
+#define WHITE_SPACE(c) ((c) == 9 || (c) == 32)
+#define LINE_TERMINATOR(c) ((c) == 10 || (c) == 13)
+#define COMMENT(c) ((c) == 35)
+#define COMMENT_CHAR(c) (SOURCE_CHAR(c) && !LINE_TERMINATOR(c))
+#define STRING_CHAR(c) (SOURCE_CHAR(c) && !LINE_TERMINATOR(c) && (c)!='"' && (c)!='\\')
+#define BLOCK_STRING_CHAR(c) (SOURCE_CHAR(c))
+#define COMMA(c) ((c) == 44)
+#define EOF_CHAR(c) ((c) == 0 || (c) == 4)
+#define PUNCTUATOR(c) (strchr("!$&().:=@[]{|}", c))
+#define HEX_DIGIT(c) (DIGIT(c) || ((c) >= 0x61 && (c) <= 0x66) || ((c) >= 0x41 && (c) <= 0x46))
+#define DIGIT(c) ((c) >= 0x30 && (c) <= 0x39)
+#define NAME_START(c) (((c) >= 0x61 && (c) <= 0x7A) || ((c) >= 0x41 && (c) <= 0x5A) || (c) == 0x5F)
+#define NAME_CONTINUE(c) (NAME_START(c) || DIGIT(c))
+
+
+// Parser shorthands
+
+#define RET void *
+#define PARAMS struct list_head *tokens, struct list_head *used, const char **err
+#define ARGS tokens, used, err
+#define INIT(type) \
+       struct graphql_token *rollback_top = list_top(tokens, struct graphql_token, list); \
+       struct graphql_##type *obj = tal(tokens, struct graphql_##type); memset(obj, 0, sizeof(struct graphql_##type)); \
+
+#define EXIT \
+       exit_label: \
+       if (*err) obj = tal_free(obj); \
+       return obj; \
+
+#define CONSUME_ONE { list_add(used, list_pop(tokens, struct graphql_token, list)); }
+#define RESTORE_ONE { list_add(tokens, list_pop(used, struct graphql_token, list)); }
+#define ROLLBACK(args) { while (list_top(tokens, struct graphql_token, list) != rollback_top) { RESTORE_ONE; } }
+#define OR if (!*err) goto exit_label; *err = NULL;
+#define REQ if (*err) { ROLLBACK(args); goto exit_label; }
+#define OPT *err = NULL;
+#define WHILE_OPT while(!*err); *err = NULL;
+#define LOOKAHEAD(args, tok) struct graphql_token *tok = list_top(tokens, struct graphql_token, list);
+#define MSG(msg) if (*err) *err = msg;
+
+
+// Parser functions
+
+RET parse_document(PARAMS);
+RET parse_definition(PARAMS);
+RET parse_executable_document(PARAMS);
+RET parse_executable_definition(PARAMS);
+RET parse_operation_definition(PARAMS);
+RET parse_operation_type(PARAMS);
+RET parse_selection_set(PARAMS);
+RET parse_selection(PARAMS);
+RET parse_field(PARAMS);
+RET parse_arguments(PARAMS);
+RET parse_argument(PARAMS);
+RET parse_alias(PARAMS);
+RET parse_fragment_spread(PARAMS);
+RET parse_fragment_definition(PARAMS);
+RET parse_fragment_name(PARAMS);
+RET parse_type_condition(PARAMS);
+RET parse_inline_fragment(PARAMS);
+RET parse_value(PARAMS);
+RET parse_int_value(PARAMS);
+RET parse_negative_sign(PARAMS);
+RET parse_non_zero_digit(PARAMS);
+RET parse_float_value(PARAMS);
+RET parse_boolean_value(PARAMS);
+RET parse_string_value(PARAMS);
+RET parse_string_character(PARAMS);
+RET parse_escaped_unicode(PARAMS);
+RET parse_escaped_character(PARAMS);
+RET parse_block_string_character(PARAMS);
+RET parse_null_value(PARAMS);
+RET parse_enum_value(PARAMS);
+RET parse_list_value(PARAMS);
+RET parse_object_value(PARAMS);
+RET parse_object_field(PARAMS);
+RET parse_variable(PARAMS);
+RET parse_variable_definitions(PARAMS);
+RET parse_variable_definition(PARAMS);
+RET parse_default_value(PARAMS);
+RET parse_type(PARAMS);
+RET parse_named_type(PARAMS);
+RET parse_list_type(PARAMS);
+RET parse_non_null_type(PARAMS);
+RET parse_non_null_type_1(PARAMS);
+RET parse_non_null_type_2(PARAMS);
+RET parse_directives(PARAMS);
+RET parse_directive(PARAMS);
+RET parse_type_system_document(PARAMS);
+RET parse_type_system_definition(PARAMS);
+RET parse_type_system_extension_document(PARAMS);
+RET parse_type_system_definition_or_extension(PARAMS);
+RET parse_type_system_extension(PARAMS);
+RET parse_description(PARAMS);
+RET parse_schema_definition(PARAMS);
+RET parse_root_operation_type_definition(PARAMS);
+RET parse_schema_extension(PARAMS);
+RET parse_type_definition(PARAMS);
+RET parse_type_extension(PARAMS);
+RET parse_scalar_type_definition(PARAMS);
+RET parse_scalar_type_extension(PARAMS);
+RET parse_object_type_definition(PARAMS);
+RET parse_implements_interfaces(PARAMS);
+RET parse_fields_definition(PARAMS);
+RET parse_field_definition(PARAMS);
+RET parse_arguments_definition(PARAMS);
+RET parse_input_value_definition(PARAMS);
+RET parse_object_type_extension(PARAMS);
+RET parse_interface_type_definition(PARAMS);
+RET parse_interface_type_extension(PARAMS);
+RET parse_union_type_definition(PARAMS);
+RET parse_union_member_types(PARAMS);
+RET parse_union_type_extension(PARAMS);
+RET parse_enum_type_definition(PARAMS);
+RET parse_enum_values_definition(PARAMS);
+RET parse_enum_value_definition(PARAMS);
+RET parse_enum_type_extension(PARAMS);
+RET parse_input_object_type_definition(PARAMS);
+RET parse_input_fields_definition(PARAMS);
+RET parse_directive_definition(PARAMS);
+RET parse_directive_locations(PARAMS);
+RET parse_directive_location(PARAMS);
+RET parse_executable_directive_location(PARAMS);
+RET parse_type_system_directive_location(PARAMS);
+
+RET parse_keyword(PARAMS, const char *keyword, const char *errmsg);
+RET parse_punct(PARAMS, int punct);
+RET parse_name(PARAMS);
+RET parse_int(PARAMS);
+RET parse_float(PARAMS);
+RET parse_string(PARAMS);
+
+// Convert input string into AST.
+const char *graphql_lexparse(const char *input, const tal_t *ctx, struct list_head **tokens, struct graphql_executable_document **doc) {
+       const char *err = graphql_lex(input, ctx, tokens);
+       if (!err)
+               err = graphql_parse(*tokens, doc);
+       return err;
+}
+
+// Convert lexed tokens into AST.
+const char *graphql_parse(struct list_head *tokens, struct graphql_executable_document **doc) {
+       struct list_head used = LIST_HEAD_INIT(used);
+       const char *err = NULL;
+       *doc = parse_executable_document(tokens, &used, &err);
+       if (err)
+               return err;
+}
+
+/* The following parser functions follow special rules:
+ *     - The declaration is standardized with RET and PARAMS
+ *     - The "err" argument is assumed to be NULL upon entrance
+ *     - The "err" argument is set on failure
+ *     - If the function fails to parse, then "tokens" shall be as it was upon entrance
+ *     - INIT and EXIT macros are used
+ *     - Macros such as REQ and OPT facilitate readability and conciseness
+ */
+
+RET parse_document(PARAMS) {
+       INIT(document);
+       obj->first_def = parse_definition(ARGS); REQ
+       struct graphql_definition *p = obj->first_def;
+       do {
+               p->next_def = parse_definition(ARGS);
+               p = p->next_def;
+       } WHILE_OPT;
+       EXIT;
+}
+
+RET parse_definition(PARAMS) {
+       INIT(definition);
+       obj->executable_def = parse_executable_definition(ARGS);
+/*     OR
+       obj->type_system_def = parse_type_system_definition_or_extension(ARGS);
+       // NOTE: Optional type system is not (yet) implemented.
+*/
+       EXIT;
+}
+
+RET parse_executable_document(PARAMS) {
+       INIT(executable_document);
+       obj->first_def = parse_executable_definition(ARGS); REQ
+       struct graphql_executable_definition *p = obj->first_def;
+       do {
+               p->next_def = parse_executable_definition(ARGS);
+               p = p->next_def;
+       } WHILE_OPT;
+       EXIT;
+}
+
+RET parse_executable_definition(PARAMS) {
+       INIT(executable_definition);
+       obj->op_def = parse_operation_definition(ARGS); MSG("invalid operation or fragment definition"); OR
+       obj->frag_def = parse_fragment_definition(ARGS); MSG("invalid operation or fragment definition"); 
+       EXIT;
+}
+
+RET parse_operation_definition(PARAMS) {
+       INIT(operation_definition);
+       obj->op_type = parse_operation_type(ARGS);
+       if (!*err) {
+               obj->op_name = parse_name(ARGS); OPT
+               obj->vars = parse_variable_definitions(ARGS); OPT
+               obj->directives = parse_directives(ARGS); OPT
+       } else
+               *err = NULL;
+       obj->sel_set = parse_selection_set(ARGS);
+       if (*err) ROLLBACK(ARGS);
+       EXIT;
+}
+
+RET parse_operation_type(PARAMS) {
+       INIT(operation_type);
+       const char *errmsg = "expected: query, mutation, or subscription";
+       obj->op_type = parse_keyword(ARGS, "query", errmsg); OR
+       obj->op_type = parse_keyword(ARGS, "mutation", errmsg); OR
+       obj->op_type = parse_keyword(ARGS, "subscription", errmsg);
+       EXIT;
+}
+
+RET parse_selection_set(PARAMS) {
+       INIT(selection_set);
+       parse_punct(ARGS, '{'); REQ;
+       obj->first = parse_selection(ARGS); REQ;
+       struct graphql_selection *p = obj->first;
+       parse_punct(ARGS, '}');
+       while (*err) {
+               *err = NULL;
+               p->next = parse_selection(ARGS); MSG("expected: selection or '}'"); REQ;
+               p = p->next;
+               parse_punct(ARGS, '}');
+       }
+       EXIT;
+}
+
+RET parse_selection(PARAMS) {
+       INIT(selection);
+       obj->field = parse_field(ARGS); OR
+       obj->frag_spread = parse_fragment_spread(ARGS); OR
+       obj->inline_frag = parse_inline_fragment(ARGS);
+       MSG("expected: field, fragment spread, or inline fragment");
+       EXIT;
+}
+
+RET parse_field(PARAMS) {
+       INIT(field);
+       obj->alias = parse_alias(ARGS); OPT
+       obj->name = parse_name(ARGS); REQ
+       obj->args = parse_arguments(ARGS); OPT
+       obj->directives = parse_directives(ARGS); OPT
+       obj->sel_set = parse_selection_set(ARGS); OPT
+       EXIT;
+}
+
+RET parse_arguments(PARAMS) {
+       INIT(arguments);
+       parse_punct(ARGS, '('); REQ
+       obj->first = parse_argument(ARGS); REQ
+       struct graphql_argument *p = obj->first;
+       parse_punct(ARGS, ')');
+       while (*err) {
+               *err = NULL;
+               p->next = parse_argument(ARGS); MSG("expected: argument or ')'"); REQ;
+               p = p->next;
+               parse_punct(ARGS, ')');
+       }
+       EXIT;
+}
+
+RET parse_argument(PARAMS) {
+       INIT(argument);
+       obj->name = parse_name(ARGS); REQ
+       parse_punct(ARGS, ':'); REQ
+       obj->val = parse_value(ARGS); REQ
+       EXIT;
+}
+
+RET parse_alias(PARAMS) {
+       INIT(alias);
+       obj->name = parse_name(ARGS); REQ
+       parse_punct(ARGS, ':'); REQ
+       EXIT;
+}
+
+RET parse_fragment_spread(PARAMS) {
+       INIT(fragment_spread);
+       parse_punct(ARGS, 0x2026); REQ // ...
+       obj->name = parse_fragment_name(ARGS); REQ
+       obj->directives = parse_directives(ARGS); OPT
+       EXIT;
+}
+
+RET parse_fragment_definition(PARAMS) {
+       INIT(fragment_definition);
+       parse_keyword(ARGS, "fragment", "fragment expected"); REQ
+       obj->name = parse_fragment_name(ARGS); REQ
+       obj->type_cond = parse_type_condition(ARGS); REQ
+       obj->directives = parse_directives(ARGS); OPT
+       obj->sel_set = parse_selection_set(ARGS); REQ
+       EXIT;
+}
+
+RET parse_fragment_name(PARAMS) {
+       INIT(fragment_name);
+       obj->name = parse_name(ARGS); REQ
+       struct graphql_token *tok = list_top(used, struct graphql_token, list);
+       if (streq(tok->token_string, "on")) {
+               *err = "invalid fragment name";
+               ROLLBACK(ARGS);
+       }
+       EXIT;
+}
+
+RET parse_type_condition(PARAMS) {
+       INIT(type_condition);
+       parse_keyword(ARGS, "on", "expected: 'on'"); REQ
+       obj->named_type = parse_named_type(ARGS); REQ
+       EXIT;
+}
+
+RET parse_inline_fragment(PARAMS) {
+       INIT(inline_fragment);
+       parse_punct(ARGS, 0x2026); REQ // ...
+       obj->type_cond = parse_type_condition(ARGS); OPT
+       obj->directives = parse_directives(ARGS); OPT
+       obj->sel_set = parse_selection_set(ARGS); REQ
+       EXIT;
+}
+
+RET parse_value(PARAMS) {
+       INIT(value);
+       obj->var = parse_variable(ARGS); // FIXME: if not const
+       OR
+       obj->int_val = parse_int_value(ARGS); OR
+       obj->float_val = parse_float_value(ARGS); OR
+       obj->str_val = parse_string_value(ARGS); OR
+       obj->bool_val = parse_boolean_value(ARGS); OR
+       obj->null_val = parse_null_value(ARGS); OR
+       obj->enum_val = parse_enum_value(ARGS); OR
+       obj->list_val = parse_list_value(ARGS); OR
+       obj->obj_val = parse_object_value(ARGS);
+       EXIT;
+}
+
+RET parse_int_value(PARAMS) {
+       INIT(int_value);
+       obj->val = parse_int(ARGS);
+       EXIT;
+}
+
+RET parse_float_value(PARAMS) {
+       INIT(float_value);
+       obj->val = parse_float(ARGS);
+       EXIT;
+}
+
+RET parse_boolean_value(PARAMS) {
+       INIT(boolean_value);
+       obj->val = parse_keyword(ARGS, "true", "invalid boolean value"); OR
+       obj->val = parse_keyword(ARGS, "false", "invalid boolean value");
+       EXIT;
+}
+
+RET parse_string_value(PARAMS) {
+       INIT(string_value);
+       obj->val = parse_string(ARGS);
+       EXIT;
+}
+
+RET parse_null_value(PARAMS) {
+       INIT(null_value);
+       obj->val = parse_keyword(ARGS, "null", "null expected");
+       EXIT;
+}
+
+RET parse_enum_value(PARAMS) {
+       INIT(enum_value);
+       obj->val = parse_name(ARGS); REQ
+       struct graphql_token *tok = list_top(used, struct graphql_token, list);
+       if (streq(tok->token_string, "true")
+        || streq(tok->token_string, "false")
+        || streq(tok->token_string, "null")) {
+               *err = "enum value cannot be true, false, or null";
+               ROLLBACK(ARGS);
+       }
+       EXIT;
+}
+
+RET parse_list_value(PARAMS) {
+       INIT(list_value);
+       parse_punct(ARGS, '['); REQ
+       parse_punct(ARGS, ']');
+       while (*err) {
+               *err = NULL;
+               parse_value(ARGS); MSG("expected: value or ']'"); REQ
+               parse_punct(ARGS, ']');
+       }
+       EXIT;
+}
+
+RET parse_object_value(PARAMS) {
+       INIT(object_value);
+       parse_punct(ARGS, '{'); REQ
+       parse_punct(ARGS, '}');
+       struct graphql_object_field *p = NULL;
+       while (*err) {
+               *err = NULL;
+               if (!p) {
+                       obj->first = p = parse_object_field(ARGS); MSG("expected: object field or '}'"); REQ
+               } else {
+                       p->next = parse_object_field(ARGS); MSG("expected: object field or '}'"); REQ
+                       p = p->next;
+               }
+               parse_punct(ARGS, '}');
+       }
+       EXIT;
+}
+
+RET parse_object_field(PARAMS) {
+       INIT(object_field);
+       obj->name = parse_name(ARGS); REQ
+       parse_punct(ARGS, ':'); REQ
+       obj->val = parse_value(ARGS); REQ
+       EXIT;
+}
+
+RET parse_variable(PARAMS) {
+       INIT(variable);
+       parse_punct(ARGS, '$'); REQ
+       obj->name = parse_name(ARGS); REQ
+       EXIT;
+}
+
+RET parse_variable_definitions(PARAMS) {
+       INIT(variable_definitions);
+       parse_punct(ARGS, '('); REQ
+       obj->first = parse_variable_definition(ARGS); REQ
+       struct graphql_variable_definition *p = obj->first;
+       parse_punct(ARGS, ')');
+       while (*err) {
+               *err = NULL;
+               p->next = parse_variable_definition(ARGS); MSG("expected: variable definition or ')'"); REQ
+               p = p->next;
+               parse_punct(ARGS, ')');
+       }
+       EXIT;
+}
+
+RET parse_variable_definition(PARAMS) {
+       INIT(variable_definition);
+       obj->var = parse_variable(ARGS); REQ
+       parse_punct(ARGS, ':'); REQ
+       obj->type = parse_type(ARGS); REQ
+       obj->default_val = parse_default_value(ARGS); OPT
+       obj->directives = parse_directives(ARGS); OPT
+       EXIT;
+}
+
+RET parse_default_value(PARAMS) {
+       INIT(default_value);
+       parse_punct(ARGS, '='); REQ
+       obj->val = parse_value(ARGS); REQ
+       EXIT;
+}
+
+RET parse_type(PARAMS) {
+       INIT(type);
+       obj->named = parse_named_type(ARGS);
+/*
+       OR
+       obj->list = parse_list_type(ARGS); OR
+       obj->non_null = parse_non_null_type(ARGS);
+*/
+       EXIT;
+}
+
+RET parse_named_type(PARAMS) {
+       INIT(named_type);
+       obj->name = parse_name(ARGS);
+       EXIT;
+}
+
+/*
+RET parse_list_type(PARAMS) {
+       INIT(list_type);
+       parse_punct(ARGS, '['); REQ
+       parse_type(ARGS); REQ
+       parse_punct(ARGS, ']'); REQ
+       EXIT;
+}
+
+RET parse_non_null_type(PARAMS) {
+       INIT(non_null_type);
+       parse_non_null_type_1(ARGS); OR
+       parse_non_null_type_2(ARGS);
+       EXIT;
+}
+
+RET parse_non_null_type_1(PARAMS) {
+       INIT(non_null_type);
+       parse_named_type(ARGS); REQ;
+       parse_punct(ARGS, '!'); REQ;
+       EXIT;
+}
+
+RET parse_non_null_type_2(PARAMS) {
+       INIT(non_null_type);
+       parse_list_type(ARGS); REQ;
+       parse_punct(ARGS, '!'); REQ;
+       EXIT;
+}
+*/
+
+RET parse_directives(PARAMS) {
+       INIT(directives);
+       obj->first = parse_directive(ARGS); REQ
+       struct graphql_directive *p = obj->first;
+       do {
+               p->next = parse_directive(ARGS);
+               p = p->next;
+       } WHILE_OPT;
+       EXIT;
+}
+
+RET parse_directive(PARAMS) {
+       INIT(directive);
+       parse_punct(ARGS, '@'); REQ
+       obj->name = parse_name(ARGS); REQ
+       obj->args = parse_arguments(ARGS); OPT
+       EXIT;
+}
+
+
+/* The following functions construct the "leaves" of the abstract syntax tree. */
+
+RET parse_keyword(PARAMS, const char *keyword, const char *errmsg) {
+       struct graphql_token *tok = list_top(tokens, struct graphql_token, list);
+       if (!tok || tok->token_type != 'a') {
+               *err = errmsg; return;
+       }
+       if (!streq(tok->token_string, keyword)) {
+               *err = errmsg; return;
+       }
+       CONSUME_ONE(ARGS);
+       return tok;
+}
+
+// Note: a static buffer is used here.
+RET parse_punct(PARAMS, int punct) {
+       static char punctbuf[16];
+       struct graphql_token *tok = list_top(tokens, struct graphql_token, list);
+       if (!tok || tok->token_type != punct) {
+               if (punct == 0x2026)
+                       sprintf(punctbuf, "expected: '...'");
+               else
+                       sprintf(punctbuf, "expected: '%c'", punct);
+               *err = punctbuf; return;
+       }
+       CONSUME_ONE(ARGS);
+       return tok;
+}
+
+RET parse_name(PARAMS) {
+       struct graphql_token *tok = list_top(tokens, struct graphql_token, list);
+       if (!tok || tok->token_type != 'a') {
+               *err = "name expected"; return 0;
+       }
+       CONSUME_ONE(ARGS);
+       return tok;
+}
+
+RET parse_int(PARAMS) {
+       struct graphql_token *tok = list_top(tokens, struct graphql_token, list);
+       if (!tok || tok->token_type != 'i') {
+               *err = "integer expected"; return;
+       }
+       CONSUME_ONE(ARGS);
+       return tok;
+}
+
+RET parse_float(PARAMS) {
+       struct graphql_token *tok = list_top(tokens, struct graphql_token, list);
+       if (!tok || tok->token_type != 'f') {
+               *err = "float expected"; return;
+       }
+       CONSUME_ONE(ARGS);
+       return tok;
+}
+
+RET parse_string(PARAMS) {
+       struct graphql_token *tok = list_top(tokens, struct graphql_token, list);
+       if (!tok || tok->token_type != 's') {
+               *err = "string expected"; return;
+       }
+       CONSUME_ONE(ARGS);
+       return tok;
+}
+
+
+// Convert input string into tokens.
+const char *graphql_lex(const char *input, const tal_t *ctx, struct list_head **tokens) {
+
+       unsigned int c;
+       const char *p, *line_beginning;
+       unsigned int line_num = 1;
+       struct list_head *tok_list;
+       struct graphql_token *tok;
+
+       // Initialize token output list.
+       tok_list = tal(ctx, struct list_head);
+       if (tokens)
+               *tokens = tok_list;
+       list_head_init(tok_list);
+
+       // Note: label and goto are used here like a continue statement except that
+        // it skips iteration, for when characters are fetched in the loop body.
+       p = input;
+       line_beginning = p;
+       do {
+               c = *p++;
+newchar:
+               // Consume line terminators and increment line counter.
+               if (LINE_TERMINATOR(c)) {
+                       unsigned int c0 = c;
+                       c = *p++;
+                       if (c0 == 10 || c0 == 13)
+                               line_num++;
+                       if (c0 == 13 && c == 10)
+                               c = *p++;
+                       line_beginning = p - 1;
+                       goto newchar;
+               }
+
+               // Consume other ignored tokens.
+               if (COMMA(c) || WHITE_SPACE(c)) {
+                       c = *p++;
+                       goto newchar;
+               }
+               if (COMMENT(c)) {
+                       while ((c = *p++) != EOF && !EOF_CHAR(c) && COMMENT_CHAR(c))
+                               ; // No-op
+                       goto newchar;
+               }
+
+               // Return success when end is reached.
+               if (EOF_CHAR(c))
+                       return GRAPHQL_SUCCESS;
+
+               // Punctuator tokens.
+               if (PUNCTUATOR(c)) {
+
+                       // Note beginning of token in input.
+                       const char *start = p - 1;
+
+                       // Handle the ... multi-character case.
+                       if (c == '.') {
+                               c = *p++;
+                               if (c != '.')
+                                       return "unrecognized punctuator";
+                               c = *p++;
+                               if (c != '.')
+                                       return "unrecognized punctuator";
+                               c = 0x2026;
+                       }
+
+                       tok = tal(tok_list, struct graphql_token);
+                       list_add_tail(tok_list, tok);
+                       tok->token_type = c;
+                       tok->token_specific = c;
+                       tok->token_string = NULL;
+                       tok->source_line = line_num;
+                       tok->source_column = start - line_beginning + 1;
+                       tok->source_len = p - start;
+
+               } else if (NAME_START(c)) {
+
+                       // Name/identifier tokens.
+                       tok = tal(tok_list, struct graphql_token);
+                       list_add_tail(tok_list, tok);
+                       tok->token_type = 'a';
+                       tok->token_specific = 'a';
+                       // tok->token_string updated below.
+                       tok->source_line = line_num;
+                       tok->source_column = p - line_beginning;
+                       // tok->source_len updated below.
+
+                       // Note the beginning of the name.
+                       const char *name_begin = p - 1;
+                       const char *name_end;
+                       int name_len;
+
+                       // Consume the rest of the token.
+                       do {
+                               c = *p++;
+                       } while (NAME_CONTINUE(c));
+
+                       // Note the end of the name and calculate the length.
+                       name_end = p - 1;
+                       name_len = name_end - name_begin;
+                       tok->source_len = name_len;
+
+                       // Copy the token string.
+                       tok->token_string = tal_strndup(tok, name_begin, name_len);
+
+                       goto newchar;
+
+               } else if (DIGIT(c) || c == '-') {
+
+                       // Number tokens.
+                       const char *num_start = p - 1;
+                       char type = 'i';
+
+                       if (c == '-') {
+                               c = *p++;
+                               if (!DIGIT(c))
+                                       return "negative sign must precede a number";
+                       }
+
+                       if (c == '0') {
+                               c = *p++;
+                               if (DIGIT(c))
+                                       return "leading zeros are not allowed";
+                       } else {
+                               do {
+                                       c = *p++;
+                               } while(DIGIT(c));
+                       }
+
+                       if (c == '.') {
+                               type = 'f';
+                               if (!DIGIT(*p))
+                                       return "invalid float value fractional part";
+                               do {
+                                       c = *p++;
+                               } while(DIGIT(c));
+                       }
+
+                       if (c == 'e' || c == 'E') {
+                               type = 'f';
+                               c = *p++;
+                               if (c == '+' || c == '-')
+                                       c = *p++;
+                               if (!DIGIT(*p))
+                                       return "invalid float value exponent part";
+                               do {
+                                       c = *p++;
+                               } while(DIGIT(c));
+                       }
+
+                       if (c == '.' || NAME_START(c))
+                               return "invalid numeric value";
+
+                       const char *num_end = p - 1;
+                       int num_len = num_end - num_start;
+
+                       tok = tal(tok_list, struct graphql_token);
+                       list_add_tail(tok_list, tok);
+                       tok->token_type = type;
+                       tok->token_string = tal_strndup(tok, num_start, num_len);
+                       tok->source_line = line_num;
+                       tok->source_column = num_start - line_beginning + 1;
+                       tok->source_len = num_len;
+
+                       goto newchar;
+
+               } else if (c == '"') {
+
+                       // String tokens.
+                       c = *p++;
+                       const char *str_begin = p - 1;
+                       const char *str_end;
+                       bool str_block = false;
+                       if (c == '"') {
+                               c = *p++;
+                               if (c == '"') {
+                                       // block string
+                                       str_block = true;
+                                       str_begin += 2;
+                                       int quotes = 0;
+                                       do {
+                                               c = *p++;
+                                               if (c == '\"') quotes++; else quotes = 0;
+                                               if (quotes == 3 && *(p-4) == '\\') quotes = 0;
+                                       } while (BLOCK_STRING_CHAR(c) && quotes < 3);
+                                       if (quotes == 3) {
+                                               c = *--p;
+                                               c = *--p;
+                                       }
+                                       str_end = p - 1;
+                                       if (c != '"')
+                                               return "unterminated string or invalid character";
+                                       c = *p++;
+                                       if (c != '"')
+                                               return "invalid string termination";
+                                       c = *p++;
+                                       if (c != '"')
+                                               return "invalid string termination";
+                               } else {
+                                       // empty string
+                                       str_end = str_begin;
+                                       --p;
+                               }
+                       } else {
+                               // normal string
+                               --p;
+                               do {
+                                       c = *p++;
+                                       if (c == '\\') {
+                                               c = *p++;
+                                               if (strchr("\"\\/bfnrtu", c)) {
+                                                       if (c == 'u') {
+                                                               c = *p++;
+                                                               if (!HEX_DIGIT(c))
+                                                                       return "invalid unicode escape sequence";
+                                                               c = *p++;
+                                                               if (!HEX_DIGIT(c))
+                                                                       return "invalid unicode escape sequence";
+                                                               c = *p++;
+                                                               if (!HEX_DIGIT(c))
+                                                                       return "invalid unicode escape sequence";
+                                                               c = *p++;
+                                                               if (!HEX_DIGIT(c))
+                                                                       return "invalid unicode escape sequence";
+                                                       } else {
+                                                               c = 'a'; // anything besides a quote to let the loop continue
+                                                       }
+                                               } else {
+                                                       return "invalid string escape sequence";
+                                               }
+                                       }
+                               } while (STRING_CHAR(c));
+                               if (c != '"')
+                                       return "unterminated string or invalid character";
+                               str_end = p - 1;
+                       }
+                       int str_len = str_end - str_begin;
+
+                       tok = tal(tok_list, struct graphql_token);
+                       list_add_tail(tok_list, tok);
+                       tok->token_type = 's';
+                       tok->token_specific = 's';
+                       tok->token_string = tal_strndup(tok, str_begin, str_len);
+                       tok->source_line = line_num;
+                       tok->source_column = str_begin - line_beginning + 1;
+                       tok->source_len = str_len;
+
+                       // Process escape sequences. These always shorten the string (so the memory allocation is always enough).
+                       char d;
+                       char *q = tok->token_string;
+                       char *rewrite_dest;
+                       int quotes = 0;
+                       while (d = *q++) {
+                               if (str_block) {
+                                       if (d == '\"') quotes++; else quotes = 0;
+                                       if (quotes == 3 && *(q-4) == '\\') {
+                                               quotes = 0;
+                                               rewrite_dest = q - 4;
+                                               strcpy(rewrite_dest, q - 3);
+                                       }
+                               } else {
+                                       if (d == '\\') {
+                                               rewrite_dest = q - 1;
+                                               d = *q++;
+                                               switch (d) {
+                                               case '\"':
+                                                       *rewrite_dest++ = '\"';
+                                                       strcpy(rewrite_dest, q--);
+                                                       break;
+                                               case 'b':
+                                                       *rewrite_dest++ = '\b';
+                                                       strcpy(rewrite_dest, q--);
+                                                       break;
+                                               case 'f':
+                                                       *rewrite_dest++ = '\f';
+                                                       strcpy(rewrite_dest, q--);
+                                                       break;
+                                               case 'n':
+                                                       *rewrite_dest++ = '\n';
+                                                       strcpy(rewrite_dest, q--);
+                                                       break;
+                                               case 'r':
+                                                       *rewrite_dest++ = '\r';
+                                                       strcpy(rewrite_dest, q--);
+                                                       break;
+                                               case 't':
+                                                       *rewrite_dest++ = '\t';
+                                                       strcpy(rewrite_dest, q--);
+                                                       break;
+                                               case 'u': {
+                                                               // Insert escaped character using UTF-8 multi-byte encoding.
+                                                               char buf[] = {*q++, *q++, *q++, *q++, 0};
+                                                               int code_point = strtol(buf, 0, 16);
+                                                               int bytes = utf8_encode(code_point, rewrite_dest);
+                                                               rewrite_dest += bytes;
+                                                               strcpy(rewrite_dest, q--);
+                                                       }
+                                                       break;
+                                               default:
+                                                       strcpy(rewrite_dest, --q);
+                                               }
+                                       }
+                               }
+                       }
+                       if (str_block) {
+                               // Strip leading lines.
+                               q = tok->token_string;
+                               for (;;) {
+                                       d = *q++;
+                                       while (WHITE_SPACE(d))
+                                               d = *q++;
+                                       if (LINE_TERMINATOR(d)) {
+                                               while (LINE_TERMINATOR(d))
+                                                       d = *q++;
+                                               strcpy(tok->token_string, q - 1);
+                                               q = tok->token_string;
+                                       } else
+                                               break;
+                               }
+
+                               // Strip trailing lines.
+                               q = tok->token_string + strlen(tok->token_string);
+                               for (;;) {
+                                       d = *--q;
+                                       while (WHITE_SPACE(d))
+                                               d = *--q;
+                                       if (LINE_TERMINATOR(d)) {
+                                               while (LINE_TERMINATOR(d))
+                                                       d = *--q;
+                                               *++q = 0;
+                                       } else
+                                               break;
+                               }
+
+                               // Look for common indentation.
+                               char *this_indent_start;
+                               const char *this_indent_end;
+                               const char *common_indent_start = NULL;
+                               const char *common_indent_end;
+                               const char *r;
+                               q = tok->token_string;
+                               do {
+                                       d = *q++;
+                                       this_indent_start = q - 1;
+                                       while (WHITE_SPACE(d))
+                                               d = *q++;
+                                       this_indent_end = q - 1;
+                                       if (LINE_TERMINATOR(d)) {
+                                               while (LINE_TERMINATOR(d))
+                                                       d = *q++;
+                                               continue;
+                                       }
+                                       if (EOF_CHAR(d))
+                                               continue;
+
+                                       if (common_indent_start == NULL) {
+                                               common_indent_start = this_indent_start;
+                                               common_indent_end = this_indent_end;
+                                       }
+                                       for (r = this_indent_start; r < this_indent_end && (r - this_indent_start + common_indent_start < common_indent_end); r++) {
+                                               if (*r != *(r - this_indent_start + common_indent_start))
+                                                       break;
+                                       }
+                                       common_indent_end = r - this_indent_start + common_indent_start;
+
+                                       while (!LINE_TERMINATOR(d) && !EOF_CHAR(d))
+                                               d = *q++;
+                                       while (LINE_TERMINATOR(d))
+                                               d = *q++;
+                                       --q;
+
+                               } while (d);
+
+                               // Remove common indentation.
+                               int common_indent_len = common_indent_end - common_indent_start;
+                               if (common_indent_len > 0) {
+                                       q = tok->token_string;
+                                       do {
+                                               d = *q++;
+                                               this_indent_start = q - 1;
+                                               while (WHITE_SPACE(d))
+                                                       d = *q++;
+                                               this_indent_end = q - 1;
+                                               if (LINE_TERMINATOR(d)) {
+                                                       while (LINE_TERMINATOR(d))
+                                                               d = *q++;
+                                                       continue;
+                                               }
+                                               if (EOF_CHAR(d))
+                                                       continue;
+
+                                               while (!LINE_TERMINATOR(d) && !EOF_CHAR(d))
+                                                       d = *q++;
+                                               --q;
+
+                                               strcpy(this_indent_start, this_indent_start + common_indent_len);
+                                               q -= common_indent_len;
+                                               d = *q++;
+
+                                               while (LINE_TERMINATOR(d))
+                                                       d = *q++;
+                                               --q;
+
+                                       } while (d);
+                               }
+                       }
+                       c = *p++;
+                       goto newchar;
+
+               } else {
+                       return "invalid source character encountered";
+               }
+
+       } while (!EOF_CHAR(c));
+
+       return "unexpected end-of-input encountered";
+}
+
+
+
diff --git a/ccan/graphql/graphql.h b/ccan/graphql/graphql.h
new file mode 100644 (file)
index 0000000..94f7fa4
--- /dev/null
@@ -0,0 +1,229 @@
+#ifndef __GRAPHQL_H__
+#define __GRAPHQL_H__ 1
+
+#include <stdio.h>
+
+#include <ccan/list/list.h>
+#include <ccan/tal/tal.h>
+
+// Coding constants
+#define GRAPHQL_SUCCESS 0
+
+// The following structures constitute the AST returned by the parser.
+
+struct graphql_directive {
+       struct graphql_directive *next;
+       struct graphql_token *name;
+       struct graphql_arguments *args;
+};
+
+struct graphql_directives {
+       struct graphql_directive *first;
+};
+
+struct graphql_named_type {
+       struct graphql_token *name;
+};
+
+struct graphql_type {
+       struct graphql_named_type *named;
+//     struct graphql_list_type *list;
+//     struct graphql_non_null_type *non_null;
+};
+
+struct graphql_default_value {
+       struct graphql_value *val;
+};
+
+struct graphql_variable_definition {
+       struct graphql_variable_definition *next;
+       struct graphql_variable *var;
+       struct graphql_type *type;
+       struct graphql_default_value *default_val;
+       struct graphql_directives *directives;
+};
+
+struct graphql_variable_definitions {
+       struct graphql_variable_definition *first;
+};
+
+struct graphql_variable {
+       struct graphql_token *name;
+};
+
+struct graphql_object_field {
+       struct graphql_object_field *next;
+       struct graphql_token *name;
+       struct graphql_value *val;
+};
+
+struct graphql_object_value {
+       struct graphql_object_field *first;
+};
+
+struct graphql_list_value {
+       struct graphql_token *val;
+};
+
+struct graphql_enum_value {
+       struct graphql_token *val;
+};
+
+struct graphql_null_value {
+       struct graphql_token *val;
+};
+
+struct graphql_string_value {
+       struct graphql_token *val;
+};
+
+struct graphql_boolean_value {
+       struct graphql_token *val;
+};
+
+struct graphql_float_value {
+       struct graphql_token *val;
+};
+
+struct graphql_int_value {
+       struct graphql_token *val;
+};
+
+struct graphql_value {
+       struct graphql_variable *var;
+       struct graphql_int_value *int_val;
+       struct graphql_float_value *float_val;
+       struct graphql_boolean_value *bool_val;
+       struct graphql_string_value *str_val;
+       struct graphql_null_value *null_val;
+       struct graphql_enum_value *enum_val;
+       struct graphql_list_value *list_val;
+       struct graphql_object_value *obj_val;
+};
+
+struct graphql_inline_fragment {
+       struct graphql_type_condition *type_cond;
+       struct graphql_directives *directives;
+       struct graphql_selection_set *sel_set;
+};
+
+struct graphql_type_condition {
+       struct graphql_named_type *named_type;
+};
+
+struct graphql_fragment_name {
+       struct graphql_token *name;
+};
+
+struct graphql_fragment_definition {
+       struct graphql_fragment_name *name;
+       struct graphql_type_condition *type_cond;
+       struct graphql_directives *directives;
+       struct graphql_selection_set *sel_set;
+};
+
+struct graphql_fragment_spread {
+       struct graphql_fragment_name *name;
+       struct graphql_directives *directives;
+};
+
+struct graphql_alias {
+       struct graphql_token *name;
+};
+
+struct graphql_argument {
+       struct graphql_argument *next;
+       struct graphql_token *name;
+       struct graphql_value *val;
+};
+
+struct graphql_arguments {
+       struct graphql_argument *first;
+};
+
+struct graphql_field {
+       struct graphql_alias *alias;
+       struct graphql_token *name;
+       struct graphql_arguments *args;
+       struct graphql_directives *directives;
+       struct graphql_selection_set *sel_set;
+};
+
+struct graphql_selection {
+       struct graphql_selection *next;
+       struct graphql_field *field;
+       struct graphql_fragment_spread *frag_spread;
+       struct graphql_inline_fragment *inline_frag;
+};
+
+struct graphql_selection_set {
+       struct graphql_selection *first;
+};
+
+struct graphql_operation_type {
+       struct graphql_token *op_type;
+};
+
+struct graphql_operation_definition {
+       struct graphql_operation_type *op_type;
+       struct graphql_token *op_name;
+       struct graphql_variable_definitions *vars;
+       struct graphql_directives *directives;
+       struct graphql_selection_set *sel_set;
+};
+
+struct graphql_executable_definition {
+       struct graphql_executable_definition *next_def;
+       struct graphql_operation_definition *op_def;
+       struct graphql_fragment_definition *frag_def;
+};
+
+struct graphql_executable_document {
+       struct graphql_executable_definition *first_def;
+};
+
+struct graphql_definition {
+       struct graphql_definition *next_def;
+       struct graphql_executable_definition *executable_def;
+       struct graphql_type_system_definition_or_extension *type_system_def;
+};
+
+struct graphql_document {
+       struct graphql_definition *first_def;
+};
+
+
+struct graphql_token {
+       struct list_node list;
+       unsigned int token_type;
+       unsigned int token_specific;
+       char *token_string;
+       unsigned int source_line;
+       unsigned int source_column;
+       unsigned int source_len;
+};
+
+/* The lexer.
+ * INPUTS:
+ *     input - string to parse
+ *     ctx - parent tal context or NULL
+ *     tokens - a variable to receive the resulting token list
+ * RETURN:
+ *     GRAPHQL_SUCCESS or an error string.
+ */
+const char *graphql_lex(const char *input, const tal_t *ctx, struct list_head **tokens);
+
+/* The parser.
+ * INPUTS:
+ *     tokens - the list produced by the lexer
+ *     doc - a variable to receive the resulting abstract syntax tree (AST)
+ * RETURN:
+ *     GRAPHQL_SUCCESS or an error string.
+ */
+const char *graphql_parse(struct list_head *tokens, struct graphql_executable_document **doc);
+
+/* The lexer and parser in one function, for convenience. */
+const char *graphql_lexparse(const char *input, const tal_t *ctx, struct list_head **tokens, struct graphql_executable_document **doc);
+
+#endif
+
diff --git a/ccan/graphql/test/run.c b/ccan/graphql/test/run.c
new file mode 100644 (file)
index 0000000..91bc322
--- /dev/null
@@ -0,0 +1,3177 @@
+#include "ccan/graphql/graphql.h"
+#include "ccan/str/str.h"
+
+/* TEST POINT MACROS
+ *
+ * The idea here is to run each test case silently, and if any test point
+ * fails, that test case is re-run verbosely to pinpoint the failure.
+ *
+ * RUN macros run a whole test case function.
+ *
+ * Different TEST_xxxx macros are provided for different test point types as
+ * follows:
+ *
+ *  TEST_CONT - Test and continue testing regardless of failure (the failure
+ *             will still be printed).
+ *  TEST_ABRT - Test and abort the test case, used when testing pointer
+ *             validity to avoid subsequent dereference errors.
+ *  TEST_STRG - Test a string value, which includes the convenience of testing
+ *             for a null pointer.
+ */
+
+#define RUN(test) { prev_fail = fail; test(source); if (fail != prev_fail) { mute = false; test(source); mute = true; } }
+#define RUN1(test,arg) { prev_fail = fail; test(source,arg); if (fail != prev_fail) { mute = false; test(source,arg); mute = true; } }
+#define RUN2(test,arg1,arg2) { prev_fail = fail; test(source,arg1,arg2); if (fail != prev_fail) { mute = false; test(source,arg1,arg2); mute = true; } }
+
+#define TEST_CONT(expr) { bool c = (expr); if (mute) c? pass++ : fail++; else printf("%s: %s\033[0m\n", c? "passed" : "\033[91mfailed", stringify(expr)); }
+#define TEST_ABRT(expr) { bool c = (expr); if (mute) c? pass++ : fail++; else printf("%s: %s\033[0m\n", c? "passed" : "\033[91mfailed", stringify(expr)); if (!c) return; }
+#define TEST_STRG(str,expr) { bool c = ((str) && streq((str),(expr))); if (mute) c? pass++ : fail++; else printf("%s: %s == %s\033[0m\n", c? "passed" : "\033[91mfailed", stringify(str), stringify(expr)); if (!c) return; }
+
+// Global variables to track overall results.
+int pass = 0, fail = 0;
+bool mute = 1;
+
+// Helper function.
+int listlen(struct list_head *tokens) {
+       struct graphql_token *tok;
+       int n=0;
+       list_for_each(tokens, tok, list) {
+               n++;
+       }
+       return n;
+}
+
+/* Test case functions begin here, called by main().
+ * Note: Memory should be freed correctly in the success case, but if there
+ * are errors, all bets are off.
+ */
+
+int check_example_3(const char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 3\n");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 11);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '{');
+       TEST_CONT(tok->source_line == 1);
+       TEST_CONT(tok->source_column == 1);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "user");
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 3);
+       TEST_CONT(tok->source_len == 4);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '(');
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 7);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 8);
+       TEST_CONT(tok->source_len == 2);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == ':');
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 10);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "4");
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 12);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == ')');
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 13);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '{');
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 15);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       TEST_CONT(tok->source_line == 3);
+       TEST_CONT(tok->source_column == 5);
+       TEST_CONT(tok->source_len == 4);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '}');
+       TEST_CONT(tok->source_line == 4);
+       TEST_CONT(tok->source_column == 3);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '}');
+       TEST_CONT(tok->source_line == 5);
+       TEST_CONT(tok->source_column == 1);
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "user");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "id");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "4");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "name");
+       tokens = tal_free(tokens);
+}
+
+int check_example_5(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 5\n");
+
+       sprintf(source, "\
+mutation {\n\
+  likeStory(storyID: 12345) {\n\
+    story {\n\
+      likeCount\n\
+    }\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 15);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "mutation");
+       TEST_CONT(tok->source_line == 1);
+       TEST_CONT(tok->source_column == 1);
+       TEST_CONT(tok->source_len == 8);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "likeStory");
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 3);
+       TEST_CONT(tok->source_len == 9);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "storyID");
+       TEST_CONT(tok->source_line == 2);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "12345");
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 22);
+       TEST_CONT(tok->source_len == 5);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "story");
+       TEST_CONT(tok->source_line == 3);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "likeCount");
+       TEST_CONT(tok->source_line == 4);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_ABRT(doc->first_def->op_def->op_type != NULL);
+       TEST_ABRT(doc->first_def->op_def->op_type->op_type != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type->op_type->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->op_type->op_type->token_string, "mutation");
+       TEST_ABRT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "likeStory");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "storyID");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "12345");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "story");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field->name->token_string, "likeCount");
+       tokens = tal_free(tokens);
+}
+
+int check_example_6(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 6\n");
+
+       sprintf(source, "\
+{\n\
+  field\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 3);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "field");
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 3);
+       TEST_CONT(tok->source_len == 5);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_ABRT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "field");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_7(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 7\n");
+
+       sprintf(source, "\
+{\n\
+  id\n\
+  firstName\n\
+  lastName\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 5);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 3);
+       TEST_CONT(tok->source_len == 2);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "firstName");
+       TEST_CONT(tok->source_line == 3);
+       TEST_CONT(tok->source_column == 3);
+       TEST_CONT(tok->source_len == 9);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "lastName");
+       TEST_CONT(tok->source_line == 4);
+       TEST_CONT(tok->source_column == 3);
+       TEST_CONT(tok->source_len == 8);
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list);
+       TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_ABRT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "id");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->next->field->name->token_string, "firstName");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->next->next->field->name->token_string, "lastName");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->next->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_8(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 8\n");
+
+       sprintf(source, "\
+{\n\
+  me {\n\
+    id\n\
+    firstName\n\
+    lastName\n\
+    birthday {\n\
+      month\n\
+      day\n\
+    }\n\
+    friends {\n\
+      name\n\
+    }\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 17);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "me");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "firstName");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "lastName");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "birthday");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "month");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "day");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "friends");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_ABRT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "me");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "id");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_string, "firstName");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_string, "lastName");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->name->token_string, "birthday");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field->name->token_string, "month");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field->name->token_string, "day");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->field->sel_set == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set->first->next->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->name->token_string, "friends");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field->name->token_string, "name");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->field->sel_set == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->field->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_9(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 9\n");
+
+       sprintf(source, "\
+# `me` could represent the currently logged in viewer.\n\
+{\n\
+  me {\n\
+    name\n\
+  }\n\
+}\n\
+\n\
+# `user` represents one of many users in a graph of data, referred to by a\n\
+# unique identifier.\n\
+{\n\
+  user(id: 4) {\n\
+    name\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 17);
+       // NOTE: Comments are ignored.
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "me");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "user");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "4");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->next_def != NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_ABRT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "me");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "name");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->next_def->next_def == NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->op_def->sel_set->first->field->name->token_string, "user");
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->op_def->sel_set->first->field->args->first->name->token_string, "id");
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->next_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "4");
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "name");
+       tokens = tal_free(tokens);
+}
+
+int check_example_10(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 10\n");
+
+       sprintf(source, "\
+{\n\
+  user(id: 4) {\n\
+    id\n\
+    name\n\
+    profilePic(size: 100)\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 18);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "user");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "4");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "profilePic");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "size");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "100");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "user");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "id");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "4");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "id");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_string, "name");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_string, "profilePic");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_string, "size");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val->token_string, "100");
+       tokens = tal_free(tokens);
+}
+
+int check_example_11(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 11\n");
+
+       sprintf(source, "\
+{\n\
+  user(id: 4) {\n\
+    id\n\
+    name\n\
+    profilePic(width: 100, height: 50)\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 21);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "user");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "4");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "profilePic");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "width");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "100");
+       // NOTE: Comma is ignored.
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "height");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "50");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "user");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "id");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "4");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "id");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_string, "name");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_string, "profilePic");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_string, "width");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val->token_string, "100");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->name->token_string, "height");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next->val->int_val->val->token_string, "50");
+       tokens = tal_free(tokens);
+}
+
+int check_example_12_and_13(const char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example Nos. 12 and 13\n");
+
+       // Test the lexer.
+       const char *param;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 11);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "picture");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_ABRT(tok->token_string != NULL && (streq(tok->token_string, "width") || streq(tok->token_string, "height")));
+       param = tok->token_string;
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_CONT(tok->token_string != NULL && ((streq(param, "width") && streq(tok->token_string, "200")) || (streq(param, "height") && streq(tok->token_string, "100"))));
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_CONT(tok->token_string != NULL && (streq(tok->token_string, "width") || streq(tok->token_string, "height")));
+       param = tok->token_string;
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_CONT(tok->token_string != NULL && ((streq(param, "width") && streq(tok->token_string, "200")) || (streq(param, "height") && streq(tok->token_string, "100"))));
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_argument *arg;
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "picture");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next->next == NULL);
+       arg = doc->first_def->op_def->sel_set->first->field->args->first;
+       if (!streq(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "width")) arg = arg->next;
+       TEST_ABRT(arg->name != NULL);
+       TEST_CONT(arg->name->token_type == 'a');
+       TEST_STRG(arg->name->token_string, "width");
+       TEST_ABRT(arg->val != NULL);
+       TEST_ABRT(arg->val->int_val != NULL);
+       TEST_ABRT(arg->val->int_val->val != NULL);
+       TEST_CONT(arg->val->int_val->val->token_type == 'i');
+       TEST_STRG(arg->val->int_val->val->token_string, "200");
+       arg = doc->first_def->op_def->sel_set->first->field->args->first;
+       if (!streq(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "height")) arg = arg->next;
+       TEST_ABRT(arg->name != NULL);
+       TEST_CONT(arg->name->token_type == 'a');
+       TEST_STRG(arg->name->token_string, "height");
+       TEST_ABRT(arg->val != NULL);
+       TEST_ABRT(arg->val->int_val != NULL);
+       TEST_ABRT(arg->val->int_val->val != NULL);
+       TEST_CONT(arg->val->int_val->val->token_type == 'i');
+       TEST_STRG(arg->val->int_val->val->token_string, "100");
+       tokens = tal_free(tokens);
+}
+
+int check_example_14(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 14\n");
+
+       sprintf(source, "\
+{\n\
+  user(id: 4) {\n\
+    id\n\
+    name\n\
+    smallPic: profilePic(size: 64)\n\
+    bigPic: profilePic(size: 1024)\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 28);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "user");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "4");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "smallPic");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "profilePic");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "size");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "64");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "bigPic");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "profilePic");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "size");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "1024");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "user");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "id");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "4");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "id");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_string, "name");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias->name->token_string, "smallPic");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_string, "profilePic");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_string, "size");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->int_val->val->token_string, "64");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->alias != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->alias->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->alias->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->alias->name->token_string, "bigPic");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->name->token_string, "profilePic");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->name->token_string, "size");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->val->int_val->val->token_string, "1024");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next->field->args->first->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_16(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 16\n");
+
+       sprintf(source, "\
+{\n\
+  zuck: user(id: 4) {\n\
+    id\n\
+    name\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 14);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "zuck");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "user");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, "4");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->alias != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->alias->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->alias->name->token_string, "zuck");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "user");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "id");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "4");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "id");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_string, "name");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_18(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 18\n");
+
+       sprintf(source, "\
+query noFragments {\n\
+  user(id: 4) {\n\
+    friends(first: 10) {\n\
+      id\n\
+      name\n\
+      profilePic(size: 50)\n\
+    }\n\
+    mutualFriends(first: 10) {\n\
+      id\n\
+      name\n\
+      profilePic(size: 50)\n\
+    }\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 44);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->next->next->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->next->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->next->next->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_19(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 19\n");
+
+       sprintf(source, "\
+query withFragments {\n\
+  user(id: 4) {\n\
+    friends(first: 10) {\n\
+      ...friendFields\n\
+    }\n\
+    mutualFriends(first: 10) {\n\
+      ...friendFields\n\
+    }\n\
+  }\n\
+}\n\
+\n\
+fragment friendFields on User {\n\
+  id\n\
+  name\n\
+  profilePic(size: 50)\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 46);
+       for (int i=0; i<17; i++)
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 0x2026);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "friendFields");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       for (int i=0; i<7; i++)
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 0x2026);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "friendFields");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       const char *e;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT((e = graphql_parse(tokens, &doc)) == NULL);
+       if (e) printf("%s\n", e);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name->name->token_string, "friendFields");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->field == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name->name->token_string, "friendFields");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next == NULL);
+       TEST_ABRT(doc->first_def->next_def != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def == NULL);
+       TEST_CONT(doc->first_def->next_def->op_def == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->name != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->name->name != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->frag_def->name->name->token_string, "friendFields");
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond->named_type != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond->named_type->name != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->type_cond->named_type->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->frag_def->type_cond->named_type->name->token_string, "User");
+       TEST_CONT(doc->first_def->next_def->frag_def->directives == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next->next != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next->next->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_20(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 20\n");
+
+       sprintf(source, "\
+query withNestedFragments {\n\
+  user(id: 4) {\n\
+    friends(first: 10) {\n\
+      ...friendFields\n\
+    }\n\
+    mutualFriends(first: 10) {\n\
+      ...friendFields\n\
+    }\n\
+  }\n\
+}\n\
+\n\
+fragment friendFields on User {\n\
+  id\n\
+  name\n\
+  ...standardProfilePic\n\
+}\n\
+\n\
+fragment standardProfilePic on User {\n\
+  profilePic(size: 50)\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 54);
+       for (int i=0; i<17; i++)
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 0x2026);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "friendFields");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       for (int i=0; i<7; i++)
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 0x2026);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "friendFields");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       const char *e;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT((e = graphql_parse(tokens, &doc)) == NULL);
+       if (e) printf("%s\n", e);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->field == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set->first->frag_spread->name->name->token_string, "friendFields");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->field == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set->first->frag_spread->name->name->token_string, "friendFields");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next == NULL);
+       TEST_ABRT(doc->first_def->next_def != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->name != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->name->name != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->frag_def->name->name->token_string, "friendFields");
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond->named_type != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond->named_type->name != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->type_cond->named_type->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->frag_def->type_cond->named_type->name->token_string, "User");
+       TEST_CONT(doc->first_def->next_def->frag_def->directives == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->next->next->field == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next->next->frag_spread != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next->next->next == NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->next_def == NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->op_def == NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->name != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->name->name != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->next_def->frag_def->name->name->token_string, "standardProfilePic");
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->type_cond != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->type_cond->named_type != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->type_cond->named_type->name != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->type_cond->named_type->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->next_def->frag_def->type_cond->named_type->name->token_string, "User");
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->directives == NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->sel_set->first->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_21(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 21\n");
+
+       sprintf(source, "\
+query FragmentTyping {\n\
+  profiles(handles: [\"zuck\", \"coca-cola\"]) {\n\
+    handle\n\
+    ...userFragment\n\
+    ...pageFragment\n\
+  }\n\
+}\n\
+\n\
+fragment userFragment on User {\n\
+  friends {\n\
+    count\n\
+  }\n\
+}\n\
+\n\
+fragment pageFragment on Page {\n\
+  likers {\n\
+    count\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 40);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "query");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "FragmentTyping");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "profiles");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "handles");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '[');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       TEST_STRG(tok->token_string, "zuck");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       TEST_STRG(tok->token_string, "coca-cola");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ']');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       const char *e;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT((e = graphql_parse(tokens, &doc)) == NULL);
+       if (e) printf("%s\n", e);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread->name != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread->name->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread->name->name->token_string, "userFragment");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread->name != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread->name->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread->name->name->token_string, "pageFragment");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next == NULL);
+       TEST_ABRT(doc->first_def->next_def != NULL);
+       TEST_CONT(doc->first_def->next_def->op_def == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->name != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->name->name != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->frag_def->name->name->token_string, "userFragment");
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond->named_type != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->type_cond->named_type->name != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->type_cond->named_type->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->frag_def->type_cond->named_type->name->token_string, "User");
+       TEST_CONT(doc->first_def->next_def->frag_def->directives == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->next_def->frag_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->next_def->frag_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->next_def == NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->op_def == NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->name != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->name->name != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->name->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->next_def->frag_def->name->name->token_string, "pageFragment");
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->type_cond != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->type_cond->named_type != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->type_cond->named_type->name != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->type_cond->named_type->name->token_type == 'a');
+       TEST_STRG(doc->first_def->next_def->next_def->frag_def->type_cond->named_type->name->token_string, "Page");
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->directives == NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->next_def->next_def->frag_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->next_def->next_def->frag_def->sel_set->first->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_23(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 23\n");
+
+       sprintf(source, "\
+query inlineFragmentTyping {\n\
+  profiles(handles: [\"zuck\", \"coca-cola\"]) {\n\
+    handle\n\
+    ... on User {\n\
+      friends {\n\
+        count\n\
+      }\n\
+    }\n\
+    ... on Page {\n\
+      likers {\n\
+        count\n\
+      }\n\
+    }\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 34);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "query");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "inlineFragmentTyping");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "profiles");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "handles");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '[');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       TEST_STRG(tok->token_string, "zuck");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       TEST_STRG(tok->token_string, "coca-cola");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ']');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       const char *e;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT((e = graphql_parse(tokens, &doc)) == NULL);
+       if (e) printf("%s\n", e);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->type_cond != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->type_cond->named_type->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->type_cond->named_type->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->type_cond->named_type->name->token_string, "User");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->type_cond != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->type_cond->named_type->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->type_cond->named_type->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->type_cond->named_type->name->token_string, "Page");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next == NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_24(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 24\n");
+
+       sprintf(source, "\
+query inlineFragmentNoType($expandedInfo: Boolean) {\n\
+  user(handle: \"zuck\") {\n\
+    id\n\
+    name\n\
+    ... @include(if: $expandedInfo) {\n\
+      firstName\n\
+      lastName\n\
+      birthday\n\
+    }\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 34);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "query");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "inlineFragmentNoType");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '$');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "expandedInfo");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "Boolean");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "user");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "handle");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       TEST_STRG(tok->token_string, "zuck");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "id");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "name");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 0x2026);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '@');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "include");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "if");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '$');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "expandedInfo");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "firstName");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "lastName");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "birthday");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->type_cond == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->name->token_string, "include");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->name->token_string, "if");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->int_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->float_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->bool_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->str_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->null_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->enum_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->list_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->obj_val == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->var != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->var->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->var->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->directives->first->args->first->val->var->name->token_string, "expandedInfo");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->next->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag->sel_set->first->next->next->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next == NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_int_value(char *source, int int_value) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Int Value Range Check on %d\n", int_value);
+
+       sprintf(source, "\
+{\n\
+  user(id: %d) {\n\
+    name\n\
+  }\n\
+}\n\
+       ", int_value);
+
+       char buf[20];
+       sprintf(buf, "%d", int_value);
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 11);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       TEST_STRG(tok->token_string, buf);
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 12);
+       TEST_CONT(tok->source_len == strlen(buf));
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 12 + strlen(buf));
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, buf);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_invalid_int_values(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Invalid Int Values\n");
+
+       char *bad_values[] = {"00", "-00", "+1", "1.", "1a", "1e", "0x123", "123L", 0};
+
+       for (int i=0; bad_values[i]; i++) {
+               sprintf(source, "\
+{\n\
+  user(id: %s) {\n\
+    name\n\
+  }\n\
+}\n\
+               ", bad_values[i]);
+
+               // Test the lexer.
+               TEST_CONT(graphql_lex(source, NULL, &tokens) != NULL);
+               TEST_ABRT(listlen(tokens) == 5);
+               tokens = tal_free(tokens);
+
+               // No need to test parser when lexer fails.
+       }
+}
+
+int check_float_value(char *source, float float_value, const char *format) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Float Value Range Check on %f\n", float_value);
+
+       char buf[100];
+       sprintf(buf, "\
+{\n\
+  user(id: %s) {\n\
+    name\n\
+  }\n\
+}\n\
+       ", format);
+       sprintf(source, buf, float_value);
+       sprintf(buf, format, float_value);
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 11);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'f');
+       TEST_STRG(tok->token_string, buf);
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 12);
+       TEST_CONT(tok->source_len == strlen(buf));
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       TEST_CONT(tok->source_line == 2);
+       TEST_CONT(tok->source_column == 12 + strlen(buf));
+       TEST_CONT(tok->source_len == 1);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val->val->token_type == 'f');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val->val->token_string, buf);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_valid_float_values(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Valid Float Values\n");
+
+       char *good_values[] = {"1.0", "1e50", "6.0221413e23", "1.23", 0};
+
+       for (int i=0; good_values[i]; i++) {
+               sprintf(source, "\
+{\n\
+  user(id: %s) {\n\
+    name\n\
+  }\n\
+}\n\
+               ", good_values[i]);
+
+               // Test the lexer.
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_ABRT(listlen(tokens) == 11);
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'f');
+               TEST_STRG(tok->token_string, good_values[i]);
+               TEST_CONT(tok->source_line == 2);
+               TEST_CONT(tok->source_column == 12);
+               TEST_CONT(tok->source_len == strlen(good_values[i]));
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+               TEST_CONT(tok->source_line == 2);
+               TEST_CONT(tok->source_column == 12 + strlen(good_values[i]));
+               TEST_CONT(tok->source_len == 1);
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+               tokens = tal_free(tokens);
+
+               // Test the parser.
+               struct graphql_executable_document *doc;
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+               TEST_ABRT(doc != NULL);
+               TEST_ABRT(doc->first_def != NULL);
+               TEST_ABRT(doc->first_def->op_def != NULL);
+               TEST_CONT(doc->first_def->next_def == NULL);
+               TEST_CONT(doc->first_def->frag_def == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val->val != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val->val->token_type == 'f');
+               TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val->val->token_string, good_values[i]);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+               tokens = tal_free(tokens);
+       }
+}
+
+int check_invalid_float_values(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Invalid Float Values\n");
+
+       char *bad_values[] = {"00.0", "-00.0", "00e1", "1.23.4", "0x1.2p3", 0};
+
+       for (int i=0; bad_values[i]; i++) {
+               sprintf(source, "\
+{\n\
+  user(id: %s) {\n\
+    name\n\
+  }\n\
+}\n\
+               ", bad_values[i]);
+
+               // Test the lexer.
+               TEST_CONT(graphql_lex(source, NULL, &tokens) != NULL);
+               TEST_ABRT(listlen(tokens) == 5);
+               tokens = tal_free(tokens);
+
+               // No need to test parser when lexer fails.
+       }
+}
+
+int check_boolean_values(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Boolean Values\n");
+
+       char *good_values[] = {"true", "false", 0};
+
+       for (int i=0; good_values[i]; i++) {
+               sprintf(source, "\
+{\n\
+  user(id: %s) {\n\
+    name\n\
+  }\n\
+}\n\
+               ", good_values[i]);
+
+               // Test the lexer.
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_ABRT(listlen(tokens) == 11);
+               tokens = tal_free(tokens);
+
+               // Test the parser.
+               struct graphql_executable_document *doc;
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+               TEST_ABRT(doc != NULL);
+               TEST_ABRT(doc->first_def != NULL);
+               TEST_ABRT(doc->first_def->op_def != NULL);
+               TEST_CONT(doc->first_def->next_def == NULL);
+               TEST_CONT(doc->first_def->frag_def == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val->val != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val->val->token_type == 'a');
+               TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val->val->token_string, good_values[i]);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+               tokens = tal_free(tokens);
+       }
+
+       char *bad_values[] = {"True", "False", "TRUE", "FALSE", 0};
+
+       for (int i=0; bad_values[i]; i++) {
+               sprintf(source, "\
+{\n\
+  user(id: %s) {\n\
+    name\n\
+  }\n\
+}\n\
+               ", bad_values[i]);
+
+               // Test the lexer.
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_ABRT(listlen(tokens) == 11);
+               tokens = tal_free(tokens);
+
+               // Test the parser (it will succeed in parsing the bad values as enum values, not boolean values).
+               struct graphql_executable_document *doc;
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+               TEST_ABRT(doc != NULL);
+               TEST_ABRT(doc->first_def != NULL);
+               TEST_ABRT(doc->first_def->op_def != NULL);
+               TEST_CONT(doc->first_def->next_def == NULL);
+               TEST_CONT(doc->first_def->frag_def == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->var == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->str_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->null_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->list_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->enum_val != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->enum_val->val != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->enum_val->val->token_type == 'a');
+               TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->enum_val->val->token_string, bad_values[i]);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+               tokens = tal_free(tokens);
+       }
+}
+
+int check_string_value(char *source, const char *test_value, const char *expected_result) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// String Value Test: %s\n", test_value);
+
+       sprintf(source, "\
+{\n\
+  user(id:%s) {\n\
+    name\n\
+  }\n\
+}\n\
+       ", test_value);
+
+       bool block = (test_value[0]=='\"' && test_value[1]=='\"' && test_value[2]=='\"')? true: false;
+       if (expected_result) {
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_ABRT(listlen(tokens) == 11);
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+               TEST_STRG(tok->token_string, expected_result);
+               TEST_CONT(tok->source_line == 2);
+               TEST_CONT(tok->source_column == 11 + (block? 3: 1));
+               TEST_CONT(tok->source_len == strlen(test_value) - (block? 6: 2));
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+               TEST_CONT(tok->source_line == 2);
+               TEST_CONT(tok->source_column == 11 + strlen(test_value));
+               TEST_CONT(tok->source_len == 1);
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+               tokens = tal_free(tokens);
+
+               // Test the parser (it will succeed in parsing the bad values as enum values, not boolean values).
+               struct graphql_executable_document *doc;
+               TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+               TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+               TEST_ABRT(doc != NULL);
+               TEST_ABRT(doc->first_def != NULL);
+               TEST_ABRT(doc->first_def->op_def != NULL);
+               TEST_CONT(doc->first_def->next_def == NULL);
+               TEST_CONT(doc->first_def->frag_def == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->var == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->enum_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->null_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->list_val == NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->str_val != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->str_val->val != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->str_val->val->token_type == 's');
+               TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->str_val->val->token_string, expected_result);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+               TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next == NULL);
+               TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+               tokens = tal_free(tokens);
+       } else {
+               TEST_CONT(graphql_lex(source, NULL, &tokens) != NULL);
+               tokens = tal_free(tokens);
+       }
+}
+
+int check_example_25_and_26(const char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 25 and 26\n");
+
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       while ((tok = list_pop(tokens, struct graphql_token, list)) && tok->token_type != 's') { }
+       if (tok) {
+               TEST_STRG(tok->token_string, "Hello,\n  World!\n\nYours,\n  GraphQL.");
+       }
+
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_29(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 29\n");
+
+       sprintf(source, "\
+{\n\
+  field(arg: null)\n\
+  field\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 9);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "null");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "field");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "arg");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->var == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->enum_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->list_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->str_val == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->null_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->null_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->null_val->val->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->null_val->val->token_string, "null");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->next->field->name->token_string, "field");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next->field->args == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_30_and_31(const char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 30 and 31\n");
+
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 15);
+       while ((tok = list_pop(tokens, struct graphql_token, list)) && !(tok->token_type == 'a' && tok->token_string != NULL && streq(tok->token_string, "lat"))) { }
+       TEST_CONT(tok);
+       if (tok) {
+               TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'f');
+               TEST_STRG(tok->token_string, "-53.211");
+       }
+       tokens = tal_free(tokens);
+
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       while ((tok = list_pop(tokens, struct graphql_token, list)) && !(tok->token_type == 'a' && tok->token_string != NULL && streq(tok->token_string, "lon"))) { }
+       TEST_CONT(tok);
+       if (tok) {
+               TEST_CONT(tok->token_type == 'a');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+               tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'f');
+               TEST_STRG(tok->token_string, "12.43");
+       }
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_argument *arg;
+       struct graphql_executable_document *doc;
+       const char *e;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT((e = graphql_parse(tokens, &doc)) == NULL);
+       if (e) printf("%s\n", e);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type == NULL);
+       TEST_CONT(doc->first_def->op_def->op_name == NULL);
+       TEST_CONT(doc->first_def->op_def->vars == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "nearestThing");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "location");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->var == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->float_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->bool_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->enum_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->list_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->null_val == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->str_val == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->name->token_type == 'a');
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->val->float_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->val->float_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->val->float_val->val->token_type == 'f');
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next->name->token_type == 'a');
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next->val->float_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next->val->float_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next->val->float_val->val->token_type == 'f');
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->obj_val->first->next->next == NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_32(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 32\n");
+
+       sprintf(source, "\
+query getZuckProfile($devicePicSize: Int) {\n\
+  user(id: 4) {\n\
+    id\n\
+    name\n\
+    profilePic(size: $devicePicSize)\n\
+  }\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 27);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '$');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'i');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '$');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // Test the parser.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(graphql_parse(tokens, &doc) == NULL);
+       TEST_ABRT(doc != NULL);
+       TEST_ABRT(doc->first_def != NULL);
+       TEST_CONT(doc->first_def->next_def == NULL);
+       TEST_CONT(doc->first_def->frag_def == NULL);
+       TEST_ABRT(doc->first_def->op_def != NULL);
+       TEST_ABRT(doc->first_def->op_def->op_type != NULL);
+       TEST_ABRT(doc->first_def->op_def->op_type->op_type != NULL);
+       TEST_CONT(doc->first_def->op_def->op_type->op_type->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->op_type->op_type->token_string, "query");
+       TEST_CONT(doc->first_def->op_def->op_name != NULL);
+       TEST_CONT(doc->first_def->op_def->op_name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->op_name->token_string, "getZuckProfile");
+       TEST_ABRT(doc->first_def->op_def->vars != NULL);
+       TEST_ABRT(doc->first_def->op_def->vars->first != NULL);
+       TEST_CONT(doc->first_def->op_def->vars->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->vars->first->var != NULL);
+       TEST_ABRT(doc->first_def->op_def->vars->first->var->name != NULL);
+       TEST_CONT(doc->first_def->op_def->vars->first->var->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->vars->first->var->name->token_string, "devicePicSize");
+       TEST_ABRT(doc->first_def->op_def->vars->first->type != NULL);
+//     TEST_CONT(doc->first_def->op_def->vars->first->type->list == NULL);
+//     TEST_CONT(doc->first_def->op_def->vars->first->type->non_null == NULL);
+       TEST_ABRT(doc->first_def->op_def->vars->first->type->named != NULL);
+       TEST_ABRT(doc->first_def->op_def->vars->first->type->named->name != NULL);
+       TEST_CONT(doc->first_def->op_def->vars->first->type->named->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->vars->first->type->named->name->token_string, "Int");
+       TEST_CONT(doc->first_def->op_def->vars->first->default_val == NULL);
+       TEST_CONT(doc->first_def->op_def->vars->first->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->name->token_string, "user");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->name->token_string, "id");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_type == 'i');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->args->first->val->int_val->val->token_string, "4");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->directives == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->name->token_string, "id");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->name->token_string, "name");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->args == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->next == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->frag_spread == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->inline_frag == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->alias == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->name->token_string, "profilePic");
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->directives == NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->sel_set == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->next == NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->name->token_string, "size");
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->var != NULL);
+       TEST_ABRT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->var->name != NULL);
+       TEST_CONT(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->var->name->token_type == 'a');
+       TEST_STRG(doc->first_def->op_def->sel_set->first->field->sel_set->first->next->next->field->args->first->val->var->name->token_string, "devicePicSize");
+       tokens = tal_free(tokens);
+}
+
+int check_example_34(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 34\n");
+
+       sprintf(source, "\
+type Person\n\
+  @addExternalFields(source: \"profiles\")\n\
+  @excludeField(name: \"photo\") {\n\
+  name: String\n\
+}\n\
+       ");
+
+       // Test the lexer.
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 21);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '@');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "addExternalFields");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '@');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "excludeField");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // The type system is not yet implemented, so parsing will fail here.
+       // This could be "phase 2" of this project.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT(graphql_parse(tokens, &doc) != NULL);
+       tokens = tal_free(tokens);
+}
+
+int check_example_35(char *source) {
+       struct list_head *tokens;
+       struct graphql_token *tok;
+       const char *err;
+
+       if (!mute) printf("// Example No. 35\n");
+
+       sprintf(source, "\
+type Person\n\
+  @excludeField(name: \"photo\")\n\
+  @addExternalFields(source: \"profiles\") {\n\
+  name: String\n\
+}\n\
+       ");
+
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_ABRT(listlen(tokens) == 21);
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '@');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "excludeField");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '@');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       TEST_STRG(tok->token_string, "addExternalFields");
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '(');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 's');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ')');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '{');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == ':');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == 'a');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok->token_type == '}');
+       tok = list_pop(tokens, struct graphql_token, list); TEST_CONT(tok == NULL);
+       tokens = tal_free(tokens);
+
+       // The type system is not yet implemented, so parsing will fail here.
+       // This could be "phase 2" of this project.
+       struct graphql_executable_document *doc;
+       TEST_CONT(graphql_lex(source, NULL, &tokens) == NULL);
+       TEST_CONT(graphql_parse(tokens, &doc) != NULL);
+       tokens = tal_free(tokens);
+}
+
+/* End of test case functions. */
+
+/* Beginning of main() test run to run all test cases. */
+
+int main(void)
+{
+       printf("\nTesting GraphQL lexer/parser...\n");
+
+       char source[1024];
+       int prev_fail; // Used by RUNx macros.
+
+       // Check the lexer with all valid line terminators.
+       char *new_line = "\n";
+       char *carriage_return = "\r";
+       char *carriage_return_new_line = "\r\n";
+       char *line_terminators[] = { new_line, carriage_return, carriage_return_new_line };
+       for (int i=0; i<3; i++) {
+               sprintf(source, "\
+{%s\
+  user(id: 4) {%s\
+    name%s\
+  }%s\
+}%s\
+               ", line_terminators[i], line_terminators[i], line_terminators[i], line_terminators[i], line_terminators[i]);
+
+               RUN(check_example_3);
+       }
+
+       RUN(check_example_5); // Parse a mutation operation and check results.
+
+       RUN(check_example_6); // Parse an unnamed query and check results.
+
+       RUN(check_example_7); // Parse multiple fields in a selection set and check results.
+       RUN(check_example_8); // Parse complex data structure and check results.
+       RUN(check_example_9); // Parse example of top-level fields and check results.
+       RUN(check_example_10); // Parse example with parameterized field and check results.
+       RUN(check_example_11); // Parse example with multiple field arguments and check results.
+
+       // Parse examples of different parameter order and check for identical results.
+       sprintf(source, "\
+{\n\
+  picture(width: 200, height: 100)\n\
+}\n\
+       ");
+       RUN(check_example_12_and_13);
+       sprintf(source, "\
+{\n\
+  picture(height: 100, width: 200)\n\
+}\n\
+       ");
+       RUN(check_example_12_and_13);
+
+       RUN(check_example_14); // Parse alias example and check results.
+       RUN(check_example_16); // Parse a top-level-field alias example and check results.
+
+       RUN(check_example_18); // Parse example and check results.
+
+       RUN(check_example_19); // Parse fragment example and check results.
+       RUN(check_example_20); // Parse another fragment example and check results.
+       RUN(check_example_21); // Parse fragment typing example and check results.
+       RUN(check_example_23); // Parse fragment typing example and check results.
+       RUN(check_example_24); // Parse fragment typing example and check results.
+
+       // Parse various int values and check results.
+       for (int i=        -15; i<=         15; i++) { RUN1(check_int_value, i); }
+       for (int i=     -32770; i<=     -32765; i++) { RUN1(check_int_value, i); }
+       for (int i=      32765; i<=      32770; i++) { RUN1(check_int_value, i); }
+       for (int i=-2147483648; i<=-2147483645; i++) { RUN1(check_int_value, i); }
+       for (int i= 2147483647; i>= 2147483645; i--) { RUN1(check_int_value, i); }
+       RUN(check_invalid_int_values);
+
+       // Parse various float values and check results.
+       for (float i=   -1.0; i<=    1.0; i+=    0.1) { RUN2(check_float_value, i, "%1.1f"); }
+       for (float i=-327.70; i<=-327.65; i+=   0.01) { RUN2(check_float_value, i, "%1.2f"); }
+       for (float i= 327.65; i<= 327.70; i+=   0.01) { RUN2(check_float_value, i, "%1.2f"); }
+       for (float i= -5e-20; i<= -1e-20; i+=  1e-20) { RUN2(check_float_value, i, "%1.0e"); }
+       for (float i=  5e-20; i>=  1e-20; i-=  1e-20) { RUN2(check_float_value, i, "%1.0e"); }
+       for (float i=  5E+20; i>=  1E+20; i-=  1E+20) { RUN2(check_float_value, i, "%1.2E"); }
+       for (float i=1.5E+20; i>=1.1E+20; i-=0.1E+20) { RUN2(check_float_value, i, "%1.1E"); }
+       RUN(check_valid_float_values);
+       RUN(check_invalid_float_values);
+
+       RUN(check_boolean_values); // Parse boolean values and check results.
+
+       // Parse various string values and check results.
+       RUN2(check_string_value, "te^st",                    NULL         ); // Missing quotes (the caret makes it an invalid token for testing purposes).
+       RUN2(check_string_value, "\"te^st\"",                "te^st"      ); // A valid string.
+       RUN2(check_string_value, "\"\"",                     ""           ); // An empty string is valid.
+       RUN2(check_string_value, "\"\"\"te^st\"\"\"",        "te^st"      ); // A block string.
+       RUN2(check_string_value, "\"te\\st\"",               NULL         ); // Backslashes are normally invalid.
+       RUN2(check_string_value, "\"te\nst\"",               NULL         ); // New-line characters are invalid except in block strings.
+       RUN2(check_string_value, "\"te\rst\"",               NULL         ); // New-line characters are invalid except in block strings.
+       RUN2(check_string_value, "\"\"\"te\nst\"\"\"",       "te\nst"     ); // New-line characters are valid in block strings.
+       RUN2(check_string_value, "\"\"\"te\rst\"\"\"",       "te\rst"     ); // New-line characters are valid in block strings.
+       RUN2(check_string_value, "\"te\"st\"",               NULL         ); // A quote in a string is invalid.
+       RUN2(check_string_value, "\"te\\\"st\"",             "te\"st"     ); // ...unless it is escaped.
+       RUN2(check_string_value, "\"\"\"te\"st\"\"\"",       "te\"st"     ); // A quote in a block string is valid.
+       RUN2(check_string_value, "\"\"\"te\"\"st\"\"\"",     "te\"\"st"   ); // It is even valid to have two quotes in a block string.
+       RUN2(check_string_value, "\"\"\"te\"\"\"st\"\"\"",   NULL         ); // Three quotes in a row are not allowed in a block string.
+       RUN2(check_string_value, "\"\"\"te\\\"\"\"st\"\"\"", "te\"\"\"st" ); // ...unless escaped.
+       RUN2(check_string_value, "\"te\\\"st\"",             "te\"st"     ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\\\st\"",             "te\\st"     ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\/st\"",              "te/st"      ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\bst\"",              "te\bst"     ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\fst\"",              "te\fst"     ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\nst\"",              "te\nst"     ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\rst\"",              "te\rst"     ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\tst\"",              "te\tst"     ); // Check escape sequence.
+       RUN2(check_string_value, "\"te\\vst\"",              NULL         ); // Invalid escape sequence.
+       RUN2(check_string_value, "\"te\\033st\"",            NULL         ); // Invalid escape sequence.
+       // Note: Unicode excape sequence is tested below.
+
+       // This block string and this string should result in identical tokens.
+       sprintf(source, "\
+mutation {\n\
+  sendEmail(message: \"\"\"\n\
+    Hello,\n\
+      World!\n\
+\n\
+    Yours,\n\
+      GraphQL.\n\
+  \"\"\")\n\
+}\n\
+       ");
+       RUN(check_example_25_and_26);
+       sprintf(source, "\
+mutation {\n\
+  sendEmail(message: \"Hello,\\n  World!\\n\\nYours,\\n  GraphQL.\")\n\
+}\n\
+       ");
+       RUN(check_example_25_and_26);
+
+       // Check block string example.
+       RUN2(check_string_value,
+"\"\"\"\n\
+This starts with and ends with an empty line,\n\
+which makes it easier to read.\n\
+\"\"\"",
+               "This starts with and ends with an empty line,\nwhich makes it easier to read.");
+
+       // Check block string counter example.
+       RUN2(check_string_value,
+"\"\"\"This does not start with or end with any empty lines,\n\
+which makes it a little harder to read.\"\"\"",
+               "This does not start with or end with any empty lines,\nwhich makes it a little harder to read.");
+
+       RUN2(check_string_value, "\"te\\u001bst\"",         "te\033st"        ); // Check unicode escape sequence.
+       RUN2(check_string_value, "\"te\\u001Bst\"",         "te\033st"        ); // Check again with other case.
+       RUN2(check_string_value, "\"\"\"te\\u001bst\"\"\"", "te\\u001bst"     ); // Escape sequences are ignored in block strings (except for the triple quote).
+       RUN2(check_string_value, "\"\"\"te\\nst\"\"\"",     "te\\nst"         ); // Escape sequences are ignored in block strings (except for the triple quote).
+       RUN2(check_string_value, "\"te\\u2026st\"",         "te\xe2\x80\xa6st"); // Check a unicode escape sequence.
+
+       RUN(check_example_29); // Parse null value and check result.
+
+       // These two input objects should have the same result.
+       sprintf(source, "\
+{\n\
+  nearestThing(location: { lon: 12.43, lat: -53.211 })\n\
+}\n\
+       ");
+       RUN(check_example_30_and_31);
+       sprintf(source, "\
+{\n\
+  nearestThing(location: { lat: -53.211, lon: 12.43 })\n\
+}\n\
+       ");
+       RUN(check_example_30_and_31);
+
+       RUN(check_example_32); // Parse an example with a variable and check result.
+
+       RUN(check_example_34); // Parse directives and check result.
+       RUN(check_example_35); // Parse directives and check result.
+
+       RUN(check_example_35); // Parse directives and check result.
+
+       printf("total passed: %d\n%stotal failed: %d\033[0m\n", pass, fail?"\033[91m":"", fail);
+
+       return fail==0? 0: 1;
+}
+