Common functionality for GrammarSnippetDirective & CompatProductionList.
| 37 | |
| 38 | |
| 39 | class GrammarSnippetBase(SphinxDirective): |
| 40 | """Common functionality for GrammarSnippetDirective & CompatProductionList.""" |
| 41 | |
| 42 | # The option/argument handling is left to the individual classes. |
| 43 | |
| 44 | grammar_re: Final = re.compile( |
| 45 | r""" |
| 46 | (?P<rule_name>^[a-zA-Z0-9_]+) # identifier at start of line |
| 47 | (?=:) # ... followed by a colon |
| 48 | | |
| 49 | (?P<rule_ref>`[^\s`]+`) # identifier in backquotes |
| 50 | | |
| 51 | (?P<single_quoted>'[^']*') # string in 'quotes' |
| 52 | | |
| 53 | (?P<double_quoted>"[^"]*") # string in "quotes" |
| 54 | """, |
| 55 | re.VERBOSE, |
| 56 | ) |
| 57 | |
| 58 | def make_grammar_snippet( |
| 59 | self, options: dict[str, Any], content: Sequence[str] |
| 60 | ) -> list[addnodes.productionlist]: |
| 61 | """Create a literal block from options & content.""" |
| 62 | |
| 63 | group_name = options['group'] |
| 64 | node_location = self.get_location() |
| 65 | production_nodes = [] |
| 66 | for rawsource, production_defs in self.production_definitions(content): |
| 67 | production = self.make_production( |
| 68 | rawsource, |
| 69 | production_defs, |
| 70 | group_name=group_name, |
| 71 | location=node_location, |
| 72 | ) |
| 73 | production_nodes.append(production) |
| 74 | |
| 75 | node = addnodes.productionlist( |
| 76 | '', |
| 77 | *production_nodes, |
| 78 | support_smartquotes=False, |
| 79 | classes=['highlight'], |
| 80 | ) |
| 81 | self.set_source_info(node) |
| 82 | return [node] |
| 83 | |
| 84 | def production_definitions( |
| 85 | self, lines: Iterable[str], / |
| 86 | ) -> Iterator[tuple[str, list[tuple[str, str]]]]: |
| 87 | """Yield pairs of rawsource and production content dicts.""" |
| 88 | production_lines: list[str] = [] |
| 89 | production_content: list[tuple[str, str]] = [] |
| 90 | for line in lines: |
| 91 | # If this line is the start of a new rule (text in the column 1), |
| 92 | # emit the current production and start a new one. |
| 93 | if not line[:1].isspace(): |
| 94 | rawsource = '\n'.join(production_lines) |
| 95 | production_lines.clear() |
| 96 | if production_content: |
nothing calls this directly
no test coverage detected
searching dependent graphs…