Skip to content

Commit d55a0af

Browse files
committed
Add soft keywords
These are like keywords but they only work in context; they are not reserved except when there is an exact match. This would enable things like match statements.
1 parent c73914a commit d55a0af

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

Parser/pegen/pegen.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,30 @@ _PyPegen_expect_token(Parser *p, int type)
753753
return t;
754754
}
755755

756+
expr_ty
757+
_PyPegen_expect_soft_keyword(Parser *p, const char *keyword)
758+
{
759+
if (p->mark == p->fill) {
760+
if (_PyPegen_fill_token(p) < 0) {
761+
p->error_indicator = 1;
762+
return NULL;
763+
}
764+
}
765+
Token *t = p->tokens[p->mark];
766+
if (t->type != NAME) {
767+
return NULL;
768+
}
769+
char* s = PyBytes_AsString(t->bytes);
770+
if (!s) {
771+
return NULL;
772+
}
773+
if (strcmp(s, keyword) != 0) {
774+
return NULL;
775+
}
776+
expr_ty res = _PyPegen_name_token(p);
777+
return res;
778+
}
779+
756780
Token *
757781
_PyPegen_get_last_nonnwhitespace_token(Parser *p)
758782
{

Parser/pegen/pegen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ int _PyPegen_lookahead_with_int(int, Token *(func)(Parser *, int), Parser *, int
121121
int _PyPegen_lookahead(int, void *(func)(Parser *), Parser *);
122122

123123
Token *_PyPegen_expect_token(Parser *p, int type);
124+
expr_ty _PyPegen_expect_soft_keyword(Parser *p, const char *keyword);
124125
Token *_PyPegen_get_last_nonnwhitespace_token(Parser *);
125126
int _PyPegen_fill_token(Parser *p);
126127
expr_ty _PyPegen_name_token(Parser *p);

Tools/peg_generator/pegen/c_generator.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ def keyword_helper(self, keyword: str) -> FunctionCall:
110110
comment=f"token='{keyword}'",
111111
)
112112

113+
def soft_keyword_helper(self, value: str) -> FunctionCall:
114+
return FunctionCall(
115+
assigned_variable="_keyword",
116+
function="_PyPegen_expect_soft_keyword",
117+
arguments=["p", value],
118+
return_type="expr_ty",
119+
nodetype=NodeTypes.NAME_TOKEN,
120+
comment=f"soft_keyword='{value}'",
121+
)
122+
113123
def visit_NameLeaf(self, node: NameLeaf) -> FunctionCall:
114124
name = node.value
115125
if name in self.non_exact_tokens:
@@ -147,7 +157,10 @@ def visit_NameLeaf(self, node: NameLeaf) -> FunctionCall:
147157
def visit_StringLeaf(self, node: StringLeaf) -> FunctionCall:
148158
val = ast.literal_eval(node.value)
149159
if re.match(r"[a-zA-Z_]\w*\Z", val): # This is a keyword
150-
return self.keyword_helper(val)
160+
if node.value.endswith("'"):
161+
return self.keyword_helper(val)
162+
else:
163+
return self.soft_keyword_helper(node.value)
151164
else:
152165
assert val in self.exact_tokens, f"{node.value} is not a known literal"
153166
type = self.exact_tokens[val]

0 commit comments

Comments
 (0)