# Copyright (C) 2016, 2017, 2018, 2019  Stefan Vargyas
# 
# This file is part of Json-Type.
# 
# Json-Type is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# Json-Type is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with Json-Type.  If not, see <http://www.gnu.org/licenses/>.

#
# json trie test suite:
#

$ . ~/regtest2.sh
$ alias json-trie-regtest='regtest2-selftest -f test-json-trie.txt -a exec=pipe -B'

# output all test names:
$ json-trie-regtest -N
...

# run all tests:
$ json-trie-regtest -A
...

--[ prereq ]--------------------------------------------------------------------

$ test -x ../lib/test-trie
$ print() { printf '%s\n' "$@"; }
$ set -o pipefail
$

--[ empty ]---------------------------------------------------------------------

$ test-trie() { ../lib/test-trie -T; }
$ echo -n|test-trie
trie=null
$ print|test-trie
trie={"val":"","lo":null,"hi":null}
node={"val":"","lo":null,"hi":null}
char='\0'
$

--[ base ]----------------------------------------------------------------------

$ test-trie() { ../lib/test-trie -T; }
$ print a b|test-trie
trie={"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":null}}
node={"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":null}}
char='a'
char='b'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
$ print b a|test-trie
trie={"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":null}
node={"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":null}
char='a'
char='b'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
$ print a b c|test-trie
trie={"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":{"sym":"c","lo":null,"eq":{"val":"c","lo":null,"hi":null},"hi":null}}}
node={"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":{"sym":"c","lo":null,"eq":{"val":"c","lo":null,"hi":null},"hi":null}}}
char='a'
char='b'
char='c'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
node={"val":"c","lo":null,"hi":null}
char='\0'
$ print b c a|test-trie
trie={"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":{"sym":"c","lo":null,"eq":{"val":"c","lo":null,"hi":null},"hi":null}}
node={"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":{"sym":"c","lo":null,"eq":{"val":"c","lo":null,"hi":null},"hi":null}}
char='a'
char='b'
char='c'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
node={"val":"c","lo":null,"hi":null}
char='\0'
$ print c b a|test-trie
trie={"sym":"c","lo":{"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":null},"eq":{"val":"c","lo":null,"hi":null},"hi":null}
node={"sym":"c","lo":{"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":null},"eq":{"val":"c","lo":null,"hi":null},"hi":null}
char='a'
char='b'
char='c'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
node={"val":"c","lo":null,"hi":null}
char='\0'
$ print a c b|test-trie
trie={"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"c","lo":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":null},"eq":{"val":"c","lo":null,"hi":null},"hi":null}}
node={"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"c","lo":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":null},"eq":{"val":"c","lo":null,"hi":null},"hi":null}}
char='a'
char='b'
char='c'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
node={"val":"c","lo":null,"hi":null}
char='\0'
$ print b a c|test-trie
trie={"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":{"sym":"c","lo":null,"eq":{"val":"c","lo":null,"hi":null},"hi":null}}
node={"sym":"b","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":null},"eq":{"val":"b","lo":null,"hi":null},"hi":{"sym":"c","lo":null,"eq":{"val":"c","lo":null,"hi":null},"hi":null}}
char='a'
char='b'
char='c'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
node={"val":"c","lo":null,"hi":null}
char='\0'
$ print c a b|test-trie
trie={"sym":"c","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":null}},"eq":{"val":"c","lo":null,"hi":null},"hi":null}
node={"sym":"c","lo":{"sym":"a","lo":null,"eq":{"val":"a","lo":null,"hi":null},"hi":{"sym":"b","lo":null,"eq":{"val":"b","lo":null,"hi":null},"hi":null}},"eq":{"val":"c","lo":null,"hi":null},"hi":null}
char='a'
char='b'
char='c'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
node={"val":"c","lo":null,"hi":null}
char='\0'
$ print ab|test-trie
trie={"sym":"a","lo":null,"eq":{"sym":"b","lo":null,"eq":{"val":"ab","lo":null,"hi":null},"hi":null},"hi":null}
node={"sym":"a","lo":null,"eq":{"sym":"b","lo":null,"eq":{"val":"ab","lo":null,"hi":null},"hi":null},"hi":null}
char='a'
node={"sym":"b","lo":null,"eq":{"val":"ab","lo":null,"hi":null},"hi":null}
char='b'
node={"val":"ab","lo":null,"hi":null}
char='\0'
$ print z ax abc abd aef aeg|test-trie
trie={"sym":"z","lo":{"sym":"a","lo":null,"eq":{"sym":"x","lo":{"sym":"b","lo":null,"eq":{"sym":"c","lo":null,"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}},"hi":{"sym":"e","lo":null,"eq":{"sym":"f","lo":null,"eq":{"val":"aef","lo":null,"hi":null},"hi":{"sym":"g","lo":null,"eq":{"val":"aeg","lo":null,"hi":null},"hi":null}},"hi":null}},"eq":{"val":"ax","lo":null,"hi":null},"hi":null},"hi":null},"eq":{"val":"z","lo":null,"hi":null},"hi":null}
node={"sym":"z","lo":{"sym":"a","lo":null,"eq":{"sym":"x","lo":{"sym":"b","lo":null,"eq":{"sym":"c","lo":null,"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}},"hi":{"sym":"e","lo":null,"eq":{"sym":"f","lo":null,"eq":{"val":"aef","lo":null,"hi":null},"hi":{"sym":"g","lo":null,"eq":{"val":"aeg","lo":null,"hi":null},"hi":null}},"hi":null}},"eq":{"val":"ax","lo":null,"hi":null},"hi":null},"hi":null},"eq":{"val":"z","lo":null,"hi":null},"hi":null}
char='a'
char='z'
node={"sym":"x","lo":{"sym":"b","lo":null,"eq":{"sym":"c","lo":null,"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}},"hi":{"sym":"e","lo":null,"eq":{"sym":"f","lo":null,"eq":{"val":"aef","lo":null,"hi":null},"hi":{"sym":"g","lo":null,"eq":{"val":"aeg","lo":null,"hi":null},"hi":null}},"hi":null}},"eq":{"val":"ax","lo":null,"hi":null},"hi":null}
char='b'
char='e'
char='x'
node={"val":"z","lo":null,"hi":null}
char='\0'
node={"sym":"c","lo":null,"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}}
char='c'
char='d'
node={"sym":"f","lo":null,"eq":{"val":"aef","lo":null,"hi":null},"hi":{"sym":"g","lo":null,"eq":{"val":"aeg","lo":null,"hi":null},"hi":null}}
char='f'
char='g'
node={"val":"ax","lo":null,"hi":null}
char='\0'
node={"val":"abc","lo":null,"hi":null}
char='\0'
node={"val":"abd","lo":null,"hi":null}
char='\0'
node={"val":"aef","lo":null,"hi":null}
char='\0'
node={"val":"aeg","lo":null,"hi":null}
char='\0'
$ print aef ae abg a abc ab abd|test-trie
trie={"sym":"a","lo":null,"eq":{"sym":"e","lo":{"sym":"b","lo":{"val":"a","lo":null,"hi":null},"eq":{"sym":"g","lo":{"sym":"c","lo":{"val":"ab","lo":null,"hi":null},"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}},"eq":{"val":"abg","lo":null,"hi":null},"hi":null},"hi":null},"eq":{"sym":"f","lo":{"val":"ae","lo":null,"hi":null},"eq":{"val":"aef","lo":null,"hi":null},"hi":null},"hi":null},"hi":null}
node={"sym":"a","lo":null,"eq":{"sym":"e","lo":{"sym":"b","lo":{"val":"a","lo":null,"hi":null},"eq":{"sym":"g","lo":{"sym":"c","lo":{"val":"ab","lo":null,"hi":null},"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}},"eq":{"val":"abg","lo":null,"hi":null},"hi":null},"hi":null},"eq":{"sym":"f","lo":{"val":"ae","lo":null,"hi":null},"eq":{"val":"aef","lo":null,"hi":null},"hi":null},"hi":null},"hi":null}
char='a'
node={"sym":"e","lo":{"sym":"b","lo":{"val":"a","lo":null,"hi":null},"eq":{"sym":"g","lo":{"sym":"c","lo":{"val":"ab","lo":null,"hi":null},"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}},"eq":{"val":"abg","lo":null,"hi":null},"hi":null},"hi":null},"eq":{"sym":"f","lo":{"val":"ae","lo":null,"hi":null},"eq":{"val":"aef","lo":null,"hi":null},"hi":null},"hi":null}
char='\0'
char='b'
char='e'
node={"sym":"g","lo":{"sym":"c","lo":{"val":"ab","lo":null,"hi":null},"eq":{"val":"abc","lo":null,"hi":null},"hi":{"sym":"d","lo":null,"eq":{"val":"abd","lo":null,"hi":null},"hi":null}},"eq":{"val":"abg","lo":null,"hi":null},"hi":null}
char='\0'
char='c'
char='d'
char='g'
node={"sym":"f","lo":{"val":"ae","lo":null,"hi":null},"eq":{"val":"aef","lo":null,"hi":null},"hi":null}
char='\0'
char='f'
node={"val":"abc","lo":null,"hi":null}
char='\0'
node={"val":"abd","lo":null,"hi":null}
char='\0'
node={"val":"abg","lo":null,"hi":null}
char='\0'
node={"val":"aef","lo":null,"hi":null}
char='\0'
$

--[ shuf ]----------------------------------------------------------------------

$ test-trie() { shuf|../lib/test-trie -T|sed -r '1{s/^(trie=).*$/\1{...}/;b};/^node=\{"val":"[^"]+","lo":null,"hi":null\}$/b;s/^(node=\{).*(\})$/\1...\2/'; }
$ print a b|test-trie
trie={...}
node={...}
char='a'
char='b'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
$ print a b c|test-trie
trie={...}
node={...}
char='a'
char='b'
char='c'
node={"val":"a","lo":null,"hi":null}
char='\0'
node={"val":"b","lo":null,"hi":null}
char='\0'
node={"val":"c","lo":null,"hi":null}
char='\0'
$ print z ax abc abd aef aeg|test-trie
trie={...}
node={...}
char='a'
char='z'
node={...}
char='b'
char='e'
char='x'
node={"val":"z","lo":null,"hi":null}
char='\0'
node={...}
char='c'
char='d'
node={...}
char='f'
char='g'
node={"val":"ax","lo":null,"hi":null}
char='\0'
node={"val":"abc","lo":null,"hi":null}
char='\0'
node={"val":"abd","lo":null,"hi":null}
char='\0'
node={"val":"aef","lo":null,"hi":null}
char='\0'
node={"val":"aeg","lo":null,"hi":null}
char='\0'
$ print aef ae abg a abc ab abd|test-trie
trie={...}
node={...}
char='a'
node={...}
char='\0'
char='b'
char='e'
node={...}
char='\0'
char='c'
char='d'
char='g'
node={...}
char='\0'
char='f'
node={"val":"abc","lo":null,"hi":null}
char='\0'
node={"val":"abd","lo":null,"hi":null}
char='\0'
node={"val":"abg","lo":null,"hi":null}
char='\0'
node={"val":"aef","lo":null,"hi":null}
char='\0'
$

--[ depths ]--------------------------------------------------------------------

$ test-trie() { ../lib/test-trie -D; }
$ print|test-trie
iter:     1
sib-iter: 1
lvl-iter: 1
$ print a b|test-trie
iter:     3
sib-iter: 2
lvl-iter: 2
$ print b a|test-trie
iter:     3
sib-iter: 2
lvl-iter: 2
$ print a b c|test-trie
iter:     4
sib-iter: 3
lvl-iter: 3
$ print b c a|test-trie
iter:     3
sib-iter: 2
lvl-iter: 3
$ print c b a|test-trie
iter:     4
sib-iter: 3
lvl-iter: 3
$ print a c b|test-trie
iter:     4
sib-iter: 3
lvl-iter: 3
$ print b a c|test-trie
iter:     3
sib-iter: 2
lvl-iter: 3
$ print c a b|test-trie
iter:     4
sib-iter: 3
lvl-iter: 3
$ print ab|test-trie
iter:     3
sib-iter: 1
lvl-iter: 1
$ print z ax abc abd aef aeg|test-trie
iter:     8
sib-iter: 2
lvl-iter: 6
$ print aef ae abg a abc ab abd|test-trie
iter:     7
sib-iter: 1
lvl-iter: 7
$ print '' a|test-trie
iter:     3
sib-iter: 2
lvl-iter: 2
$ print aw ax by bz|test-trie
iter:     5
sib-iter: 2
lvl-iter: 4
$

--[ sgb-words ]-----------------------------------------------------------------

$ wc -l < sgb-words.txt
5757
$ test-trie() { set -o pipefail && ../lib/test-trie -p 2M -D < sgb-words.txt; }
$ test-trie
iter:     29
sib-iter: 14
lvl-iter: 5757
$ test-trie() { set -o pipefail && ../lib/test-trie -p 2M -T "$@" < sgb-words.txt 2>&1 >/dev/null|sed -r '/fatal error:/{s|(fatal error: )\s*\./+|\1|;s/:[0-9]+:/:???:/}'; }
$ test-trie -l 5756
test-trie: fatal error: trie-impl.h:???:test_trie_lvl_iterator_inc: stack overflow
command failed: test-trie -l 5756
$ test-trie -l 5757
$

--[ rebalance ]-----------------------------------------------------------------

$ json() { env LD_LIBRARY_PATH=../lib ../src/json --no-error "$@" || return 0; }
$ test-trie() { local u=''; [ "$1" == '-u' ] && { u='u'; shift; }; ../lib/test-trie -R|sed -${u:+n}r ${u:+'H;$! b;g;s/^\n//;'}'s/,?"(lo|hi)":null//g'${u:+';s/^([^\n]+)\n\1$/\1/;p'}|json -Po -m; }
$ print '' a|test-trie
{
.   "val": "",
.   "hi": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "a"
.   .   }
.   }
}
{
.   "sym": "a",
.   "lo": {
.   .   "val": ""
.   },
.   "eq": {
.   .   "val": "a"
.   }
}
$ print a ''|test-trie -u
{
.   "sym": "a",
.   "lo": {
.   .   "val": ""
.   },
.   "eq": {
.   .   "val": "a"
.   }
}
$ print a b|test-trie
{
.   "sym": "a",
.   "eq": {
.   .   "val": "a"
.   },
.   "hi": {
.   .   "sym": "b",
.   .   "eq": {
.   .   .   "val": "b"
.   .   }
.   }
}
{
.   "sym": "b",
.   "lo": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "a"
.   .   }
.   },
.   "eq": {
.   .   "val": "b"
.   }
}
$ print b a|test-trie -u
{
.   "sym": "b",
.   "lo": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "a"
.   .   }
.   },
.   "eq": {
.   .   "val": "b"
.   }
}
$ print a b c|test-trie
{
.   "sym": "a",
.   "eq": {
.   .   "val": "a"
.   },
.   "hi": {
.   .   "sym": "b",
.   .   "eq": {
.   .   .   "val": "b"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "c"
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "b",
.   "lo": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "a"
.   .   }
.   },
.   "eq": {
.   .   "val": "b"
.   },
.   "hi": {
.   .   "sym": "c",
.   .   "eq": {
.   .   .   "val": "c"
.   .   }
.   }
}
$ print c b a|test-trie
{
.   "sym": "c",
.   "lo": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "a"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "b"
.   .   }
.   },
.   "eq": {
.   .   "val": "c"
.   }
}
{
.   "sym": "b",
.   "lo": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "a"
.   .   }
.   },
.   "eq": {
.   .   "val": "b"
.   },
.   "hi": {
.   .   "sym": "c",
.   .   "eq": {
.   .   .   "val": "c"
.   .   }
.   }
}
$ print b a c|test-trie -u
{
.   "sym": "b",
.   "lo": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "a"
.   .   }
.   },
.   "eq": {
.   .   "val": "b"
.   },
.   "hi": {
.   .   "sym": "c",
.   .   "eq": {
.   .   .   "val": "c"
.   .   }
.   }
}
$ print a b c d|test-trie
{
.   "sym": "a",
.   "eq": {
.   .   "val": "a"
.   },
.   "hi": {
.   .   "sym": "b",
.   .   "eq": {
.   .   .   "val": "b"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "c"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "d",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "d"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "c",
.   "lo": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "a"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "b"
.   .   }
.   },
.   "eq": {
.   .   "val": "c"
.   },
.   "hi": {
.   .   "sym": "d",
.   .   "eq": {
.   .   .   "val": "d"
.   .   }
.   }
}
$ print d c b a|test-trie
{
.   "sym": "d",
.   "lo": {
.   .   "sym": "c",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "a"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "b"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "c"
.   .   }
.   },
.   "eq": {
.   .   "val": "d"
.   }
}
{
.   "sym": "c",
.   "lo": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "a"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "b"
.   .   }
.   },
.   "eq": {
.   .   "val": "c"
.   },
.   "hi": {
.   .   "sym": "d",
.   .   "eq": {
.   .   .   "val": "d"
.   .   }
.   }
}
$ print c b a d|test-trie -u
{
.   "sym": "c",
.   "lo": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "a"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "b"
.   .   }
.   },
.   "eq": {
.   .   "val": "c"
.   },
.   "hi": {
.   .   "sym": "d",
.   .   "eq": {
.   .   .   "val": "d"
.   .   }
.   }
}
$ print a b c d e|test-trie
{
.   "sym": "a",
.   "eq": {
.   .   "val": "a"
.   },
.   "hi": {
.   .   "sym": "b",
.   .   "eq": {
.   .   .   "val": "b"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "c"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "d",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "d"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "e",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "e"
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "d",
.   "lo": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "a"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "b"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "c"
.   .   .   }
.   .   }
.   },
.   "eq": {
.   .   "val": "d"
.   },
.   "hi": {
.   .   "sym": "e",
.   .   "eq": {
.   .   .   "val": "e"
.   .   }
.   }
}
$ print e d c b a|test-trie
{
.   "sym": "e",
.   "lo": {
.   .   "sym": "d",
.   .   "lo": {
.   .   .   "sym": "c",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "a"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "b"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "c"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "d"
.   .   }
.   },
.   "eq": {
.   .   "val": "e"
.   }
}
{
.   "sym": "d",
.   "lo": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "a"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "b"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "c"
.   .   .   }
.   .   }
.   },
.   "eq": {
.   .   "val": "d"
.   },
.   "hi": {
.   .   "sym": "e",
.   .   "eq": {
.   .   .   "val": "e"
.   .   }
.   }
}
$ print d b c a e|test-trie -u
{
.   "sym": "d",
.   "lo": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "a"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "b"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "c"
.   .   .   }
.   .   }
.   },
.   "eq": {
.   .   "val": "d"
.   },
.   "hi": {
.   .   "sym": "e",
.   .   "eq": {
.   .   .   "val": "e"
.   .   }
.   }
}
$ print x xa|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "val": "x",
.   .   "hi": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xa"
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "a",
.   .   "lo": {
.   .   .   "val": "x"
.   .   },
.   .   "eq": {
.   .   .   "val": "xa"
.   .   }
.   }
}
$ print xa x|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "a",
.   .   "lo": {
.   .   .   "val": "x"
.   .   },
.   .   "eq": {
.   .   .   "val": "xa"
.   .   }
.   }
}
$ print xa xb|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "xa"
.   .   },
.   .   "hi": {
.   .   .   "sym": "b",
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xa"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xb"
.   .   }
.   }
}
$ print xb xa|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xa"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xb"
.   .   }
.   }
}
$ print xa xb xc|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "xa"
.   .   },
.   .   "hi": {
.   .   .   "sym": "b",
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xa"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xb"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "xc"
.   .   .   }
.   .   }
.   }
}
$ print xc xb xa|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "c",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xc"
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xa"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xb"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "xc"
.   .   .   }
.   .   }
.   }
}
$ print xb xa xc|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xa"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xb"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "xc"
.   .   .   }
.   .   }
.   }
}
$ print xa xb xc xd|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "xa"
.   .   },
.   .   "hi": {
.   .   .   "sym": "b",
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "d",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xd"
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "c",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xc"
.   .   },
.   .   "hi": {
.   .   .   "sym": "d",
.   .   .   "eq": {
.   .   .   .   "val": "xd"
.   .   .   }
.   .   }
.   }
}
$ print xd xc xb xa|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "d",
.   .   "lo": {
.   .   .   "sym": "c",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xa"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xb"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xc"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xd"
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "c",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xc"
.   .   },
.   .   "hi": {
.   .   .   "sym": "d",
.   .   .   "eq": {
.   .   .   .   "val": "xd"
.   .   .   }
.   .   }
.   }
}
$ print xc xb xa xd|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "c",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xc"
.   .   },
.   .   "hi": {
.   .   .   "sym": "d",
.   .   .   "eq": {
.   .   .   .   "val": "xd"
.   .   .   }
.   .   }
.   }
}
$ print xa xb xc xd xe|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "xa"
.   .   },
.   .   "hi": {
.   .   .   "sym": "b",
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "d",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xd"
.   .   .   .   .   },
.   .   .   .   .   "hi": {
.   .   .   .   .   .   "sym": "e",
.   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   "val": "xe"
.   .   .   .   .   .   }
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "d",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xd"
.   .   },
.   .   "hi": {
.   .   .   "sym": "e",
.   .   .   "eq": {
.   .   .   .   "val": "xe"
.   .   .   }
.   .   }
.   }
}
$ print xe xd xc xb xa|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "e",
.   .   "lo": {
.   .   .   "sym": "d",
.   .   .   "lo": {
.   .   .   .   "sym": "c",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "b",
.   .   .   .   .   "lo": {
.   .   .   .   .   .   "sym": "a",
.   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   "val": "xa"
.   .   .   .   .   .   }
.   .   .   .   .   },
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xb"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xd"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xe"
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "d",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xd"
.   .   },
.   .   "hi": {
.   .   .   "sym": "e",
.   .   .   "eq": {
.   .   .   .   "val": "xe"
.   .   .   }
.   .   }
.   }
}
$ print xd xb xc xa xe|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "d",
.   .   "lo": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "xd"
.   .   },
.   .   "hi": {
.   .   .   "sym": "e",
.   .   .   "eq": {
.   .   .   .   "val": "xe"
.   .   .   }
.   .   }
.   }
}
$ print xy xya|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "val": "xy",
.   .   .   "hi": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xya"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "a",
.   .   .   "lo": {
.   .   .   .   "val": "xy"
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xya"
.   .   .   }
.   .   }
.   }
}
$ print xya xy|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "a",
.   .   .   "lo": {
.   .   .   .   "val": "xy"
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xya"
.   .   .   }
.   .   }
.   }
}
$ print xya xyb|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xya"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "b",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xya"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyb"
.   .   .   }
.   .   }
.   }
}
$ print xyb xya|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xya"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyb"
.   .   .   }
.   .   }
.   }
}
$ print xya xyb xyc|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xya"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "b",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyc"
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xya"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyc"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xyc xyb xya|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "c",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xya"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyc"
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xya"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyc"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xyb xya xyc|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xya"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyc"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xya xyb xyc xyd|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xya"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "b",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyc"
.   .   .   .   .   },
.   .   .   .   .   "hi": {
.   .   .   .   .   .   "sym": "d",
.   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   "val": "xyd"
.   .   .   .   .   .   }
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "c",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xya"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyc"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "d",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyd"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xyd xyc xyb xya|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "d",
.   .   .   "lo": {
.   .   .   .   "sym": "c",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "b",
.   .   .   .   .   "lo": {
.   .   .   .   .   .   "sym": "a",
.   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   "val": "xya"
.   .   .   .   .   .   }
.   .   .   .   .   },
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyb"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyc"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyd"
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "c",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xya"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyc"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "d",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyd"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xyc xyb xya xyd|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "c",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xya"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyc"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "d",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyd"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xya xyb xyc xyd xye|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "xya"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "b",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyc"
.   .   .   .   .   },
.   .   .   .   .   "hi": {
.   .   .   .   .   .   "sym": "d",
.   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   "val": "xyd"
.   .   .   .   .   .   },
.   .   .   .   .   .   "hi": {
.   .   .   .   .   .   .   "sym": "e",
.   .   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   .   "val": "xye"
.   .   .   .   .   .   .   }
.   .   .   .   .   .   }
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "d",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xya"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyc"
.   .   .   .   .   }
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyd"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "e",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xye"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xye xyd xyc xyb xya|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "e",
.   .   .   "lo": {
.   .   .   .   "sym": "d",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "lo": {
.   .   .   .   .   .   "sym": "b",
.   .   .   .   .   .   "lo": {
.   .   .   .   .   .   .   "sym": "a",
.   .   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   .   "val": "xya"
.   .   .   .   .   .   .   }
.   .   .   .   .   .   },
.   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   "val": "xyb"
.   .   .   .   .   .   }
.   .   .   .   .   },
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyc"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyd"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xye"
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "d",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xya"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyc"
.   .   .   .   .   }
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyd"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "e",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xye"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xyd xyb xyc xya xye|test-trie -u
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "d",
.   .   .   "lo": {
.   .   .   .   "sym": "b",
.   .   .   .   "lo": {
.   .   .   .   .   "sym": "a",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xya"
.   .   .   .   .   }
.   .   .   .   },
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xyb"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "xyc"
.   .   .   .   .   }
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xyd"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "e",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xye"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print xa xb xc ya yb yc za zb zc|test-trie
{
.   "sym": "x",
.   "eq": {
.   .   "sym": "a",
.   .   "eq": {
.   .   .   "val": "xa"
.   .   },
.   .   "hi": {
.   .   .   "sym": "b",
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   }
.   .   }
.   },
.   "hi": {
.   .   "sym": "y",
.   .   "eq": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "ya"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "b",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "yb"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "c",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "yc"
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   },
.   .   "hi": {
.   .   .   "sym": "z",
.   .   .   "eq": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "za"
.   .   .   .   },
.   .   .   .   "hi": {
.   .   .   .   .   "sym": "b",
.   .   .   .   .   "eq": {
.   .   .   .   .   .   "val": "zb"
.   .   .   .   .   },
.   .   .   .   .   "hi": {
.   .   .   .   .   .   "sym": "c",
.   .   .   .   .   .   "eq": {
.   .   .   .   .   .   .   "val": "zc"
.   .   .   .   .   .   }
.   .   .   .   .   }
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
{
.   "sym": "y",
.   "lo": {
.   .   "sym": "x",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   }
.   .   }
.   },
.   "eq": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "ya"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "yb"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "yc"
.   .   .   }
.   .   }
.   },
.   "hi": {
.   .   "sym": "z",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "za"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "zb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "zc"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$ print yb ya yc xb xa xc zb za zc|test-trie -u
{
.   "sym": "y",
.   "lo": {
.   .   "sym": "x",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xa"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "xb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "xc"
.   .   .   .   }
.   .   .   }
.   .   }
.   },
.   "eq": {
.   .   "sym": "b",
.   .   "lo": {
.   .   .   "sym": "a",
.   .   .   "eq": {
.   .   .   .   "val": "ya"
.   .   .   }
.   .   },
.   .   "eq": {
.   .   .   "val": "yb"
.   .   },
.   .   "hi": {
.   .   .   "sym": "c",
.   .   .   "eq": {
.   .   .   .   "val": "yc"
.   .   .   }
.   .   }
.   },
.   "hi": {
.   .   "sym": "z",
.   .   "eq": {
.   .   .   "sym": "b",
.   .   .   "lo": {
.   .   .   .   "sym": "a",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "za"
.   .   .   .   }
.   .   .   },
.   .   .   "eq": {
.   .   .   .   "val": "zb"
.   .   .   },
.   .   .   "hi": {
.   .   .   .   "sym": "c",
.   .   .   .   "eq": {
.   .   .   .   .   "val": "zc"
.   .   .   .   }
.   .   .   }
.   .   }
.   }
}
$

