Cthulhu  0.2.10
Cthulhu compiler collection
query.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 #include "json/query.h"
3 #include "json/json.h"
4 
5 #include "base/panic.h"
6 #include "arena/arena.h"
7 #include "std/typed/vector.h"
8 #include "std/vector.h"
9 
10 #include "io/io.h"
11 #include "interop/compile.h"
12 
13 #include "notify/notify.h"
14 
15 #include "cthulhu/events/events.h"
16 
17 #include "query_scan.h"
18 
19 #include "query_bison.h" // IWYU pragma: keep
20 #include "query_flex.h" // IWYU pragma: keep
21 
22 CT_CALLBACKS(kQueryCallbacks, query);
23 
24 static json_t *eval_query(json_t *json, const query_ast_t *query, arena_t *arena)
25 {
26  if (json == NULL)
27  return NULL;
28 
29  switch (query->kind)
30  {
31  case eQueryObject:
32  return json;
33  case eQueryField:
34  {
35  json_t *object = eval_query(json, query->object, arena);
36  if (!object)
37  return NULL;
38 
39  if (object->kind != eJsonObject)
40  return NULL;
41 
42  return json_map_get(object, arena_strndup(query->field.text, query->field.length, arena));
43  }
44  case eQueryIndex:
45  {
46  json_t *object = eval_query(json, query->object, arena);
47  if (!object)
48  return NULL;
49 
50  if (object->kind != eJsonArray)
51  return NULL;
52 
53  int idx = mpz_get_si(query->index);
54  if (idx < 0)
55  return NULL;
56 
57  if (idx >= typevec_len(&object->array))
58  return NULL;
59 
60  return typevec_offset(&object->array, idx);
61  }
62  case eQueryMap:
63  {
64  json_t *object = eval_query(json, query->object, arena);
65  if (!object)
66  return NULL;
67 
68  if (object->kind != eJsonObject)
69  return NULL;
70 
71  return json_map_get(object, arena_strndup(query->field.text, query->field.length, arena));
72  }
73 
74  default:
75  CT_NEVER("invalid query kind %d", query->kind);
76  }
77 }
78 
79 static json_t *query_internal(json_t *json, const char *query, logger_t *logger, scan_t **scanout, arena_t *arena)
80 {
81  CTASSERT(json != NULL);
82  CTASSERT(query != NULL);
83  CTASSERT(logger != NULL);
84  CTASSERT(arena != NULL);
85 
86  io_t *io = io_string("query", query, arena);
87 
88  query_scan_t ctx = {
89  .reports = logger,
90  };
91 
92  scan_t *scan = scan_io("json query", io, arena);
93  scan_set_context(scan, &ctx);
94 
95  if (scanout)
96  *scanout = scan;
97 
98  parse_result_t result = scan_buffer(scan, &kQueryCallbacks);
99 
100  if (result.result != eParseOk)
101  {
102  return NULL;
103  }
104 
105  return eval_query(json, result.tree, arena);
106 }
107 
108 STA_DECL
109 json_t *json_query(json_t *json, const char *query, logger_t *logger, arena_t *arena)
110 {
111  return query_internal(json, query, logger, NULL, arena);
112 }
113 
114 STA_DECL
115 json_t *json_query_type(json_t *json, const char *query, json_kind_t kind, logger_t *logger, arena_t *arena)
116 {
117  CT_ASSERT_RANGE(kind, 0, eJsonCount);
118 
119  scan_t *scan;
120 
121  json_t *result = query_internal(json, query, logger, &scan, arena);
122  if (!result)
123  return NULL;
124 
125  if (result->kind == kind)
126  return result;
127 
128  node_t node = node_make(scan, result->where);
129 
130  msg_notify(logger, &kEvent_ReturnTypeMismatch, &node, "expected %s, got %s", json_kind_name(kind), json_kind_name(result->kind));
131 
132  return NULL;
133 }
CT_NODISCARD CT_SCAN_API scan_t * scan_io(const char *language, io_t *io, arena_t *arena)
create a scanner from an io source
Definition: scan.c:121
CT_SCAN_API void scan_set_context(scan_t *scan, void *value)
get the context of a scanner
Definition: scan.c:80
#define STA_DECL
sal2 annotation on function implementations to copy annotations from the declaration
STA_RET_STRING colour_t idx
Definition: colour.h:98
CT_INTEROP_API parse_result_t scan_buffer(scan_t *scan, const scan_callbacks_t *callbacks)
parse the contents of a scanner into a language specific ast
Definition: compile.c:26
@ eParseOk
parse was successful
Definition: compile.h:76
CT_NODISCARD CT_IO_API io_t * io_string(const char *name, const char *string, arena_t *arena)
create an IO view of a string create a readonly IO view of a string
Definition: view.c:90
CT_JSON_API const char * json_kind_name(json_kind_t kind)
get the name of a json kind
Definition: ast.c:16
json_kind_t
the kind of json value
Definition: json.h:34
CT_JSON_API json_t * json_map_get(const json_t *json, const char *key)
get a json value from an object by key
Definition: json.c:17
@ eJsonCount
Definition: json.h:38
CT_NODISCARD CT_SCAN_API node_t node_make(const scan_t *scan, where_t where)
create a new node on the stack
Definition: node.c:49
CT_NODISCARD CT_ARENA_API char * arena_strndup(STA_READS(len) const char *str, size_t len, arena_t *arena)
allocate a copy of a string with a maximum length from a custom allocator
CT_NOTIFY_API event_builder_t msg_notify(INOUT_NOTNULL logger_t *logs, const diagnostic_t *diagnostic, const node_t *node, STA_FORMAT_STRING const char *fmt,...)
notify the logger of a new message
#define CT_ASSERT_RANGE(value, min, max)
assert that a value is in a range inclusive bounds check
Definition: panic.h:148
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
Definition: vector.c:120
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
Definition: vector.c:191
@ eQueryObject
Definition: query_ast.h:16
@ eQueryIndex
Definition: query_ast.h:19
@ eQueryField
Definition: query_ast.h:17
@ eQueryMap
Definition: query_ast.h:18
an allocator object
Definition: arena.h:86
io object implementation
Definition: impl.h:122
a json value
Definition: json.h:43
typevec_t array
the array value of this node
Definition: json.h:71
where_t where
the source location of the json value
Definition: json.h:50
json_kind_t kind
the kind of json value
Definition: json.h:45
a logging sink
Definition: notify.c:14
a position in a source file
Definition: node.h:23
parse_error_t result
Definition: compile.h:92
void * tree
Definition: compile.h:95
query_ast_type_t kind
Definition: query_ast.h:26
mpz_t index
Definition: query_ast.h:36
text_t field
Definition: query_ast.h:33
query_ast_t * object
Definition: query_ast.h:30
logger_t * reports
Definition: query_scan.h:14
a source file scanner
Definition: scan.h:24
size_t length
the number of characters in the text
Definition: text.h:19
STA_DECL json_t * json_query_type(json_t *json, const char *query, json_kind_t kind, logger_t *logger, arena_t *arena)
query a json object and ensure it is of a specific type
Definition: query.c:115
CT_CALLBACKS(kQueryCallbacks, query)
STA_DECL json_t * json_query(json_t *json, const char *query, logger_t *logger, arena_t *arena)
query a json object
Definition: query.c:109