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.
Assigning candidates to self is a bit ugly. Is it done to make it possible to pass `self._normalize` to `RecommendationFinder`? If yes, a better solutions would be delaying the creation of `RecommendationFinder`. I don't fully understand why `_normalize` actually needs `self.candidates` either, without them passing it to the finder would be fine.