--[ rebalance2 ]----------------------------------------------------------------

$ json() { env LD_LIBRARY_PATH=../lib ../src/json --no-error "$@" || return 0; }
$ test-trie() { ../lib/test-trie -R|sed -nr '2{s/,?"(lo|hi)":null//g;p;q}'|json -Po; }
$ test-shuf() { diff -u100 -L "$1" <(print $1|test-trie) -L "shuffed $1" <(print $1|shuf|test-trie); }
#
# # meta command:
# $ json-trie-regtest -C rebalance|ssed -nR 's/^print\s+(.*?)\s*\|\s*test-trie\s+-u\s*$/\1/p'|while read -r a; do a="$(print $a|sort|sed -n 'H;$! b;g;s/^\n//;s/\n/ /g;p')"; echo "test-shuf \"$a\""; done
#
$ test-shuf "'' a"
$ test-shuf "a b"
$ test-shuf "a b c"
$ test-shuf "a b c d"
$ test-shuf "a b c d e"
$ test-shuf "x xa"
$ test-shuf "xa xb"
$ test-shuf "xa xb xc"
$ test-shuf "xa xb xc xd"
$ test-shuf "xa xb xc xd xe"
$ test-shuf "xy xya"
$ test-shuf "xya xyb"
$ test-shuf "xya xyb xyc"
$ test-shuf "xya xyb xyc xyd"
$ test-shuf "xya xyb xyc xyd xye"
$ test-shuf "xa xb xc ya yb yc za zb zc"
$

