Text Editor: add Python 3.10 soft keywords to `builtinfunc` list

Python 3.10 has added "soft keywords" [0] to their list of identifiers.
This patch adds these soft keywords to the list of builtin functions
that the text editor searches for when highlighting Python code.

The only soft keywords that Python 3.10 current has are: `match`,
`case`, and `_`, but more will likely be added in future versions.

Currently, the `_` soft keyword is ignored from highlighting. It is a
wildcard matching pattern when used with `case` (similar to `default`
for `switch`es in C/C++), but `_` is far more often used in other
contexts where highlighting the `_` might seem strange. For example,
ignoring elements when unpacking tuples (`_, g, _, a = color`).

This patch also updates the commented Python code for creating the list
of keywords, for convenience.

Before:

{F13012878}

After:

{F13012880}

Example from PEP-636 [1]

Note: These soft keywords are only reserved under specific contexts.
However, in order for the text editor to know when the keywords are used
in the appropriate contexts, the text editor would need a full-blown
Python grammar [2] parser. So, for now, these keywords are simply added
in along with the other keywords in order to highlight them in the text
editor.

[0]: https://docs.python.org/3/reference/lexical_analysis.html#soft-keywords
[1]: https://peps.python.org/pep-0636/#matching-specific-values
[2]: https://docs.python.org/3/reference/grammar.html

Ref D14707
This commit is contained in:
Jon Denning 2022-04-21 12:30:14 +10:00 committed by Campbell Barton
parent 5fc488559c
commit c6ed879f9a
1 changed files with 18 additions and 8 deletions

View File

@ -33,24 +33,33 @@ static int txtfmt_py_find_builtinfunc(const char *string)
int i, len;
/* list is from...
* ", ".join(['"%s"' % kw
* for kw in __import__("keyword").kwlist
* if kw not in {"False", "None", "True", "def", "class"}])
* for kw in sorted(__import__("keyword").kwlist + __import__("keyword").softkwlist)
* if kw not in {"False", "None", "True", "def", "class", "_"}])
*
* ... and for this code:
* print("\n".join(['else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;' % kw
* for kw in __import__("keyword").kwlist
* if kw not in {"False", "None", "True", "def", "class"}]))
* import keyword
* ignore = {"False", "None", "True", "def", "class", "_"}
* keywords = sorted(set(keyword.kwlist + keyword.softkwlist) - ignore)
* longest = max(len(kw) for kw in keywords)
* first = 'if (STR_LITERAL_STARTSWITH(string, "%s",%s len)) { i = len;'
* middle = '} else if (STR_LITERAL_STARTSWITH(string, "%s",%s len)) { i = len;'
* last = '} else %s { i = 0;'
* print("\n".join([(first if i==0 else middle) % (kw, ' '*(longest - len(kw)))
* for (i, kw) in enumerate(keywords)]) + "\n" +
* last % (' '*(longest-2)) + "\n" +
* "}")
*/
/* Keep aligned args for readability. */
/* clang-format off */
if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "del", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "elif", len)) { i = len;
@ -65,6 +74,7 @@ static int txtfmt_py_find_builtinfunc(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "in", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "is", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "match", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "nonlocal", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "not", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "or", len)) { i = len;