Skip to main content

Online edition for BLOGE 0.9.8-RC1 · facts verified 2026-09-15 · 中文

Appendix A — Built-in Functions

Every guard, constraint, and expression in bloge DSL has the same toolbox of built-in functions available. This appendix is the single reference for that toolbox: every name, every signature, every gotcha. Bookmark this page once you start writing real DSL.

When You Need This Reference

QuestionSection
What does coalesce / ifNull / isNull do?Null & Default Handling
Can I do regex inside a when: guard?String & Regex
How do I sum or average a list field?Math & Aggregation
How do I read a value out of a nested map?Map & Object
How do I render a timestamp or compute a duration?Date & Time
How do I sign or hash a payload?Optional Crypto Modules
How do I check whether a function call is allowed at compile time?Purity & Compile-Time Evaluation

Find a Function by Task

I need to…Start with
clean, split, match, or format textString functions
total, compare, round, or aggregate numbersMath and aggregation
filter, map, flatten, or inspect a listCollection functions
read nested object or map fields safelyMap/object plus null handling
convert a value before schema validationType conversion
calculate a deadline or durationDate/time functions
create a digest or signatureOptional crypto module

Chapter 5 (Branches that Decide) introduces these functions inside when: guards. Chapter 7 (Designing Good Operators) uses them inside operator constraints and usageExample. Chapter 15 (State Machines) uses them inside transition guards. Wherever you see an expression in bloge DSL, this list is what you can call.

Function Call Syntax

All functions use standard call syntax:

when: concat("Hello, ", ctx.name) == "Hello, Alice"
when: contains(split(ctx.tags, ","), "premium")
when: padLeft(toString(ctx.id), 10, "0")

bloge does not use a Unix-style pipe operator (|) for function composition. The | token is reserved by the lexer for the logical OR operator (||). Compose functions by nesting calls.

Null Handling Convention

Core built-ins are null-safe by default. Passing null either:

  • returns null (safe-nav semantics), or
  • returns a sensible default — size(null) → 0, isEmpty(null) → true, concat(null, "x") → "x", etc.

You can rely on this convention to write fewer defensive guards. The optional crypto module is the one exception — see its section below.

Purity & Compile-Time Evaluation

Most functions are pure — given the same input they always produce the same output and have no side effects. The DSL compiler is allowed to fold pure-function calls at compile time when arguments are constant.

A small number of functions are impure and may not be folded:

  • now() — current timestamp from the engine's time source
  • today() — current date from the engine's time source
  • uuid() — random UUID
  • secret(name) — secret lookup (crypto module)

In strict compile-time-only contexts (constants, schema constraints) the compiler will reject impure calls. Use them inside runtime guards instead.


1. String Functions (17)

FunctionSignatureReturnsDescription
concatconcat(arg1, arg2, …)StringConcatenates all arguments as strings. null arguments are treated as empty.
substringsubstring(str, start [, end])StringSubstring from start (inclusive) to end (exclusive); clamps to bounds.
uppercase / upperuppercase(str)StringUpper-case the string.
lowercase / lowerlowercase(str)StringLower-case the string.
trimtrim(str)StringStrip leading and trailing whitespace.
replacereplace(str, oldStr, newStr)StringReplace every literal occurrence of oldStr.
startsWithstartsWith(str, prefix)BooleanPrefix test; false on null.
endsWithendsWith(str, suffix)BooleanSuffix test; false on null.
indexOfindexOf(str, target)NumberIndex of first occurrence, or -1.
length / lenlength(str)NumberString length. Also works on lists and maps. 0 on null.
matchesmatches(str, regex)BooleanRegex match. Returns false on null or invalid pattern (no exception).
replaceAllreplaceAll(str, regex, replacement)StringRegex replace-all. Returns original on null or bad pattern.
splitsplit(str, delimiter)ListSplit by literal delimiter (not regex). Empty list on null.
joinjoin(list, delimiter)StringJoin list elements with delimiter. Null elements become empty strings.
padLeftpadLeft(str, length, padChar)StringLeft-pad to length using a single pad character.
padRightpadRight(str, length, padChar)StringRight-pad to length using a single pad character.
when: startsWith(ctx.email, "admin@") and contains(ctx.email, "@")
when: matches(ctx.phone, "^\\+?[0-9 ]{6,}$")
when: padLeft(toString(ctx.orderId), 8, "0") == "00012345"

2. Math & Aggregation (10)

FunctionSignatureReturnsDescription
absabs(n)NumberAbsolute value.
minmin(a, b)NumberMinimum of two numbers.
maxmax(a, b)NumberMaximum of two numbers.
roundround(n)NumberRound to nearest integer (Math.round).
ceilceil(n)NumberRound up to nearest integer.
floorfloor(n)NumberRound down to nearest integer.
clampclamp(n, min, max)NumberConstrain n to [min, max].
powpow(base, exponent)Numberbase ^ exponent.
sumsum(list)NumberSum of numeric elements. Null elements skipped. Empty list → 0.
avgavg(list)NumberAverage of numeric elements. Empty/null → null.
when: sum(ctx.items.*.price) > 1000
when: clamp(ctx.retries, 0, 5) == ctx.retries

