trying to port web app starter from PHP

This commit is contained in:
Udo 2026-04-19 09:38:23 +00:00
parent 46d98a092f
commit be514d63d6
546 changed files with 76910 additions and 2807 deletions

1980
README.md

File diff suppressed because it is too large Load Diff

58
codesearch Executable file
View File

@ -0,0 +1,58 @@
#!/bin/bash
set -euo pipefail
cd "$(dirname "$0")"
show_help() {
cat <<'EOF'
Usage:
./codesearch <pattern> [rg options...]
Examples:
./codesearch "ws_send"
./codesearch "RENDER\\(Request& context\\)"
./codesearch -tcpp "compiler_invoke"
./codesearch -g '*.uce' "context.call"
Notes:
- This is a thin wrapper around ripgrep (`rg`).
- It searches from the repository root.
- Generated/build directories are excluded by default:
`.git/`, `bin/`, `dist/`, and `work/`.
EOF
}
if [[ $# -eq 0 ]]; then
show_help
exit 1
fi
case "${1:-}" in
-h|--help|help)
show_help
exit 0
;;
esac
if command -v rg >/dev/null 2>&1; then
exec rg \
--line-number \
--column \
--smart-case \
--glob '!.git/**' \
--glob '!bin/**' \
--glob '!dist/**' \
--glob '!work/**' \
"$@"
fi
pattern="$1"
shift || true
echo "ripgrep (rg) is not installed; falling back to grep." >&2
exec grep -RIn \
--exclude-dir=.git \
--exclude-dir=bin \
--exclude-dir=dist \
--exclude-dir=work \
-- "$pattern" .

View File

@ -1,20 +0,0 @@
:sig
WS()
:desc
Defines the WebSocket message handler for the current `.ws.uce` page.
The same page may expose both `RENDER()` and `WS()`. `RENDER()` serves the initial HTTP response, while `WS()` is called whenever a complete WebSocket message arrives for that page.
UCE reassembles fragmented messages before calling `WS()`. Text and binary frames are both delivered. Use `ws_opcode()` and `ws_is_binary()` to distinguish them.
The `call` parameter passed into `WS()` contains:
- `message`
- `connection_id`
- `scope`
- `opcode`
- `document_uri`
:see
>websocket

View File

@ -1,13 +0,0 @@
:sig
f64 draw_float(f64 from, f64 to)
:params
from : minimum value
to : maximum value
return value : a noise value between 'from' and 'to'
:desc
This function works exactly like generate_float(), but context->random_index is used for the 'index' value and context->random_seed is used for the seed. After this function has been called, the context->random_index is increased by one. At the start of every request, context->random_seed is automatically populated with a new seed value.
:see
>noise

View File

@ -1,13 +0,0 @@
:sig
u64 draw_int(u64 from, u64 to)
:params
from : minimum value
to : maximum value
return value : a noise value between 'from' and 'to'
:desc
This function works exactly like generate_int(), but context->random_index is used for the 'index' value and context->random_seed is used for the seed. After this function has been called, the context->random_index is increased by one. At the start of every request, context->random_seed is automatically populated with a new seed value.
:see
>noise

View File

@ -1,16 +0,0 @@
:sig
void render_file(String file_name, DTree& call_param = null)
:params
file_name : UCE file to load and execute
call_param : optional, call parameter
:desc
Calls another UCE file and executes its RENDER() function.
:Example
// call a common page template
render_file("page-template.uce");
:see
>ob

View File

@ -1,17 +0,0 @@
:sig
u64 ws_broadcast(String message, String scope = "")
:params
message : text message to send
scope : optional scope identifier, defaults to the current WebSocket page scope
return value : number of clients the message was queued for
:desc
Queues a text WebSocket message for every client connected to the given scope and returns the number of recipients.
If `scope` is omitted, the current page scope is used.
This helper currently sends text frames only.
:see
>websocket

View File

@ -1,15 +0,0 @@
:sig
bool ws_send_to(String connection_id, String message)
:params
connection_id : ID of the target WebSocket client
message : text message to send
return value : true if the target connection exists and the message was queued
:desc
Queues a text WebSocket message for one specific connected client.
This helper currently sends text frames only.
:see
>websocket

View File

@ -1,19 +0,0 @@
Copyright (c) HTML5 Boilerplate
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Please read: https://msdn.microsoft.com/en-us/library/ie/dn455106.aspx -->
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="tile.png"/>
<square150x150logo src="tile.png"/>
<wide310x150logo src="tile-wide.png"/>
<square310x310logo src="tile.png"/>
</tile>
</msapplication>
</browserconfig>

View File

@ -1,263 +0,0 @@
/*! HTML5 Boilerplate v8.0.0 | MIT License | https://html5boilerplate.com/ */
/* main.css 2.1.0 | MIT License | https://github.com/h5bp/main.css#readme */
/*
* What follows is the result of much research on cross-browser styling.
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
* Kroc Camen, and the H5BP dev community and team.
*/
/* ==========================================================================
Base styles: opinionated defaults
========================================================================== */
html {
color: #222;
font-size: 1em;
line-height: 1.4;
}
/*
* Remove text-shadow in selection highlight:
* https://twitter.com/miketaylr/status/12228805301
*
* Vendor-prefixed and regular ::selection selectors cannot be combined:
* https://stackoverflow.com/a/16982510/7133471
*
* Customize the background color to match your design.
*/
::-moz-selection {
background: #b3d4fc;
text-shadow: none;
}
::selection {
background: #b3d4fc;
text-shadow: none;
}
/*
* A better looking default horizontal rule
*/
hr {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #ccc;
margin: 1em 0;
padding: 0;
}
/*
* Remove the gap between audio, canvas, iframes,
* images, videos and the bottom of their containers:
* https://github.com/h5bp/html5-boilerplate/issues/440
*/
audio,
canvas,
iframe,
img,
svg,
video {
vertical-align: middle;
}
/*
* Remove default fieldset styles.
*/
fieldset {
border: 0;
margin: 0;
padding: 0;
}
/*
* Allow only vertical resizing of textareas.
*/
textarea {
resize: vertical;
}
/* ==========================================================================
Author's custom styles
========================================================================== */
/* ==========================================================================
Helper classes
========================================================================== */
/*
* Hide visually and from screen readers
*/
.hidden,
[hidden] {
display: none !important;
}
/*
* Hide only visually, but have it available for screen readers:
* https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
*
* 1. For long content, line feeds are not interpreted as spaces and small width
* causes content to wrap 1 word per line:
* https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
*/
.sr-only {
border: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
/* 1 */
}
/*
* Extends the .sr-only class to allow the element
* to be focusable when navigated to via the keyboard:
* https://www.drupal.org/node/897638
*/
.sr-only.focusable:active,
.sr-only.focusable:focus {
clip: auto;
height: auto;
margin: 0;
overflow: visible;
position: static;
white-space: inherit;
width: auto;
}
/*
* Hide visually and from screen readers, but maintain layout
*/
.invisible {
visibility: hidden;
}
/*
* Clearfix: contain floats
*
* For modern browsers
* 1. The space content is one way to avoid an Opera bug when the
* `contenteditable` attribute is included anywhere else in the document.
* Otherwise it causes space to appear at the top and bottom of elements
* that receive the `clearfix` class.
* 2. The use of `table` rather than `block` is only necessary if using
* `:before` to contain the top-margins of child elements.
*/
.clearfix::before,
.clearfix::after {
content: " ";
display: table;
}
.clearfix::after {
clear: both;
}
/* ==========================================================================
EXAMPLE Media Queries for Responsive Design.
These examples override the primary ('mobile first') styles.
Modify as content requires.
========================================================================== */
@media only screen and (min-width: 35em) {
/* Style adjustments for viewports that meet the condition */
}
@media print,
(-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 1.25dppx),
(min-resolution: 120dpi) {
/* Style adjustments for high resolution devices */
}
/* ==========================================================================
Print styles.
Inlined to avoid the additional HTTP request:
https://www.phpied.com/delay-loading-your-print-css/
========================================================================== */
@media print {
*,
*::before,
*::after {
background: #fff !important;
color: #000 !important;
/* Black prints faster */
box-shadow: none !important;
text-shadow: none !important;
}
a,
a:visited {
text-decoration: underline;
}
a[href]::after {
content: " (" attr(href) ")";
}
abbr[title]::after {
content: " (" attr(title) ")";
}
/*
* Don't show links that are fragment identifiers,
* or use the `javascript:` pseudo protocol
*/
a[href^="#"]::after,
a[href^="javascript:"]::after {
content: "";
}
pre {
white-space: pre-wrap !important;
}
pre,
blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
/*
* Printing Tables:
* https://web.archive.org/web/20180815150934/http://css-discuss.incutio.com/wiki/Printing_Tables
*/
thead {
display: table-header-group;
}
tr,
img {
page-break-inside: avoid;
}
p,
h2,
h3 {
orphans: 3;
widows: 3;
}
h2,
h3 {
page-break-after: avoid;
}
}

View File

@ -1,349 +0,0 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

View File

@ -1,15 +0,0 @@
# humanstxt.org/
# The humans responsible & technology colophon
# TEAM
<name> -- <role> -- <twitter>
# THANKS
<name>
# TECHNOLOGY COLOPHON
CSS3, HTML5
Apache Server Configs, jQuery, Modernizr, Normalize.css

View File

View File

@ -1,7 +0,0 @@
#load "config/settings.uce"
#load "lib/site.uce"
RENDER()
{
render_file("pages/page.html.uce");
}

View File

@ -1,24 +0,0 @@
// Avoid `console` errors in browsers that lack a console.
(function() {
var method;
var noop = function () {};
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
}());
// Place any jQuery/helper plugins in here.

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
EXPORT
String bla(String x)
{
return(x + "!");
}

View File

@ -1,47 +0,0 @@
EXPORT DTree* my_custom_func(DTree* var)
{
<>
Hello
</>
return(0);
}
RENDER()
{
<><!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta property="og:title" content="">
<meta property="og:type" content="">
<meta property="og:url" content="">
<meta property="og:image" content="">
<link rel="manifest" href="site.webmanifest">
<link rel="apple-touch-icon" href="icon.png">
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/main.css">
<meta name="theme-color" content="#606060">
</head>
<body>
<?
String view_name = safe_name(first(context->get["view"], "default")) + ".uce";
if(file_exists(view_name))
render_file(view_name);
else
print("view not found");
?>
</body>
</html>
</>
}

View File

@ -1,5 +0,0 @@
# www.robotstxt.org/
# Allow crawling of all content
User-agent: *
Disallow:

View File

@ -1,12 +0,0 @@
{
"short_name": "",
"name": "",
"icons": [{
"src": "icon.png",
"type": "image/png",
"sizes": "192x192"
}],
"start_url": "/?utm_source=homescreen",
"background_color": "#fafafa",
"theme_color": "#fafafa"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,8 +1,12 @@
#ifndef UCE_SET_CURRENT_REQUEST_DEFINED
#define UCE_SET_CURRENT_REQUEST_DEFINED
/*load_declarations*/
extern "C" void set_current_request(Request* _request)
{
context = _request;
signal(SIGSEGV, on_segfault);
/*load_units*/
}
#endif

View File

@ -0,0 +1,3 @@
Markup Functions
markdown_to_ast
markdown_to_html

View File

@ -1,10 +1,15 @@
Output / Invocation Functions
1_RENDER
call_file
component
component_exists
component_resolve
load
ob_close
ob_get
ob_get_close
ob_start
print
render_component
render_file

5
site/doc/areas/types.txt Normal file
View File

@ -0,0 +1,5 @@
Types
DTree
String
StringMap

View File

@ -1,6 +1,5 @@
WebSocket Functions
ws_broadcast
ws_close
ws_connection_count
ws_connection_id

View File

@ -19,10 +19,10 @@ void render_see_section(String name)
}
RENDER()
RENDER(Request& context)
{
String page = first(context->get["p"], "index");
String page = first(context.get["p"], "index");
<><html>
<head>

View File

@ -1,5 +1,5 @@
:sig
Request* context;
Request& context;
:ServerState* server
Contains the current server state
@ -22,12 +22,18 @@ The current session
:String session_id
ID of the session cookie
String session_name
:String session_name
Name of the session cookie
:DTree var
Variable user-defined data
:DTree call
Invocation or message-local structured data
:DTree connection
Broker-owned per-WebSocket-connection state. Inside `WS(Request& context)`, updates to this tree persist for the lifetime of that socket connection.
:std::vector<UploadedFile> uploaded_files
Files that have been uploaded in the current request
@ -43,9 +49,6 @@ The current request's "random" noise generator seed
:u64 random_index
The current request's "random" noise generator index position
:MemoryArena* mem
Contains the current request's memory arena
:bool flags.log_request
Whether the request should be logged
@ -55,9 +58,10 @@ Whether the request should be logged
f64 stats.time_start
f64 stats.time_end
:invoke(String file_name, [DTree& call_param])
Invokes the UCE file 'file_name'
:render_file(String file_name, [Request& context])
Invokes another UCE file using the current or supplied request context
:see
>types

View File

@ -0,0 +1,24 @@
:sig
RENDER(Request& context)
:desc
Defines the main HTTP render handler for the current `.uce` page.
When a page is requested over HTTP, the runtime loads the target file and calls its `RENDER(Request& context)` function.
Pages may also export additional named render handlers with `RENDER:NAME(Request& context)`.
Named render handlers are not used for the page's direct HTTP entrypoint. They are intended for component-style sub-rendering through helpers such as `component("components/card:BODY", props, context)` or `render_component("components/card:BODY", props, context)`.
The default page entrypoint is always the plain `RENDER(Request& context)` handler.
The request environment is passed explicitly through `context`, including params, cookies, post data, session state, headers, uploaded files, and the current `context.call` tree.
For a normal direct page request, `context.call` starts empty.
If the page is invoked from another UCE file via `render_file(file_name, context)`, the callee receives that same `context`.
Pages intended to serve WebSocket traffic may expose both `RENDER(Request& context)` and `WS(Request& context)`. In that case `RENDER(Request& context)` serves the initial HTTP response and `WS(Request& context)` handles subsequent WebSocket messages.
:see
>ob

26
site/doc/pages/1_WS.txt Normal file
View File

@ -0,0 +1,26 @@
:sig
WS(Request& context)
:desc
Defines the WebSocket message handler for the current `.ws.uce` page.
The same page may expose both `RENDER(Request& context)` and `WS(Request& context)`. `RENDER(Request& context)` serves the initial HTTP response, while `WS(Request& context)` is called whenever a complete WebSocket message arrives for that page.
UCE reassembles fragmented messages before calling `WS(Request& context)`. Text and binary frames are both delivered. Use `context.call`, `context.connection`, `ws_opcode()`, and `ws_is_binary()` to inspect the current message.
`context.connection` is a broker-owned `DTree` for the current socket. It starts empty for a new client and persists across later `WS(Request& context)` calls on that same connection.
The current message data is available in `context.call`:
context.call["message"] : current message payload
context.call["connection_id"] : sender connection ID
context.call["scope"] : current endpoint scope
context.call["opcode"] : WebSocket opcode of the current message
context.call["document_uri"] : request URI of the current endpoint
:see
>websocket

View File

@ -0,0 +1,95 @@
:sig
UCE source preprocessing
:desc
UCE runs a small custom source-to-source preprocessor before Clang sees a `.uce` or `.ws.uce` file.
The implementation lives in `src/lib/compiler.cpp`. It does not try to parse all of C++. Instead, it performs a narrow character-wise rewrite that understands UCE literal blocks, inline code islands, `#load`, and `EXPORT` harvesting, then writes a generated `.cpp` file and compiles that file into a shared object.
:Syntax
- `<> ... </>` enters literal-output mode.
- Inside a literal block, `<? ... ?>` emits raw C++.
- Inside a literal block, `<?= expression ?>` emits `print(html_escape(expression));`.
- Inside a literal block, `<?: expression ?>` emits `print(expression);` without HTML escaping.
- `#load "other.uce"` injects another UCE unit at compile time.
- `RENDER(Request& context)` and `WS(Request& context)` are normal C++ macros from `src/lib/compiler.h`.
- `EXPORT` is also a normal C++ macro, but the custom pass additionally records exported declarations for metadata.
:Pipeline
- The generated file starts by including `COMPILER_SYS_PATH/src/lib/uce_lib.h`.
- It then inlines the configured setup template from `SETUP_TEMPLATE` (by default `scripts/setup.h.template`), which defines `set_current_request(Request*)`.
- It inserts `#line 1` before page code so compiler diagnostics point back to the original `.uce` file.
- Each literal block is rewritten into one or more `print(R"( ... )");` calls.
- `<? ... ?>` temporarily breaks out of literal printing, emits the enclosed C++ unchanged, then resumes literal output.
- `<?= ... ?>` becomes `print(html_escape(...));`. The runtime currently provides `html_escape()` overloads for `String`, `u64`, and `f64`.
- `<?: ... ?>` becomes `print(...);` and is intended for trusted markup or already-escaped content.
- `#load "file.uce"` is replaced with a generated C++ `#include` that points at the loaded unit's preprocessed `.cpp` file under `BIN_DIRECTORY`.
- Lines beginning with `EXPORT` are scanned so their declarations can be written to a sibling `.exports.txt` file.
- The final generated source is written to `BIN_DIRECTORY + src_path + "/" + source_file + ".cpp"`.
- `scripts/compile` then compiles that generated `.cpp` into `source_file + ".so"` with `clang++ -shared -std=c++20 ...`.
:GeneratedFiles
- Source file: `/some/path/page.uce`
- Generated C++: `BIN_DIRECTORY/some/path/page.uce.cpp`
- Shared object: `BIN_DIRECTORY/some/path/page.uce.so`
- Export list: `BIN_DIRECTORY/some/path/page.uce.exports.txt`
:Example
Example 1: literal output with escaped data
`RENDER(Request& context)`
`{`
` &lt;&gt;&lt;h1&gt;&lt;?= context.params["DOCUMENT_URI"] ?&gt;&lt;/h1&gt;&lt;/&gt;`
`}`
Roughly becomes:
`print(R"(&lt;h1&gt;)");`
`print(html_escape(context.params["DOCUMENT_URI"]));`
`print(R"(&lt;/h1&gt;)");`
Example 1b: literal output with trusted unescaped markup
`RENDER(Request& context)`
`{`
` &lt;&gt;&lt;div class="panel"&gt;&lt;?: component("components/card", context.call, context) ?&gt;&lt;/div&gt;&lt;/&gt;`
`}`
Roughly becomes:
`print(R"(&lt;div class="panel"&gt;)");`
`print(component("components/card", context.call, context));`
`print(R"(&lt;/div&gt;)");`
Example 2: compile-time composition
`#load "partials/nav.uce"`
`RENDER(Request& context)`
`{`
` &lt;&gt;&lt;body&gt;...&lt;/body&gt;&lt;/&gt;`
`}`
The loaded file is resolved relative to the current source file unless the path is already absolute.
:Rules
- Literal mode starts only on the exact token `<>`.
- Literal mode ends only on the exact token `</>`.
- `#load` is recognized only when the current line starts with `#load ` at column 1.
- `EXPORT` harvesting likewise only triggers when the current line starts with `EXPORT` at column 1 and is followed by whitespace.
- Relative `#load` paths are expanded against the including unit's source directory.
- `render_file()` and `call_file()` are runtime APIs; `#load` is a compile-time include/composition feature.
:Limitations
- This pass is character-wise, not a full parser.
- Outside literal blocks it only tracks double-quoted C++ strings while deciding whether `<>` should open literal mode.
- It does not understand comments, raw string literals, templates, or general C++ token structure.
- Inside literal blocks it tracks single and double quotes while scanning a `<? ... ?>` island so quoted `?>` text does not close the island early.
- Literal blocks are not nested.
- Because literal output is emitted as a C++ raw string literal `R"( ... )"`, literal content must not contain the exact terminator sequence `)"` or the generated C++ will break.
- `#load` depends on the target unit's generated `.cpp` existing and being compilable. If the target cannot be preprocessed or compiled correctly, the including file will fail to compile as well.
:Debugging
- When a page is compiled, inspect the generated file under `BIN_DIRECTORY` first. That file shows the exact C++ produced by the UCE preprocessor.
- Compiler errors usually point back to the `.uce` source because the preprocessor inserts `#line 1`, but the generated `.cpp` is still the best place to inspect expansion problems.
- If a `#load` include looks wrong, check the current file's directory, the configured `BIN_DIRECTORY`, and whether the loaded page already produced its own generated `.cpp`.
:see
load
render_file
call_file
0_context

27
site/doc/pages/DTree.txt Normal file
View File

@ -0,0 +1,27 @@
:sig
DTree
:desc
Dynamic tree/container type used throughout UCE for structured data.
`DTree` can hold a `String`, `f64`, `bool`, pointer, or a nested map of child `DTree` values.
Use `t["key"]` to access or create child entries. Use `push()` / `pop()` when treating it like an array-like container with numeric string keys.
Common uses include:
`json_decode()` / `json_encode()`
`context.var`
`context.call`
`call_file()` return values
Useful methods include:
`to_string()`
`to_json()`
`get_type_name()`
`set_bool()`
`remove()`
`clear()`
`each()`
:see
>types

16
site/doc/pages/String.txt Normal file
View File

@ -0,0 +1,16 @@
:sig
String
:desc
Primary string type used throughout UCE.
`String` is an alias for `std::string`.
It is used for request data, headers, cookie values, file contents, query strings, JSON text, and WebSocket payloads.
Because it is backed by `std::string`, it is binary-safe and may also contain raw bytes.
For UTF-8-aware splitting, use helpers such as `split_utf8()` instead of assuming one byte equals one character.
:see
>types

View File

@ -0,0 +1,22 @@
:sig
StringMap
:desc
Associative container mapping `String` keys to `String` values.
`StringMap` is an alias for `std::map<String, String>`.
It is commonly used for:
`context.params`
`context.get`
`context.post`
`context.cookies`
`context.session`
`context.header`
Because it uses `std::map`, `map["key"]` will create an empty entry when that key does not already exist.
Related helpers such as `parse_query()` and `encode_query()` convert between query strings and `StringMap` values.
:see
>types

View File

@ -0,0 +1,28 @@
:sig
String component(String name, [DTree props], [Request& context])
:desc
Renders another `.uce` file as a component and returns the captured output as a `String`.
`component()` resolves the target file relative to the current page and also tries the `components/` prefix automatically, mirroring the shorthand used by the web app starter example project.
Component props are passed in `context.call`.
Because `<?= ... ?>` HTML-escapes its value, embed component markup with `<?: component(...) ?>`, `print(component(...))`, or use `render_component(...)` for direct output.
When `name` contains a colon, such as `components/card:BODY`, the part after the colon selects a named render handler exported from the component file through `RENDER:BODY(Request& context)`.
The default handler is `RENDER(Request& context)`.
Resolution order is:
exact file name
exact file name with `.uce`
the same two forms under `components/`
Example:
`DTree props;`
`props["title"] = "Status";`
`&lt;&gt;&lt;?: component("workspace/panel", props, context) ?&gt;&lt;/&gt;`
:see
>ob

View File

@ -0,0 +1,14 @@
:sig
bool component_exists(String name)
:desc
Checks whether a component file can be resolved from the current page context.
Resolution tries the exact name first and then the `components/` shorthand form.
If `name` contains a colon, only the file portion is used for existence checks.
This is useful when a page wants to render an optional component if it is present without hard-failing when it is missing.
:see
>ob

View File

@ -0,0 +1,14 @@
:sig
String component_resolve(String name)
:desc
Resolves a component name to the concrete `.uce` file path that will be loaded.
Resolution tries the exact file name first, then the same name with `.uce` appended, and then the same two forms under the `components/` prefix.
If `name` contains a colon, only the file portion is used for resolution.
This is primarily a debugging helper so you can see which concrete file a shorthand component name maps to.
:see
>ob

View File

@ -0,0 +1,13 @@
:sig
f64 draw_float(f64 from, f64 to)
:params
from : minimum value
to : maximum value
return value : a noise value between 'from' and 'to'
:desc
This function works exactly like generate_float(), but context.random_index is used for the 'index' value and context.random_seed is used for the seed. After this function has been called, the context.random_index is increased by one. At the start of every request, context.random_seed is automatically populated with a new seed value.
:see
>noise

View File

@ -0,0 +1,13 @@
:sig
u64 draw_int(u64 from, u64 to)
:params
from : minimum value
to : maximum value
return value : a noise value between 'from' and 'to'
:desc
This function works exactly like generate_int(), but context.random_index is used for the 'index' value and context.random_seed is used for the seed. After this function has been called, the context.random_index is increased by one. At the start of every request, context.random_seed is automatically populated with a new seed value.
:see
>noise

View File

@ -0,0 +1,77 @@
:sig
DTree markdown_to_ast(String src)
DTree markdown_to_ast(String src, DTree options)
:params
src : markdown source text
options : optional markdown options tree
return value : a `DTree` document AST
:desc
Parses Markdown source into a structured `DTree` document tree.
The parser targets a practical GitHub-flavored subset by default:
- ATX headings (`#`)
- setext headings
- paragraphs
- blockquotes
- ordered and unordered lists
- task list items
- fenced code blocks
- tables
- horizontal rules
- emphasis / strong / strikethrough
- links, images, autolinks, and code spans
- `:::` directive blocks for component-based extensions
The returned AST uses `type` plus node-specific fields such as `level`, `text`, `lang`, `href`, `src`, `name`, `argument`, `attrs`, and `children`.
Top-level documents use:
`type = "document"`
`children = [...]`
Common block nodes:
`heading`
`paragraph`
`blockquote`
`list`
`list_item`
`code_block`
`table`
`directive`
`hr`
Common inline nodes:
`text`
`code`
`strong`
`em`
`strike`
`link`
`image`
`raw_html`
:Example
`DTree options = json_decode("{\"components\":{\":::warning\":\"components/markdown/warning\"}}");`
`DTree ast = markdown_to_ast(file_get_contents("README.md"), options);`
`print(json_encode(ast));`
:Options
`options["gfm"]`
Enables GitHub-style extras such as tables, task lists, strikethrough, and bare-URL autolinks.
Defaults to true.
`options["allow_html"]`
Allows raw HTML passthrough nodes to be captured and rendered.
Defaults to false.
`options["components"]`
Component hook map used later by `markdown_to_html()`.
The parser preserves directive data needed by those hooks.
:see
markdown_to_html
component
render_component
json_encode
DTree

View File

@ -0,0 +1,100 @@
:sig
String markdown_to_html(String src)
String markdown_to_html(String src, DTree options)
:params
src : markdown source text
options : optional markdown options tree
return value : rendered HTML string
:desc
Renders Markdown source into HTML and returns the generated markup as a `String`.
`markdown_to_html()` does not write to the output stream directly. This keeps it aligned with the UCE naming convention where `render_*` names are reserved for direct-output helpers.
Because the return value is HTML markup, embed it with `<?: markdown_to_html(...) ?>`, `print(markdown_to_html(...))`, or pass it through a component.
By default the function aims at a practical GitHub-flavored Markdown target, including tables, task lists, fenced code blocks, autolinks, and strikethrough.
:Example
`DTree options;`
`options["components"][":::warning"] = "components/markdown/warning";`
`options["components"]["node.code_block"] = "components/markdown/code_block";`
`String html = markdown_to_html(file_get_contents("guide.md"), options);`
`print(html);`
:SupportedSyntax
- headings with `#` or setext underlines
- paragraphs
- ordered and unordered lists
- task lists
- blockquotes
- fenced code blocks
- horizontal rules
- tables
- inline emphasis, strong, strikethrough, code spans
- links, images, and bare `http://` / `https://` URLs
- `:::name ... :::` directive blocks
:Options
`options["gfm"]`
Defaults to true.
Turns on GitHub-style extras such as tables, task lists, autolinks, and strikethrough.
`options["allow_html"]`
Defaults to false.
When true, raw HTML blocks and inline tags may pass through as `raw_html` nodes instead of being escaped as plain text.
`options["components"]`
Declares renderer extension points using normal UCE components.
Exact directive hooks:
`options["components"][":::warning"] = "components/markdown/warning"`
This hook is selected for `:::warning ... :::` blocks.
Generic node hooks:
`options["components"]["node.code_block"] = "components/markdown/code_block"`
`options["components"]["node.table"] = "components/markdown/table"`
`options["components"]["node.link"] = "components/markdown/link"`
`options["components"]["node.directive"] = "components/markdown/directive"`
If both an exact directive hook and a generic `node.directive` hook exist, the exact directive hook wins.
:ComponentProps
When a markdown hook component is called, its props arrive in `context.call`.
Useful fields include:
`context.call["hook"]` : matched hook key such as `:::warning` or `node.code_block`
`context.call["target"]` : resolved component target name
`context.call["default_html"]` : renderer output without the hook
`context.call["children_html"]` : already-rendered child HTML
`context.call["node"]` : full AST node
`context.call["type"]` : node type
`context.call["name"]` : directive name when applicable
`context.call["argument"]` : directive remainder after the name
`context.call["text"]` : source text for nodes such as `code_block`
`context.call["lang"]` : fenced code language
`context.call["href"]` / `context.call["src"]` / `context.call["title"]`
`context.call["options"]` : full markdown options tree
This lets a component either replace the HTML completely or wrap `default_html` / `children_html`.
:DirectiveSchema
Directive blocks use this form:
`:::warning title="Heads up"`
`Body markdown here`
`:::`
The parser stores:
`node["name"] = "warning"`
`node["argument"] = ...` for bare trailing text
`node["attrs"] = ...` for parsed `key=value` pairs such as `title="Heads up"`
This makes directive components a good fit for alerts, callouts, cards, embeds, and any richer page-level markdown extension.
:see
markdown_to_ast
component
render_component
json_decode
String

Some files were not shown because too many files have changed in this diff Show More