--[ gen-code-expanded-base0 ]---------------------------------------------------

$ test-trie() { ../lib/test-trie -G --expanded-path; }
$ print a|test-trie
    if (*p ++ == 'a' &&
        *p == 0)
        return "a";
    return NULL;
$ print a ab|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
    }
    return NULL;
$ print a ab abc|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            if (*p ++ == 'c' &&
                *p == 0)
                return "abc";
        }
    }
    return NULL;
$ print a b|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
    }
    return NULL;
$ print a b abc bac abd|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
        }
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
        if (*p ++ == 'a' &&
            *p ++ == 'c' &&
            *p == 0)
            return "bac";
    }
    return NULL;
$ print a bb ba c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print a bb ba cc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p == 0)
            return "cc";
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print a bb ba cde|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e' &&
            *p == 0)
            return "cde";
    }
    return NULL;
$ print a bb ba cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e' &&
            *p ++ == 'f' &&
            *p == 0)
            return "cdef";
    }
    return NULL;
$ print a bb ba cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e' &&
            *p ++ == 'f') {
            if (*p == 0)
                return "cdef";
            if (*p ++ == 'g' &&
                *p == 0)
                return "cdefg";
        }
    }
    return NULL;
$ print a bb bac cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p ++ == 'c' &&
                *p == 0)
                return "bac";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e' &&
            *p ++ == 'f' &&
            *p == 0)
            return "cdef";
    }
    return NULL;