3. Collection Functions (13)

FunctionSignatureReturnsDescription
sizesize(collection)NumberSize of list, map, or string. 0 on null.
containscontains(collection, item)BooleanMembership. Lists → exact match; strings → substring; maps → key lookup.
firstfirst(list)anyFirst element, or null.
lastlast(list)anyLast element, or null.
isEmptyisEmpty(collection)BooleanTrue if empty or null.
distinctdistinct(list)ListRemove duplicates, preserve order.
flattenflatten(listOfLists)ListFlatten one level. Non-list elements pass through.
sortsort(list)ListSort using natural order (falls back to toString); nulls first.
taketake(list, n)ListFirst n elements.
dropdrop(list, n)ListSkip first n elements.
reversereverse(list)ListReverse list order.
anyany(list, value)BooleanTrue if any element equals value.
allall(list, value)BooleanTrue if every element equals value. Empty list → true.
when: contains(ctx.tags, "premium") and size(ctx.items) > 0
when: any(ctx.errors, "TIMEOUT")
when: all(distinct(ctx.statuses), "OK")

4. Map & Object (5)

FunctionSignatureReturnsDescription
keyskeys(map)ListAll keys as a list.
valuesvalues(map)ListAll values as a list.
entriesentries(map)ListList of {key, value} maps.
mergemerge(map1, map2)MapShallow merge; map2 overwrites map1.
hashas(map, key)BooleanWhether the map contains the key.
when: has(ctx.headers, "X-Trace-Id")
when: size(keys(ctx.attributes)) > 3

5. Null & Default Handling (3)

FunctionSignatureReturnsDescription
coalescecoalesce(v1, v2, …)anyFirst non-null argument, or null if all are null.
isNullisNull(value)BooleanValue is null.
isNotNullisNotNull(value)BooleanValue is not null.

coalesce is the workhorse for default values. ifNull (see Advanced) is a two-argument variant that reads more naturally for a single fallback.

when: isNotNull(ctx.userId)
let region = coalesce(ctx.region, ctx.country, "GLOBAL")

6. Type Conversion (5)

FunctionSignatureReturnsDescription
toStringtoString(value)StringConvert any value to its string form.
toNumbertoNumber(value)NumberParse number from string, or return the numeric value. Invalid strings coerce to 0.
toBooleantoBoolean(value)BooleanParse "true" / "false" or pass through boolean.
toInttoInt(value)NumberConvert to integer; truncates decimals.
typeOftypeOf(value)String"String", "Number", "Boolean", "List", "Map", "Object", or "Null".
when: toNumber(ctx.amountStr) > 100
when: typeOf(ctx.payload) == "Map"

7. Date/Time (6)

All dates flow as ISO-8601 strings (yyyy-MM-ddTHH:mm:ssZ). Use these helpers to format, parse, add, and diff them.

FunctionSignatureReturnsPure?Description
nownow()StringCurrent timestamp from GraphEngine.currentTimeSource().
todaytoday()StringCurrent date yyyy-MM-dd (UTC).
formatDateformatDate(isoStr, pattern)StringFormat ISO instant with a DateTimeFormatter pattern (e.g. "yyyy-MM-dd HH:mm").
parseDateparseDate(str, pattern)StringParse with a pattern; returns an ISO-8601 instant.
addDurationaddDuration(isoStr, durationStr)StringAdd a duration. Accepts "2h", "30m", "1d", "500ms", or ISO-8601 form "PT2H".
diffDurationdiffDuration(iso1, iso2, unit)NumberDistance between two instants. unit: "s"/"seconds", "m"/"minutes", "h"/"hours", "d"/"days".
when: diffDuration(ctx.createdAt, now(), "h") > 24
let expiresAt = addDuration(now(), "30m")

Determinism tip. Inside replay-sensitive contexts (durable sessions, deterministic tests) prefer parseDate/addDuration driven by stored timestamps over now() / today().


8. Utility / ID (2)

FunctionSignatureReturnsPure?Description
uuiduuid()StringRandom UUID v4.
formatformat(template, arg1, arg2, …)StringJava String.format style placeholders (%s, %d, …). Returns template on format error.
let traceId = uuid()
let message = format("Order %s failed after %d retries", ctx.orderId, ctx.retries)

9. Advanced Utility (8)

FunctionSignatureReturnsDescription
regexExtractregexExtract(str, pattern [, group])StringFirst match for a regex group (default 1); null if no match.
regexExtractAllregexExtractAll(str, pattern)ListAll non-overlapping matches.
getFieldgetField(obj, fieldName)anyRead a field from a map or bean (reflection); null-safe.
setFieldsetField(obj, fieldName, value)MapReturn a shallow copy with the field updated (immutable semantics).
templatetemplate(str, bindings)StringReplace ${key} placeholders using a map of bindings.
rangerange(start, end)ListInteger sequence [start, end).
mapOfmapOf(k1, v1, k2, v2, …)MapBuild a map from alternating key/value arguments.
listOflistOf(e1, e2, …)ListBuild a list from arguments.
ifNullifNull(value, default)anyvalue if non-null, otherwise default.
let host = regexExtract(ctx.url, "https?://([^/]+)/")
let updated = setField(ctx.user, "lastSeenAt", now())
let greeting = template("Hello, ${name}!", mapOf("name", ctx.name))

