Skip to content

Pseudocode DSL

The pseudo-code DSL is a compact generation notation for executable sigMAX handlers.

It is not a general-purpose programming language and it is not a runtime interpreter. It is a controlled bridge between contracts, generated C subset code, WASM modules and the runtime primitives exposed by runtime/C/sigma.h.

The current runtime repository makes this boundary concrete through runtime/functions.toon, runtime/C/sigma.h, generated storage declarations and component contracts. Those files define what the DSL may express and what it must never invent.

The DSL describes handler behavior at the level that matters for deterministic generation:

DSL concernRuntime counterpart
Read route/body inputinput_get_param_string, input_read_object
Validate and normalize valuesbounded string, conversion, URL, regex and math helpers
Call storage or servicesprimitive_call_typed with a declared target such as storage.invoice.get
Build public outputresponse status plus ObjectIR fields
Raise handled errorsstatus, structured error primitive, then return -1
Stay inside policycapabilities, bindings, generated storage and agreements

This keeps the generated handler small enough to review while preserving the real execution constraints of the WASM runtime.

The runtime repository validates a contract-first flow where generated business handlers call only sigMAX primitives:

StepResponsibility
ContractDeclares features, routes, storage intent, runtime primitives and required binary behavior.
Pseudocode DSLCaptures the handler algorithm using a constrained vocabulary.
C subsetMaterializes the algorithm with sigma.h helpers and imports.
WASMRuns inside the sigMAX runtime without direct host access.
AgreementRecords generated artifacts, storage operations, bindings and validation evidence.

The DSL should therefore stay close to contract language, but every operation must have a deterministic lowering path.

The runtime primitive catalog defines the safety rules that generated pseudo-code must preserve.

  • Use only declared sigMAX primitives.
  • Include only runtime/sigma.h from generated C handlers.
  • Do not call Linux functions directly.
  • Do not use libc malloc or free; use sx_malloc and sx_free only when stack buffers are not enough.
  • Do not use direct SQL, raw sockets, filesystem access, system, exec or process APIs.
  • Do not build public HTTP responses as raw JSON strings.
  • Build responses through response and ObjectIR primitives.
  • Initialize fixed-size structs with sx_memzero.
  • Validate inputs before storage, HTTP or service calls.
  • Return 0 after a successful response.
  • For handled errors, set the status, emit the error and return -1.

Generated handlers follow the same convention as the C/WASM primitive surface.

ResultMeaning
>= 0Success, bytes written, boolean success marker or handle depending on the primitive.
< 0sigMAX error code.
-1Handled business/API error after the response status and structured error have been emitted.
0Successful handler completion after the response has been generated.

This convention is intentionally simple so validation can detect mismatched success/error paths.

Generated pseudo-code is sigmax.pseudo/v0.1 text. It is not JSON, YAML, Markdown or C. A generated function starts with compact metadata lines: the first token is always the two-character key #S, followed by the full DSL schema version.

PrefixRequiredMeaning
#SyesSchema/version line. The first line is #S sigmax.pseudo/v0.1.
#MyesBinary or route module name.
#FyesExported handler function and return type, such as handle_get_invoice -> i32.
#CoptionalContract path used to generate the pseudo-code.
#DoptionalShort description.
#VoptionalAdditional generated artifact version.

After metadata, executable operations use two-uppercase-letter DSL instructions. Inline @... aliases are reserved for explicit pseudo functions such as @string.len(...); raw C calls such as sx_strlen(...) stay forbidden in generated pseudo-code.

The parser accepts the following V1 instruction shape. The generator should emit these instructions, then deterministic tooling lowers them to the C subset and runtime primitives.

DSLEquivalent loweringTypical use
VAC variable declarationDeclare binary-contract variables or scalar temporaries.
INsx_memzero or scalar zeroingInitialize declared values before use.
IPinput_get_param_stringRead a path parameter into a bounded field.
IQinput_get_param_stringRead a query parameter into a bounded field.
IHinput_get_param_stringRead an allowed header into a bounded field.
IBinput_read_objectRead a typed request body.
OEstatus plus error_validation or error_raiseAttach handled error behavior to the previous failable instruction.
VRstring presence check plus validation errorRequire a non-empty string field.
VNnumeric minimum check plus validation errorRequire a numeric field to be at least a minimum value.
LEscalar assignmentCompute into a declared scalar temporary.
CPbounded copy loopCopy a fixed-size array field.
ASfield assignment or bounded copyAssign a scalar or structured field.
CAprimitive_call_typedCall a declared storage or service binding.
HGsx_http_getCall a capability-controlled logical HTTP target.
SHsx_sha256_hexHash bounded data as SHA-256 hex.
B6sx_base64_encodeBase64-encode bounded data.
BDsx_base64_decodeBase64-decode bounded data.
RMsx_regex_matchMatch bounded input with a bounded regex.
RRsx_regex_removeRemove regex matches from bounded input.
JSsx_json_get_stringExtract a string field from bounded JSON.
JIsx_json_get_i64Extract an int64 field from bounded JSON.
JFsx_json_get_f64Extract a float64 field from bounded JSON.
JBsx_json_get_boolExtract a boolean field from bounded JSON.
TNsx_now_unix_msRead current time when allowed.
TFsx_format_unix_ms_iso8601Format a timestamp as UTC ISO-8601.
UEsx_url_encodePercent-encode a URL component.
UDsx_url_decodeDecode a percent-encoded URL component.
QEsx_query_param_encodeEncode one query key/value pair.
IFC if blockBranch on a safe comparison.
ELC else blockOpen the alternative branch.
ENblock closeClose an IF or EL block.
STresponse_statusSet the public HTTP status.
EVerror_validationEmit a validation error.
ERerror_raiseEmit a structured runtime/API error.
OBobj_beginStart ObjectIR output.
OIobj_field_i64Emit an integer ObjectIR field.
OSobj_field_stringEmit a string ObjectIR field.
OXobj_endClose ObjectIR output.
REC returnReturn 0 or -1.

