Custom Query Programming
NEW QUERY defines a custom multi-word command; QUERY calls it. It works the way operations do — define once, call by name — except the name is a sequence of words, and some of those words can be values supplied at call time.
Shape
A query is a list of steps. STEP declares one; NEXT moves to the following one; END closes the sequence.
NEW QUERY AS OPEN
STEP "Tell"
NEXT
STEP "the"
NEXT
STEP "time"
NEW DATE AND TIME SET ?now
AFTER EMIT ?now
END
CLOSE
QUERY Tell the time
QUERY is mandatory. A custom query is only ever reached through the QUERY verb. Writing Tell the time on its own is an unrecognized verb and a FATAL error, exactly as any other unknown statement is — the runtime does not guess that a bare statement might be a custom command.Any step may carry OcaltQL code, which runs when that step is matched. A step with no code contributes only its word.
Literal Words
NEW QUERY AS OPEN
STEP "deploy"
NEXT
STEP "now"
EMIT "deploying"
END
CLOSE
AFTER QUERY deploy now
SKIPPABLE
A step marked SKIPPABLE may be omitted at call time. Its code does not run when it is skipped.
NEW QUERY AS OPEN
STEP "Tell"
NEXT
STEP "the" SKIPPABLE
NEXT
STEP "time"
NEW DATE AND TIME SET ?now
AFTER EMIT ?now
END
CLOSE
AFTER QUERY Tell the time
AFTER QUERY Tell time
(* Both call the same query *)
A Word From a Variable
Placing a variable before STEP makes that variable’s value the step’s word. This is resolved at registration — it fixes the word, it does not accept a value at call time.
STRING "release" SET ?verb
AFTER NEW QUERY AS OPEN
STEP "start"
NEXT ?verb
STEP
END
CLOSE
AFTER QUERY start release
(* The second word is fixed as "release" — whatever ?verb held when
the query was defined *)
Accepting Values
STEP VALUE accepts whatever is written in that position at call time. Inside that step’s code, the global !VALUE holds what was supplied.
NEW QUERY AS OPEN
STEP "greet"
NEXT
STEP VALUE
EMIT "hello " & !VALUE
END
CLOSE
AFTER QUERY greet "Bongani"
AFTER STRING "Kea" SET ?name
AFTER QUERY greet ?name
VALUE declares; !VALUE reads. STEP VALUE is the declaration — it says this step accepts something rather than matching a fixed word. Inside that step’s code the supplied value is the global !VALUE, like any other global."...", '...' or `...`. A value step is not skippable; pass an empty string or an empty variable when there is nothing to give.Typed and Constrained Values
| Form | Accepts |
|---|---|
STEP VALUE | Anything — a variable or a string |
STEP VALUE NUMBER | Numbers only |
STEP VALUE NUMBER MIN 2 MAX 99 | A number within that range |
STEP VALUE STRING MIN 5 MAX 10 | A string of that length |
STEP VALUE EXCEPT "," AND "*" | Any string containing none of the exceptions |
NEW QUERY AS OPEN
STEP "add"
NEXT
STEP "one" "to" SKIPPABLE
NEXT
STEP VALUE NUMBER MIN 2 MAX 99
CALCULATE !VALUE + 1 SET ?answer
AFTER EMIT ?answer
END
CLOSE
AFTER QUERY add one to 41
(* Emits 42 *)
NEW QUERY AS OPEN
STEP "user"
NEXT
STEP VALUE STRING MIN 5 MAX 10
EMIT "username: " & !VALUE
END
CLOSE
AFTER NEW QUERY AS OPEN
STEP "tag"
NEXT
STEP VALUE EXCEPT "," AND "*"
EMIT "tag: " & !VALUE
END
CLOSE
Alternatives
Two forms. OR STEP gives a step more than one acceptable word. FALLBACK gives the whole position an alternative step to try when the preceding one does not match.
NEW QUERY AS OPEN
STEP "show" OR STEP "display"
NEXT
STEP "status"
EMIT "all systems go"
END
CLOSE
AFTER QUERY show status
AFTER QUERY display status
NEW QUERY AS OPEN
STEP "set"
NEXT
STEP "optionA"
EMIT "took option A"
FALLBACK
STEP "optionB"
EMIT "took option B"
END
CLOSE
AFTER QUERY set optionB
(* Emits: took option B *)
CASE and SEPARATOR
Matching is case-insensitive and space-separated by default. Both are set on the query itself, and apply to every step in it.
NEW QUERY CASE "sensitive" SEPARATOR "." AS OPEN
STEP "Tell"
NEXT
STEP "the"
NEXT
STEP "time"
NEW DATE AND TIME SET ?now
AFTER EMIT ?now
END
CLOSE
AFTER QUERY Tell.the.time
STEP "second last word" is one step when the separator is ".".Persistent Queries
NEW PERSISTENT QUERY registers across executions, exactly as persistent operations do. Define it once; call it from any later script.
NEW PERSISTENT QUERY AS OPEN
STEP "deploy"
NEXT
STEP VALUE
EMIT "deploying " & !VALUE
END
CLOSE
(* ...any later script... *)
QUERY deploy "api"
When a Call Fails
| Situation | Result |
|---|---|
| A statement matches no verb | FATAL — Unrecognized verb. No custom-query lookup is attempted; only QUERY reaches a custom query. |
QUERY with a first word matching no registered query | E7002 — catchable |
| A later step does not match, or a value fails its constraint | E7002 — catchable. Steps already matched have run, and their output stands. |
NEW QUERY AS OPEN
STEP "Tell"
NEXT
STEP "the"
EMIT "the..."
END
CLOSE
AFTER QUERY Tell the zzz OR CATCH ERROR SET ?e
AFTER EMIT "|" & ?e("code")
(* Emits: the...|E7002 *)
Full Verb Reference
| Verb | Description |
|---|---|
NEW QUERY [CASE "sensitive"] [SEPARATOR "x"] AS OPEN ... END CLOSE | Define a custom multi-word command |
NEW PERSISTENT QUERY ... AS OPEN ... END CLOSE | Same, registered across executions |
STEP "word" [SKIPPABLE] | A literal word, optionally omittable |
NEXT ?var then STEP | The variable’s value at registration becomes the word |
STEP VALUE [NUMBER|STRING] [MIN n MAX n] [EXCEPT "a" AND "b"] | Accept a value at call time, optionally typed and constrained. !VALUE holds it inside the step. |
STEP "a" OR STEP "b" | Either word matches this step |
NEXT / FALLBACK / END | Advance a step, offer an alternative step, close the sequence |
QUERY word word ... | Call a custom query. Mandatory — there is no bare form. |