$ print a bbx ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print a bbx bay ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p ++ == 'y' &&
                *p == 0)
                return "bay";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print a cde cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e') {
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f' &&
                *p == 0)
                return "cdef";
        }
    }
    return NULL;
$ print a cde cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e') {
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f') {
                if (*p == 0)
                    return "cdef";
                if (*p ++ == 'g' &&
                    *p == 0)
                    return "cdefg";
            }
        }
    }
    return NULL;
$ print a cde cdef cdefgh|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e') {
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f') {
                if (*p == 0)
                    return "cdef";
                if (*p ++ == 'g' &&
                    *p ++ == 'h' &&
                    *p == 0)
                    return "cdefgh";
            }
        }
    }
    return NULL;
$ print a cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e' &&
            *p ++ == 'f') {
            if (*p == 0)
                return "cdef";
            if (*p ++ == 'g' &&
                *p == 0)
                return "cdefg";
        }
    }
    return NULL;
$ print ab|test-trie
    if (*p ++ == 'a' &&
        *p ++ == 'b' &&
        *p == 0)
        return "ab";
    return NULL;
$ print ab bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print ab bb ba cde|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'd' &&
            *p ++ == 'e' &&
            *p == 0)
            return "cde";
    }
    return NULL;
$ print ab bbx ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print ab c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print abc bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p ++ == 'c' &&
            *p == 0)
            return "abc";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print abcd abde abef|test-trie
    if (*p ++ == 'a' &&
        *p ++ == 'b') {
        switch (*p ++) {
        case 'c':
            if (*p ++ == 'd' &&
                *p == 0)
                return "abcd";
            return NULL;
        case 'd':
            if (*p ++ == 'e' &&
                *p == 0)
                return "abde";
            return NULL;
        case 'e':
            if (*p ++ == 'f' &&
                *p == 0)
                return "abef";
        }
    }
    return NULL;
$ print abg a abc ab abd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
                return NULL;
            case 'g':
                if (*p == 0)
                    return "abg";
            }
        }
    }
    return NULL;
$ print ac ab|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print aef ae abg a abc ab abd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
                return NULL;
            case 'g':
                if (*p == 0)
                    return "abg";
            }
            return NULL;
        case 'e':
            if (*p == 0)
                return "ae";
            if (*p ++ == 'f' &&
                *p == 0)
                return "aef";
        }
    }
    return NULL;
$ print cde cdef cdefgh|test-trie
    if (*p ++ == 'c' &&
        *p ++ == 'd' &&
        *p ++ == 'e') {
        if (*p == 0)
            return "cde";
        if (*p ++ == 'f') {
            if (*p == 0)
                return "cdef";
            if (*p ++ == 'g' &&
                *p ++ == 'h' &&
                *p == 0)
                return "cdefgh";
        }
    }
    return NULL;
$ print cdef cdefg|test-trie
    if (*p ++ == 'c' &&
        *p ++ == 'd' &&
        *p ++ == 'e' &&
        *p ++ == 'f') {
        if (*p == 0)
            return "cdef";
        if (*p ++ == 'g' &&
            *p == 0)
            return "cdefg";
    }
    return NULL;
$ print cdex cdfy cdgz cdhw|test-trie
    if (*p ++ == 'c' &&
        *p ++ == 'd') {
        switch (*p ++) {
        case 'e':
            if (*p ++ == 'x' &&
                *p == 0)
                return "cdex";
            return NULL;
        case 'f':
            if (*p ++ == 'y' &&
                *p == 0)
                return "cdfy";
            return NULL;
        case 'g':
            if (*p ++ == 'z' &&
                *p == 0)
                return "cdgz";
            return NULL;
        case 'h':
            if (*p ++ == 'w' &&
                *p == 0)
                return "cdhw";
        }
    }
    return NULL;
$ print ce cdex cdfy cdgz cdhw|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'd':
            switch (*p ++) {
            case 'e':
                if (*p ++ == 'x' &&
                    *p == 0)
                    return "cdex";
                return NULL;
            case 'f':
                if (*p ++ == 'y' &&
                    *p == 0)
                    return "cdfy";
                return NULL;
            case 'g':
                if (*p ++ == 'z' &&
                    *p == 0)
                    return "cdgz";
                return NULL;
            case 'h':
                if (*p ++ == 'w' &&
                    *p == 0)
                    return "cdhw";
            }
            return NULL;
        case 'e':
            if (*p == 0)
                return "ce";
        }
    }
    return NULL;
$ print pot potato pottery tattoo tempo|test-trie
    switch (*p ++) {
    case 'p':
        if (*p ++ == 'o' &&
            *p ++ == 't') {
            if (*p == 0)
                return "pot";
            switch (*p ++) {
            case 'a':
                if (*p ++ == 't' &&
                    *p ++ == 'o' &&
                    *p == 0)
                    return "potato";
                return NULL;
            case 't':
                if (*p ++ == 'e' &&
                    *p ++ == 'r' &&
                    *p ++ == 'y' &&
                    *p == 0)
                    return "pottery";
            }
        }
        return NULL;
    case 't':
        switch (*p ++) {
        case 'a':
            if (*p ++ == 't' &&
                *p ++ == 't' &&
                *p ++ == 'o' &&
                *p ++ == 'o' &&
                *p == 0)
                return "tattoo";
            return NULL;
        case 'e':
            if (*p ++ == 'm' &&
                *p ++ == 'p' &&
                *p ++ == 'o' &&
                *p == 0)
                return "tempo";
        }
    }
    return NULL;
$

--[ gen-code-expanded-base ]----------------------------------------------------

$ test-trie() { ../lib/test-trie -G --expanded-path; }
$ echo -n|test-trie
    return NULL;
$ print a|test-trie
    if (*p ++ == 'a' &&
        *p == 0)
        return "a";
    return NULL;
$ print a b|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
    }
    return NULL;
$ print a b c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print a ab abc|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            if (*p ++ == 'c' &&
                *p == 0)
                return "abc";
        }
    }
    return NULL;
$ print a ab ac|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print a ab ac ad|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            return NULL;
        case 'd':
            if (*p == 0)
                return "ad";
        }
    }
    return NULL;
$ print a abd ac|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p ++ == 'd' &&
                *p == 0)
                return "abd";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print a ab ac acd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            if (*p ++ == 'd' &&
                *p == 0)
                return "acd";
        }
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print a bb ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p ++ == 'b' &&
            *p == 0)
            return "bb";
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p ++ == 'c' &&
            *p == 0)
            return "ccc";
    }
    return NULL;
$ print abc abd acde|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            if (*p ++ == 'd' &&
                *p ++ == 'e' &&
                *p == 0)
                return "acde";
        }
    }
    return NULL;
$ print abc abd acde ac|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            if (*p ++ == 'd' &&
                *p ++ == 'e' &&
                *p == 0)
                return "acde";
        }
    }
    return NULL;
$ print abc abd acde acfg|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            switch (*p ++) {
            case 'd':
                if (*p ++ == 'e' &&
                    *p == 0)
                    return "acde";
                return NULL;
            case 'f':
                if (*p ++ == 'g' &&
                    *p == 0)
                    return "acfg";
            }
        }
    }
    return NULL;
$ print cde cfg cfgx cfgxy cfgxyz cfgxzzz|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'd':
            if (*p ++ == 'e' &&
                *p == 0)
                return "cde";
            return NULL;
        case 'f':
            if (*p ++ == 'g') {
                if (*p == 0)
                    return "cfg";
                if (*p ++ == 'x') {
                    if (*p == 0)
                        return "cfgx";
                    switch (*p ++) {
                    case 'y':
                        if (*p == 0)
                            return "cfgxy";
                        if (*p ++ == 'z' &&
                            *p == 0)
                            return "cfgxyz";
                        return NULL;
                    case 'z':
                        if (*p ++ == 'z' &&
                            *p ++ == 'z' &&
                            *p == 0)
                            return "cfgxzzz";
                    }
                }
            }
        }
    }
    return NULL;