Recognized but not implemented for V1 emission: CO, VX, VG, VL, VM, CV, FR, OF, OO, ON. Reserved and forbidden in V1: WH, GO, SW, BR, CT.

The example below is representative pseudo-code for a generated GET /invoices/{id} handler. It is compact on purpose: every two-letter instruction has a deterministic lowering path.

#S sigmax.pseudo/v0.1
#M get_invoice
#F handle_get_invoice -> i32
#C contracts/binary/get_invoice.contract.yaml
VA req:GetInvoiceRequest invoice:Invoice
IN req invoice
IP id -> req.id max 32
OE 400 EV id "Missing invoice id"
CA storage.invoice.get req -> invoice
OE 503 ER STORAGE_UNAVAILABLE "Storage service unavailable"
IF invoice.found == 0
ST 404
ER INVOICE_NOT_FOUND "Invoice not found"
RE -1
EN
ST 200
OB
OI invoice_id invoice.invoice_id
OI total_cents invoice.total_cents
OX
RE 0

This is not executable source by itself. The generator lowers it to C subset code using input_get_param_string, primitive_call_typed, response_status, ObjectIR primitives and the typed c_repr structures recorded by the contracts and agreements.

The generated C shape below is representative of the deterministic lowering. Exact struct definitions and helper signatures come from the binary contract, generated c_repr files and runtime/C/sigma.h.

#include "runtime/sigma.h"
typedef struct {
char id[32];
} GetInvoiceRequest;
typedef struct {
int32_t found;
int64_t invoice_id;
int64_t total_cents;
} Invoice;
int32_t handle_get_invoice(void) {
GetInvoiceRequest req;
Invoice invoice;
int32_t rc;
sx_memzero(&req, sizeof(req));
sx_memzero(&invoice, sizeof(invoice));
rc = input_get_param_string("id", req.id, sizeof(req.id));
if (rc < 0 || sx_is_blank(req.id, sizeof(req.id)) != 0) {
response_status(400);
error_validation("id", "Missing invoice id");
return -1;
}
rc = primitive_call_typed(
"storage.invoice.get",
&req,
sizeof(req),
&invoice,
sizeof(invoice)
);
if (rc < 0) {
response_status(503);
error_raise("STORAGE_UNAVAILABLE", "Storage service unavailable");
return -1;
}
if (invoice.found == 0) {
response_status(404);
error_raise("INVOICE_NOT_FOUND", "Invoice not found");
return -1;
}
response_status(200);
obj_begin();
obj_field_i64("invoice_id", invoice.invoice_id);
obj_field_i64("total_cents", invoice.total_cents);
obj_end();
return 0;
}

runtime/functions.toon also records compact @... aliases for primitive references. They are catalog vocabulary for generation and review; V1 executable pseudo-code should still use the two-letter instructions above, except for accepted inline pseudo functions such as @string.len(...).

AliasLowers toAliasLowers to
@zerosx_memzero@malsx_malloc
@freesx_free@gparinput_get_param_string
@bodyinput_read_object@pcallprimitive_call_typed
@statresponse_status@verrerror_validation
@errerror_raise@obegobj_begin
@oi64obj_field_i64@ostrobj_field_string
@oendobj_end@string.lensx_strlen
@stnlnsx_strnlen@steqsx_streq
@stneqsx_strneq@emptysx_is_empty
@blanksx_is_blank@copysx_copy
@cpynsx_copy_n@trimsx_trim
@lowersx_to_lower@uppersx_to_upper
@pi64sx_parse_i64@i64ssx_i64_to_string
@add64sx_i64_add_checked@mul64sx_i64_mul_checked
@rmatsx_regex_match@rremsx_regex_remove
@hgetsx_http_get@hpostsx_http_post_json
@hreqsx_http_request_json_ext@jstrsx_json_get_string
@ji64sx_json_get_i64@jf64sx_json_get_f64
@jboolsx_json_get_bool@shasx_sha256_hex
@b64esx_base64_encode@b64dsx_base64_decode
@nowsx_now_unix_ms@fmtmssx_format_unix_ms_iso8601
@urlensx_url_encode@urldcsx_url_decode
@qencsx_query_param_encode@jbinisx_json_builder_init
@jbbosx_json_builder_begin_object@jbssx_json_builder_field_string
@jbi64sx_json_builder_field_i64@jbbsx_json_builder_field_bool
@jbeosx_json_builder_end_object@jblensx_json_builder_len
@hmacsx_hmac_sha256_hex@uuidsx_uuid_v4
@randsx_random_bytes@kvstrsx_kv_find_string
@kvi64sx_kv_find_i64