10. JSON Functions (2)

JSON helpers are registered when a JsonCodec is provided to the DSL compiler. They are part of BuiltInFunctions.registerAll(registry, jsonCodec).

FunctionSignatureReturnsDescription
toJsontoJson(obj)StringSerialize to JSON via the configured codec.
fromJsonfromJson(str)anyDeserialize JSON to Map / List / primitive.
let payload = toJson(mapOf("orderId", ctx.orderId, "total", ctx.total))
let parsed = fromJson(ctx.responseBody)

If no JsonCodec is configured, calls to these names will fail at DSL compilation with an unknown-function error.


Optional Modules (bloge-functions-crypto)

The bloge-functions-crypto module is loaded automatically via Java ServiceLoader when its JAR is on the classpath. It exposes three families of functions. Crypto functions that resolve secrets require a SecretProvider to be configured on the engine.

Crypto (5)

FunctionSignatureReturnsPure?Description
hmacSha256hmacSha256(data, keyRef)StringHMAC-SHA256 hex digest. keyRef is resolved via SecretProvider.
hmacSha512hmacSha512(data, keyRef)StringHMAC-SHA512 hex digest.
aesEncryptaesEncrypt(plaintext, keyRef [, ivRef])StringAES-256-CBC; base64 output. Random IV when not supplied.
aesDecryptaesDecrypt(ciphertext, keyRef [, ivRef])StringAES-256-CBC; expects base64 input.
secretsecret(name)StringResolve a secret by name from the SecretProvider.

Hash (4)

FunctionSignatureReturnsDescription
md5md5(str)StringMD5 hex digest.
sha1sha1(str)StringSHA-1 hex digest.
sha256sha256(str)StringSHA-256 hex digest.
sha512sha512(str)StringSHA-512 hex digest.

Encoding (6)

FunctionSignatureReturnsDescription
base64Encodebase64Encode(str)StringBase64 encode UTF-8 string.
base64Decodebase64Decode(str)StringBase64 decode; null on invalid input.
hexEncodehexEncode(str)StringHex encode UTF-8 string.
hexDecodehexDecode(str)StringHex decode; null on invalid input.
urlEncodeurlEncode(str)StringURL encode (UTF-8).
urlDecodeurlDecode(str)StringURL decode (UTF-8); null on invalid input.
let signature = hmacSha256(ctx.requestBody, "webhook-secret")
let fingerprint = sha256(ctx.userId)
let safeQuery = urlEncode(ctx.search)

Crypto module exception. Unlike core functions, crypto/hash functions may throw on invalid input (bad keys, malformed ciphertext). Validate inputs at the boundary or wrap calls inside operators that handle the failure mode you want.


Common Mistakes

  • Pipe operator. value | uppercase is not valid bloge DSL. Write uppercase(value). The lexer reads | as the start of ||.
  • Regex split. split(s, ",") splits on the literal string ",", not a regex. Use replaceAll first if you need pattern-based splitting.
  • Date math without ISO strings. addDuration("2024-01-01", "1d") will fail — the first argument must be an ISO-8601 instant. Use addDuration(parseDate("2024-01-01", "yyyy-MM-dd"), "1d") if you have a bare date.
  • Mutating maps. setField does not mutate in place; it returns a copy. Bind the result: let updated = setField(ctx.user, "name", "Alice").
  • Impure calls in constants. now() and uuid() are rejected in compile-time-only positions (constant folding, schema constants). Move them into runtime guards or operator outputs.
  • Crypto without SecretProvider. hmacSha256 / aesEncrypt will fail if SecretProvider is not configured on the engine. Wire it in your Spring or manual bootstrap (see Chapter 20).
  • toBoolean on numbers. toBoolean(1) returns null, not true. Only "true" / "false" strings and actual booleans are accepted.

Relationship to Main Chapters

  • Chapter 5 — Branches that Decide. Where when: guards are introduced — the primary place you compose these functions.
  • Chapter 7 — Designing Good Operators. Uses constraints and usageExample expressions; the same function set applies.
  • Chapter 14 — Multi-Turn Sessions and Chapter 15 — State Machines. Use guard expressions for session phase transitions and state-machine transitions; both compile through the same ExpressionEvaluator.
  • Chapter 9 — Tooling Workflow. The operator-metadata.json exporter surfaces these function names to IDE tooling so completion and validation match what the compiler will accept.
  • Chapter 20 — Spring and Production Wiring. Where JsonCodec and SecretProvider are configured, enabling the optional JSON and crypto helpers above.

Verification. The 72-function core surface matches BuiltInFunctionsTest.registerAll_populatesExpectedNumberOfEntries() in bloge-core. Add the two JSON helpers and the eleven crypto/hash/encoding helpers to reach the 85 functions documented here.