Meta: Implement code generation for CSS keyword values
This commit is contained in:
parent
9a3f2b23a1
commit
521beb5a96
4 changed files with 62 additions and 1 deletions
|
|
@ -16,5 +16,13 @@ class Type:
|
|||
return output + "\n"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Keyword:
|
||||
value: str
|
||||
|
||||
def dump(self, indent: int) -> str:
|
||||
return f"{'': >{indent}}Keyword: {self.value}\n"
|
||||
|
||||
|
||||
# https://drafts.csswg.org/css-values-4/#component-types
|
||||
ComponentValue = Union[Type]
|
||||
ComponentValue = Union[Type, Keyword]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from Utils.CSSGrammar.Parser.component_values import Keyword
|
||||
from Utils.CSSGrammar.Parser.component_values import Type
|
||||
from Utils.CSSGrammar.Parser.token import Token
|
||||
from Utils.CSSGrammar.Parser.token import TokenType
|
||||
|
|
@ -41,6 +42,9 @@ class Tokenizer:
|
|||
case "<":
|
||||
return self.consume_a_non_terminal_token()
|
||||
|
||||
if is_identifier_character(self.lexer.peek()):
|
||||
return self.consume_a_keyword_token()
|
||||
|
||||
raise SyntaxError("CSSGrammar::Tokenizer: Unexpected character")
|
||||
|
||||
def consume_custom_ident_blacklist(self) -> list[str]:
|
||||
|
|
@ -87,3 +91,10 @@ class Tokenizer:
|
|||
raise SyntaxError("CSSGrammar::Tokenizer: Expected '>'")
|
||||
|
||||
return Token.create_component_value(Type(name, custom_ident_blacklist))
|
||||
|
||||
def consume_a_keyword_token(self) -> Token:
|
||||
value = self.consume_an_identifier()
|
||||
|
||||
assert value
|
||||
|
||||
return Token.create_component_value(Keyword(value))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from typing import TextIO
|
||||
|
||||
from Utils.CSSGrammar.Parser.component_values import Keyword
|
||||
from Utils.CSSGrammar.Parser.component_values import Type
|
||||
from Utils.CSSGrammar.Parser.grammar_node import CombinatorGrammarNode
|
||||
from Utils.CSSGrammar.Parser.grammar_node import CombinatorType
|
||||
|
|
@ -7,6 +8,7 @@ from Utils.CSSGrammar.Parser.grammar_node import ComponentValueGrammarNode
|
|||
from Utils.CSSGrammar.Parser.grammar_node import GrammarNode
|
||||
from Utils.CSSGrammar.Parser.parser import parse_value_definition_grammar
|
||||
from Utils.utils import snake_casify
|
||||
from Utils.utils import title_casify
|
||||
|
||||
|
||||
def generate_css_parser_expression_for_type_component_value(out: TextIO, cpp_name: str, type: Type) -> None:
|
||||
|
|
@ -25,6 +27,11 @@ def generate_css_parser_expression_for_type_component_value(out: TextIO, cpp_nam
|
|||
out.write(f"auto {cpp_name} = parse_{type_name}_value(tokens{additional_arguments});\n")
|
||||
|
||||
|
||||
def generate_css_parser_expression_for_keyword_component_value(out: TextIO, cpp_name: str, keyword: Keyword) -> None:
|
||||
keyword_name = title_casify(keyword.value)
|
||||
out.write(f"auto {cpp_name} = parse_specific_keyword_value(tokens, Keyword::{keyword_name});\n")
|
||||
|
||||
|
||||
def generate_css_parser_expression_for_component_value_grammar_node(
|
||||
out: TextIO, cpp_name: str, grammar_node: ComponentValueGrammarNode
|
||||
) -> None:
|
||||
|
|
@ -32,6 +39,9 @@ def generate_css_parser_expression_for_component_value_grammar_node(
|
|||
case Type() as type_component_value:
|
||||
generate_css_parser_expression_for_type_component_value(out, cpp_name, type_component_value)
|
||||
return
|
||||
case Keyword() as keyword:
|
||||
generate_css_parser_expression_for_keyword_component_value(out, cpp_name, keyword)
|
||||
return
|
||||
|
||||
raise TypeError(f"Unhandled component value type: {type(grammar_node.component_value).__name__}")
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,38 @@ class TestCSSGrammarParser(unittest.TestCase):
|
|||
""",
|
||||
)
|
||||
|
||||
def test_parse_keyword(self) -> None:
|
||||
syntax = parse_value_definition_grammar("auto")
|
||||
self.assertEqual(
|
||||
syntax.dump(),
|
||||
"""ComponentValue
|
||||
Keyword: auto
|
||||
""",
|
||||
)
|
||||
|
||||
def test_parse_hyphenated_keyword(self) -> None:
|
||||
syntax = parse_value_definition_grammar("max-content")
|
||||
self.assertEqual(
|
||||
syntax.dump(),
|
||||
"""ComponentValue
|
||||
Keyword: max-content
|
||||
""",
|
||||
)
|
||||
|
||||
def test_parse_keyword_alternatives(self) -> None:
|
||||
syntax = parse_value_definition_grammar("auto | none | <length>")
|
||||
self.assertEqual(
|
||||
syntax.dump(),
|
||||
"""Combinator(Alternatives):
|
||||
ComponentValue
|
||||
Keyword: auto
|
||||
ComponentValue
|
||||
Keyword: none
|
||||
ComponentValue
|
||||
Type: length
|
||||
""",
|
||||
)
|
||||
|
||||
def test_parse_alternatives(self) -> None:
|
||||
syntax = parse_value_definition_grammar("<foo> | <bar> | <baz>")
|
||||
self.assertEqual(
|
||||
|
|
|
|||
Loading…
Reference in a new issue