$ print cge cfg cfgx cfgxy cfgxyz cfgxzzz|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'f':
            if (*p ++ == 'g') {
                if (*p == 0)
                    return "cfg";
                if (*p ++ == 'x') {
                    if (*p == 0)
                        return "cfgx";
                    switch (*p ++) {
                    case 'y':
                        if (*p == 0)
                            return "cfgxy";
                        if (*p ++ == 'z' &&
                            *p == 0)
                            return "cfgxyz";
                        return NULL;
                    case 'z':
                        if (*p ++ == 'z' &&
                            *p ++ == 'z' &&
                            *p == 0)
                            return "cfgxzzz";
                    }
                }
            }
            return NULL;
        case 'g':
            if (*p ++ == 'e' &&
                *p == 0)
                return "cge";
        }
    }
    return NULL;
$ print a abcd abcdefg h hijk|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (*p ++ == 'b' &&
            *p ++ == 'c' &&
            *p ++ == 'd') {
            if (*p == 0)
                return "abcd";
            if (*p ++ == 'e' &&
                *p ++ == 'f' &&
                *p ++ == 'g' &&
                *p == 0)
                return "abcdefg";
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        if (*p ++ == 'i' &&
            *p ++ == 'j' &&
            *p ++ == 'k' &&
            *p == 0)
            return "hijk";
    }
    return NULL;
$ print a abcd abcdefg abcdxyz h hijk|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (*p ++ == 'b' &&
            *p ++ == 'c' &&
            *p ++ == 'd') {
            if (*p == 0)
                return "abcd";
            switch (*p ++) {
            case 'e':
                if (*p ++ == 'f' &&
                    *p ++ == 'g' &&
                    *p == 0)
                    return "abcdefg";
                return NULL;
            case 'x':
                if (*p ++ == 'y' &&
                    *p ++ == 'z' &&
                    *p == 0)
                    return "abcdxyz";
            }
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        if (*p ++ == 'i' &&
            *p ++ == 'j' &&
            *p ++ == 'k' &&
            *p == 0)
            return "hijk";
    }
    return NULL;
$ print a abcd abcdefg abcdxyz h hijk hlm|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (*p ++ == 'b' &&
            *p ++ == 'c' &&
            *p ++ == 'd') {
            if (*p == 0)
                return "abcd";
            switch (*p ++) {
            case 'e':
                if (*p ++ == 'f' &&
                    *p ++ == 'g' &&
                    *p == 0)
                    return "abcdefg";
                return NULL;
            case 'x':
                if (*p ++ == 'y' &&
                    *p ++ == 'z' &&
                    *p == 0)
                    return "abcdxyz";
            }
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        switch (*p ++) {
        case 'i':
            if (*p ++ == 'j' &&
                *p ++ == 'k' &&
                *p == 0)
                return "hijk";
            return NULL;
        case 'l':
            if (*p ++ == 'm' &&
                *p == 0)
                return "hlm";
        }
    }
    return NULL;
$

--[ gen-code-expanded-filenames ]-----------------------------------------------

$ ../lib/test-trie -G --expanded-path < filenames.txt
    if (*p ++ == 'c' &&
        *p ++ == '+' &&
        *p ++ == '+' &&
        *p ++ == 'p' &&
        *p ++ == 'y' &&
        *p ++ == '-' &&
        *p ++ == 't' &&
        *p ++ == 'r' &&
        *p ++ == 'e' &&
        *p ++ == 'e' &&
        *p ++ == '-' &&
        *p ++ == 'd' &&
        *p ++ == 'e' &&
        *p ++ == 'm' &&
        *p ++ == 'o' &&
        *p ++ == '/') {
        switch (*p ++) {
        case '.':
            if (*p ++ == 's' &&
                *p ++ == 'r' &&
                *p ++ == 'c' &&
                *p ++ == '-') {
                switch (*p ++) {
                case 'd':
                    if (*p ++ == 'i' &&
                        *p ++ == 'r' &&
                        *p ++ == 's' &&
                        *p == 0)
                        return "c++py-tree-demo/.src-dirs";
                    return NULL;
                case 'f':
                    if (*p ++ == 'i' &&
                        *p ++ == 'l' &&
                        *p ++ == 'e' &&
                        *p ++ == 's' &&
                        *p == 0)
                        return "c++py-tree-demo/.src-files";
                }
            }
            return NULL;
        case 'b':
            if (*p ++ == 'i' &&
                *p ++ == 'n' &&
                *p ++ == '.' &&
                *p ++ == 'p' &&
                *p ++ == 'a' &&
                *p ++ == 't' &&
                *p ++ == 'c' &&
                *p ++ == 'h' &&
                *p == 0)
                return "c++py-tree-demo/bin.patch";
            return NULL;
        case 'c':
            if (*p ++ == '+' &&
                *p ++ == '+' &&
                *p ++ == 'p' &&
                *p ++ == 'y') {
                switch (*p ++) {
                case '-':
                    if (*p ++ == 't' &&
                        *p ++ == 'r' &&
                        *p ++ == 'e' &&
                        *p ++ == 'e') {
                        switch (*p ++) {
                        case '-':
                            switch (*p ++) {
                            case 'a':
                                if (*p ++ == 'u' &&
                                    *p ++ == 't' &&
                                    *p ++ == 'h' &&
                                    *p ++ == 'o' &&
                                    *p ++ == 'r' &&
                                    *p ++ == '.' &&
                                    *p ++ == 't' &&
                                    *p ++ == 'x' &&
                                    *p ++ == 't' &&
                                    *p == 0)
                                    return "c++py-tree-demo/c++py-tree-author.txt";
                                return NULL;
                            case 'd':
                                if (*p ++ == 'e' &&
                                    *p ++ == 'm' &&
                                    *p ++ == 'o' &&
                                    *p ++ == '.' &&
                                    *p ++ == 't' &&
                                    *p ++ == 'x' &&
                                    *p ++ == 't' &&
                                    *p == 0)
                                    return "c++py-tree-demo/c++py-tree-demo.txt";
                                return NULL;
                            case 'r':
                                if (*p ++ == 'e' &&
                                    *p ++ == 'a' &&
                                    *p ++ == 'd' &&
                                    *p ++ == 'm' &&
                                    *p ++ == 'e' &&
                                    *p ++ == '.') {
                                    switch (*p ++) {
                                    case 'p':
                                        if (*p ++ == 'd' &&
                                            *p ++ == 'f' &&
                                            *p == 0)
                                            return "c++py-tree-demo/c++py-tree-readme.pdf";
                                        return NULL;
                                    case 't':
                                        switch (*p ++) {
                                        case 'e':
                                            if (*p ++ == 'x' &&
                                                *p == 0)
                                                return "c++py-tree-demo/c++py-tree-readme.tex";
                                            return NULL;
                                        case 'x':
                                            if (*p ++ == 't' &&
                                                *p == 0)
                                                return "c++py-tree-demo/c++py-tree-readme.txt";
                                        }
                                    }
                                }
                            }
                            return NULL;
                        case '.':
                            switch (*p ++) {
                            case 'p':
                                if (*p ++ == 'd' &&
                                    *p ++ == 'f' &&
                                    *p == 0)
                                    return "c++py-tree-demo/c++py-tree.pdf";
                                return NULL;
                            case 't':
                                switch (*p ++) {
                                case 'e':
                                    if (*p ++ == 'x' &&
                                        *p == 0)
                                        return "c++py-tree-demo/c++py-tree.tex";
                                    return NULL;
                                case 'x':
                                    if (*p ++ == 't' &&
                                        *p == 0)
                                        return "c++py-tree-demo/c++py-tree.txt";
                                }
                            }
                        }
                    }
                    return NULL;
                case '/':
                    switch (*p ++) {
                    case '.':
                        if (*p ++ == 's' &&
                            *p ++ == 'r' &&
                            *p ++ == 'c' &&
                            *p ++ == '-') {
                            switch (*p ++) {
                            case 'd':
                                if (*p ++ == 'i' &&
                                    *p ++ == 'r' &&
                                    *p ++ == 's' &&
                                    *p == 0)
                                    return "c++py-tree-demo/c++py/.src-dirs";
                                return NULL;
                            case 'f':
                                if (*p ++ == 'i' &&
                                    *p ++ == 'l' &&
                                    *p ++ == 'e' &&
                                    *p ++ == 's' &&
                                    *p == 0)
                                    return "c++py-tree-demo/c++py/.src-files";
                            }
                        }
                        return NULL;
                    case 'A':
                        if (*p ++ == 'U' &&
                            *p ++ == 'T' &&
                            *p ++ == 'H' &&
                            *p ++ == 'O' &&
                            *p ++ == 'R' &&
                            *p == 0)
                            return "c++py-tree-demo/c++py/AUTHOR";
                        return NULL;
                    case 'M':
                        if (*p ++ == 'a' &&
                            *p ++ == 'k' &&
                            *p ++ == 'e' &&
                            *p ++ == 'f' &&
                            *p ++ == 'i' &&
                            *p ++ == 'l' &&
                            *p ++ == 'e' &&
                            *p == 0)
                            return "c++py-tree-demo/c++py/Makefile";
                        return NULL;
                    case 'R':
                        if (*p ++ == 'E' &&
                            *p ++ == 'A' &&
                            *p ++ == 'D' &&
                            *p ++ == 'M' &&
                            *p ++ == 'E' &&
                            *p == 0)
                            return "c++py-tree-demo/c++py/README";
                    }
                }
            }
        }
    }
    return NULL;
$

--[ gen-code-function-base0 ]---------------------------------------------------

$ test-trie() { ../lib/test-trie -G --no-expanded-path; }
$ print a|test-trie
    if (*p ++ == 'a' &&
        *p == 0)
        return "a";
    return NULL;
