parse.parse_string("a", mode=0)
"""
self.run_test(grammar_source, test_source)
+
+ def test_no_soft_keywords(self) -> None:
+ grammar_source = """
+ start: expr+ NEWLINE? ENDMARKER
+ expr: 'foo'
+ """
+ grammar = parse_string(grammar_source, GrammarParser)
+ parser_source = generate_c_parser_source(grammar)
+ assert "expect_soft_keyword" not in parser_source
+
+ def test_soft_keywords(self) -> None:
+ grammar_source = """
+ start: expr+ NEWLINE? ENDMARKER
+ expr: "foo"
+ """
+ grammar = parse_string(grammar_source, GrammarParser)
+ parser_source = generate_c_parser_source(grammar)
+ assert "expect_soft_keyword" in parser_source
+
+ def test_soft_keywords_parse(self) -> None:
+ grammar_source = """
+ start: "if" expr '+' expr NEWLINE
+ expr: NAME
+ """
+ test_source = """
+ valid_cases = ["if if + if"]
+ invalid_cases = ["if if"]
+ self.check_input_strings_for_grammar(valid_cases, invalid_cases)
+ """
+ self.run_test(grammar_source, test_source)
comment=f"token='{keyword}'",
)
+ def soft_keyword_helper(self, value: str) -> FunctionCall:
+ return FunctionCall(
+ assigned_variable="_keyword",
+ function="_PyPegen_expect_soft_keyword",
+ arguments=["p", value],
+ return_type="expr_ty",
+ nodetype=NodeTypes.NAME_TOKEN,
+ comment=f"soft_keyword='{value}'",
+ )
+
def visit_NameLeaf(self, node: NameLeaf) -> FunctionCall:
name = node.value
if name in self.non_exact_tokens:
def visit_StringLeaf(self, node: StringLeaf) -> FunctionCall:
val = ast.literal_eval(node.value)
if re.match(r"[a-zA-Z_]\w*\Z", val): # This is a keyword
- return self.keyword_helper(val)
+ if node.value.endswith("'"):
+ return self.keyword_helper(val)
+ else:
+ return self.soft_keyword_helper(node.value)
else:
assert val in self.exact_tokens, f"{node.value} is not a known literal"
type = self.exact_tokens[val]
self.print("{")
# We have parsed successfully all the conditions for the option.
with self.indent():
+ node_str = str(node).replace('"', '\\"')
self.print(
- f'D(fprintf(stderr, "%*c+ {rulename}[%d-%d]: %s succeeded!\\n", p->level, \' \', _mark, p->mark, "{node}"));'
+ f'D(fprintf(stderr, "%*c+ {rulename}[%d-%d]: %s succeeded!\\n", p->level, \' \', _mark, p->mark, "{node_str}"));'
)
# Prepare to emmit the rule action and do so
if node.action and "EXTRA" in node.action:
self.print(f"{{ // {node}")
with self.indent():
self._check_for_errors()
+ node_str = str(node).replace('"', '\\"')
self.print(
- f'D(fprintf(stderr, "%*c> {rulename}[%d-%d]: %s\\n", p->level, \' \', _mark, p->mark, "{node}"));'
+ f'D(fprintf(stderr, "%*c> {rulename}[%d-%d]: %s\\n", p->level, \' \', _mark, p->mark, "{node_str}"));'
)
# Prepare variable declarations for the alternative
vars = self.collect_vars(node)
self.handle_alt_normal(node, is_gather, rulename)
self.print("p->mark = _mark;")
+ node_str = str(node).replace('"', '\\"')
self.print(
f"D(fprintf(stderr, \"%*c%s {rulename}[%d-%d]: %s failed!\\n\", p->level, ' ',\n"
- f' p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "{node}"));'
+ f' p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "{node_str}"));'
)
if "_cut_var" in vars:
self.print("if (_cut_var) {")