mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
parser: Simplify parser construction
- Replace several different parse nodes with Match, which matches the exact text of a token but not the token type - Allow arrays to be used in place of Sequence
This commit is contained in:
parent
ad6a2cf538
commit
8d587b62a0
11 changed files with 182 additions and 211 deletions
|
@ -155,18 +155,18 @@ a11y_prop = Group(
|
||||||
A11yProperty,
|
A11yProperty,
|
||||||
Statement(
|
Statement(
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
Op(":"),
|
":",
|
||||||
value.expected("a value"),
|
value.expected("a value"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
a11y = Group(
|
a11y = Group(
|
||||||
A11y,
|
A11y,
|
||||||
Sequence(
|
[
|
||||||
Keyword("accessibility", True),
|
Keyword("accessibility"),
|
||||||
OpenBlock(),
|
"{",
|
||||||
Until(a11y_prop, CloseBlock()),
|
Until(a11y_prop, "}"),
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,28 +52,23 @@ class Item(BaseTypedAttribute):
|
||||||
|
|
||||||
item = Group(
|
item = Group(
|
||||||
Item,
|
Item,
|
||||||
Sequence(
|
[
|
||||||
Optional(
|
Optional([
|
||||||
Sequence(
|
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
Op(":"),
|
":",
|
||||||
)
|
]),
|
||||||
),
|
|
||||||
value,
|
value,
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
items = Group(
|
items = Group(
|
||||||
Items,
|
Items,
|
||||||
Sequence(
|
[
|
||||||
Keyword("items", True),
|
Keyword("items"),
|
||||||
OpenBracket(),
|
"[",
|
||||||
Delimited(
|
Delimited(item, ","),
|
||||||
item,
|
"]",
|
||||||
Comma()
|
]
|
||||||
),
|
|
||||||
CloseBracket(),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,22 +49,22 @@ class FilterString(AstNode):
|
||||||
def create_node(tag_name: str, singular: str):
|
def create_node(tag_name: str, singular: str):
|
||||||
return Group(
|
return Group(
|
||||||
Filters,
|
Filters,
|
||||||
Sequence(
|
[
|
||||||
Keyword(tag_name, True),
|
Keyword(tag_name),
|
||||||
UseLiteral("tag_name", tag_name),
|
UseLiteral("tag_name", tag_name),
|
||||||
OpenBracket(),
|
"[",
|
||||||
Delimited(
|
Delimited(
|
||||||
Group(
|
Group(
|
||||||
FilterString,
|
FilterString,
|
||||||
Sequence(
|
[
|
||||||
UseQuoted("name"),
|
UseQuoted("name"),
|
||||||
UseLiteral("tag_name", singular),
|
UseLiteral("tag_name", singular),
|
||||||
)
|
]
|
||||||
),
|
),
|
||||||
Comma(),
|
",",
|
||||||
),
|
),
|
||||||
CloseBracket(),
|
"]",
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ layout_prop = Group(
|
||||||
LayoutProperty,
|
LayoutProperty,
|
||||||
Statement(
|
Statement(
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
Op(":"),
|
":",
|
||||||
value.expected("a value"),
|
value.expected("a value"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -61,9 +61,9 @@ layout_prop = Group(
|
||||||
layout = Group(
|
layout = Group(
|
||||||
Layout,
|
Layout,
|
||||||
Sequence(
|
Sequence(
|
||||||
Keyword("layout", True),
|
Keyword("layout"),
|
||||||
OpenBlock(),
|
"{",
|
||||||
Until(layout_prop, CloseBlock()),
|
Until(layout_prop, "}"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -51,94 +51,94 @@ menu_contents = Sequence()
|
||||||
|
|
||||||
menu_section = Group(
|
menu_section = Group(
|
||||||
Menu,
|
Menu,
|
||||||
Sequence(
|
[
|
||||||
Keyword("section"),
|
"section",
|
||||||
UseLiteral("tag", "section"),
|
UseLiteral("tag", "section"),
|
||||||
Optional(UseIdent("id")),
|
Optional(UseIdent("id")),
|
||||||
menu_contents
|
menu_contents
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_submenu = Group(
|
menu_submenu = Group(
|
||||||
Menu,
|
Menu,
|
||||||
Sequence(
|
[
|
||||||
Keyword("submenu"),
|
"submenu",
|
||||||
UseLiteral("tag", "submenu"),
|
UseLiteral("tag", "submenu"),
|
||||||
Optional(UseIdent("id")),
|
Optional(UseIdent("id")),
|
||||||
menu_contents
|
menu_contents
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_attribute = Group(
|
menu_attribute = Group(
|
||||||
MenuAttribute,
|
MenuAttribute,
|
||||||
Sequence(
|
[
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
Op(":"),
|
":",
|
||||||
value.expected("a value"),
|
value.expected("a value"),
|
||||||
StmtEnd().expected("`;`"),
|
Match(";").expected(),
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_item = Group(
|
menu_item = Group(
|
||||||
Menu,
|
Menu,
|
||||||
Sequence(
|
[
|
||||||
Keyword("item"),
|
"item",
|
||||||
UseLiteral("tag", "item"),
|
UseLiteral("tag", "item"),
|
||||||
Optional(UseIdent("id")),
|
Optional(UseIdent("id")),
|
||||||
OpenBlock().expected("`{`"),
|
Match("{").expected(),
|
||||||
Until(menu_attribute, CloseBlock()),
|
Until(menu_attribute, "}"),
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_item_shorthand = Group(
|
menu_item_shorthand = Group(
|
||||||
Menu,
|
Menu,
|
||||||
Sequence(
|
[
|
||||||
Keyword("item"),
|
"item",
|
||||||
UseLiteral("tag", "item"),
|
UseLiteral("tag", "item"),
|
||||||
OpenParen(),
|
"(",
|
||||||
Group(
|
Group(
|
||||||
MenuAttribute,
|
MenuAttribute,
|
||||||
Sequence(UseLiteral("name", "label"), value),
|
[UseLiteral("name", "label"), value],
|
||||||
),
|
),
|
||||||
Optional(Sequence(
|
Optional([
|
||||||
Comma(),
|
",",
|
||||||
Optional(Sequence(
|
Optional([
|
||||||
Group(
|
Group(
|
||||||
MenuAttribute,
|
MenuAttribute,
|
||||||
Sequence(UseLiteral("name", "action"), value),
|
[UseLiteral("name", "action"), value],
|
||||||
),
|
),
|
||||||
Optional(Sequence(
|
Optional([
|
||||||
Comma(),
|
",",
|
||||||
Group(
|
Group(
|
||||||
MenuAttribute,
|
MenuAttribute,
|
||||||
Sequence(UseLiteral("name", "icon"), value),
|
[UseLiteral("name", "icon"), value],
|
||||||
),
|
),
|
||||||
))
|
])
|
||||||
))
|
])
|
||||||
)),
|
]),
|
||||||
CloseParen().expected("')'"),
|
Match(")").expected(),
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_contents.children = [
|
menu_contents.children = [
|
||||||
OpenBlock(),
|
Match("{"),
|
||||||
Until(AnyOf(
|
Until(AnyOf(
|
||||||
menu_section,
|
menu_section,
|
||||||
menu_submenu,
|
menu_submenu,
|
||||||
menu_item_shorthand,
|
menu_item_shorthand,
|
||||||
menu_item,
|
menu_item,
|
||||||
menu_attribute,
|
menu_attribute,
|
||||||
), CloseBlock()),
|
), "}"),
|
||||||
]
|
]
|
||||||
|
|
||||||
menu = Group(
|
menu = Group(
|
||||||
Menu,
|
Menu,
|
||||||
Sequence(
|
[
|
||||||
Keyword("menu"),
|
"menu",
|
||||||
UseLiteral("tag", "menu"),
|
UseLiteral("tag", "menu"),
|
||||||
Optional(UseIdent("id")),
|
Optional(UseIdent("id")),
|
||||||
menu_contents
|
menu_contents
|
||||||
),
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,18 +60,18 @@ class Widget(AstNode):
|
||||||
|
|
||||||
widgets = Group(
|
widgets = Group(
|
||||||
Widgets,
|
Widgets,
|
||||||
Sequence(
|
[
|
||||||
Keyword("widgets", True),
|
Keyword("widgets"),
|
||||||
OpenBracket(),
|
"[",
|
||||||
Delimited(
|
Delimited(
|
||||||
Group(
|
Group(
|
||||||
Widget,
|
Widget,
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
),
|
),
|
||||||
Comma(),
|
",",
|
||||||
),
|
),
|
||||||
CloseBracket(),
|
"]",
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,15 +61,12 @@ item = Group(
|
||||||
|
|
||||||
strings = Group(
|
strings = Group(
|
||||||
Items,
|
Items,
|
||||||
Sequence(
|
[
|
||||||
Keyword("strings", True),
|
Keyword("strings"),
|
||||||
OpenBracket(),
|
"[",
|
||||||
Delimited(
|
Delimited(item, ","),
|
||||||
item,
|
"]",
|
||||||
Comma()
|
]
|
||||||
),
|
|
||||||
CloseBracket(),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,18 +46,18 @@ class StyleClass(AstNode):
|
||||||
|
|
||||||
styles = Group(
|
styles = Group(
|
||||||
Styles,
|
Styles,
|
||||||
Sequence(
|
[
|
||||||
Keyword("styles", True),
|
Keyword("styles"),
|
||||||
OpenBracket(),
|
"[",
|
||||||
Delimited(
|
Delimited(
|
||||||
Group(
|
Group(
|
||||||
StyleClass,
|
StyleClass,
|
||||||
UseQuoted("name")
|
UseQuoted("name")
|
||||||
),
|
),
|
||||||
Comma(),
|
",",
|
||||||
),
|
),
|
||||||
CloseBracket(),
|
"]",
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,7 @@ class Err(ParseNode):
|
||||||
""" ParseNode that emits a compile error if it fails to parse. """
|
""" ParseNode that emits a compile error if it fails to parse. """
|
||||||
|
|
||||||
def __init__(self, child, message):
|
def __init__(self, child, message):
|
||||||
self.child = child
|
self.child = to_parse_node(child)
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
def _parse(self, ctx):
|
def _parse(self, ctx):
|
||||||
|
@ -258,7 +258,7 @@ class Fail(ParseNode):
|
||||||
""" ParseNode that emits a compile error if it parses successfully. """
|
""" ParseNode that emits a compile error if it parses successfully. """
|
||||||
|
|
||||||
def __init__(self, child, message):
|
def __init__(self, child, message):
|
||||||
self.child = child
|
self.child = to_parse_node(child)
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
def _parse(self, ctx):
|
def _parse(self, ctx):
|
||||||
|
@ -277,7 +277,7 @@ class Group(ParseNode):
|
||||||
""" ParseNode that creates a match group. """
|
""" ParseNode that creates a match group. """
|
||||||
def __init__(self, ast_type, child):
|
def __init__(self, ast_type, child):
|
||||||
self.ast_type = ast_type
|
self.ast_type = ast_type
|
||||||
self.child = child
|
self.child = to_parse_node(child)
|
||||||
|
|
||||||
def _parse(self, ctx: ParseContext) -> bool:
|
def _parse(self, ctx: ParseContext) -> bool:
|
||||||
ctx.skip()
|
ctx.skip()
|
||||||
|
@ -288,7 +288,7 @@ class Group(ParseNode):
|
||||||
class Sequence(ParseNode):
|
class Sequence(ParseNode):
|
||||||
""" ParseNode that attempts to match all of its children in sequence. """
|
""" ParseNode that attempts to match all of its children in sequence. """
|
||||||
def __init__(self, *children):
|
def __init__(self, *children):
|
||||||
self.children = children
|
self.children = [to_parse_node(child) for child in children]
|
||||||
|
|
||||||
def _parse(self, ctx) -> bool:
|
def _parse(self, ctx) -> bool:
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
|
@ -301,7 +301,7 @@ class Statement(ParseNode):
|
||||||
""" ParseNode that attempts to match all of its children in sequence. If any
|
""" ParseNode that attempts to match all of its children in sequence. If any
|
||||||
child raises an error, the error will be logged but parsing will continue. """
|
child raises an error, the error will be logged but parsing will continue. """
|
||||||
def __init__(self, *children):
|
def __init__(self, *children):
|
||||||
self.children = children
|
self.children = [to_parse_node(child) for child in children]
|
||||||
|
|
||||||
def _parse(self, ctx) -> bool:
|
def _parse(self, ctx) -> bool:
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
|
@ -325,7 +325,7 @@ class AnyOf(ParseNode):
|
||||||
""" ParseNode that attempts to match exactly one of its children. Child
|
""" ParseNode that attempts to match exactly one of its children. Child
|
||||||
nodes are attempted in order. """
|
nodes are attempted in order. """
|
||||||
def __init__(self, *children):
|
def __init__(self, *children):
|
||||||
self.children = children
|
self.children = [to_parse_node(child) for child in children]
|
||||||
|
|
||||||
def _parse(self, ctx):
|
def _parse(self, ctx):
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
|
@ -339,8 +339,8 @@ class Until(ParseNode):
|
||||||
the child does not match, one token is skipped and the match is attempted
|
the child does not match, one token is skipped and the match is attempted
|
||||||
again. """
|
again. """
|
||||||
def __init__(self, child, delimiter):
|
def __init__(self, child, delimiter):
|
||||||
self.child = child
|
self.child = to_parse_node(child)
|
||||||
self.delimiter = delimiter
|
self.delimiter = to_parse_node(delimiter)
|
||||||
|
|
||||||
def _parse(self, ctx):
|
def _parse(self, ctx):
|
||||||
while not self.delimiter.parse(ctx).succeeded():
|
while not self.delimiter.parse(ctx).succeeded():
|
||||||
|
@ -362,7 +362,7 @@ class ZeroOrMore(ParseNode):
|
||||||
times). It cannot fail to parse. If its child raises an exception, one token
|
times). It cannot fail to parse. If its child raises an exception, one token
|
||||||
will be skipped and parsing will continue. """
|
will be skipped and parsing will continue. """
|
||||||
def __init__(self, child):
|
def __init__(self, child):
|
||||||
self.child = child
|
self.child = to_parse_node(child)
|
||||||
|
|
||||||
|
|
||||||
def _parse(self, ctx):
|
def _parse(self, ctx):
|
||||||
|
@ -379,8 +379,8 @@ class Delimited(ParseNode):
|
||||||
""" ParseNode that matches its first child any number of times (including zero
|
""" ParseNode that matches its first child any number of times (including zero
|
||||||
times) with its second child in between and optionally at the end. """
|
times) with its second child in between and optionally at the end. """
|
||||||
def __init__(self, child, delimiter):
|
def __init__(self, child, delimiter):
|
||||||
self.child = child
|
self.child = to_parse_node(child)
|
||||||
self.delimiter = delimiter
|
self.delimiter = to_parse_node(delimiter)
|
||||||
|
|
||||||
def _parse(self, ctx):
|
def _parse(self, ctx):
|
||||||
while self.child.parse(ctx).matched() and self.delimiter.parse(ctx).matched():
|
while self.child.parse(ctx).matched() and self.delimiter.parse(ctx).matched():
|
||||||
|
@ -392,60 +392,36 @@ class Optional(ParseNode):
|
||||||
""" ParseNode that matches its child zero or one times. It cannot fail to
|
""" ParseNode that matches its child zero or one times. It cannot fail to
|
||||||
parse. """
|
parse. """
|
||||||
def __init__(self, child):
|
def __init__(self, child):
|
||||||
self.child = child
|
self.child = to_parse_node(child)
|
||||||
|
|
||||||
def _parse(self, ctx):
|
def _parse(self, ctx):
|
||||||
self.child.parse(ctx)
|
self.child.parse(ctx)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class StaticToken(ParseNode):
|
class Eof(ParseNode):
|
||||||
""" Base class for ParseNodes that match a token type without inspecting
|
""" ParseNode that matches an EOF token. """
|
||||||
the token's contents. """
|
|
||||||
token_type: T.Optional[TokenType] = None
|
|
||||||
|
|
||||||
def _parse(self, ctx: ParseContext) -> bool:
|
def _parse(self, ctx: ParseContext) -> bool:
|
||||||
return ctx.next_token().type == self.token_type
|
token = ctx.next_token()
|
||||||
|
return token.type == TokenType.EOF
|
||||||
class StmtEnd(StaticToken):
|
|
||||||
token_type = TokenType.STMT_END
|
|
||||||
|
|
||||||
class Eof(StaticToken):
|
|
||||||
token_type = TokenType.EOF
|
|
||||||
|
|
||||||
class OpenBracket(StaticToken):
|
|
||||||
token_type = TokenType.OPEN_BRACKET
|
|
||||||
|
|
||||||
class CloseBracket(StaticToken):
|
|
||||||
token_type = TokenType.CLOSE_BRACKET
|
|
||||||
|
|
||||||
class OpenBlock(StaticToken):
|
|
||||||
token_type = TokenType.OPEN_BLOCK
|
|
||||||
|
|
||||||
class CloseBlock(StaticToken):
|
|
||||||
token_type = TokenType.CLOSE_BLOCK
|
|
||||||
|
|
||||||
class OpenParen(StaticToken):
|
|
||||||
token_type = TokenType.OPEN_PAREN
|
|
||||||
|
|
||||||
class CloseParen(StaticToken):
|
|
||||||
token_type = TokenType.CLOSE_PAREN
|
|
||||||
|
|
||||||
class Comma(StaticToken):
|
|
||||||
token_type = TokenType.COMMA
|
|
||||||
|
|
||||||
|
|
||||||
class Op(ParseNode):
|
class Match(ParseNode):
|
||||||
""" ParseNode that matches the given operator. """
|
""" ParseNode that matches the given literal token. """
|
||||||
def __init__(self, op):
|
def __init__(self, op):
|
||||||
self.op = op
|
self.op = op
|
||||||
|
|
||||||
def _parse(self, ctx: ParseContext) -> bool:
|
def _parse(self, ctx: ParseContext) -> bool:
|
||||||
token = ctx.next_token()
|
token = ctx.next_token()
|
||||||
if token.type != TokenType.OP:
|
|
||||||
return False
|
|
||||||
return str(token) == self.op
|
return str(token) == self.op
|
||||||
|
|
||||||
|
def expected(self, expect: str = None):
|
||||||
|
""" Convenience method for err(). """
|
||||||
|
if expect is None:
|
||||||
|
return self.err(f"Expected '{self.op}'")
|
||||||
|
else:
|
||||||
|
return self.err("Expected " + expect)
|
||||||
|
|
||||||
|
|
||||||
class UseIdent(ParseNode):
|
class UseIdent(ParseNode):
|
||||||
""" ParseNode that matches any identifier and sets it in a key=value pair on
|
""" ParseNode that matches any identifier and sets it in a key=value pair on
|
||||||
|
@ -529,17 +505,22 @@ class UseLiteral(ParseNode):
|
||||||
|
|
||||||
|
|
||||||
class Keyword(ParseNode):
|
class Keyword(ParseNode):
|
||||||
""" Matches the given identifier. """
|
""" Matches the given identifier and sets it as a named token, with the name
|
||||||
def __init__(self, kw, set_token=False):
|
being the identifier itself. """
|
||||||
|
def __init__(self, kw):
|
||||||
self.kw = kw
|
self.kw = kw
|
||||||
self.set_token = True
|
self.set_token = True
|
||||||
|
|
||||||
def _parse(self, ctx: ParseContext):
|
def _parse(self, ctx: ParseContext):
|
||||||
token = ctx.next_token()
|
token = ctx.next_token()
|
||||||
if token.type != TokenType.IDENT:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if self.set_token:
|
|
||||||
ctx.set_group_val(self.kw, True, token)
|
ctx.set_group_val(self.kw, True, token)
|
||||||
|
|
||||||
return str(token) == self.kw
|
return str(token) == self.kw
|
||||||
|
|
||||||
|
|
||||||
|
def to_parse_node(value) -> ParseNode:
|
||||||
|
if isinstance(value, str):
|
||||||
|
return Match(value)
|
||||||
|
elif isinstance(value, list):
|
||||||
|
return Sequence(*value)
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
|
@ -32,8 +32,8 @@ def parse(tokens) -> T.Tuple[ast.UI, T.Optional[MultipleErrors]]:
|
||||||
gtk_directive = Group(
|
gtk_directive = Group(
|
||||||
ast.GtkDirective,
|
ast.GtkDirective,
|
||||||
Statement(
|
Statement(
|
||||||
Keyword("using").err("File must start with a \"using Gtk\" directive (e.g. `using Gtk 4.0;`)"),
|
Match("using").err("File must start with a \"using Gtk\" directive (e.g. `using Gtk 4.0;`)"),
|
||||||
Keyword("Gtk").err("File must start with a \"using Gtk\" directive (e.g. `using Gtk 4.0;`)"),
|
Match("Gtk").err("File must start with a \"using Gtk\" directive (e.g. `using Gtk 4.0;`)"),
|
||||||
UseNumberText("version").expected("a version number for GTK"),
|
UseNumberText("version").expected("a version number for GTK"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -41,7 +41,7 @@ def parse(tokens) -> T.Tuple[ast.UI, T.Optional[MultipleErrors]]:
|
||||||
import_statement = Group(
|
import_statement = Group(
|
||||||
ast.Import,
|
ast.Import,
|
||||||
Statement(
|
Statement(
|
||||||
Keyword("using"),
|
"using",
|
||||||
UseIdent("namespace").expected("a GIR namespace"),
|
UseIdent("namespace").expected("a GIR namespace"),
|
||||||
UseNumberText("version").expected("a version number"),
|
UseNumberText("version").expected("a version number"),
|
||||||
)
|
)
|
||||||
|
@ -56,7 +56,7 @@ def parse(tokens) -> T.Tuple[ast.UI, T.Optional[MultipleErrors]]:
|
||||||
ast.Property,
|
ast.Property,
|
||||||
Statement(
|
Statement(
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
Op(":"),
|
":",
|
||||||
AnyOf(
|
AnyOf(
|
||||||
*OBJECT_HOOKS,
|
*OBJECT_HOOKS,
|
||||||
object,
|
object,
|
||||||
|
@ -69,15 +69,15 @@ def parse(tokens) -> T.Tuple[ast.UI, T.Optional[MultipleErrors]]:
|
||||||
ast.Property,
|
ast.Property,
|
||||||
Statement(
|
Statement(
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
Op(":"),
|
":",
|
||||||
Keyword("bind"),
|
"bind",
|
||||||
UseIdent("bind_source").expected("the ID of a source object to bind from"),
|
UseIdent("bind_source").expected("the ID of a source object to bind from"),
|
||||||
Op("."),
|
".",
|
||||||
UseIdent("bind_property").expected("a property name to bind from"),
|
UseIdent("bind_property").expected("a property name to bind from"),
|
||||||
ZeroOrMore(AnyOf(
|
ZeroOrMore(AnyOf(
|
||||||
Sequence(Keyword("sync-create"), UseLiteral("sync_create", True)),
|
["sync-create", UseLiteral("sync_create", True)],
|
||||||
Sequence(Keyword("inverted"), UseLiteral("invert-boolean", True)),
|
["inverted", UseLiteral("inverted", True)],
|
||||||
Sequence(Keyword("bidirectional"), UseLiteral("bidirectional", True)),
|
["bidirectional", UseLiteral("bidirectional", True)],
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -86,47 +86,47 @@ def parse(tokens) -> T.Tuple[ast.UI, T.Optional[MultipleErrors]]:
|
||||||
ast.Signal,
|
ast.Signal,
|
||||||
Statement(
|
Statement(
|
||||||
UseIdent("name"),
|
UseIdent("name"),
|
||||||
Optional(Sequence(
|
Optional([
|
||||||
Op("::"),
|
"::",
|
||||||
UseIdent("detail_name").expected("a signal detail name"),
|
UseIdent("detail_name").expected("a signal detail name"),
|
||||||
)),
|
]),
|
||||||
Op("=>"),
|
"=>",
|
||||||
UseIdent("handler").expected("the name of a function to handle the signal"),
|
UseIdent("handler").expected("the name of a function to handle the signal"),
|
||||||
OpenParen().expected("argument list"),
|
Match("(").expected("argument list"),
|
||||||
Optional(UseIdent("object")).expected("object identifier"),
|
Optional(UseIdent("object")).expected("object identifier"),
|
||||||
CloseParen().expected("`)`"),
|
Match(")").expected(),
|
||||||
ZeroOrMore(AnyOf(
|
ZeroOrMore(AnyOf(
|
||||||
Sequence(Keyword("swapped"), UseLiteral("swapped", True)),
|
[Keyword("swapped"), UseLiteral("swapped", True)],
|
||||||
Sequence(Keyword("after"), UseLiteral("after", True)),
|
[Keyword("after"), UseLiteral("after", True)],
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
child = Group(
|
child = Group(
|
||||||
ast.Child,
|
ast.Child,
|
||||||
Sequence(
|
[
|
||||||
Optional(Sequence(
|
Optional([
|
||||||
OpenBracket(),
|
"[",
|
||||||
Optional(Sequence(Keyword("internal-child"), UseLiteral("internal_child", True))),
|
Optional(["internal-child", UseLiteral("internal_child", True)]),
|
||||||
UseIdent("child_type").expected("a child type"),
|
UseIdent("child_type").expected("a child type"),
|
||||||
CloseBracket(),
|
"]",
|
||||||
)),
|
]),
|
||||||
object,
|
object,
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
object_content = Group(
|
object_content = Group(
|
||||||
ast.ObjectContent,
|
ast.ObjectContent,
|
||||||
Sequence(
|
[
|
||||||
OpenBlock(),
|
"{",
|
||||||
Until(AnyOf(
|
Until(AnyOf(
|
||||||
*OBJECT_CONTENT_HOOKS,
|
*OBJECT_CONTENT_HOOKS,
|
||||||
binding,
|
binding,
|
||||||
property,
|
property,
|
||||||
signal,
|
signal,
|
||||||
child,
|
child,
|
||||||
), CloseBlock()),
|
), "}"),
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# work around the recursive reference
|
# work around the recursive reference
|
||||||
|
@ -138,22 +138,20 @@ def parse(tokens) -> T.Tuple[ast.UI, T.Optional[MultipleErrors]]:
|
||||||
|
|
||||||
template = Group(
|
template = Group(
|
||||||
ast.Template,
|
ast.Template,
|
||||||
Sequence(
|
[
|
||||||
Keyword("template"),
|
"template",
|
||||||
UseIdent("name").expected("template class name"),
|
UseIdent("name").expected("template class name"),
|
||||||
Optional(
|
Optional([
|
||||||
Sequence(
|
Match(":"),
|
||||||
Op(":"),
|
|
||||||
class_name.expected("parent class"),
|
class_name.expected("parent class"),
|
||||||
)
|
]),
|
||||||
),
|
|
||||||
object_content.expected("block"),
|
object_content.expected("block"),
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
ui = Group(
|
ui = Group(
|
||||||
ast.UI,
|
ast.UI,
|
||||||
Sequence(
|
[
|
||||||
gtk_directive,
|
gtk_directive,
|
||||||
ZeroOrMore(import_statement),
|
ZeroOrMore(import_statement),
|
||||||
Until(AnyOf(
|
Until(AnyOf(
|
||||||
|
@ -161,7 +159,7 @@ def parse(tokens) -> T.Tuple[ast.UI, T.Optional[MultipleErrors]]:
|
||||||
template,
|
template,
|
||||||
object,
|
object,
|
||||||
), Eof()),
|
), Eof()),
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx = ParseContext(tokens)
|
ctx = ParseContext(tokens)
|
||||||
|
|
|
@ -23,16 +23,16 @@ from .parse_tree import *
|
||||||
|
|
||||||
|
|
||||||
class_name = AnyOf(
|
class_name = AnyOf(
|
||||||
Sequence(
|
[
|
||||||
UseIdent("namespace"),
|
UseIdent("namespace"),
|
||||||
Op("."),
|
".",
|
||||||
UseIdent("class_name"),
|
UseIdent("class_name"),
|
||||||
),
|
],
|
||||||
Sequence(
|
[
|
||||||
Op("."),
|
".",
|
||||||
UseIdent("class_name"),
|
UseIdent("class_name"),
|
||||||
UseLiteral("ignore_gir", True),
|
UseLiteral("ignore_gir", True),
|
||||||
),
|
],
|
||||||
UseIdent("class_name"),
|
UseIdent("class_name"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,31 +51,31 @@ ident_value = Group(
|
||||||
|
|
||||||
flags_value = Group(
|
flags_value = Group(
|
||||||
ast.FlagsValue,
|
ast.FlagsValue,
|
||||||
Sequence(
|
[
|
||||||
Group(ast.Flag, UseIdent("value")),
|
Group(ast.Flag, UseIdent("value")),
|
||||||
Op("|"),
|
"|",
|
||||||
Delimited(Group(ast.Flag, UseIdent("value")), Op("|")),
|
Delimited(Group(ast.Flag, UseIdent("value")), "|"),
|
||||||
),
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
translated_string = Group(
|
translated_string = Group(
|
||||||
ast.TranslatedStringValue,
|
ast.TranslatedStringValue,
|
||||||
AnyOf(
|
AnyOf(
|
||||||
Sequence(
|
[
|
||||||
Keyword("_"),
|
"_",
|
||||||
OpenParen(),
|
"(",
|
||||||
UseQuoted("value").expected("a quoted string"),
|
UseQuoted("value").expected("a quoted string"),
|
||||||
CloseParen().expected("`)`"),
|
Match(")").expected(),
|
||||||
),
|
],
|
||||||
Sequence(
|
[
|
||||||
Keyword("C_"),
|
"C_",
|
||||||
OpenParen(),
|
"(",
|
||||||
UseQuoted("context").expected("a quoted string"),
|
UseQuoted("context").expected("a quoted string"),
|
||||||
Comma(),
|
",",
|
||||||
UseQuoted("value").expected("a quoted string"),
|
UseQuoted("value").expected("a quoted string"),
|
||||||
Optional(Comma()),
|
Optional(","),
|
||||||
CloseParen().expected("`)`"),
|
Match(")").expected(),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue