-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
24 changed files
with
647 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// SPDX-License-Identifier: LGPL-3.0-or-later | ||
#include "json/json.h" | ||
|
||
#include "arena/arena.h" | ||
#include "interop/compile.h" | ||
|
||
#include "io/io.h" | ||
#include "notify/notify.h" | ||
#include "base/panic.h" | ||
|
||
#include "query_scan.h" | ||
|
||
#include "query_bison.h" // IWYU pragma: keep | ||
#include "query_flex.h" // IWYU pragma: keep | ||
#include "std/typed/vector.h" | ||
#include "std/vector.h" | ||
|
||
CT_CALLBACKS(kQueryCallbacks, query); | ||
|
||
static json_t *eval_query(json_t *json, const query_ast_t *query, arena_t *arena) | ||
{ | ||
if (json == NULL) | ||
return NULL; | ||
|
||
switch (query->kind) | ||
{ | ||
case eQueryObject: | ||
return json; | ||
case eQueryField: | ||
{ | ||
json_t *object = eval_query(json, query->object, arena); | ||
if (!object) | ||
return NULL; | ||
|
||
if (object->kind != eJsonObject) | ||
return NULL; | ||
|
||
return json_map_get(object, arena_strndup(query->field.text, query->field.length, arena)); | ||
} | ||
case eQueryIndex: | ||
{ | ||
json_t *object = eval_query(json, query->object, arena); | ||
if (!object) | ||
return NULL; | ||
|
||
if (object->kind != eJsonArray) | ||
return NULL; | ||
|
||
int idx = mpz_get_si(query->index); | ||
if (idx < 0) | ||
return NULL; | ||
|
||
if (idx >= vector_len(object->array)) | ||
return NULL; | ||
|
||
return vector_get(object->array, idx); | ||
} | ||
case eQueryMap: | ||
{ | ||
json_t *object = eval_query(json, query->object, arena); | ||
if (!object) | ||
return NULL; | ||
|
||
if (object->kind != eJsonObject) | ||
return NULL; | ||
|
||
return json_map_get(object, arena_strndup(query->field.text, query->field.length, arena)); | ||
} | ||
|
||
default: | ||
CT_NEVER("invalid query kind %d", query->kind); | ||
} | ||
} | ||
|
||
USE_DECL | ||
json_t *json_query(json_t *json, const char *query, arena_t *arena) | ||
{ | ||
CTASSERT(json != NULL); | ||
CTASSERT(query != NULL); | ||
CTASSERT(arena != NULL); | ||
|
||
io_t *io = io_string("query", query, arena); | ||
|
||
logger_t *logger = logger_new(arena); | ||
|
||
query_scan_t ctx = { | ||
.reports = logger, | ||
}; | ||
|
||
scan_t *scan = scan_io("json query", io, arena); | ||
scan_set_context(scan, &ctx); | ||
|
||
parse_result_t result = scan_buffer(scan, &kQueryCallbacks); | ||
|
||
if (result.result != eParseOk) | ||
{ | ||
typevec_t *messages = logger_get_events(logger); | ||
for (size_t i = 0; i < typevec_len(messages); i++) | ||
{ | ||
event_t *event = typevec_offset(messages, i); | ||
printf("error: %s\n", event->message); | ||
} | ||
return NULL; | ||
} | ||
|
||
return eval_query(json, result.tree, arena); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
%option extra-type="scan_t*" | ||
%option 8bit nodefault | ||
%option noyywrap noinput nounput | ||
%option noyyalloc noyyrealloc noyyfree | ||
%option reentrant bison-bridge bison-locations | ||
%option never-interactive batch | ||
%option prefix="query" | ||
|
||
%{ | ||
#include "query_bison.h" | ||
#include "interop/flex.h" | ||
#include "interop/memory.h" | ||
#include "cthulhu/events/events.h" | ||
%} | ||
|
||
WS [ \t\r\v\n\f] | ||
ESCAPES (\\(['"\?\\abfnrtv]|[0-7]{1,3}|x[a-fA-F0-9]+)) | ||
|
||
%% | ||
|
||
{WS}+ ; | ||
|
||
"[" { return LBRACKET; } | ||
"]" { return RBRACKET; } | ||
"." { return DOT; } | ||
|
||
[-]"0"[0-7]* { query_parse_integer(yylval->integer, yyextra, *yylloc, yytext, 8); return INTEGER; } | ||
[-]"0"[bB][01]+ { query_parse_integer(yylval->integer, yyextra, *yylloc, yytext + 2, 2); return INTEGER; } | ||
[-]"0"[xX][0-9a-fA-F]+ { query_parse_integer(yylval->integer, yyextra, *yylloc, yytext + 2, 16); return INTEGER; } | ||
[-]?[0-9]+ { query_parse_integer(yylval->integer, yyextra, *yylloc, yytext, 10); return INTEGER; } | ||
|
||
[a-zA-Z_][a-zA-Z0-9_]* { query_parse_string(&yylval->string, yyextra, *yylloc, yytext, yyleng); return IDENT; } | ||
\"([^"\\\n]|{ESCAPES})*\" { query_parse_string(&yylval->string, yyextra, *yylloc, yytext + 1, yyleng - 2); return STRING; } | ||
|
||
. { | ||
query_scan_t *scan = query_scan_context(yyextra); | ||
evt_scan_unknown(scan->reports, node_new(yyextra, *yylloc), yytext); | ||
} | ||
|
||
%% | ||
|
||
FLEX_MEMORY(query) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
%define parse.error verbose | ||
%define api.pure full | ||
%lex-param { void *scan } | ||
%parse-param { void *scan } { scan_t *x } | ||
%locations | ||
%expect 0 | ||
%define api.prefix {query} | ||
|
||
%code top { | ||
#include "interop/flex.h" | ||
#include "interop/bison.h" | ||
|
||
#include "std/typed/vector.h" | ||
#include "std/vector.h" | ||
} | ||
|
||
%code requires { | ||
#include "query_ast.h" | ||
#include "query_scan.h" | ||
#define YYSTYPE QUERYSTYPE | ||
#define YYLTYPE QUERYLTYPE | ||
} | ||
|
||
%{ | ||
int querylex(void *lval, void *loc, scan_t *scan); | ||
void queryerror(where_t *where, void *state, scan_t *scan, const char *msg); | ||
%} | ||
|
||
%union { | ||
mpz_t integer; | ||
text_t string; | ||
|
||
query_ast_t *ast; | ||
} | ||
|
||
%token | ||
LBRACKET "[" | ||
RBRACKET "]" | ||
DOT "." | ||
|
||
%token<string> | ||
STRING | ||
|
||
%token<integer> | ||
INTEGER | ||
|
||
%token<string> | ||
IDENT | ||
|
||
%type<ast> | ||
root expr | ||
|
||
%start root | ||
|
||
%% | ||
|
||
root: expr { scan_set(x, $1); } | ||
; | ||
|
||
expr: IDENT { $$ = query_ast_object(x, $1); } | ||
| expr DOT IDENT { $$ = query_ast_field(x, $1, $3); } | ||
| expr LBRACKET INTEGER RBRACKET { $$ = query_ast_index(x, $1, $3); } | ||
| expr LBRACKET STRING RBRACKET { $$ = query_ast_map(x, $1, $3); } | ||
; | ||
|
||
%% |
Oops, something went wrong.