decided in favor of dedicated COMPONENT() macro, updates to documentation

This commit is contained in:
udo
2026-04-19 11:34:03 +00:00
parent be514d63d6
commit 2b5586d7df
56 changed files with 926 additions and 401 deletions
+120 -23
View File
@@ -146,6 +146,18 @@ String preprocess_named_render_syntax(String content)
line = indent + "EXPORT void render_" + safe_name(render_name) + render_signature;
}
}
else if(trimmed.rfind("COMPONENT:", 0) == 0)
{
String signature = trimmed.substr(10);
auto open_paren_pos = signature.find("(");
if(open_paren_pos != String::npos)
{
String render_name = trim(signature.substr(0, open_paren_pos));
String render_signature = signature.substr(open_paren_pos);
if(render_name != "")
line = indent + "EXPORT void component_render_" + safe_name(render_name) + render_signature;
}
}
result += line + line_break;
current_line = "";
@@ -285,6 +297,7 @@ void load_shared_unit(Request* context, SharedUnit* su, String file_name)
//setup_unit_paths(context, su, file_name);
su->on_render = 0;
su->on_component = 0;
su->on_websocket = 0;
su->on_setup = 0;
su->compiler_messages = "";
@@ -308,6 +321,8 @@ void load_shared_unit(Request* context, SharedUnit* su, String file_name)
printf("Error - %s in %s\n", error, su->file_name.c_str());
su->on_render = (request_ref_handler)dlsym(su->so_handle, "render");
dlerror();
su->on_component = (request_ref_handler)dlsym(su->so_handle, "component_render");
dlerror();
su->on_websocket = (request_ref_handler)dlsym(su->so_handle, "websocket");
dlerror();
su->api_declarations = split(file_get_contents(su->api_file_name), "\n");
@@ -466,6 +481,34 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
}
namespace {
struct UnitInvocationScope
{
Request* context = 0;
String previous_working_directory;
String previous_unit_file;
UnitInvocationScope(Request* context, SharedUnit* su)
{
this->context = context;
previous_working_directory = get_cwd();
previous_unit_file = context->resources.current_unit_file;
set_cwd(su->src_path);
context->resources.current_unit_file = su->file_name;
}
~UnitInvocationScope()
{
if(!context)
return;
context->resources.current_unit_file = previous_unit_file;
set_cwd(previous_working_directory);
}
};
}
String component_normalize_path(String name)
{
name = trim(name);
@@ -477,26 +520,30 @@ String component_normalize_path(String name)
void component_parse_target(String target, String& file_name, String& render_name)
{
target = trim(target);
render_name = "render";
render_name = "";
auto render_split_pos = target.find(":");
if(render_split_pos != String::npos)
{
render_name = trim(target.substr(render_split_pos + 1));
target = trim(target.substr(0, render_split_pos));
if(render_name == "")
render_name = "render";
}
file_name = target;
}
String component_resolve_path(String name)
String component_resolve_path(String name, Request* request_context = 0)
{
String target_name = trim(name);
String file_name;
String render_name;
component_parse_target(name, file_name, render_name);
component_parse_target(target_name, file_name, render_name);
if(file_name == "")
return("");
{
if(target_name.rfind(":", 0) == 0 && request_context && request_context->resources.current_unit_file != "")
file_name = request_context->resources.current_unit_file;
else
return("");
}
StringList candidates;
auto push_candidate = [&] (String candidate) {
@@ -530,7 +577,7 @@ String component_resolve_path(String name)
return("");
}
String render_handler_symbol(String render_name)
String page_render_handler_symbol(String render_name)
{
render_name = trim(render_name);
if(render_name == "" || render_name == "render")
@@ -538,9 +585,17 @@ String render_handler_symbol(String render_name)
return("render_" + safe_name(render_name));
}
request_ref_handler get_render_handler(SharedUnit* su, String render_name)
String component_handler_symbol(String render_name)
{
String symbol = render_handler_symbol(render_name);
render_name = trim(render_name);
if(render_name == "")
return("component_render");
return("component_render_" + safe_name(render_name));
}
request_ref_handler get_page_render_handler(SharedUnit* su, String render_name)
{
String symbol = page_render_handler_symbol(render_name);
if(symbol == "render")
return(su->on_render);
@@ -554,6 +609,22 @@ request_ref_handler get_render_handler(SharedUnit* su, String render_name)
return(handler);
}
request_ref_handler get_component_handler(SharedUnit* su, String render_name)
{
String symbol = component_handler_symbol(render_name);
if(symbol == "component_render")
return(su->on_component);
auto it = su->api_functions.find(symbol);
if(it != su->api_functions.end())
return((request_ref_handler)it->second);
auto handler = (request_ref_handler)dlsym(su->so_handle, symbol.c_str());
dlerror();
su->api_functions[symbol] = (void*)handler;
return(handler);
}
bool compiler_invoke_render(Request* context, String file_name, String render_name, String* error_out = 0)
{
auto su = compiler_load_shared_unit(context, file_name, "", false);
@@ -567,7 +638,7 @@ bool compiler_invoke_render(Request* context, String file_name, String render_na
return(false);
}
auto handler = get_render_handler(su, render_name);
auto handler = get_page_render_handler(su, render_name);
if(!handler)
{
if(error_out)
@@ -580,11 +651,41 @@ bool compiler_invoke_render(Request* context, String file_name, String render_na
return(false);
}
String prev_wd = get_cwd();
set_cwd(su->src_path);
UnitInvocationScope invoke_scope(context, su);
su->on_setup(context);
handler(*context);
return(true);
}
bool compiler_invoke_component(Request* context, String file_name, String render_name, String* error_out = 0)
{
auto su = compiler_load_shared_unit(context, file_name, "", false);
if(!su)
return(false);
if(!su->on_setup)
{
if(error_out)
*error_out = "internal error: set_current_request() not defined in " + file_name;
return(false);
}
auto handler = get_component_handler(su, render_name);
if(!handler)
{
if(error_out)
{
if(trim(render_name) == "")
*error_out = "no COMPONENT() entry point";
else
*error_out = "no COMPONENT:" + render_name + "() entry point";
}
return(false);
}
UnitInvocationScope invoke_scope(context, su);
su->on_setup(context);
handler(*context);
set_cwd(prev_wd);
return(true);
}
@@ -618,11 +719,9 @@ void compiler_invoke_websocket(Request* context, String file_name)
return;
}
String prev_wd = get_cwd();
set_cwd(su->src_path);
UnitInvocationScope invoke_scope(context, su);
su->on_setup(context);
su->on_websocket(*context);
set_cwd(prev_wd);
}
void render_file(String file_name)
@@ -638,7 +737,7 @@ void render_file(String file_name, Request& context)
String component_resolve(String name)
{
return(component_resolve_path(name));
return(component_resolve_path(name, context));
}
bool component_exists(String name)
@@ -674,10 +773,10 @@ void render_component(String name, DTree props, Request& context)
String render_name;
component_parse_target(name, file_name, render_name);
String resolved_name = component_resolve_path(file_name);
String resolved_name = component_resolve_path(name, &context);
if(resolved_name == "")
{
print(component_error_banner("component not found: " + file_name));
print(component_error_banner("component not found: " + trim(name)));
return;
}
@@ -685,7 +784,7 @@ void render_component(String name, DTree props, Request& context)
context.call = props;
String error_message = "";
if(!compiler_invoke_render(&context, resolved_name, render_name, &error_message) && error_message != "")
if(!compiler_invoke_component(&context, resolved_name, render_name, &error_message) && error_message != "")
print(component_error_banner(error_message));
context.call = previous_call;
@@ -747,11 +846,9 @@ DTree* call_file(String file_name, String function_name, DTree* call_param)
}
else
{
String prev_wd = get_cwd();
set_cwd(su->src_path);
UnitInvocationScope invoke_scope(context, su);
su->on_setup(context);
result = f(call_param);
set_cwd(prev_wd);
}
}
}
+1
View File
@@ -1,6 +1,7 @@
#pragma once
#define RENDER(X) extern "C" void render(Request& context)
#define COMPONENT(X) extern "C" void component_render(Request& context)
#define WS(X) extern "C" void websocket(Request& context)
#define EXPORT extern "C"
+46 -6
View File
@@ -67,13 +67,13 @@ String DTree::to_string()
return("");
}
String DTree::to_json()
String DTree::to_json(char quote_char)
{
const DTree& target = deref();
switch(target.type)
{
case('S'):
return(json_escape(target._String));
return(json_escape(target._String, quote_char));
break;
case('F'):
return(std::to_string(target._float));
@@ -121,6 +121,41 @@ String DTree::get_type_name()
return("unknown");
}
DTree DTree::get_by_path(String path, String delim)
{
const DTree* current = &deref();
if(path == "")
return(*current);
size_t start = 0;
while(start <= path.length())
{
size_t end = path.find(delim, start);
String segment;
if(end == String::npos)
segment = path.substr(start);
else
segment = path.substr(start, end - start);
if(segment == "")
{
if(end == String::npos)
break;
start = end + delim.length();
continue;
}
current = &current->deref();
if(current->type != 'M')
return(DTree());
auto it = current->_map.find(segment);
if(it == current->_map.end())
return(DTree());
current = &it->second;
if(end == String::npos)
break;
start = end + delim.length();
}
return(current->deref());
}
bool DTree::is_reference()
{
return(type == 'R');
@@ -374,16 +409,21 @@ String var_dump(DTree map, String prefix, String postfix)
return(result);
}
String json_escape(String s)
String json_escape(String s, char quote_char)
{
//return(String("\"")+s+"\"");
String result;
u32 i = 0;
result.append(1, '"');
result.append(1, quote_char);
while(i < s.length())
{
char c = s[i];
switch(c)
if(c == quote_char)
{
result.append(1, '\\');
result.append(1, quote_char);
}
else switch(c)
{
case('\t'):
result.append("\\t");
@@ -412,6 +452,6 @@ String json_escape(String s)
}
i += 1;
}
result.append(1, '"');
result.append(1, quote_char);
return(result);
}
+3 -2
View File
@@ -1,6 +1,6 @@
#pragma once
String json_escape(String s);
String json_escape(String s, char quote_char = '"');
struct DTree {
@@ -16,8 +16,9 @@ struct DTree {
void each(std::function <void (DTree t, String key)> f);
bool is_array();
String to_string();
String to_json();
String to_json(char quote_char = '"');
String get_type_name();
DTree get_by_path(String path, String delim = "/");
bool is_reference();
DTree* reference_target();
const DTree* reference_target() const;
+12 -2
View File
@@ -359,6 +359,11 @@ String html_escape(f64 a)
return(std::to_string(a));
}
String json_encode(String s, char quote_char)
{
return(json_escape(s, quote_char));
}
u64 int_val(String s, u32 base)
{
return(strtol(s.c_str(), 0, base));
@@ -386,7 +391,7 @@ String nibble(String& haystack, String delim)
}
}
String json_encode(DTree t)
String json_encode(DTree t, char quote_char)
{
String result = "";
if(t.is_array())
@@ -397,7 +402,7 @@ String json_encode(DTree t)
if(count > 0)
result += ", ";
count += 1;
result += json_escape(key) + ": " + json_encode(item);
result += json_escape(key, quote_char) + ": " + json_encode(item, quote_char);
});
result += "}";
}
@@ -632,6 +637,11 @@ String ob_get_close()
}
String safe_name(String raw)
{
return(ascii_safe_name(raw));
}
String ascii_safe_name(String raw)
{
String result = "";
for(auto c : raw)
+3 -1
View File
@@ -80,7 +80,8 @@ String html_escape(String s);
String html_escape(u64 a);
String html_escape(f64 a);
String json_encode(DTree t);
String json_encode(String s, char quote_char = '"');
String json_encode(DTree t, char quote_char = '"');
DTree json_decode(String s);
String var_dump(StringMap map, String prefix = "", String postfix = "\n");
@@ -92,5 +93,6 @@ String ob_get();
String ob_get_close();
String safe_name(String raw);
String ascii_safe_name(String raw);
#define is_bit_set(var,pos) ((var) & (1<<(pos)))
+13
View File
@@ -129,6 +129,19 @@ String dirname(String fn)
return(result);
}
String path_join(String base, String child)
{
if(base == "")
return(child);
if(child == "")
return(base);
if(child[0] == '/')
return(child);
if(base[base.length() - 1] == '/')
return(base + child);
return(base + "/" + child);
}
bool mkdir(String path)
{
shell_exec(String("mkdir -p ")+" "+shell_escape(path));
+1
View File
@@ -6,6 +6,7 @@ String shell_exec(String cmd);
String shell_escape(String raw);
String basename(String fn);
String dirname(String fn);
String path_join(String base, String child);
bool mkdir(String path);
bool file_exists(String path);
String file_get_contents(String file_name);
+46
View File
@@ -14,6 +14,41 @@
#include "types.h"
namespace {
String http_status_reason(s32 code)
{
switch(code)
{
case 200: return("OK");
case 201: return("Created");
case 202: return("Accepted");
case 204: return("No Content");
case 301: return("Moved Permanently");
case 302: return("Found");
case 303: return("See Other");
case 304: return("Not Modified");
case 307: return("Temporary Redirect");
case 308: return("Permanent Redirect");
case 400: return("Bad Request");
case 401: return("Unauthorized");
case 403: return("Forbidden");
case 404: return("Not Found");
case 405: return("Method Not Allowed");
case 409: return("Conflict");
case 422: return("Unprocessable Content");
case 429: return("Too Many Requests");
case 500: return("Internal Server Error");
case 501: return("Not Implemented");
case 502: return("Bad Gateway");
case 503: return("Service Unavailable");
case 504: return("Gateway Timeout");
default: return("");
}
}
}
SharedUnit::~SharedUnit()
{
if(so_handle)
@@ -45,6 +80,17 @@ void Request::ob_start()
ob = ob_stack.back();
}
void Request::set_status(s32 code, String reason)
{
if(reason == "")
reason = http_status_reason(code);
String prefix = params["GATEWAY_INTERFACE"] != "" ? "Status: " : "HTTP/1.1 ";
response_code = prefix + std::to_string(code);
if(reason != "")
response_code += " " + reason;
flags.status = code;
}
Request::~Request()
{
for(auto* stream : ob_stack)
+4
View File
@@ -80,6 +80,7 @@ struct SharedUnit {
request_handler on_setup;
request_ref_handler on_render;
request_ref_handler on_component;
request_ref_handler on_websocket;
String compiler_messages;
@@ -128,6 +129,7 @@ struct Request {
StringMap session;
DTree var;
DTree cfg;
DTree call;
DTree connection;
@@ -181,10 +183,12 @@ struct Request {
u8 websocket_opcode = 0;
bool websocket_is_binary = false;
bool websocket_is_text = false;
String current_unit_file = "";
std::string params_buffer;
} resources;
void ob_start();
void set_status(s32 code, String reason = "");
~Request();