The runtime catalog groups primitives by whether they are pure helpers or host-controlled imports.

FamilyKindDSL meaning
Runtimecorememory zeroing, bounded allocation and shared return codes.
Inputhostread route parameters, headers, typed bodies or raw validated JSON.
Response and ObjectIRhostproduce public HTTP output in a structured way.
Storage and invocationhostcall a declared binding such as storage.invoice.create.
String, convert, math, URL, KVpuredeterministic local helpers with bounded buffers.
Regex, JSON, HTTP, crypto, timehostruntime-controlled helpers with capability and size checks.
JSON builderpurebuild small internal JSON payloads for allowed calls.
Secret and randomhostuse host-managed secrets or randomness without exposing raw host state.

Pure helpers can be used without capabilities. Host primitives require the capability and import declared by the contract or agreement.

The runtime repository shows the intended storage model with generated/storage.yaml.

The WASM handler does not know PostgreSQL exists. It calls primitive_call_typed with a logical operation name such as storage.invoice.get or storage.invoice.create. The runtime resolves that target through route bindings, invokes the storage service, converts between JSON and c_repr, and returns a typed output buffer.

LayerExample
DSLcall declared storage operation
C subsetprimitive_call_typed("storage.invoice.get", ...)
Runtime bindingroute binding and capability check
Storage declarationgenerated/storage.yaml operation
Storage servicegeneric select_one or insert_one interpreter
Public handlermaps storage result to ObjectIR and HTTP status

This is why direct SQL is forbidden in generated handlers. SQL belongs to generated storage declarations and migration/init files, not to WASM business code.

The DSL must make capability use explicit.

  • HTTP targets are logical names, never arbitrary URLs.
  • Unknown HTTP targets, methods, paths and headers are denied.
  • Random and current time are denied unless the route declares the capability.
  • Secret helpers receive a logical secret_ref; they do not expose raw secret bytes.
  • Regex and JSON helpers are runtime-controlled and bounded.
  • Every host import used by generated code must be allowed by the binary contract.
Capability areaExample primitive
Inputinput.body.read, input.params.read
Responseresponse.write, objectir.write
Storage/invocationprimitive.call
HTTPhttp.get, http.post_json, http.request_json_ext
JSONjson.read
Regexregex.match, regex.remove
Cryptocrypto.hash, crypto.base64
Time/random/secrettime.now, random.uuid, secret.hmac_sha256

The catalog records concrete default limits for generated code and validation.

AreaDefault limit
Regex pattern256 bytes
Regex input/output8192 bytes
HTTP response body8192 bytes
JSON input8192 bytes
JSON path256 bytes
Random bytes1024 bytes
UUID output37 bytes including null terminator
HMAC SHA-256 hex output65 bytes including null terminator

Generated pseudo-code should treat those limits as design constraints, not implementation details.

A generated handler should normally follow a predictable sequence.

  1. Read typed input or route parameters.
  2. Validate required fields and parse primitive values.
  3. Use pure helpers for deterministic transformations.
  4. Call host primitives only when declared by the route and binary contract.
  5. Build public output through ObjectIR.
  6. Set status before success or handled error output.
  7. Return 0 on success, -1 after handled errors, or a negative primitive error when the runtime cannot continue.
Forbidden behaviorReason
Direct SQL in handler logicStorage behavior belongs to generated storage declarations.
Direct filesystem accessWASM modules must not access host files.
Raw sockets or arbitrary URLsNetworking must go through policy-controlled logical targets.
libc allocation and unsafe string functionsMemory and buffers must remain bounded and inspectable.
Raw JSON public responsesPublic output should use response/ObjectIR primitives.
Invented primitive namesThe runtime can only register known imports in the sigmax namespace.

When documenting or generating pseudo-code, prefer the smallest expression that still preserves:

  • the contract-level intent;
  • the exact primitive or helper family;
  • the required capability;
  • the typed input and output boundary;
  • the success and handled-error path;
  • the agreement evidence that will prove what was generated.

That keeps the DSL readable for humans and strict enough for deterministic generation.