Parser Reference¶
The ibcli parser is responsible for tab completion, abbreviation expansion, and routing each typed command to its handler function. This page explains the internals.
Overview¶
Every command is registered in the COMMANDS dict with a match-line key - a string where literal words and <special> tokens are space-separated. For example:
The parser walks a typed line left-to-right, expanding each word against the word list at the current context depth.
Abbreviation (abbrev)¶
The abbrev(words) function builds a map of every unambiguous prefix to its full word, mirroring Perl's Text::Abbrev.
Rules:
- A full word always maps to itself (e.g.,
show → show). - A prefix that is itself a full word in the list is not considered ambiguous with longer words (the full word wins).
- A prefix matching two or more distinct longer words is ambiguous and excluded from the map.
abbrev(["configure", "show", "set"])
→ {"c": "configure", "co": "configure", ..., "configure": "configure",
"sh": "show", "sho": "show", "show": "show",
"se": "set", "set": "set"}
Prefix s is ambiguous (show vs set) and therefore excluded.
expand_word¶
expand_word(inword, words) matches a single token against the word list at the current context. Returns a 4-tuple (done, sptype, expword, matches).
Priority order:
- Unique abbreviation of a literal word →
done=True,expword=<full_word>+space - Ambiguous literal prefix →
done=False,matches=[list of matching literals + any specials] - Matches a
<special>regex (only if no literal matches) →done=False,sptype=<special>,expword=inword - No match →
done=False,expword="",matches=sorted(words)
This priority order is load-bearing: a literal next-word (e.g., add) always wins over a <zone> special that would also syntactically match.
expand_line¶
expand_line(line) walks all tokens left-to-right and returns (expanded, error, match_line).
expanded- the concrete command with full words and user-supplied values, space-separated.error- an empty string on success, or an error message (ambiguous/unknown).match_line- likeexpandedbut with user-supplied values replaced by<special>tokens, used as the key intoCOMMANDS.
On an unknown word, the error format is:
where the caret is positioned at the column where the unknown token starts.
get_context¶
get_context(match_line) looks up COMMANDS[match_line].words, splits on whitespace, and expands a|b|c alternates
and key=<special> pairs by side-effect - inserting derived entries into COMMANDS on first access. This mirrors the
Perl add_context trick.
For key=<special> pairs (e.g., comment=<comment>):
commentis added as a literal word to the context.- A new
COMMANDSentry is created for<matchline> commentwithwords=<comment>. - A new
COMMANDSentry is created for<matchline> comment <comment>that inherits the parent's word list and handler.
This allows the parser to consume comment "my comment" as two tokens after the handler-level node.
SPECOPS tokens¶
Special tokens are matched by regex. Each <token> in a word list corresponds to an entry in SPECOPS:
| Token | Pattern | Matches |
|---|---|---|
<zone> |
^\S+$ |
Any non-whitespace string |
<ip> |
Partial IP pattern | 1.2.3 or 1.2.3.4 |
<n.n.n.n/mm> |
Full IP/CIDR or IPv6/prefix | 10.0.0.0/8 or 2001:db8::/32 |
<mac> |
[\w:]+ |
aa:bb:cc:dd:ee:ff or aabbccddeeff |
<name> |
^\S+$ |
Any non-whitespace string |
<value> |
^("([^"]+)"\|\S+)$ |
Any token or quoted string |
<comment> |
^("([^"]+)"\|\S+)$ |
Any token or quoted string |
<num> |
^\d+$ |
Integers only |
<cr> |
^$ |
Empty string (signals valid stop) |
<name=value> |
^\S+=\S+$ |
Bare key=value token |
</cidr> |
^/\d{1,2}$ |
Prefix suffix like /24 |
Tokenizer: key=value splitting¶
The tokenizer (_tokenize) splits bare key=value tokens on the first =, treating them as two separate tokens:
This happens for tokens that:
- Contain
= - Do not start with
< - Are not quoted
Key=value split affects parsing
Because key=value is split before matching, the <name=value> SPECOPS token never matches in practice for
user input - the tokenizer splits it first. The <name=value> token exists in SPECOPS for completeness but is
effectively unused in normal command parsing. See Known Quirks.
Quoted string handling¶
Double-quoted strings are treated as a single token by the tokenizer:
The quotes are preserved through tokenization. Handlers strip quotes from values when constructing WAPI payloads.
Alias substitution¶
Before expand_line runs, process_line applies prefix substitution for two built-in aliases:
| Alias | Replacement |
|---|---|
pwd |
show debug pwd |
info |
show debug session |
See user-guide/aliases.md for the full list and removal history.
Completer integration¶
The IbcliCompleter in completer.py uses expand_line and get_context to compute completions for prompt_toolkit:
- Call
expand_line(line_before_cursor). - If error contains "Unknown", return no completions.
- Get
lastargfrom the line. - Strip the last arg from the match_line to get the current context.
- Call
get_context(context)to get the word list. - Call
expand_word(lastarg, words)to get completions. - Yield
Completionobjects.
Complete-while-typing is disabled (complete_while_typing=False), matching the Perl tab-only behaviour.