$ print a ab|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
    }
    return NULL;
$ print a ab abc|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            if (*p ++ == 'c' &&
                *p == 0)
                return "abc";
        }
    }
    return NULL;
$ print a b|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
    }
    return NULL;
$ print a b abc bac abd|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
        }
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
        if (equal(p, "ac"))
            return "bac";
    }
    return NULL;
$ print a bb ba c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print a bb ba cc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p == 0)
            return "cc";
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bb ba cde|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "de"))
            return "cde";
    }
    return NULL;
$ print a bb ba cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "def"))
            return "cdef";
    }
    return NULL;
$ print a bb ba cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (prefix("def", p)) {
            p += 3;
            if (*p == 0)
                return "cdef";
            if (*p ++ == 'g' &&
                *p == 0)
                return "cdefg";
        }
    }
    return NULL;
$ print a bb bac cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p ++ == 'c' &&
                *p == 0)
                return "bac";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "def"))
            return "cdef";
    }
    return NULL;
$ print a bbx ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bbx bay ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p ++ == 'y' &&
                *p == 0)
                return "bay";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a cde cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("de", p)) {
            p += 2;
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f' &&
                *p == 0)
                return "cdef";
        }
    }
    return NULL;
$ print a cde cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("de", p)) {
            p += 2;
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f') {
                if (*p == 0)
                    return "cdef";
                if (*p ++ == 'g' &&
                    *p == 0)
                    return "cdefg";
            }
        }
    }
    return NULL;
$ print a cde cdef cdefgh|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("de", p)) {
            p += 2;
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f') {
                if (*p == 0)
                    return "cdef";
                if (equal(p, "gh"))
                    return "cdefgh";
            }
        }
    }
    return NULL;
$ print a cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("def", p)) {
            p += 3;
            if (*p == 0)
                return "cdef";
            if (*p ++ == 'g' &&
                *p == 0)
                return "cdefg";
        }
    }
    return NULL;
$ print ab|test-trie
    if (equal(p, "ab"))
        return "ab";
    return NULL;
$ print ab bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print ab bb ba cde|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "de"))
            return "cde";
    }
    return NULL;
$ print ab bbx ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print ab c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print abc bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (equal(p, "bc"))
            return "abc";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print abcd abde abef|test-trie
    if (prefix("ab", p)) {
        p += 2;
        switch (*p ++) {
        case 'c':
            if (*p ++ == 'd' &&
                *p == 0)
                return "abcd";
            return NULL;
        case 'd':
            if (*p ++ == 'e' &&
                *p == 0)
                return "abde";
            return NULL;
        case 'e':
            if (*p ++ == 'f' &&
                *p == 0)
                return "abef";
        }
    }
    return NULL;
$ print abg a abc ab abd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
                return NULL;
            case 'g':
                if (*p == 0)
                    return "abg";
            }
        }
    }
    return NULL;
$ print ac ab|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print aef ae abg a abc ab abd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
                return NULL;
            case 'g':
                if (*p == 0)
                    return "abg";
            }
            return NULL;
        case 'e':
            if (*p == 0)
                return "ae";
            if (*p ++ == 'f' &&
                *p == 0)
                return "aef";
        }
    }
    return NULL;
$ print cde cdef cdefgh|test-trie
    if (prefix("cde", p)) {
        p += 3;
        if (*p == 0)
            return "cde";
        if (*p ++ == 'f') {
            if (*p == 0)
                return "cdef";
            if (equal(p, "gh"))
                return "cdefgh";
        }
    }
    return NULL;
$ print cdef cdefg|test-trie
    if (prefix("cdef", p)) {
        p += 4;
        if (*p == 0)
            return "cdef";
        if (*p ++ == 'g' &&
            *p == 0)
            return "cdefg";
    }
    return NULL;
$ print cdex cdfy cdgz cdhw|test-trie
    if (prefix("cd", p)) {
        p += 2;
        switch (*p ++) {
        case 'e':
            if (*p ++ == 'x' &&
                *p == 0)
                return "cdex";
            return NULL;
        case 'f':
            if (*p ++ == 'y' &&
                *p == 0)
                return "cdfy";
            return NULL;
        case 'g':
            if (*p ++ == 'z' &&
                *p == 0)
                return "cdgz";
            return NULL;
        case 'h':
            if (*p ++ == 'w' &&
                *p == 0)
                return "cdhw";
        }
    }
    return NULL;
$ print ce cdex cdfy cdgz cdhw|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'd':
            switch (*p ++) {
            case 'e':
                if (*p ++ == 'x' &&
                    *p == 0)
                    return "cdex";
                return NULL;
            case 'f':
                if (*p ++ == 'y' &&
                    *p == 0)
                    return "cdfy";
                return NULL;
            case 'g':
                if (*p ++ == 'z' &&
                    *p == 0)
                    return "cdgz";
                return NULL;
            case 'h':
                if (*p ++ == 'w' &&
                    *p == 0)
                    return "cdhw";
            }
            return NULL;
        case 'e':
            if (*p == 0)
                return "ce";
        }
    }
    return NULL;
$ print pot potato pottery tattoo tempo|test-trie
    switch (*p ++) {
    case 'p':
        if (prefix("ot", p)) {
            p += 2;
            if (*p == 0)
                return "pot";
            switch (*p ++) {
            case 'a':
                if (equal(p, "to"))
                    return "potato";
                return NULL;
            case 't':
                if (equal(p, "ery"))
                    return "pottery";
            }
        }
        return NULL;
    case 't':
        switch (*p ++) {
        case 'a':
            if (equal(p, "ttoo"))
                return "tattoo";
            return NULL;
        case 'e':
            if (equal(p, "mpo"))
                return "tempo";
        }
    }
    return NULL;
$

--[ gen-code-function-base ]----------------------------------------------------

$ test-trie() { ../lib/test-trie -G --no-expanded-path; }
$ echo -n|test-trie
    return NULL;
$ print a|test-trie
    if (*p ++ == 'a' &&
        *p == 0)
        return "a";
    return NULL;
$ print a b|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
    }
    return NULL;
$ print a b c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print a ab abc|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            if (*p ++ == 'c' &&
                *p == 0)
                return "abc";
        }
    }
    return NULL;
$ print a ab ac|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print a ab ac ad|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            return NULL;
        case 'd':
            if (*p == 0)
                return "ad";
        }
    }
    return NULL;
$ print a abd ac|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p ++ == 'd' &&
                *p == 0)
                return "abd";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print a ab ac acd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            if (*p ++ == 'd' &&
                *p == 0)
                return "acd";
        }
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bb ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p ++ == 'b' &&
            *p == 0)
            return "bb";
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (equal(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print abc abd acde|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            if (equal(p, "de"))
                return "acde";
        }
    }
    return NULL;
$ print abc abd acde ac|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            if (equal(p, "de"))
                return "acde";
        }
    }
    return NULL;
$ print abc abd acde acfg|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            switch (*p ++) {
            case 'd':
                if (*p ++ == 'e' &&
                    *p == 0)
                    return "acde";
                return NULL;
            case 'f':
                if (*p ++ == 'g' &&
                    *p == 0)
                    return "acfg";
            }
        }
    }
    return NULL;
$ print cde cfg cfgx cfgxy cfgxyz cfgxzzz|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'd':
            if (*p ++ == 'e' &&
                *p == 0)
                return "cde";
            return NULL;
        case 'f':
            if (*p ++ == 'g') {
                if (*p == 0)
                    return "cfg";
                if (*p ++ == 'x') {
                    if (*p == 0)
                        return "cfgx";
                    switch (*p ++) {
                    case 'y':
                        if (*p == 0)
                            return "cfgxy";
                        if (*p ++ == 'z' &&
                            *p == 0)
                            return "cfgxyz";
                        return NULL;
                    case 'z':
                        if (equal(p, "zz"))
                            return "cfgxzzz";
                    }
                }
            }
        }
    }
    return NULL;
$ print cge cfg cfgx cfgxy cfgxyz cfgxzzz|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'f':
            if (*p ++ == 'g') {
                if (*p == 0)
                    return "cfg";
                if (*p ++ == 'x') {
                    if (*p == 0)
                        return "cfgx";
                    switch (*p ++) {
                    case 'y':
                        if (*p == 0)
                            return "cfgxy";
                        if (*p ++ == 'z' &&
                            *p == 0)
                            return "cfgxyz";
                        return NULL;
                    case 'z':
                        if (equal(p, "zz"))
                            return "cfgxzzz";
                    }
                }
            }
            return NULL;
        case 'g':
            if (*p ++ == 'e' &&
                *p == 0)
                return "cge";
        }
    }
    return NULL;
$ print a abcd abcdefg h hijk|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (prefix("bcd", p)) {
            p += 3;
            if (*p == 0)
                return "abcd";
            if (equal(p, "efg"))
                return "abcdefg";
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        if (equal(p, "ijk"))
            return "hijk";
    }
    return NULL;
$ print a abcd abcdefg abcdxyz h hijk|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (prefix("bcd", p)) {
            p += 3;
            if (*p == 0)
                return "abcd";
            switch (*p ++) {
            case 'e':
                if (equal(p, "fg"))
                    return "abcdefg";
                return NULL;
            case 'x':
                if (equal(p, "yz"))
                    return "abcdxyz";
            }
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        if (equal(p, "ijk"))
            return "hijk";
    }
    return NULL;
$ print a abcd abcdefg abcdxyz h hijk hlm|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (prefix("bcd", p)) {
            p += 3;
            if (*p == 0)
                return "abcd";
            switch (*p ++) {
            case 'e':
                if (equal(p, "fg"))
                    return "abcdefg";
                return NULL;
            case 'x':
                if (equal(p, "yz"))
                    return "abcdxyz";
            }
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        switch (*p ++) {
        case 'i':
            if (equal(p, "jk"))
                return "hijk";
            return NULL;
        case 'l':
            if (*p ++ == 'm' &&
                *p == 0)
                return "hlm";
        }
    }
    return NULL;
