Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Help/markdown/New_in_Current_Version.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ The ANSI version shares the same source code with the Unicode version, but repli

## Miscellaneous

(4.1.1) **FIXED:** in an analyzer run by [callanalyzer](callanalyzer.md), passes with `@NODES _ROOT` or `@PATH _ROOT` matched nothing, because the root they were given was the passed node under its own name. A called analyzer now gets a root of its own named `_ROOT`, holding the node's children, so it selects and traverses exactly as it does on a text of its own. **FIXED:** a word already in the knowledge base with no attributes of its own was never looked up in a lazily loaded `*full` dictionary, so it got no part of speech. Such bare words are common, because every attribute name is a dictionary word, and in a called analyzer the knowledge base is shared with the caller. They are now looked up once.

(4.1.0) **One analyzer can call another.** [callanalyzer](callanalyzer.md) runs another analyzer's passes on the subtree under a parse node, so one analyzer can be built from several separately written ones that all share a single parse tree and knowledge base. The called analyzer changes the caller's tree directly and puts its results under the concept it was given, which it gets with [callconcept](callconcept.md). It is loaded on the first call, together with its dictionaries and `.kbb` files, and stays in memory, so later calls pay nothing to load it. Its `dicttok` pass does not retokenize; it looks up the node's words, including in lazily loaded `*full` dictionaries, and gives them their dictionary attributes. Each call starts with empty `G()` variables. An analyzer cannot call itself, directly or through another analyzer. This completes what [findana](findana.md) started in 1.6.

(3.8.2) **JSON in and out as built-in functions.** [jsonwrite](jsonwrite.md) replaces the `JsonKB` family in `KBFuncs.nlp` with a built-in that produces byte-identical output. Serializing the knowledge base is where a knowledge-base analyzer spends most of its time -- on the date-time analyzer the thirteen-line output pass that calls `JsonKB` and `SaveKB` was 43.9% of total runtime -- and the built-in is about 3x faster on that pass. `JsonKB` is now a one-line wrapper, so an analyzer picks up the speedup by refreshing its copy of `KBFuncs.nlp`; newly created analyzers get it automatically. [jsonparse](jsonparse.md) is the inverse and reads a JSON document into concepts, which previously required the `json2kbb` Python library pass -- that needs Python on the machine, which the npm and pypi distributions do not provide, and it silently skips rebuilding when a stale `.kbb` is present. **FIXED:** a python pass shelled out to the literal command `python`, absent on macOS 12.3+ and most Linux distributions, and reported failure only when `system()` returned a negative value -- which never happens for command-not-found, so a failing pass was silent and its analyzer ran on with no data (3.8.1).
Expand Down
2 changes: 1 addition & 1 deletion Help/markdown/callanalyzer.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ analyzerStr - type: str

`callanalyzer` lets you build one analyzer out of several separately written analyzers, all working on the same parse tree and the same knowledge base. For example, an analyzer that finds addresses can hand each address node to an address analyzer, and an analyzer that finds sentences can hand each sentence node to a parser.

**What the called analyzer works on.** The called analyzer has no text or parse tree of its own. Its passes run on the subtree under `pnode`: its rules match `pnode`'s children the way an analyzer's rules normally match the children of the root, and `pnroot()` returns `pnode`. It changes the caller's tree directly, so any nodes it builds, renames or gives variables are still there when the call returns. It also uses the caller's knowledge base, and [callconcept](callconcept.md) returns `concept`, the concept it was given for its results. Anything it adds under that concept is in the caller's knowledge base immediately.
**What the called analyzer works on.** The called analyzer has no text or parse tree of its own. Its passes run on the subtree under `pnode`. For the length of the call it gets a root of its own, named `_ROOT`, which holds `pnode`'s children, so its passes select and traverse exactly as they do on a text of their own: `@NODES _ROOT`, `@PATH _ROOT` and `pnroot()` all refer to that root, and no pass can reach `pnode`'s siblings. When the call returns, the children, as the called analyzer left them, are back under `pnode`; variables set on the stand-in root are discarded. The called analyzer changes the caller's tree directly, so any nodes it builds, renames or gives variables are still there when the call returns. It also uses the caller's knowledge base, and [callconcept](callconcept.md) returns `concept`, the concept it was given for its results. Anything it adds under that concept is in the caller's knowledge base immediately.

**What is loaded once.** The first call builds the called analyzer's passes and reads its `kb/user` dictionary (`.dict`) and `.kbb` files into the knowledge base. Its lazily loaded `*full.dict` and `*full.kbb` files are registered with the knowledge base rather than read. The analyzer then stays in memory, so later calls read nothing again. Loading is often most of an analyzer's running time, so calling the same analyzer on hundreds of nodes costs little more than the analysis itself. Its `.kb` files are not read: they are a complete saved knowledge base, and reading one into a knowledge base that already exists would add every attribute value a second time.

Expand Down
Loading