Missing/misspelled variable name recommendations

This is the equivalent of PR #1776 but for variables instead of keywords. 

I've moved some of the reusable recommendation code from `namespace.py` to `utils/match.py` in a new `FuzzyMatcher` class. Trying to balance code duplication and complexity in this refactoring was tricky, so criticism/ideas are welcome.

There are a lot of special cases for variable naming, including accessing variable indexes, accessing extended variables, and accessing nested variables. I have only partially handled these special cases - recommendations for misspellings of the base variable name will generally work, but anything more complex will not work, and the recommendations will not include the index or extended variable syntax. 

I reworded some of the missing variable error messages, just to make them subjectively sound better. For example, `Non-existing variable '%s'` is now `Variable '%s' not found`. This breaks many tests throughout `atest`, but in this PR I have not fixed those tests yet. I'll fix them if this rewording/rephrasing is approved. 

For example recommendations, please see the new test cases I've added.
One possibility to make `RecommendationFinder` API more generic would be something like this:

+ Add `__init__` that takes `normalizer` function as an argument. Should probably have `None` (i.e. no normalization) as default.
+ Change `find_recommendations` so that it:
  - accepts just a list of strings, not a mapping, as candidates,
  - automatically normalizes the given name, as well as candidates, using the `normalizer` given to `__init__`, and
  - returns matches as original candidate names, not normalized.
+ If one recommendation maps to multiple value (like in keyword recommendations), handling that is caller responsibility.

Without actually writing the code it's impossible to tell for sure does this make sense. This isn't too high priority either.