- MQL syntax, nesting and numeric traps
- Null, empty and blank fields of an API payload
- Booleans and feature flags typed by hand
- Comments, line ends and quoting: a CSV export for Excel
- Variables: dynamic names, counters and their traps
- Variable scope: execute, call and include compared
- Discount rules engine with mql and eval
- Coded errors, nested try and a finally step: a payment pipeline
- Loops: continue, break, retry with backoff and parallel
- Atom lists: negotiate the language of a response
MQL syntax, nesting and numeric traps
The rule of every MQL statement (category, action, parameters), operator order decided only by nesting, n-ary operators, and the numeric traps: double rounding, division by zero, a non-number giving null, bare words and the difference between equal and ==.
#1. Syntax: category, action, then the parameters, separated by spaces; -> "[len]" (string length "MentDB"); #2. No operator precedence: the nesting decides. Price 12 + 8 x 3 then the reverse; -> "[a]" (+ 12 (* 8 3)); -> "[b]" (* (+ 12 8) 3); #3. Arithmetic operators take any number of operands; -> "[sum]" (+ 10 20 30 40); #4. Numbers are strings that look like numbers: double precision traps; -> "[float]" (+ 0.1 0.2); -> "[exact]" (bd+ 0.1 0.2); -> "[div0]" (/ 1 0); -> "[sci]" (* 1e3 2); -> "[nan]" (+ 1 "abc"); #5. A word without quotes is a string too, quotes are needed for spaces; -> "[word]" (concat Hello "-" World); #6. Compare texts with equal, numbers with ==; concat "string length: " [len] ", 12 + 8x3 = " [a] ", 12+8 x3 = " [b] ", sum of four: " [sum] [_n_] "+ 0.1 0.2 = " [float] ", bd+ 0.1 0.2 = " [exact] [_n_] "1/0 = " [div0] ", 1e3 x 2 = " [sci] ", 1 + abc = " [nan] ", is null: " (is null [nan]) [_n_] "bare words: " [word] [_n_] "equal 1.0 1 = " (equal "1.0" "1") ", == 1.0 1 = " (== "1.0" "1") ", type is_number 1e3 = " (type is_number "1e3") ", type is_integer 2.0 = " (type is_integer "2.0" 5);
string length: 6, 12 + 8x3 = 36, 12+8 x3 = 60, sum of four: 100 + 0.1 0.2 = 0.30000000000000004, bd+ 0.1 0.2 = 0.3 1/0 = Infinity, 1e3 x 2 = 2000, 1 + abc = , is null: 1 bare words: Hello-World equal 1.0 1 = 0, == 1.0 1 = 1, type is_number 1e3 = 1, type is_integer 2.0 = 0
- Use
bd+ bd- bd* bd/for money,bi*for big integers. + 1 "abc"returns null without error: validate inputs withtype is_numberfirst.
Null, empty and blank fields of an API payload
Classify the fields of a partner payload (missing value, JSON null, empty, spaces, the text null) with is null, is empty, is null or empty and string is_blank, and see how a null variable behaves.
#1. A customer payload from a partner API: missing, null, empty and blank fields; json load "tuto_lang_cust" "{\"name\": \"Ana Lopez\", \"phone\": null, \"company\": \"\", \"vat\": \" \", \"note\": \"null\"}"; -> "[report]" ""; -> "[fields]" "name,phone,company,vat,note"; for (-> "[i]" 1) (<= [i] (atom size [fields] ",")) (++ "[i]") { -> "[f]" (atom get [fields] [i] ","); -> "[v]" (json select "tuto_lang_cust" (concat "/" [f])); #2. Four different tests, four different answers; -> "[report]" (concat [report] (string rpad [f] "." 9) " is null " (is null [v]) ", is empty " (is empty [v]) ", is null or empty " (is null or empty [v]) ", string is_blank " (string is_blank [v]) [_n_]); }; json unload "tuto_lang_cust"; #3. A null variable exists, prints as nothing in concat, and is not the text null; -> "[fax]" null; concat [report] "fax exists: " (env exist var "[fax]") ", printed: [" [fax] "], is null: " (is null [fax]) ", text null is null: " (is null "null");
name..... is null 0, is empty 0, is null or empty 0, string is_blank 0 phone.... is null 1, is empty 0, is null or empty 1, string is_blank 1 company.. is null 0, is empty 1, is null or empty 1, string is_blank 1 vat...... is null 0, is empty 0, is null or empty 0, string is_blank 1 note..... is null 0, is empty 0, is null or empty 0, string is_blank 0 fax exists: 1, printed: [], is null: 1, text null is null: 0
is empty nullis 0 andis null or empty " "is 0: usestring is_blankfor required text fields.- The text "null" is not null: compare it with
equalif a partner sends it.
Booleans and feature flags typed by hand
Read feature flags from a config line: if is true only for 1 or true, so yes, TRUE, 2 or a variable holding the text true are false; normalize with type is_enum and see how and, or, xor and not treat non-boolean texts.
#1. Feature flags typed by hand in a config file; -> "[flags]" "dark_mode=1,beta=true,export=yes,chat=TRUE,audit=2,legacy=0"; -> "[out]" ""; for (-> "[i]" 1) (<= [i] (atom size [flags] ",")) (++ "[i]") { -> "[name]" (atom get (atom get [flags] [i] ",") 1 "="); -> "[raw]" (atom get (atom get [flags] [i] ",") 2 "="); #2. if sees true only for 1 and true, any other text is false; -> "[as_if]" (if ([raw]) {"ON"} {"off"}); #3. Normalize: accept a closed list of words, refuse the others; -> "[norm]" (case (type is_enum (string lower [raw]) "1,true,yes,on") {true} (type is_enum (string lower [raw]) "0,false,no,off") {false} {"invalid"} ); -> "[out]" (concat [out] [name] "=" [raw] ": raw if " [as_if] ", normalized " [norm] [_n_]); }; #4. Trap: the literal true is 1, but a variable holding the text true stays a text; -> "[txt]" "true"; #5. true and false are 1 and 0, and the boolean operators follow the same rule; concat [out] "true is " true ", false is " false ", not yes = " (not "yes") ", and 1 yes = " (and 1 "yes") ", or 0 true = " (or 0 "true") ", xor 1 0 = " (xor 1 0) [_n_] "if literal true: " (if (true) {"ON"} {"off"}) ", if variable holding true: " (if ([txt]) {"ON"} {"off"}) [_n_] "type is_bool Y Y N = " (type is_bool "Y" "Y" "N");
dark_mode=1: raw if ON, normalized 1 beta=true: raw if off, normalized 1 export=yes: raw if off, normalized 1 chat=TRUE: raw if off, normalized 1 audit=2: raw if off, normalized invalid legacy=0: raw if off, normalized 0 true is 1, false is 0, not yes = 0, and 1 yes = 0, or 0 true = 1, xor 1 0 = 1 if literal true: ON, if variable holding true: off type is_bool Y Y N = 1
- Store flags as 1/0 so
if ([flag])works without conversion. - Trap: the literal true is 1, but
-> "[b]" "true"stores the text true, which is false in if.
Comments, line ends and quoting: a CSV export for Excel
Build a CSV with CRLF line ends ([_r_][_n_]) and quotes doubled inside fields, make the invisible characters visible, and run the two comment traps: a lone string starting with # is a comment, and a comment stops at the first semicolon.
#1. Suppliers to export for Excel: CSV with CRLF line ends; -> "[rows]" "Le \"Bistrot\" SARL|Paris|1250.5,Acme Ltd|London|980"; -> "[csv]" (concat "name;city;amount" [_r_] [_n_]); for (-> "[i]" 1) (<= [i] (atom size [rows] ",")) (++ "[i]") { -> "[r]" (atom get [rows] [i] ","); #2. In a string only \" is an escape: CSV doubles the quotes of a field; -> "[name]" (string replace (atom get [r] 1 "|") "\"" "\"\""); -> "[csv]" (concat [csv] "\"" [name] "\";" (atom get [r] 2 "|") ";" (atom get [r] 3 "|") [_r_] [_n_]); }; #3. Make the invisible characters visible to check the file; -> "[shown]" (string replace (string replace [csv] [_r_] "<CR>") [_n_] (concat "<LF>" [_n_])); #4. Two comment traps, run with eval to show them; -> "[trap1]" (eval "\"# total\";"); -> "[trap2]" (try {eval "#see the doc; part two;";} {"error: the comment stopped at the first semicolon"} "[e]"); #5. A backslash alone is a normal character; concat [shown] "bytes: " (string length [csv]) ", lines: " (string regexp_count [csv] [_n_]) [_n_] "a lone string starting with # gives: " [trap1] [_n_] [trap2] [_n_] "the text \n has " (string length "\n") " characters";
name;city;amount<CR><LF> "Le ""Bistrot"" SARL";Paris;1250.5<CR><LF> "Acme Ltd";London;980<CR><LF> bytes: 77, lines: 3 a lone string starting with # gives: This is a comment ... error: the comment stopped at the first semicolon the text \n has 2 characters
- Only
\"is an escape in a string:\nis two characters, use [_n_] for a line feed. - To return a text that starts with #, build it:
concat "#" "total".
Variables: dynamic names, counters and their traps
Total the orders per country with variable names built at run time (env set var / env get var / env exist var), then the traps: concat_var appends to the variable, a quoted name is only a text, ++ on an unknown variable is an error, env del var removes one.
#1. Orders of the day: country and amount; -> "[orders]" "FR:120,DE:80,FR:45.5,IT:60,DE:20,FR:10"; -> "[codes]" ""; for (-> "[i]" 1) (<= [i] (atom size [orders] ",")) (++ "[i]") { -> "[c]" (atom get (atom get [orders] [i] ",") 1 ":"); -> "[amt]" (atom get (atom get [orders] [i] ",") 2 ":"); -> "[codes]" (concat [codes] (if (is empty [codes]) {""} {","}) [c]); #2. A variable name is a string, so it can be built: one total per country; -> "[var]" (concat "[total_" [c] "]"); if (not (env exist var [var])) {env set var [var] 0;}; env set var [var] (+ (env get var [var]) [amt]); }; #3. Read them back by name; -> "[countries]" (atom distinct [codes] ","); -> "[report]" ""; for (-> "[i]" 1) (<= [i] (atom size [countries] ",")) (++ "[i]") { -> "[c]" (atom get [countries] [i] ","); -> "[report]" (concat [report] [c] "=" (env get var (concat "[total_" [c] "]")) " "); }; #4. Traps: concat_var appends to the variable, a name in quotes is only a text; -> "[path]" "/api"; concat_var "[path]" "/v2" "/orders"; -> "[alias]" "[path]"; #5. ++ works on decimals, an unknown variable is an error, env del var removes one; -> "[rate]" 1.5; ++ "[rate]"; -> "[unknown]" (try {++ "[visits]";} {"error: [visits] does not exist"} "[e]"); env del var "[total_IT]"; concat "totals: " (string trim [report]) [_n_] "concat_var: " [path] ", alias: " [alias] [_n_] "++ 1.5 = " [rate] ", " [unknown] [_n_] "after env del var, total_IT exists: " (env exist var "[total_IT]");
totals: FR=175.5 DE=100 IT=60 concat_var: /api/v2/orders, alias: [path] ++ 1.5 = 2.5, error: [visits] does not exist after env del var, total_IT exists: 0
Variable scope: execute, call and include compared
Create a VAT helper script and run it three ways: execute starts a new environment (the caller country is not seen, nothing leaks), call shares the caller environment (country seen, local variables left behind) and checks the typed parameters, include shares it too but skips the parameter checks.
#1. A shared helper: price with VAT, the country is read from the caller if it exists; script create exe "tuto.lang.vat" false 1 (param (var "[amount]" {type is_number [amount]} "Amount without VAT" is_null:false is_empty:false "100") ) "Add the VAT of the current country" { -> "[rate]" (if (env exist var "[country]") {switch ([country]) ("DE") {19} ("FR") {20} {0}} {20}); -> "[vat]" (math round (/ (* [amount] [rate]) 100) 2); + [amount] [vat]; } "The amount with VAT"; -> "[country]" "DE"; #2. execute: new environment, the caller country is not seen, nothing comes back but the result; -> "[r1]" (execute "tuto.lang.vat.exe" "[amount]" 100); -> "[leak1]" (env exist var "[vat]"); #3. call: same environment, the script sees the country and leaves its variables; -> "[r2]" (call "tuto.lang.vat.exe" "[amount]" 100); -> "[leak2]" (concat (env exist var "[vat]") ", vat=" [vat] ", rate=" [rate]); env del var "[vat]"; #4. Parameters are checked by execute and call, include does not check them; -> "[r3]" (try {call "tuto.lang.vat.exe" "[amount]" "abc";} {string regexp_extract [e] "\[\[\[ (.*) \]\]\]" 1} "[e]"); -> "[r4]" (try {include "tuto.lang.vat.exe" "[amount]" "abc";} {string regexp_extract [e] "\[\[\[ (.*) \]\]\]" 1} "[e]"); script delete "tuto.lang.vat.exe"; concat "execute: " [r1] " (default 20%), vat left in caller: " [leak1] [_n_] "call: " [r2] " (DE 19%), left in caller: " [leak2] [_n_] "call with abc: " [r3] [_n_] "include with abc, the script runs and fails inside: " [r4] [_n_] "script still exists: " (script exist "tuto.lang.vat.exe");
execute: 120 (default 20%), vat left in caller: 0 call: 119 (DE 19%), left in caller: 1, vat=19, rate=19 call with abc: Sorry, the variable '[amount]' in the script 'tuto.lang.vat.exe' is not valid (type is_number [amount];). include with abc, the script runs and fails inside: Sorry, the number to round cannot be null. script still exists: 0
- Use execute for services, call for helpers that must read the context, include only for trusted snippets.
- Clean the variables a called script leaves with
env del var.
Discount rules engine with mql and eval
Keep business rules as MQL text with mql {...} (not run, variables not replaced), run them per order with eval so they read the values of that moment, inject a user value safely with mql encode, and compare parentheses, blocks and the lazy branches of if.
#1. Discount rules written by the sales team, kept as MQL code; -> "[rule_qty]" (mql {if (>= [qty] 10) {* [total] 0.10} {0};}); -> "[rule_vip]" (mql {if (equal [tier] "gold") {* [total] 0.05} {0};}); #2. mql keeps the text as it is: nothing is run and the variables are not replaced; -> "[stored]" [rule_qty]; #3. eval runs the text later, with the values of that moment; -> "[orders]" "12:250:gold,3:90:silver,20:400:silver"; -> "[out]" ""; for (-> "[i]" 1) (<= [i] (atom size [orders] ",")) (++ "[i]") { -> "[o]" (atom get [orders] [i] ","); -> "[qty]" (atom get [o] 1 ":"); -> "[total]" (atom get [o] 2 ":"); -> "[tier]" (atom get [o] 3 ":"); -> "[disc]" (+ (eval [rule_qty]) (eval [rule_vip])); -> "[out]" (concat [out] "order " [i] ": " [total] " - " [disc] " = " (- [total] [disc]) [_n_]); }; #4. A value typed by a user goes into generated code through mql encode; -> "[shop]" "Le \"Bistrot\""; -> "[code]" (concat "string upper \"" (mql encode [shop]) "\";"); #5. Parentheses are evaluated before the call, a block in if runs only when chosen; -> "[runs]" 0; if (false) {++ "[runs]";} {"skipped"}; concat "stored rule: " [stored] [_n_] [out] "generated code: " [code] " gives " (eval [code]) [_n_] "the true block of if false ran " [runs] " time, concat a {+ 1 1} = " (concat "a" {+ 1 1});
stored rule: if (>= [qty] 10) {* [total] 0.10} {0};
order 1: 250 - 37.5 = 212.5
order 2: 90 - 0 = 90
order 3: 400 - 40 = 360
generated code: string upper "Le \"Bistrot\""; gives LE "BISTROT"
the true block of if false ran 0 time, concat a {+ 1 1} = a2- Store the rules in a
tuto_parameter or a node so the sales team changes them without a deploy. - Wrap
evalof user code in try, and refuse some words first (see the safe formula evaluator recipe).
Coded errors, nested try and a finally step: a payment pipeline
A charge script raises business codes (CARD_DECLINED, LIMIT); the caller wraps the error with context in an inner try, maps the original code to an HTTP status in the outer try, frees its JSON work key on both paths like a finally block, and checks that the error variable does not exist after a clean try.
#1. A payment service that raises coded business errors; script create exe "tuto.lang.charge" false 1 (param (var "[card]" {type is_varchar [card] 19} "Card number" is_null:false is_empty:false "4111111111111111") (var "[amount]" {type is_number [amount]} "Amount" is_null:false is_empty:false "25") ) "Charge a card" { if (string ends_with [card] "0000") {exception ("CARD_DECLINED") ("the bank declined the card");}; if (> [amount] 1000) {exception ("LIMIT") (concat "amount " [amount] " over the limit of 1000");}; concat "charged " [amount]; } "A confirmation"; #2. Each payment: a JSON work key that must be freed whatever happens; -> "[payments]" "4111111111111111:25,4000000000000000:40,4111111111111111:1500"; -> "[out]" ""; for (-> "[i]" 1) (<= [i] (atom size [payments] ",")) (++ "[i]") { -> "[p]" (atom get [payments] [i] ","); json load "tuto_lang_tx" "{}"; try { #3. Inner try: add context then raise again with a new code; try { -> "[msg]" (execute "tuto.lang.charge.exe" "[card]" (atom get [p] 1 ":") "[amount]" (atom get [p] 2 ":")); } { exception ("PAYMENT_FAILED") (concat "payment " [i] " / " (string regexp_extract [inner] "([A-Z_]+: [^\n]*)$" 1)); } "[inner]"; -> "[status]" (concat "200 " [msg]); } { #4. Map the business code of the original error to an HTTP status; -> "[code]" (string regexp_extract [err] "([A-Z_]+): [^:\n]*$" 1); -> "[status]" (concat (switch ([code]) ("CARD_DECLINED") {"402"} ("LIMIT") {"422"} {"500"}) " " (string regexp_extract [err] "PAYMENT_FAILED: ([^\n]*)" 1)); } "[err]"; #5. Finally-like step: runs after both paths; json unload "tuto_lang_tx"; -> "[out]" (concat [out] [status] [_n_]); }; script delete "tuto.lang.charge.exe"; #6. Trap: after a try without error, its error variable does not exist; try {+ 1 1;} {"never"} "[err2]"; concat [out] "work key still loaded: " (json exist "tuto_lang_tx") ", error variable after a clean try: " (env exist var "[err2]");
200 charged 25 402 payment 2 / CARD_DECLINED: the bank declined the card 422 payment 3 / LIMIT: amount 1500 over the limit of 1000 work key still loaded: 0, error variable after a clean try: 0
- The error text stacks one line per level: the last line ends with code: message.
- Write the failed payments with
log writefor the support team.
Loops: continue, break, retry with backoff and parallel
An import reads a feed line by line, skips comments and blank lines with continue, stops at the END marker with break, then pushes the total to a flaky partner with a repeat loop and an exponential backoff. Three independent checks run at the same time with parallel.
#1. A feed file to import: skip comments and blank lines, stop at the END marker; -> "[feed]" "# export 2026-11-01|A1;12||B7;oops|# warehouse 2|C2;5|END|Z9;99"; -> "[ok]" 0; -> "[bad]" ""; -> "[qty]" 0; for (-> "[i]" 1) (<= [i] (atom size [feed] "|")) (++ "[i]") { -> "[line]" (string trim (atom get [feed] [i] "|")); if (or (equal [line] "") (string starts_with [line] "#")) {continue;}; if (equal [line] "END") {break;}; -> "[q]" (atom get [line] 2 ";"); if (not (type is_integer [q] 6)) {-> "[bad]" (concat [bad] "line " [i] " ");} {++ "[ok]"; -> "[qty]" (+ [qty] [q]);}; }; #2. Push the total to a flaky partner: retry with an exponential backoff; -> "[try]" 0; -> "[delay]" 100; -> "[sent]" 0; -> "[trace]" ""; repeat (< [try] 5) { ++ "[try]"; #The partner answers 503 twice, then 200; -> "[http]" (if (< [try] 3) {503} {200}); -> "[trace]" (concat [trace] "try " [try] ": " [http] (if (equal [http] 200) {""} {concat ", wait " [delay] " ms"}) [_n_]); if (equal [http] 200) {-> "[sent]" 1; break;}; wait [delay]; -> "[delay]" (* [delay] 2); }; #3. Three independent checks at the same time; -> "[par]" (parallel {date is_weekend "2026-11-01"} {type is_email "ops@example.com"} {math round (/ [qty] 3) 2}); -> "[i]" 0; -> "[checks]" ""; while (< [i] 3) { -> "[checks]" (concat [checks] (json load select "rx_p4m_par" [par] (concat "/[" [i] "]/result")) " "); ++ "[i]"; }; json unload "rx_p4m_par"; concat "imported " [ok] " lines, qty " [qty] ", rejected: " [bad] [_n_] [trace] "sent: " [sent] [_n_] "parallel results: " [checks]
imported 2 lines, qty 17, rejected: line 4 try 1: 503, wait 100 ms try 2: 503, wait 200 ms try 3: 200 sent: 1 parallel results: 1 1 5.67
parallelreturns a JSON array of {status, result}: read it withjson load select.- Put a maximum on every retry loop, here 5 tries: an endless
repeatblocks a stack thread.
Atom lists: negotiate the language of a response
A web service reads the Accept-Language header, cleans it into atoms, extracts the language tags and their weights, and picks the best language supported by the site. Other atom functions show how to count, find and cut the list.
#1. The Accept-Language header of a request and the languages of the site; -> "[header]" " fr-RE , en;q=0.8, fr;q=0.9 ,de;q=0.3, en ;q=0.5, *;q=0.1 "; -> "[site]" "en,fr,es"; #2. Clean atoms, one per language, best weight first; -> "[langs]" (atom lrtrim [header] ","); -> "[best]" ""; -> "[bestq]" -1; for (-> "[i]" 1) (<= [i] (atom size [langs] ",")) (++ "[i]") { -> "[part]" (atom get [langs] [i] ","); -> "[tag]" (string lower (atom get_first_lrtrim [part] ";")); -> "[q]" (if (string contains [part] "q=") {atom get_last [part] "="} {1}); #fr-RE is served by fr; -> "[base]" (atom get_first [tag] "-"); if (and (> (atom find [site] [base] ",") 0) (> [q] [bestq])) {-> "[best]" [base]; -> "[bestq]" [q];}; }; #3. More atom tools on the same list; -> "[tags]" ""; for (-> "[i]" 1) (<= [i] (atom size [langs] ",")) (++ "[i]") {-> "[tags]" (concat [tags] (if (equal [i] 1) {""} {","}) (atom get_first_lrtrim (atom get [langs] [i] ",") ";"));}; -> "[uniq]" (atom distinct_lrtrim_1sbefore [tags] ","); -> "[upto]" (atom before_includ [tags] (atom position [tags] "fr" ",") ","); -> "[before]" (atom before_exclud [tags] (atom position [tags] "fr" ",") ","); concat "atoms: " [langs] [_n_] "language tags: " [tags] ", distinct: " [uniq] [_n_] "en appears " (atom count [tags] "en" ",") " times, fr at position " (atom position [tags] "fr" ",") [_n_] "up to fr: " [upto] " | before fr: " [before] [_n_] "Content-Language: " [best] " (q=" [bestq] ")"
atoms: fr-RE,en;q=0.8,fr;q=0.9,de;q=0.3,en ;q=0.5,*;q=0.1 language tags: fr-RE,en,fr,de,en,*, distinct: fr-RE, en, fr, de, * en appears 2 times, fr at position 3 up to fr: fr-RE,en,fr | before fr: fr-RE,en Content-Language: fr (q=1)
atom before_includandatom before_excludtake a position: get it withatom position.- Return the chosen language in a Content-Language header of the web service response.
