feat!: many work useles with hemar

This commit is contained in:
2025-05-10 11:00:36 +00:00
parent 4db5cc171b
commit 5f52fc42af
10 changed files with 503 additions and 127 deletions

229
flake.nix
View File

@@ -201,87 +201,161 @@
buildInputs = [pkgs.stack]; buildInputs = [pkgs.stack];
}); });
}; };
nixosConfigurations."${system}_manual_test" = nixpkgs.lib.nixosSystem { nixosConfigurations = {
inherit system; "${system}_manual_test" = nixpkgs.lib.nixosSystem {
modules = [ inherit system;
self.nixosModules."preset.default" modules = [
self.nixosModules."hardware.hetzner" self.nixosModules."preset.default"
({modulesPath, pkgs, ...}: { self.nixosModules."hardware.hetzner"
imports = [ ({modulesPath, pkgs, ...}: {
(modulesPath + "/profiles/qemu-guest.nix") imports = [
]; (modulesPath + "/profiles/qemu-guest.nix")
];
users.users.root.openssh.authorizedKeys.keys = [ ]; environment.systemPackages = with pkgs; [
environment.systemPackages = with pkgs; [ (pkgs.writers.writeMinCBin "minc-hello-world" ["<stdio.h>"] /*c*/ ''
(pkgs.writers.writeMinCBin "minc-hello-world" ["<stdio.h>"] /*c*/ '' printf("hello world\n");
printf("hello world\n"); '')
'') (pkgs.writers.writeMinCBin "minc-env" ["<stdio.h>" "<stdlib.h>"] /*c*/ ''
(pkgs.writers.writeMinCBin "minc-env" ["<stdio.h>" "<stdlib.h>"] /*c*/ '' char *env_name;
char *env_name; if (argc > 1) {
if (argc > 1) { env_name = argv[1];
env_name = argv[1]; } else {
} else { env_name = "HOME";
env_name = "HOME"; }
} char *value = getenv(env_name);
char *value = getenv(env_name); if (value) {
if (value) { printf("%s: %s\n", env_name, value);
printf("%s: %s\n", env_name, value); } else {
} else { printf("Environment variable %s not found.\n", env_name);
printf("Environment variable %s not found.\n", env_name); }
} '')
'') (pkgs.writers.writeMinCBin "minc-env-check" ["<stdio.h>" "<stdlib.h>"] /*c*/ ''
(pkgs.writers.writeMinCBin "minc-env-check" ["<stdio.h>" "<stdlib.h>"] /*c*/ '' char *env_name;
char *env_name; if (argc > 1) {
if (argc > 1) { env_name = argv[1];
env_name = argv[1]; } else {
} else { env_name = "HOME";
env_name = "HOME"; }
}
char *value = getenv(env_name); char *value = getenv(env_name);
if (value) { if (value) {
char buffer[128]; char buffer[128];
sprintf(buffer, "echo $%s\n", env_name); sprintf(buffer, "echo $%s\n", env_name);
system(buffer); system(buffer);
} else { } else {
printf("Environment variable %s not found.\n", env_name); printf("Environment variable %s not found.\n", env_name);
} }
'') '')
]; ];
programs.zsh.shellAliases = {
jc = ''journalctl'';
sc = ''journalctl'';
nv = ''nvim'';
sd = "shutdown now";
};
virtualisation = { users.users.root.openssh.authorizedKeys.keys = [
vmVariant = { ''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrbBG+U07f7OKvOxYIGYCaNvyozzxQF+I9Fb5TYZErK yukkop vm-postgres''
systemd.services.fix-root-perms = { ];
description = "Fix root directory permissions";
after = [ "local-fs.target" ]; programs.zsh.shellAliases = self.lib.sharedShellAliases;
wantedBy = [ "multi-user.target" ];
serviceConfig = { virtualisation = {
Type = "oneshot"; vmVariant = {
ExecStart = "${pkgs.coreutils}/bin/chmod 755 /"; systemd.services.fix-root-perms = {
description = "Fix root directory permissions";
after = [ "local-fs.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.coreutils}/bin/chmod 755 /";
};
};
virtualisation = {
diskSize = 1024*6;
diskImage = null;
forwardPorts = [ ];
}; };
}; };
virtualisation = { };
diskSize = 1024*6; networking.firewall = {
diskImage = null; enable = true;
forwardPorts = [ ]; allowedTCPPorts = [
80
];
};
})
];
pkgs = import nixpkgs {inherit system; overlays = [ self.overlays.default ];};
};
"${system}_hemar_test" = nixpkgs.lib.nixosSystem {
inherit system;
modules = [
self.nixosModules."preset.default"
self.nixosModules."hardware.hetzner"
({modulesPath, pkgs, ...}: {
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
users.users.root.openssh.authorizedKeys.keys = [
''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrbBG+U07f7OKvOxYIGYCaNvyozzxQF+I9Fb5TYZErK yukkop vm-postgres''
];
services.postgresql =
let
package = pkgs.postgresql_15;
in {
enable = true;
package = package;
settings =
{
port = 64317;
listen_addresses = lib.mkForce "*";
shared_preload_libraries = "";
};
extensions = [ package.pkgs.hemar ];
authentication = builtins.concatStringsSep "\n" [
"local all all trust"
"host sameuser all 127.0.0.1/32 scram-sha-256"
"host sameuser all ::1/128 scram-sha-256"
];
initialScript = pkgs.writeText "init-sql-script" ''
CREATE EXTENSION "hemar";
SELECT hemar.parse('{% zalupa %}');
SELECT hemar.parse('{% zalupa %}');
'';
};
environment.systemPackages = with pkgs; [ ];
programs.zsh.shellAliases = self.lib.sharedShellAliases // {
conn = "sudo su postgres -c 'psql -p 64317'";
};
virtualisation = {
vmVariant = {
systemd.services.fix-root-perms = {
description = "Fix root directory permissions";
after = [ "local-fs.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.coreutils}/bin/chmod 755 /";
};
};
virtualisation = {
diskSize = 1024*6;
diskImage = null;
forwardPorts = [ ];
};
}; };
}; };
}; networking.firewall = {
networking.firewall = { enable = true;
enable = true; allowedTCPPorts = [
allowedTCPPorts = [ 80
80 ];
]; };
}; })
}) ];
]; pkgs = import nixpkgs {inherit system; overlays = [ self.overlays.default ];};
pkgs = import nixpkgs {inherit system; overlays = [ self.overlays.default ];}; };
}; };
}) })
// { // {
@@ -532,6 +606,13 @@
# -- For all systems -- # -- For all systems --
inherit dotEnv minorEnvironment parseEnv forAllSystemsWithPkgs forSpecSystemsWithPkgs; inherit dotEnv minorEnvironment parseEnv forAllSystemsWithPkgs forSpecSystemsWithPkgs;
sharedShellAliases = {
jc = ''journalctl'';
sc = ''journalctl'';
nv = ''nvim'';
sd = "shutdown now";
};
readEnvironment = { envVarsToRead, prefix ? "" }: readEnvironment = { envVarsToRead, prefix ? "" }:
builtins.listToAttrs builtins.listToAttrs
(map (name: { (map (name: {

View File

@@ -0,0 +1,47 @@
[
{
"type": "SECTION",
"content": {
"iterator": "item",
"collection": "items"
},
"body": [
{
"type": "INTERPOLATE",
"content": {
"key": "name"
}
},
{
"type": "TEXT",
"content": {
"content": " "
}
},
{
"type": "INTERPOLATE",
"content": {
"key": "item.name"
}
},
{
"type": "TEXT",
"content": {
"content": " "
}
}
]
},
{
"type": "TEXT",
"content": {
"content": " "
}
},
{
"type": "INTERPOLATE",
"content": {
"key": "name2"
}
}
]

View File

@@ -1429,14 +1429,14 @@ Json *json_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s) {
return result; return result;
} }
char *json_to_string__(POSITION_INFO_DECLARATION, Arena *arena, const Json * const item) { char *json_to_str__(POSITION_INFO_DECLARATION, Arena *arena, const Json * const item) {
return json_to_string_with_opts__(POSITION_INFO, arena, item, JSON_NORAW); return json_to_str_with_opts__(POSITION_INFO, arena, item, JSON_NORAW);
} }
/* Minimal JSON printer with raw output option. /* Minimal JSON printer with raw output option.
When raw is non-zero and the item is a JSON_STRING, it is printed without quotes. When raw is non-zero and the item is a JSON_STRING, it is printed without quotes.
*/ */
char *json_to_string_with_opts__(POSITION_INFO_DECLARATION, Arena *arena, const Json * const item, JsonRawOpt raw) { char *json_to_str_with_opts__(POSITION_INFO_DECLARATION, Arena *arena, const Json * const item, JsonRawOpt raw) {
// Function entry with DEBUG level // Function entry with DEBUG level
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO, raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
"FORMAT: Starting JSON conversion to string (item: %p, raw_mode: %s)", "FORMAT: Starting JSON conversion to string (item: %p, raw_mode: %s)",
@@ -1479,7 +1479,7 @@ char *json_to_string_with_opts__(POSITION_INFO_DECLARATION, Arena *arena, const
while (child) { while (child) {
ptr += sprintf(ptr, "\"%s\":", child->key ? child->key : ""); ptr += sprintf(ptr, "\"%s\":", child->key ? child->key : "");
char *child_str = json_to_string_with_opts__(POSITION_INFO, arena, child, raw); char *child_str = json_to_str_with_opts__(POSITION_INFO, arena, child, raw);
if (child_str) { if (child_str) {
ptr += sprintf(ptr, "%s", child_str); ptr += sprintf(ptr, "%s", child_str);
} else { } else {
@@ -1509,7 +1509,7 @@ char *json_to_string_with_opts__(POSITION_INFO_DECLARATION, Arena *arena, const
"FORMAT: Processing JSON array elements"); "FORMAT: Processing JSON array elements");
while (child) { while (child) {
char *child_str = json_to_string_with_opts__(POSITION_INFO, arena, child, raw); char *child_str = json_to_str_with_opts__(POSITION_INFO, arena, child, raw);
if (child_str) { if (child_str) {
ptr += sprintf(ptr, "%s", child_str); ptr += sprintf(ptr, "%s", child_str);
} else { } else {
@@ -2280,8 +2280,8 @@ TemplateConfig template_default_config__(POSITION_INFO_DECLARATION, Arena *arena
}, },
.Section = { .Section = {
.control = string_to_view_ptr__(POSITION_INFO, arena, "for "), .control = string_to_view_ptr__(POSITION_INFO, arena, "for "),
.source = string_to_view_ptr__(POSITION_INFO, arena, " in "), .source = string_to_view_ptr__(POSITION_INFO, arena, "in "),
.begin = string_to_view_ptr__(POSITION_INFO, arena, " do ") .begin = string_to_view_ptr__(POSITION_INFO, arena, "do ")
}, },
.Interpolate = { .Interpolate = {
.invoke = string_to_view_ptr__(POSITION_INFO, arena, "") .invoke = string_to_view_ptr__(POSITION_INFO, arena, "")
@@ -2862,6 +2862,84 @@ char *template_node_to_json_str__(POSITION_INFO_DECLARATION, Arena *arena, const
return result; return result;
} }
// ----------
// -- diff --
// ----------
//int diff_str__(POSITION_INFO_DECLARATION, Arena *arena, const char **str1, const char **str2) {
// if (!str1 || !str2) {
// return 0;
// }
//
// const char *s1 = *str1;
// const char *s2 = *str2;
//
// int diff = 0;
//
// while (*s1 && *s2) {
// if (*s1 != *s2) {
// diff++;
// }
// s1++;
// s2++;
// }
//
// return diff;
//}
// --------------
// -- Colorize --
// --------------
char *colorize_partial_patterns(char *output, const char *input, PatternHighlight *patterns, size_t pattern_count) {
size_t len = strlen(input);
if (!output) return NULL;
size_t out_idx = 0;
for (size_t i = 0; i < len;) {
int matched = 0;
for (size_t j = 0; j < pattern_count; j++) {
size_t pat_len = strlen(patterns[j].pattern);
if (strncmp(&input[i], patterns[j].pattern, pat_len) == 0) {
const char *pre = &input[i];
const char *hl_start = &input[i + patterns[j].highlight_start];
const char *hl_end = &input[i + patterns[j].highlight_start + patterns[j].highlight_len];
// Copy pre-highlight part
size_t pre_len = patterns[j].highlight_start;
memcpy(&output[out_idx], pre, pre_len);
out_idx += pre_len;
// Add color code and highlighted part
size_t color_len = strlen(patterns[j].color);
memcpy(&output[out_idx], patterns[j].color, color_len);
out_idx += color_len;
memcpy(&output[out_idx], hl_start, patterns[j].highlight_len);
out_idx += patterns[j].highlight_len;
memcpy(&output[out_idx], "\033[0m", 4);
out_idx += 4;
// Copy post-highlight part
size_t post_len = pat_len - patterns[j].highlight_start - patterns[j].highlight_len;
memcpy(&output[out_idx], hl_end, post_len);
out_idx += post_len;
i += pat_len;
matched = 1;
break;
}
}
if (!matched) {
output[out_idx++] = input[i++];
}
}
output[out_idx] = '\0';
return output;
}
// --------- // ---------
// -- End -- // -- End --
// --------- // ---------

View File

@@ -427,6 +427,8 @@ char* arena_strncpy__(const char *file, const char *func, int line, Arena *arena
static Arena disposable_arena __attribute__((unused)) = {0}; static Arena disposable_arena __attribute__((unused)) = {0};
#define DISPOSABLE_ARENA_FREE arena_free(&disposable_arena)
#define DISPOSABLE_ARENA __extension__ ({ \ #define DISPOSABLE_ARENA __extension__ ({ \
if (disposable_arena.begin == NULL) { \ if (disposable_arena.begin == NULL) { \
disposable_arena = arena_init__(__FILE__, __func__, __LINE__, MEM_MiB * 8); \ disposable_arena = arena_init__(__FILE__, __func__, __LINE__, MEM_MiB * 8); \
@@ -653,11 +655,11 @@ RESULT(Json, Json);
Json *json_parse__(const char* file, const char* func, int line, Arena *arena, const char **s); Json *json_parse__(const char* file, const char* func, int line, Arena *arena, const char **s);
#define json_parse(arena, s) json_parse__(__FILE__, __func__, __LINE__, arena, s) #define json_parse(arena, s) json_parse__(__FILE__, __func__, __LINE__, arena, s)
char *json_to_string__(const char* file, const char* func, int line, Arena *arena, const Json * const item); char *json_to_str__(const char* file, const char* func, int line, Arena *arena, const Json * const item);
#define json_to_string(arena, item) json_to_string__(__FILE__, __func__, __LINE__, arena, item) #define JSON_TO_STR(arena, item) json_to_str__(__FILE__, __func__, __LINE__, arena, item)
#define json_to_string_with_opts(arena, item, raw) json_to_string_with_opts__(__FILE__, __func__, __LINE__, arena, item, raw) char *json_to_str_with_opts__(const char* file, const char* func, int line, Arena *arena, const Json * const item, JsonRawOpt raw);
char *json_to_string_with_opts__(const char* file, const char* func, int line, Arena *arena, const Json * const item, JsonRawOpt raw); #define JSON_TO_STR_WITH_OPTS(arena, item, raw) json_to_str_with_opts__(__FILE__, __func__, __LINE__, arena, item, raw)
/* Retrieve an object item by key (case-sensitive) */ /* Retrieve an object item by key (case-sensitive) */
Json *json_get_object_item__(const char* file, const char* func, int line, const Json * const object, const char * const key); Json *json_get_object_item__(const char* file, const char* func, int line, const Json * const object, const char * const key);
@@ -839,4 +841,31 @@ TemplateNode init_template_node__(const char *file, const char *func, int line,
#define init_template_node(arena, type) \ #define init_template_node(arena, type) \
init_template_node__(__FILE__, __func__, __LINE__, arena, type) init_template_node__(__FILE__, __func__, __LINE__, arena, type)
#define TEMPLATE_NODE_DISPOSABLE_JSON(node) __extension__ ({ \
Arena *debug_arena = DISPOSABLE_ARENA; \
const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, &node); \
Json *json = json_parse(debug_arena, &json_str); \
arena_strdup(debug_arena, JSON_TO_PRETTY_STR(debug_arena, json)); \
})
#define TEMPLATE_NODE_PRETTY_JSON(node, arena) __extension__ ({ \
Arena *debug_arena = DISPOSABLE_ARENA; \
const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, &node); \
Json *json = json_parse(debug_arena, &json_str); \
arena_strdup(arena, JSON_TO_PRETTY_STR(debug_arena, json)); \
})
// --------------
// -- Colorize --
// --------------
typedef struct {
const char *pattern;
int highlight_start;
int highlight_len;
const char *color;
} PatternHighlight;
char *colorize_partial_patterns(char *output, const char *input, PatternHighlight *patterns, size_t pattern_count);
#endif // EPRINTF_H #endif // EPRINTF_H

View File

@@ -0,0 +1,47 @@
[
{
"type": "SECTION",
"content": {
"iterator": "item",
"collection": "items"
},
"body": [
{
"type": "INTERPOLATE",
"content": {
"key": "name"
}
},
{
"type": "TEXT",
"content": {
"content": " "
}
},
{
"type": "INTERPOLATE",
"content": {
"key": "item.name"
}
},
{
"type": "TEXT",
"content": {
"content": " "
}
}
]
},
{
"type": "TEXT",
"content": {
"content": " "
}
},
{
"type": "INTERPOLATE",
"content": {
"key": "name2"
}
}
]

View File

@@ -53,7 +53,7 @@ static void test_get_object_items(Arena *arena) {
static void test_print_json_object(Arena *arena) { static void test_print_json_object(Arena *arena) {
const char *json = "{\"key\":\"value\", \"num\":3.14}"; const char *json = "{\"key\":\"value\", \"num\":3.14}";
Json *root = json_parse(arena, &json); Json *root = json_parse(arena, &json);
char *printed = json_to_string(arena, root); char *printed = JSON_TO_STR(arena, root);
assert(strstr(printed, "\"key\":") != NULL); assert(strstr(printed, "\"key\":") != NULL);
assert(strstr(printed, "\"value\"") != NULL); assert(strstr(printed, "\"value\"") != NULL);
assert(strstr(printed, "\"num\":") != NULL); assert(strstr(printed, "\"num\":") != NULL);
@@ -64,7 +64,7 @@ static void test_print_json_object(Arena *arena) {
static void test_print_json_number(Arena *arena) { static void test_print_json_number(Arena *arena) {
const char *json = "123.456"; const char *json = "123.456";
Json *root = json_parse(arena, &json); Json *root = json_parse(arena, &json);
char *printed = json_to_string(arena, root); char *printed = JSON_TO_STR(arena, root);
double val = atof(printed); double val = atof(printed);
assert(val == 123.456); assert(val == 123.456);
} }
@@ -73,7 +73,7 @@ static void test_print_json_number(Arena *arena) {
static void test_print_json_string(Arena *arena) { static void test_print_json_string(Arena *arena) {
const char *json = "\"test string\""; const char *json = "\"test string\"";
Json *root = json_parse(arena, &json); Json *root = json_parse(arena, &json);
char *printed = json_to_string(arena, root); char *printed = JSON_TO_STR(arena, root);
assert(strcmp(printed, "\"test string\"") == 0); assert(strcmp(printed, "\"test string\"") == 0);
} }
@@ -99,12 +99,12 @@ static void test_nested_json_object(Arena *arena) {
static void test_arena_reset_reuse(Arena *arena) { static void test_arena_reset_reuse(Arena *arena) {
const char *json1 = "{\"key\":\"value\"}"; const char *json1 = "{\"key\":\"value\"}";
Json *root1 = json_parse(arena, &json1); Json *root1 = json_parse(arena, &json1);
char *printed1 = json_to_string(arena, root1); char *printed1 = JSON_TO_STR(arena, root1);
assert(strcmp(printed1, "{\"key\":\"value\"}") == 0); assert(strcmp(printed1, "{\"key\":\"value\"}") == 0);
arena_reset(arena); arena_reset(arena);
const char *json2 = "\"another test\""; const char *json2 = "\"another test\"";
Json *root2 = json_parse(arena, &json2); Json *root2 = json_parse(arena, &json2);
char *printed2 = json_to_string(arena, root2); char *printed2 = JSON_TO_STR(arena, root2);
assert(strcmp(printed2, "\"another test\"") == 0); assert(strcmp(printed2, "\"another test\"") == 0);
} }

View File

@@ -233,12 +233,87 @@ static void simplest_separator_test_template_parse(Arena *arena, TemplateConfig
TemplateNode node = RESULT_SOME_VALUE(template_result); TemplateNode node = RESULT_SOME_VALUE(template_result);
char *result_str = TEMPLATE_NODE_PRETTY_JSON(node, arena);
char *expected_result_str = arena_strdup(arena,
"[\n"
" {\n"
" \"type\": \"SECTION\",\n"
" \"content\": {\n"
" \"iterator\": \"item\",\n"
" \"collection\": \"items\"\n"
" },\n"
" \"body\": [\n"
" {\n"
" \"type\": \"INTERPOLATE\",\n"
" \"content\": {\n"
" \"key\": \"name\"\n"
" }\n"
" },\n"
" {\n"
" \"type\": \"TEXT\",\n"
" \"content\": {\n"
" \"content\": \" \"\n"
" }\n"
" },\n"
" {\n"
" \"type\": \"INTERPOLATE\",\n"
" \"content\": {\n"
" \"key\": \"item.name\"\n"
" }\n"
" },\n"
" {\n"
" \"type\": \"TEXT\",\n"
" \"content\": {\n"
" \"content\": \" \"\n"
" }\n"
" }\n"
" ]\n"
" },\n"
" {\n"
" \"type\": \"TEXT\",\n"
" \"content\": {\n"
" \"content\": \" \"\n"
" }\n"
" },\n"
" {\n"
" \"type\": \"INTERPOLATE\",\n"
" \"content\": {\n"
" \"key\": \"name2\"\n"
" }\n"
" }\n"
"]");
raise_log("result_str: \n%s", result_str);
assert(strcmp(result_str, expected_result_str) == 0);
}
static void simplest_execute_test_template_parse(Arena *arena, TemplateConfig *config) {
const char *template_str =
"{% %}"
"{% execute RETURN 'aaaaaa' %}"
"{% name %}"
"{% name2 %}"
"{% name3 %}";
TemplateResult template_result = template_parse(arena, &template_str, config);
if (IS_RESULT_ERROR(template_result)) {
raise_exception("template_parse failed");
return;
}
TemplateNode node = RESULT_SOME_VALUE(template_result);
//char *result_str;
{ // some debug output { // some debug output
Arena *debug_arena = DISPOSABLE_ARENA; Arena *debug_arena = DISPOSABLE_ARENA;
const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, &node); const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, &node);
raise_log("json_str: \n%s", json_str); raise_log("json_str: \n%s", json_str);
Json *json = json_parse(debug_arena, &json_str); Json *json = json_parse(debug_arena, &json_str);
raise_notice("json_str: \n%s", JSON_TO_PRETTY_STR(debug_arena, json)); raise_notice("json_str: \n%s", JSON_TO_PRETTY_STR(debug_arena, json));
//result_str = arena_strdup(arena, JSON_TO_PRETTY_STR(debug_arena, json));
} }
} }
@@ -274,6 +349,10 @@ int main(void) {
printf("%sTest 4: simplest_separator_test_template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET)); printf("%sTest 4: simplest_separator_test_template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
arena_reset(&arena); arena_reset(&arena);
simplest_execute_test_template_parse(&arena, &config);
printf("%sTest 5: simplest_execute_test_template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
arena_reset(&arena);
logger_free(); logger_free();
arena_free(&config_arena); arena_free(&config_arena);
arena_free(&arena); arena_free(&arena);

17
package/c/hemar/default.nix Executable file
View File

@@ -0,0 +1,17 @@
{ postgresql, pkg-config, patchelf }:
buildPostgresqlExtension { inherit postgresql; } {
pname = "hemar";
version = "0.1";
src = ./.;
nativeBuildInputs = [pkg-config c-hectic];
dontShrinkRPath = true;
postFixup = ''
echo ">>> postFixup running..."
${patchelf}/bin/patchelf --set-rpath ${c-hectic}/lib $out/lib/hemar.so
'';
preInstall = ''mkdir $out'';
};

View File

@@ -40,7 +40,7 @@ RETURNS void
AS 'hemar', 'pg_test_log_2' AS 'hemar', 'pg_test_log_2'
LANGUAGE C STRICT; LANGUAGE C STRICT;
CREATE FUNCTION "hemar"."template_parse"(text) CREATE FUNCTION "hemar"."parse"("template" text)
RETURNS void RETURNS text
AS 'hemar', 'pg_template_parse' AS 'hemar', 'pg_template_parse'
LANGUAGE C STRICT; LANGUAGE C STRICT;

View File

@@ -14,12 +14,12 @@ PG_MODULE_MAGIC;
#define INIT \ #define INIT \
logger_init(); \ logger_init(); \
logger_level(LOG_LEVEL_TRACE); \
logger_set_file(LOG_FILE); \ logger_set_file(LOG_FILE); \
logger_set_output_mode(LOG_OUTPUT_BOTH); \ logger_set_output_mode(LOG_OUTPUT_BOTH); \
Arena arena = arena_init(MEM_MiB); Arena arena = arena_init(MEM_MiB);
#define FREE \ #define FREE \
DISPOSABLE_ARENA_FREE; \
arena_free(&arena); \ arena_free(&arena); \
logger_free(); logger_free();
@@ -66,7 +66,7 @@ static char *json_value_to_string(Arena *arena, const Json *json) {
return ""; return "";
case JSON_ARRAY: case JSON_ARRAY:
case JSON_OBJECT: case JSON_OBJECT:
return json_to_string(arena, json); return JSON_TO_STR(arena, json);
default: default:
return ""; return "";
} }
@@ -81,7 +81,7 @@ static char *render_text_node(Arena *arena, const TemplateNode *node) {
return ""; return "";
} }
return node->value.text.content; return node->value->text.content;
} }
/* Render an interpolation node */ /* Render an interpolation node */
@@ -93,7 +93,7 @@ static char *render_interpolation_node(Arena *arena, const TemplateNode *node, c
return ""; return "";
} }
key = node->value.interpolate.key; key = node->value->interpolate.key;
value = json_get_by_path(arena, context, key); value = json_get_by_path(arena, context, key);
if (!value) { if (!value) {
@@ -129,9 +129,9 @@ static char *render_section_node(Arena *arena, const TemplateNode *node, const J
return ""; return "";
} }
collection_key = node->value.section.collection; collection_key = node->value->section.collection;
iterator_name = node->value.section.iterator; iterator_name = node->value->section.iterator;
body = node->value.section.body; body = node->value->section.body;
collection = json_get_by_path(arena, context, collection_key); collection = json_get_by_path(arena, context, collection_key);
@@ -191,7 +191,7 @@ static char *render_include_node(Arena *arena, const TemplateNode *node, const J
if (!node || node->type != TEMPLATE_NODE_INCLUDE || !context) { if (!node || node->type != TEMPLATE_NODE_INCLUDE || !context) {
return ""; return "";
} }
include_key = node->value.include.key; include_key = node->value->include.key;
include_value = json_get_by_path(arena, context, include_key); include_value = json_get_by_path(arena, context, include_key);
if (!include_value || include_value->type != JSON_ARRAY) { if (!include_value || include_value->type != JSON_ARRAY) {
@@ -213,7 +213,7 @@ static char *render_include_node(Arena *arena, const TemplateNode *node, const J
const char *template_str = template_json->value.string; const char *template_str = template_json->value.string;
const Json *include_context = context_json ? context_json : context; const Json *include_context = context_json ? context_json : context;
TemplateConfig config = template_default_config(); TemplateConfig config = template_default_config(arena);
TemplateResult template_result = template_parse(arena, &template_str, &config); TemplateResult template_result = template_parse(arena, &template_str, &config);
if (!IS_RESULT_ERROR(template_result)) { if (!IS_RESULT_ERROR(template_result)) {
@@ -290,19 +290,6 @@ static char *render_template_node(Arena *arena, const TemplateNode *node, const
strcpy(output + output_pos, rendered); strcpy(output + output_pos, rendered);
output_pos += rendered_len; output_pos += rendered_len;
if (current->children) {
char *children_rendered = render_template_node(arena, current->children, context);
size_t children_len = strlen(children_rendered);
if (output_pos + children_len + 1 > buffer_size) {
buffer_size = (output_pos + children_len + 1) * 2;
output = arena_realloc(arena, output, buffer_size / 2, buffer_size);
}
strcpy(output + output_pos, children_rendered);
output_pos += children_len;
}
current = current->next; current = current->next;
} }
@@ -338,7 +325,6 @@ Datum pg_render(PG_FUNCTION_ARGS)
TemplateNode root_node; TemplateNode root_node;
TemplateResult template_result; TemplateResult template_result;
TemplateConfig config;
Json *context; Json *context;
@@ -349,6 +335,7 @@ Datum pg_render(PG_FUNCTION_ARGS)
/* Parse the JSON context */ /* Parse the JSON context */
const char *json_ptr = context_str; const char *json_ptr = context_str;
TemplateConfig config = template_default_config(&arena);
context = json_parse(&arena, &json_ptr); context = json_parse(&arena, &json_ptr);
if (!context) { if (!context) {
@@ -359,7 +346,6 @@ Datum pg_render(PG_FUNCTION_ARGS)
/* Parse the template text */ /* Parse the template text */
template_ptr = template_str; template_ptr = template_str;
config = template_default_config();
template_result = template_parse(&arena, &template_ptr, &config); template_result = template_parse(&arena, &template_ptr, &config);
if (IS_RESULT_ERROR(template_result)) { if (IS_RESULT_ERROR(template_result)) {
@@ -411,13 +397,16 @@ PG_FUNCTION_INFO_V1(pg_template_parse);
Datum pg_template_parse(PG_FUNCTION_ARGS) { Datum pg_template_parse(PG_FUNCTION_ARGS) {
INIT; INIT;
TemplateConfig config; text *context_text = PG_GETARG_TEXT_PP(0);
char *content = text_to_cstring(context_text);
const char *template_ptr; const char *template_ptr;
TemplateResult template_result; TemplateResult template_result;
TemplateConfig config = template_default_config(&arena);
template_ptr = "{{ name }}"; raise_info("start parsing....");
config = template_default_config();
template_result = template_parse(&arena, &template_ptr, &config); template_result = template_parse(&arena, &template_ptr, &config);
raise_info("parsing finished....");
if (IS_RESULT_ERROR(template_result)) { if (IS_RESULT_ERROR(template_result)) {
FREE; FREE;
@@ -426,9 +415,18 @@ Datum pg_template_parse(PG_FUNCTION_ARGS) {
RESULT_ERROR_MESSAGE(template_result)))); RESULT_ERROR_MESSAGE(template_result))));
} }
const char *json_str = "{\"a\": 1}"; const char *json_str = TEMPLATE_NODE_TO_JSON_STR(&arena, &(RESULT_SOME_VALUE(template_result)));
Jsonb *jb = DatumGetJsonbP(DirectFunctionCall1(jsonb_in, CStringGetDatum(json_str))); Json *json = json_parse(&arena, &json_str); \
char *result_str = JSON_TO_STR(&arena, json);
raise_notice("%s", result_str);
char *result_str_clone = malloc(strlen(result_str) + 1);
if (result_str_clone) strcpy(result_str_clone, result_str);
FREE; FREE;
PG_RETURN_VOID();
text *result = cstring_to_text(result_str_clone);
PG_RETURN_TEXT_P(result);
} }