$

--[ gen-code-function-filenames ]-----------------------------------------------

$ ../lib/test-trie -G --no-expanded-path < filenames.txt
    if (prefix("c++py-tree-demo/", p)) {
        p += 16;
        switch (*p ++) {
        case '.':
            if (prefix("src-", p)) {
                p += 4;
                switch (*p ++) {
                case 'd':
                    if (equal(p, "irs"))
                        return "c++py-tree-demo/.src-dirs";
                    return NULL;
                case 'f':
                    if (equal(p, "iles"))
                        return "c++py-tree-demo/.src-files";
                }
            }
            return NULL;
        case 'b':
            if (equal(p, "in.patch"))
                return "c++py-tree-demo/bin.patch";
            return NULL;
        case 'c':
            if (prefix("++py", p)) {
                p += 4;
                switch (*p ++) {
                case '-':
                    if (prefix("tree", p)) {
                        p += 4;
                        switch (*p ++) {
                        case '-':
                            switch (*p ++) {
                            case 'a':
                                if (equal(p, "uthor.txt"))
                                    return "c++py-tree-demo/c++py-tree-author.txt";
                                return NULL;
                            case 'd':
                                if (equal(p, "emo.txt"))
                                    return "c++py-tree-demo/c++py-tree-demo.txt";
                                return NULL;
                            case 'r':
                                if (prefix("eadme.", p)) {
                                    p += 6;
                                    switch (*p ++) {
                                    case 'p':
                                        if (equal(p, "df"))
                                            return "c++py-tree-demo/c++py-tree-readme.pdf";
                                        return NULL;
                                    case 't':
                                        switch (*p ++) {
                                        case 'e':
                                            if (*p ++ == 'x' &&
                                                *p == 0)
                                                return "c++py-tree-demo/c++py-tree-readme.tex";
                                            return NULL;
                                        case 'x':
                                            if (*p ++ == 't' &&
                                                *p == 0)
                                                return "c++py-tree-demo/c++py-tree-readme.txt";
                                        }
                                    }
                                }
                            }
                            return NULL;
                        case '.':
                            switch (*p ++) {
                            case 'p':
                                if (equal(p, "df"))
                                    return "c++py-tree-demo/c++py-tree.pdf";
                                return NULL;
                            case 't':
                                switch (*p ++) {
                                case 'e':
                                    if (*p ++ == 'x' &&
                                        *p == 0)
                                        return "c++py-tree-demo/c++py-tree.tex";
                                    return NULL;
                                case 'x':
                                    if (*p ++ == 't' &&
                                        *p == 0)
                                        return "c++py-tree-demo/c++py-tree.txt";
                                }
                            }
                        }
                    }
                    return NULL;
                case '/':
                    switch (*p ++) {
                    case '.':
                        if (prefix("src-", p)) {
                            p += 4;
                            switch (*p ++) {
                            case 'd':
                                if (equal(p, "irs"))
                                    return "c++py-tree-demo/c++py/.src-dirs";
                                return NULL;
                            case 'f':
                                if (equal(p, "iles"))
                                    return "c++py-tree-demo/c++py/.src-files";
                            }
                        }
                        return NULL;
                    case 'A':
                        if (equal(p, "UTHOR"))
                            return "c++py-tree-demo/c++py/AUTHOR";
                        return NULL;
                    case 'M':
                        if (equal(p, "akefile"))
                            return "c++py-tree-demo/c++py/Makefile";
                        return NULL;
                    case 'R':
                        if (equal(p, "EADME"))
                            return "c++py-tree-demo/c++py/README";
                    }
                }
            }
        }
    }
    return NULL;
$

--[ gen-code-function-strcmp-base0 ]--------------------------------------------

$ test-trie() { ../lib/test-trie -G --no-expanded-path --strcmp-func; }
$ print a|test-trie
    if (*p ++ == 'a' &&
        *p == 0)
        return "a";
    return NULL;
$ print a ab|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
    }
    return NULL;
$ print a ab abc|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            if (*p ++ == 'c' &&
                *p == 0)
                return "abc";
        }
    }
    return NULL;
$ print a b|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
    }
    return NULL;
$ print a b abc bac abd|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
        }
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
        if (!strcmp(p, "ac"))
            return "bac";
    }
    return NULL;
$ print a bb ba c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print a bb ba cc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (*p ++ == 'c' &&
            *p == 0)
            return "cc";
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bb ba cde|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "de"))
            return "cde";
    }
    return NULL;
$ print a bb ba cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "def"))
            return "cdef";
    }
    return NULL;
$ print a bb ba cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (prefix("def", p)) {
            p += 3;
            if (*p == 0)
                return "cdef";
            if (*p ++ == 'g' &&
                *p == 0)
                return "cdefg";
        }
    }
    return NULL;
$ print a bb bac cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p ++ == 'c' &&
                *p == 0)
                return "bac";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "def"))
            return "cdef";
    }
    return NULL;
$ print a bbx ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bbx bay ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p ++ == 'y' &&
                *p == 0)
                return "bay";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a cde cdef|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("de", p)) {
            p += 2;
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f' &&
                *p == 0)
                return "cdef";
        }
    }
    return NULL;
$ print a cde cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("de", p)) {
            p += 2;
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f') {
                if (*p == 0)
                    return "cdef";
                if (*p ++ == 'g' &&
                    *p == 0)
                    return "cdefg";
            }
        }
    }
    return NULL;
$ print a cde cdef cdefgh|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("de", p)) {
            p += 2;
            if (*p == 0)
                return "cde";
            if (*p ++ == 'f') {
                if (*p == 0)
                    return "cdef";
                if (!strcmp(p, "gh"))
                    return "cdefgh";
            }
        }
    }
    return NULL;
$ print a cdef cdefg|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'c':
        if (prefix("def", p)) {
            p += 3;
            if (*p == 0)
                return "cdef";
            if (*p ++ == 'g' &&
                *p == 0)
                return "cdefg";
        }
    }
    return NULL;
$ print ab|test-trie
    if (!strcmp(p, "ab"))
        return "ab";
    return NULL;
$ print ab bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print ab bb ba cde|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "de"))
            return "cde";
    }
    return NULL;
$ print ab bbx ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p ++ == 'x' &&
                *p == 0)
                return "bbx";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print ab c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p ++ == 'b' &&
            *p == 0)
            return "ab";
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print abc bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (!strcmp(p, "bc"))
            return "abc";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print abcd abde abef|test-trie
    if (prefix("ab", p)) {
        p += 2;
        switch (*p ++) {
        case 'c':
            if (*p ++ == 'd' &&
                *p == 0)
                return "abcd";
            return NULL;
        case 'd':
            if (*p ++ == 'e' &&
                *p == 0)
                return "abde";
            return NULL;
        case 'e':
            if (*p ++ == 'f' &&
                *p == 0)
                return "abef";
        }
    }
    return NULL;
$ print abg a abc ab abd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
                return NULL;
            case 'g':
                if (*p == 0)
                    return "abg";
            }
        }
    }
    return NULL;
$ print ac ab|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print aef ae abg a abc ab abd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
                return NULL;
            case 'g':
                if (*p == 0)
                    return "abg";
            }
            return NULL;
        case 'e':
            if (*p == 0)
                return "ae";
            if (*p ++ == 'f' &&
                *p == 0)
                return "aef";
        }
    }
    return NULL;
$ print cde cdef cdefgh|test-trie
    if (prefix("cde", p)) {
        p += 3;
        if (*p == 0)
            return "cde";
        if (*p ++ == 'f') {
            if (*p == 0)
                return "cdef";
            if (!strcmp(p, "gh"))
                return "cdefgh";
        }
    }
    return NULL;
$ print cdef cdefg|test-trie
    if (prefix("cdef", p)) {
        p += 4;
        if (*p == 0)
            return "cdef";
        if (*p ++ == 'g' &&
            *p == 0)
            return "cdefg";
    }
    return NULL;
$ print cdex cdfy cdgz cdhw|test-trie
    if (prefix("cd", p)) {
        p += 2;
        switch (*p ++) {
        case 'e':
            if (*p ++ == 'x' &&
                *p == 0)
                return "cdex";
            return NULL;
        case 'f':
            if (*p ++ == 'y' &&
                *p == 0)
                return "cdfy";
            return NULL;
        case 'g':
            if (*p ++ == 'z' &&
                *p == 0)
                return "cdgz";
            return NULL;
        case 'h':
            if (*p ++ == 'w' &&
                *p == 0)
                return "cdhw";
        }
    }
    return NULL;
$ print ce cdex cdfy cdgz cdhw|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'd':
            switch (*p ++) {
            case 'e':
                if (*p ++ == 'x' &&
                    *p == 0)
                    return "cdex";
                return NULL;
            case 'f':
                if (*p ++ == 'y' &&
                    *p == 0)
                    return "cdfy";
                return NULL;
            case 'g':
                if (*p ++ == 'z' &&
                    *p == 0)
                    return "cdgz";
                return NULL;
            case 'h':
                if (*p ++ == 'w' &&
                    *p == 0)
                    return "cdhw";
            }
            return NULL;
        case 'e':
            if (*p == 0)
                return "ce";
        }
    }
    return NULL;
$ print pot potato pottery tattoo tempo|test-trie
    switch (*p ++) {
    case 'p':
        if (prefix("ot", p)) {
            p += 2;
            if (*p == 0)
                return "pot";
            switch (*p ++) {
            case 'a':
                if (!strcmp(p, "to"))
                    return "potato";
                return NULL;
            case 't':
                if (!strcmp(p, "ery"))
                    return "pottery";
            }
        }
        return NULL;
    case 't':
        switch (*p ++) {
        case 'a':
            if (!strcmp(p, "ttoo"))
                return "tattoo";
            return NULL;
        case 'e':
            if (!strcmp(p, "mpo"))
                return "tempo";
        }
    }
    return NULL;
