23 KiB
TinyMUX Function Matrix Survey
This survey maps the ~493 registered softcode functions across their "units of operation":
- Scalar arguments: discrete values passed as comma-separated args
- Word / list items: space-delimited (or sep-delimited) tokens
- Grapheme clusters: user-perceived characters (Unicode-aware)
- Bytes: raw storage units (intentionally thin -- not a user-facing model)
The important design constraint is that TinyMUX is trying hard to avoid
exposing bytes as a first-class user model. strmem() exists as a
diagnostic escape hatch, not as the start of a byte-oriented API family.
Current vs aspirational: This document describes actual current
semantics. Where a function's implementation does not match its
aspirational unit model (e.g., wordpos() uses byte offsets rather than
grapheme offsets, foreach() iterates code points rather than grapheme
clusters), the table labels the actual behavior and notes the gap. The
"Gaps" sections describe what would be needed to reach full grapheme
coverage.
A secondary constraint: vectors (vadd, vsub, etc.) are a specialized list sub-family, not a separate dimension. They operate on space-delimited numeric lists with optional separator overrides.
1. Numeric and Logical Reductions
1a. Arithmetic
| Operation | Scalar (args) | Integer Scalar | List Reduction | Integer List | Vector |
|---|---|---|---|---|---|
| Addition | add() |
iadd() |
ladd(), lmath(sum) |
-- | vadd() |
| Subtraction | sub() |
isub() |
lmath(sub) |
-- | vsub() |
| Multiplication | mul() |
imul() |
lmath(mul) |
-- | vmul() (scalar-vector) |
| Division | fdiv() |
idiv() |
lmath(div) |
-- | -- |
| Floor Division | floordiv() |
-- | -- | -- | -- |
| Modulus | mod() |
-- | lmath(mod) |
-- | -- |
| Remainder | remainder() |
-- | -- | -- | -- |
| Float Mod | fmod() |
-- | -- | -- | -- |
| Power | power() |
-- | -- | -- | -- |
| Abs Value | abs() |
iabs() |
-- | -- | -- |
| Sign | sign() |
isign() |
-- | -- | -- |
| Increment | inc() |
-- | -- | -- | -- |
| Decrement | dec() |
-- | -- | -- | -- |
| Min | min() |
-- | lmin(), lmath(min) |
-- | -- |
| Max | max() |
-- | lmax(), lmath(max) |
-- | -- |
| Mean | mean() |
-- | lmath(mean)/lmath(avg) |
-- | -- |
| Median | median() |
-- | lmath(median) |
-- | -- |
| Std Dev | stddev() |
-- | -- | -- | -- |
| Dot Product | -- | -- | -- | -- | vdot() |
| Cross Product | -- | -- | -- | -- | vcross() |
| Magnitude | -- | -- | -- | -- | vmag() |
| Unit Vector | -- | -- | -- | -- | vunit() |
| Dimension | -- | -- | -- | -- | vdim() = words() |
| Distance | dist2d(), dist3d() |
-- | -- | -- | -- |
| Sqrt | sqrt() |
-- | -- | -- | -- |
| Exp / Log | exp(), ln(), log() |
-- | -- | -- | -- |
| Trig | sin(), cos(), tan(), asin(), acos(), atan(), atan2() |
-- | -- | -- | -- |
| Constants | pi(), e() |
-- | -- | -- | -- |
| Base Convert | baseconv() |
-- | -- | -- | -- |
| Rounding | ceil(), floor(), round(), trunc() |
-- | -- | -- | -- |
| Spelling | spellnum(), roman() |
-- | -- | -- | -- |
| Random | rand(), die(), successes() |
-- | lrand(), pickrand() |
-- | -- |
| Distribute | -- | -- | distribute() |
-- | -- |
1b. Logical and Bitwise
| Operation | Scalar (args) | Short-Circuit | Bool Variant | List Reduction |
|---|---|---|---|---|
| AND | and() |
cand() |
andbool(), candbool() |
land() |
| OR | or() |
cor() |
orbool(), corbool() |
lor() |
| XOR | xor() |
-- | -- | lxor() |
| NOT | not() |
-- | -- | -- |
| Bitwise AND | band() |
-- | -- | lband() |
| Bitwise OR | bor() |
-- | -- | lbor() |
| Bitwise XOR | bxor() |
-- | -- | lbxor() |
| Bitwise NAND | bnand() |
-- | -- | -- |
| Shift Left | shl() |
-- | -- | -- |
| Shift Right | shr() |
-- | -- | -- |
1c. Comparison
| Operation | Numeric | String | List |
|---|---|---|---|
| Equal | eq() |
strmatch(), match() |
-- |
| Not Equal | neq() |
-- | -- |
| Greater Than | gt() |
-- | -- |
| Greater or Equal | gte() |
-- | -- |
| Less Than | lt() |
-- | -- |
| Less or Equal | lte() |
-- | -- |
| Compare (3-way) | -- | comp() |
-- |
| Lexicographic Min | -- | alphamin() |
-- |
| Lexicographic Max | -- | alphamax() |
-- |
| Between | between() |
-- | -- |
| Bound/Clamp | bound() |
-- | -- |
| Edit Distance | -- | strdistance() |
-- |
| Soundex | -- | soundex(), soundlike() |
-- |
Gaps in Numeric / Logical
Integer list reductions: DONE —limath()added, covering add, sub, mul, div, mod, min, max, median for 64-bit integers.Horizontal bitwise reducers: DONE —lband(),lbor(),lbxor()added.: DONE — boolean list parity reduction added.lxor()- List comparison: no element-wise compare that returns a list of
results (like a vectorized
eq()). This may be too specialized to matter;mix()can approximate it. floordiv()has no integer or list variant.remainder()vsmod(): two scalar modulus operations; neither has a list variant.
2. Spatial and Sequence Operations
2a. Counting
| What | Word / List | Grapheme | Byte |
|---|---|---|---|
| Count items | words() |
strlen() |
strmem() |
2b. Extraction / Slicing
| Operation | Word / List | Grapheme |
|---|---|---|
| Positional slice | extract(str,first,len,isep,osep) |
mid(str,start,len) |
| First item | first(str,sep) |
left(str,len) |
| All but first | rest(str,sep), lrest(str,sep) |
-- |
| Last item | last(str,sep) |
right(str,len) |
| All but last | -- | -- |
| Truncate | -- | strtrunc(str,len) |
| Multi-index select | elements(str,positions,isep,osep) |
-- |
| Range by delim | index(str,token,sep,count) |
-- |
| Before/After token | before(str,token) / after(str,token) |
-- |
| Delete-and-return | delextract(str,first,len,sep) |
-- |
2c. Searching / Finding
| Operation | Word / List | Grapheme | Regex |
|---|---|---|---|
| Find first (exact) | member(list,word,sep) |
pos(pattern,str) |
regmatch() / regmatchi() |
| Find first (wild) | match(list,pattern,sep) |
strmatch(str,pattern) |
-- |
| Find all positions | matchall(list,pattern,sep) |
lpos(str,sub) |
-- |
| Grab matching item | grab(list,pattern,sep) |
-- | regrab() / regrabi() |
| Grab all matching | graball(list,pattern,sep) |
-- | regraball() / regraballi() |
| Filter by function | filter(obj/attr,list,...) |
-- | -- |
| Filter by boolean | filterbool(obj/attr,list,...) |
-- | -- |
| Grep attributes | grep(obj,pattern,attr) / grepi() |
-- | regrep() / regrepi() |
2d. Modification (Insert / Delete / Replace)
| Operation | Word / List | Grapheme | Regex |
|---|---|---|---|
| Delete by position | ldelete(list,pos,isep,osep) |
delete(str,pos,len), strdelete(str,pos,len) |
-- |
| Insert at position | linsert(list,pos,word,sep), insert(list,pos,word,isep,osep) |
strinsert(str,pos,text) |
-- |
| Replace by position | lreplace(list,pos,word,isep,osep), replace(list,pos,word,isep,osep) |
strreplace(str,start,len,new) |
-- |
| Conditional replace | splice(list,old,new,isep,osep) |
-- | -- |
| List-aware edit | ledit(str,from,to,isep,osep) |
-- | -- |
| Remove by value | remove(list,word,isep,osep) |
-- | -- |
| Regex replace | -- | -- | regedit() / regediti() / regeditall() / regeditalli() |
The following are string-level operations. They work on raw strings or character sets, not on grapheme clusters or list words. They are listed separately to keep the unit model clean.
| Operation | Function | Notes |
|---|---|---|
| Substring replace | edit(str,from,to,...) |
Whole-string find-and-replace, not grapheme-indexed |
| Strip characters | strip(str,chars) |
Removes characters from a set; not grapheme-cluster-aware |
| Transliterate | tr(str,from,to) |
Grapheme-cluster-to-grapheme-cluster mapping; ASCII ranges expanded, non-ASCII clusters literal |
| Escape recovery | translate(str,mode) |
Turns hidden internal codes (color, etc.) back into MUX escape sequences |
2e. Reordering
| Operation | Word / List | Grapheme |
|---|---|---|
| Reverse | revwords(str,sep,osep) |
reverse(str) |
| Shuffle | shuffle(list,sep,osep) |
scramble(str) |
| Sort | sort(list,type,sep,osep) |
-- |
| Sort by function | sortby(obj/attr,list,sep,osep) |
-- |
| Sort by key | sortkey(obj/attr,list,sep,osep,count) |
-- |
| Merge (sorted) | merge(list1,list2,type) |
-- |
2f. Set Operations
| Operation | Word / List | Grapheme |
|---|---|---|
| Union | setunion(l1,l2,isep,osep,type) |
missing |
| Intersection | setinter(l1,l2,isep,osep,type) |
missing |
| Difference | setdiff(l1,l2,isep,osep,type) |
missing |
| Unique | unique(list,isep,osep,type) |
missing |
Gaps in Sequence Operations
"All but last" extraction: DONE —butlast()added.Grapheme-level sort: DONE —strsort()added.Grapheme set operations: DONE —strunion(),strdiff(),strinter(),strunique()all added.Grapheme-to-list bridge: DONE —graphemes(str, osep)added.- Conditional grapheme replace:
splice()does conditional replace at word level; there is no grapheme-level equivalent (replace grapheme cluster X with Y everywhere).edit()does this for substrings, butsplice()compares whole words. - Nth occurrence search:
pos()finds the first substring;lpos()finds all positions.DONE —posn(str, sub, n)was missingposn()added. - List-aware regex:
regedit()family operates on the whole string. There is nolregedit()that applies a regex to each list element.
3. Higher-Order / Iteration Functions
These bridge the scalar and list worlds by applying scalar logic across list elements.
| Function | Input | Semantics |
|---|---|---|
iter(list, pattern, isep, osep) |
list | Evaluate pattern for each element; ## = value, #@ = index |
citer(list, pattern, osep) |
list | Column-iter: iterate with comma separation |
list(list, pattern, sep) |
list | Like iter but output is newline-separated (for side effects) |
map(obj/attr, list, ...) |
list | Call a softcode function for each element |
filter(obj/attr, list, ...) |
list | Keep elements where function returns true |
filterbool(obj/attr, list, ...) |
list | Keep elements where function returns non-empty |
fold(obj/attr, list, base, sep) |
list | Left fold: accumulate via softcode function |
mix(obj/attr, l1, l2, ..., sep) |
multi-list | Zip + map: call function with parallel elements |
step(obj/attr, list, step, isep, osep) |
list | Map with step-size windowing |
foreach(obj/attr, str, isep, osep) |
UTF-8 code point | Call function for each code point (not grapheme-cluster-aware) |
while(cond, body, init, limit, isep, osep) |
scalar | Iterate while condition is true |
munge(obj/attr, l1, l2, sep) |
list | Reorder l2 by sorted-order of l1 |
sortby(obj/attr, list, sep, osep) |
list | Sort list by comparison function |
sortkey(obj/attr, list, sep, osep, count) |
list | Sort list by key-extraction function |
Gaps in Iteration
foreach()iterates UTF-8 code points, not grapheme clusters. It walks by lead-byte length, so a multi-code-point cluster (e.g., family emoji) is split into separate calls. All other iterators work at the word/list level. Astrmap()orgraphemes()-based approach would be more compositional and correctly grapheme-aware.- No
reduce()alias:fold()is the standard left-fold, but some MU* platforms also offerreduce(). Low priority sincefold()already exists. No: DONE —zip()without function applicationzip()added.- No
enumerate(): returnsindex:valuepairs. Achievable withiter()+#@but not directly available.
4. Bridging Word Units and Grapheme Units
This is the sparsest and most strategically useful part of the matrix. TinyMUX has strong support inside each dimension but fewer tools for moving between them.
| Bridge | Current Support | Status |
|---|---|---|
| Word index -> word text | extract(), first(), rest(), last() |
covered |
| Grapheme offset -> grapheme slice | mid(), strdelete(), strinsert(), strreplace() |
covered |
| Grapheme position -> containing word | wordpos(str, charpos, sep) |
covered |
| Word index -> grapheme start/end | wordstart(), wordend() |
covered |
| String -> grapheme list | graphemes() |
covered |
| Grapheme list -> string | lcat(list,isep,osep) |
covered (list-consuming joiner; the inverse of graphemes()) |
Note: wordpos() now indexes by grapheme cluster (fixed): it bounds
charpos against the grapheme count and walks grapheme clusters
(utf8_next_grapheme) to resolve the position, matching its "character
position" documentation and the grapheme-correct wordstart()/wordend().
The previous implementation used charpos as a raw byte offset
(cp[charpos - 1]) while bounding against the code-point count, so it
returned the wrong word for multi-byte UTF-8. Behaviour is unchanged for
pure-ASCII input (one cluster == one byte == one code point). Regression
coverage: testcases/wordpos_fn.mux TC003 (accented é and a skin-tone
grapheme cluster).
Best Additions
-- DONE.wordstart(str, word, sep)/wordend(str, word, sep)-- DONE.graphemes(str, osep)-- DONE.posn(str, sub, n)wordspan(str, word, sep)-- returnstart endas a structured pair (lower priority;wordstart/wordendare simpler).
5. Case Conversion and Text Formatting
| Operation | Scalar / String | List |
|---|---|---|
| Lower case | lcstr() |
-- |
| Upper case | ucstr() |
-- |
| Capitalize first | capstr() |
caplist(list, sep, osep) |
| Case all words | caseall() |
-- |
| Accent | accent(str, pattern) |
-- |
| Trim whitespace | trim(str, side, chars) |
-- |
| Squish whitespace | squish(str, sep) |
-- |
| Pad left | lpad(str, width, fill), ljust(str, width, fill) |
-- |
| Pad right | rpad(str, width, fill), rjust(str, width, fill) |
-- |
| Center | center(str, width, fill), cpad(str, width, fill) |
-- |
| Repeat | repeat(str, count) |
-- |
| Space | space(count) |
-- |
| Columns | columns(list, width, sep, osep) |
-- |
| Table | table(list, width, ...) |
-- |
| Wrap | wrap(str, width, ...) |
-- |
| Wrap columns | wrapcolumns(str, cols, width, ...) |
-- |
| Printf | printf(fmt, args...) |
-- |
| Itemize | itemize(list, sep, conj, punct) |
-- |
| ANSI color | ansi(codes, str, ...) |
-- |
| Strip ANSI | stripansi(str) |
-- |
| Strip accents | stripaccents(str) |
-- |
| Garble | garble(str, type) |
-- |
| Color depth | colordepth(dbref) |
-- |
Gaps in Formatting
- List-level case conversion:
lcstr()anducstr()operate on whole strings. There is nolclist()oruclist()that lowercases each list element independently. (Low priority --iter()+lcstr()covers it.) title(): capitalize each word --caseall()may cover this depending on semantics, but it is worth verifying.
6. Encoding, Hashing, and Type Conversion
| Operation | Functions |
|---|---|
| Base64 | encode64(), decode64() |
| URL encoding | url_escape(), url_unescape() |
| Crypt | encrypt(), decrypt() |
| Hash | sha1(), digest(), hmac(), crc32(), crc32obj() |
| Char <-> Code | chr(), ord() |
| Pack/Unpack | pack(), unpack() |
| Escape | escape(), secure() |
| JSON | json(), json_mod(), json_query(), isjson() |
| CTU (unit conv) | ctu() |
| Type testing | isint(), isnum(), israt(), isword(), isdbref(), isobjid(), isalpha(), isalnum(), isdigit() |
| Subnet match | subnetmatch() |
Gaps
- No
isjsonpath()or JSON-to-list bridge (e.g.,json_keys(),json_values()).json_query()partially covers this. - Type-testing functions are scalar-only. No
lisint()orlisnum()for testing every element in a list. (Low priority --filter()+isnum()works.)
7. Control Flow and Evaluation
| Pattern | Scalar | Short-Circuit | List-Oriented |
|---|---|---|---|
| If/Else | if(), ifelse() |
-- | -- |
| Switch | switch(), switchall() |
-- | -- |
| Case | case(), caseall() |
-- | -- |
| Choose | choose() |
-- | -- |
| Default | default(), edefault() |
-- | -- |
| First non-empty | firstof(), strfirstof() |
yes (FN_NOEVAL) | -- |
| All non-empty | allof(), strallof() |
yes (FN_NOEVAL) | -- |
| Call user fn | u(), ulocal(), udefault(), ulambda() |
-- | map(), filter(), fold() |
| Eval string | eval(), s(), subeval(), asteval() |
-- | -- |
| Obj-context eval | objeval() |
-- | -- |
| Localize | localize(), letq() |
-- | -- |
| Sandbox | sandbox() |
-- | -- |
| Trace | trace() |
-- | -- |
| Null | null(), @@() |
-- | -- |
| Literal | lit() |
-- | -- |
| Error | error() |
-- | -- |
| Registers | setq(), setr(), unsetq(), listq(), r() |
-- | -- |
| Counters | inc(), dec() |
-- | -- |
| Iter state | itext(), inum(), ilev() |
-- | -- |
| Function depth | fdepth(), fcount() |
-- | -- |
| Benchmark | benchmark(), astbench(), rvbench() |
-- | -- |
8. Complete Gap Summary and Recommendations
Tier 1 -- High Value, Low Risk
These fill the most commonly felt gaps and have clean semantics.
| Proposed Function | What It Does | Why |
|---|---|---|
graphemes(str, osep) |
DONE | |
wordstart(str, word, sep) |
DONE | |
wordend(str, word, sep) |
DONE | |
lxor(list, sep) |
DONE |
Tier 2 -- Solid Value, Straightforward
| Proposed Function | What It Does | Why |
|---|---|---|
lband(list, sep) |
DONE | |
lbor(list, sep) |
DONE | |
lbxor(list, sep) |
DONE | |
limath(op, list, sep) |
DONE | |
posn(str, sub, n) |
DONE | |
strsort(str) |
DONE | |
strunique(str) |
DONE |
Tier 3 -- Nice to Have
| Proposed Function | What It Does | Why |
|---|---|---|
strunion(s1, s2) |
DONE | |
strdiff(s1, s2) |
DONE | |
strinter(s1, s2) |
DONE | |
butlast(str, sep) |
DONE | |
zip(l1, l2, sep) |
DONE |
What NOT to Add
- Byte-level API family (
strmid,bpos,blpos): cuts against TinyMUX's current direction. Bytes are an implementation detail. - Code-point API (
cpcount,cpmid): introduces a third indexing model between bytes and grapheme clusters. Confusing for users. - List-level type testers (
lisint,lisnum):filter()+isnum()already covers this with no new surface area. lregedit(): regex-per-list-element can be composed withiter()+regedit(). Not common enough to justify a dedicated function.
Appendix A: Complete Function-to-Dimension Map
Legend: S = scalar/args, W = word/list, G = grapheme, V = vector, R = regex, O = object/db, T = time, C = channel/comms, M = mail, J = JSON, X = system/admin
Functions omitted from the matrix body above (object, time, channel, mail, system) are categorized here for completeness.
Object / Database (O)
attrcnt, attrib_set, children, clone, con, controls,
create, destroy, elock, entrances, exit, findable, flags,
fullname, get, get_eval, grep, grepi, hasattr, hasattrp,
hasflag, haspower, hasquota, hastype, home, inzone,
lastcreate, lattr, lattrcmds, lattrp, lcon, lexits,
lflags, link, lparent, loc, locate, lock, lockdecode,
lockencode, lplayers, lrooms, lthings, money, moniker,
name, ncon, nearby, nexits, next, nplayers, nthings, num,
obj, objid, objmem, owner, parent, pfind, pmatch, room,
rloc, route, search, set, tel, trigger, type, valid,
visible, where, wipe, xget, zone, zchildren, zexits,
zfun, zrooms, zthings, zwho
Time (T)
convsecs, convtime, ctime, digittime, etimefmt, exptime,
moon, mtime, secs, singletime, startsecs, starttime,
restartsecs, restarttime, restarts, time, timefmt, writetime
Channel / Communication (C)
cbuffer, cdesc, cemit, cflags, chanfind, chaninfo,
channels, chanobj, chanuser, chanusers, cmogrifier, cmsgs,
cowner, crecall, cstatus, cusers, cwho, comalias,
comtitle, emit, nsemit, nsoemit, nspemit, nsremit, oemit,
pemit, prompt, remit
Mail (M)
mail, mailcount, mailflags, mailfrom, mailinfo, maillist,
mailreview, mailsend, mailsize, mailstats, mailsubj, malias
System / Admin (X)
addrlog, beep, bittype, cmds, config, conn, connlast,
connleft, connlog, connmax, connnum, connrecord, conntotal,
doing, dumping, dynhelp, gmcp, height, host, idle,
jitstats, lcmds, lports, lwho, mudname, motd, objmem,
playmem, pocvm2, poll, ports, rvbench, siteinfo, stats,
terminfo, textfile, version, width
Pronouns / English (used with O)
aposs, art, obj, poss, pose, subj, verb
Lua
lua()
Internal (GOD-only, JIT support)
_check_u_perm, _default_get, _edefault_get, _restore_cargs,
_restore_qregs, _save_cargs, _save_qregs, _set_ncargs,
_write_carg
Appendix B: Cross-Platform Comparison Notes
Functions present in PennMUSH or RhostMUSH but absent from TinyMUX that would fit naturally into the matrix:
| Function | Platform | Dimension | Notes |
|---|---|---|---|
nattr() |
Penn | O | Count of attributes (TinyMUX has attrcnt()) |
lsearch() |
Penn | O | List-returning search (TinyMUX search() already returns a list) |
reswitch() |
Penn | S | Regex switch (achievable with switch()+regmatch()) |
speak() |
Penn | S | Say/pose formatter |
textentries() |
Penn | S | Count entries in a text file |
ordinal() |
Penn | S | 1st, 2nd, 3rd... |
nameq() / isname() |
Rhost | O | Named q-register operations |
mix() multi-list |
Penn | W | TinyMUX already has this |
Most cross-platform gaps are either already covered by TinyMUX equivalents or are domain-specific enough to not warrant adoption. The structural gaps identified in Section 8 (grapheme bridge, integer list reducers, bitwise list reducers) are TinyMUX-specific and not addressed by copying functions from other platforms.