$

--[ gen-code-function-strcmp-base ]---------------------------------------------

$ test-trie() { ../lib/test-trie -G --no-expanded-path --strcmp-func; }
$ echo -n|test-trie
    return NULL;
$ print a|test-trie
    if (*p ++ == 'a' &&
        *p == 0)
        return "a";
    return NULL;
$ print a b|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
    }
    return NULL;
$ print a b c|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p == 0)
            return "b";
        return NULL;
    case 'c':
        if (*p == 0)
            return "c";
    }
    return NULL;
$ print a ab abc|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        if (*p ++ == 'b') {
            if (*p == 0)
                return "ab";
            if (*p ++ == 'c' &&
                *p == 0)
                return "abc";
        }
    }
    return NULL;
$ print a ab ac|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print a ab ac ad|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            return NULL;
        case 'd':
            if (*p == 0)
                return "ad";
        }
    }
    return NULL;
$ print a abd ac|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p ++ == 'd' &&
                *p == 0)
                return "abd";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
        }
    }
    return NULL;
$ print a ab ac acd|test-trie
    if (*p ++ == 'a') {
        if (*p == 0)
            return "a";
        switch (*p ++) {
        case 'b':
            if (*p == 0)
                return "ab";
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            if (*p ++ == 'd' &&
                *p == 0)
                return "acd";
        }
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bb ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        if (*p ++ == 'b' &&
            *p == 0)
            return "bb";
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print a bb ba ccc|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        return NULL;
    case 'b':
        switch (*p ++) {
        case 'a':
            if (*p == 0)
                return "ba";
            return NULL;
        case 'b':
            if (*p == 0)
                return "bb";
        }
        return NULL;
    case 'c':
        if (!strcmp(p, "cc"))
            return "ccc";
    }
    return NULL;
$ print abc abd acde|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            if (!strcmp(p, "de"))
                return "acde";
        }
    }
    return NULL;
$ print abc abd acde ac|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            if (*p == 0)
                return "ac";
            if (!strcmp(p, "de"))
                return "acde";
        }
    }
    return NULL;
$ print abc abd acde acfg|test-trie
    if (*p ++ == 'a') {
        switch (*p ++) {
        case 'b':
            switch (*p ++) {
            case 'c':
                if (*p == 0)
                    return "abc";
                return NULL;
            case 'd':
                if (*p == 0)
                    return "abd";
            }
            return NULL;
        case 'c':
            switch (*p ++) {
            case 'd':
                if (*p ++ == 'e' &&
                    *p == 0)
                    return "acde";
                return NULL;
            case 'f':
                if (*p ++ == 'g' &&
                    *p == 0)
                    return "acfg";
            }
        }
    }
    return NULL;
$ print cde cfg cfgx cfgxy cfgxyz cfgxzzz|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'd':
            if (*p ++ == 'e' &&
                *p == 0)
                return "cde";
            return NULL;
        case 'f':
            if (*p ++ == 'g') {
                if (*p == 0)
                    return "cfg";
                if (*p ++ == 'x') {
                    if (*p == 0)
                        return "cfgx";
                    switch (*p ++) {
                    case 'y':
                        if (*p == 0)
                            return "cfgxy";
                        if (*p ++ == 'z' &&
                            *p == 0)
                            return "cfgxyz";
                        return NULL;
                    case 'z':
                        if (!strcmp(p, "zz"))
                            return "cfgxzzz";
                    }
                }
            }
        }
    }
    return NULL;
$ print cge cfg cfgx cfgxy cfgxyz cfgxzzz|test-trie
    if (*p ++ == 'c') {
        switch (*p ++) {
        case 'f':
            if (*p ++ == 'g') {
                if (*p == 0)
                    return "cfg";
                if (*p ++ == 'x') {
                    if (*p == 0)
                        return "cfgx";
                    switch (*p ++) {
                    case 'y':
                        if (*p == 0)
                            return "cfgxy";
                        if (*p ++ == 'z' &&
                            *p == 0)
                            return "cfgxyz";
                        return NULL;
                    case 'z':
                        if (!strcmp(p, "zz"))
                            return "cfgxzzz";
                    }
                }
            }
            return NULL;
        case 'g':
            if (*p ++ == 'e' &&
                *p == 0)
                return "cge";
        }
    }
    return NULL;
$ print a abcd abcdefg h hijk|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (prefix("bcd", p)) {
            p += 3;
            if (*p == 0)
                return "abcd";
            if (!strcmp(p, "efg"))
                return "abcdefg";
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        if (!strcmp(p, "ijk"))
            return "hijk";
    }
    return NULL;
$ print a abcd abcdefg abcdxyz h hijk|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (prefix("bcd", p)) {
            p += 3;
            if (*p == 0)
                return "abcd";
            switch (*p ++) {
            case 'e':
                if (!strcmp(p, "fg"))
                    return "abcdefg";
                return NULL;
            case 'x':
                if (!strcmp(p, "yz"))
                    return "abcdxyz";
            }
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        if (!strcmp(p, "ijk"))
            return "hijk";
    }
    return NULL;
$ print a abcd abcdefg abcdxyz h hijk hlm|test-trie
    switch (*p ++) {
    case 'a':
        if (*p == 0)
            return "a";
        if (prefix("bcd", p)) {
            p += 3;
            if (*p == 0)
                return "abcd";
            switch (*p ++) {
            case 'e':
                if (!strcmp(p, "fg"))
                    return "abcdefg";
                return NULL;
            case 'x':
                if (!strcmp(p, "yz"))
                    return "abcdxyz";
            }
        }
        return NULL;
    case 'h':
        if (*p == 0)
            return "h";
        switch (*p ++) {
        case 'i':
            if (!strcmp(p, "jk"))
                return "hijk";
            return NULL;
        case 'l':
            if (*p ++ == 'm' &&
                *p == 0)
                return "hlm";
        }
    }
    return NULL;
$

--[ gen-code-function-strcmp-filenames ]----------------------------------------

$ ../lib/test-trie -G --no-expanded-path --strcmp-func < filenames.txt
    if (prefix("c++py-tree-demo/", p)) {
        p += 16;
        switch (*p ++) {
        case '.':
            if (prefix("src-", p)) {
                p += 4;
                switch (*p ++) {
                case 'd':
                    if (!strcmp(p, "irs"))
                        return "c++py-tree-demo/.src-dirs";
                    return NULL;
                case 'f':
                    if (!strcmp(p, "iles"))
                        return "c++py-tree-demo/.src-files";
                }
            }
            return NULL;
        case 'b':
            if (!strcmp(p, "in.patch"))
                return "c++py-tree-demo/bin.patch";
            return NULL;
        case 'c':
            if (prefix("++py", p)) {
                p += 4;
                switch (*p ++) {
                case '-':
                    if (prefix("tree", p)) {
                        p += 4;
                        switch (*p ++) {
                        case '-':
                            switch (*p ++) {
                            case 'a':
                                if (!strcmp(p, "uthor.txt"))
                                    return "c++py-tree-demo/c++py-tree-author.txt";
                                return NULL;
                            case 'd':
                                if (!strcmp(p, "emo.txt"))
                                    return "c++py-tree-demo/c++py-tree-demo.txt";
                                return NULL;
                            case 'r':
                                if (prefix("eadme.", p)) {
                                    p += 6;
                                    switch (*p ++) {
                                    case 'p':
                                        if (!strcmp(p, "df"))
                                            return "c++py-tree-demo/c++py-tree-readme.pdf";
                                        return NULL;
                                    case 't':
                                        switch (*p ++) {
                                        case 'e':
                                            if (*p ++ == 'x' &&
                                                *p == 0)
                                                return "c++py-tree-demo/c++py-tree-readme.tex";
                                            return NULL;
                                        case 'x':
                                            if (*p ++ == 't' &&
                                                *p == 0)
                                                return "c++py-tree-demo/c++py-tree-readme.txt";
                                        }
                                    }
                                }
                            }
                            return NULL;
                        case '.':
                            switch (*p ++) {
                            case 'p':
                                if (!strcmp(p, "df"))
                                    return "c++py-tree-demo/c++py-tree.pdf";
                                return NULL;
                            case 't':
                                switch (*p ++) {
                                case 'e':
                                    if (*p ++ == 'x' &&
                                        *p == 0)
                                        return "c++py-tree-demo/c++py-tree.tex";
                                    return NULL;
                                case 'x':
                                    if (*p ++ == 't' &&
                                        *p == 0)
                                        return "c++py-tree-demo/c++py-tree.txt";
                                }
                            }
                        }
                    }
                    return NULL;
                case '/':
                    switch (*p ++) {
                    case '.':
                        if (prefix("src-", p)) {
                            p += 4;
                            switch (*p ++) {
                            case 'd':
                                if (!strcmp(p, "irs"))
                                    return "c++py-tree-demo/c++py/.src-dirs";
                                return NULL;
                            case 'f':
                                if (!strcmp(p, "iles"))
                                    return "c++py-tree-demo/c++py/.src-files";
                            }
                        }
                        return NULL;
                    case 'A':
                        if (!strcmp(p, "UTHOR"))
                            return "c++py-tree-demo/c++py/AUTHOR";
                        return NULL;
                    case 'M':
                        if (!strcmp(p, "akefile"))
                            return "c++py-tree-demo/c++py/Makefile";
                        return NULL;
                    case 'R':
                        if (!strcmp(p, "EADME"))
                            return "c++py-tree-demo/c++py/README";
                    }
                }
            }
        }
    }
    return NULL;
$


