mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-06 16:19:07 -04:00
Compare commits
3 commits
76ed182163
...
a20d21f8fb
Author | SHA1 | Date | |
---|---|---|---|
|
a20d21f8fb | ||
|
d6f4b88d35 | ||
|
02344139c2 |
23 changed files with 57 additions and 54 deletions
|
@ -41,7 +41,7 @@ from .types import ClassName
|
|||
from .ui import UI
|
||||
from .values import (
|
||||
ArrayValue,
|
||||
ExprLiteral,
|
||||
ExprValue,
|
||||
Flag,
|
||||
Flags,
|
||||
IdentLiteral,
|
||||
|
|
|
@ -82,6 +82,6 @@ class ScopeCtx:
|
|||
|
||||
|
||||
@dataclass
|
||||
class ExprLiteralCtx:
|
||||
class ExprValueCtx:
|
||||
"""Indicates that the context is an expression literal, where the
|
||||
"item" keyword may be used."""
|
||||
|
|
|
@ -21,13 +21,12 @@
|
|||
from .binding import Binding
|
||||
from .common import *
|
||||
from .contexts import ValueTypeCtx
|
||||
from .gtkbuilder_template import Template
|
||||
from .values import ArrayValue, ObjectValue, Value
|
||||
from .values import ArrayValue, ExprValue, ObjectValue, Value
|
||||
|
||||
|
||||
class Property(AstNode):
|
||||
grammar = Statement(
|
||||
UseIdent("name"), ":", AnyOf(Binding, ObjectValue, Value, ArrayValue)
|
||||
UseIdent("name"), ":", AnyOf(Binding, ExprValue, ObjectValue, Value, ArrayValue)
|
||||
)
|
||||
|
||||
@property
|
||||
|
@ -35,7 +34,7 @@ class Property(AstNode):
|
|||
return self.tokens["name"]
|
||||
|
||||
@property
|
||||
def value(self) -> T.Union[Binding, ObjectValue, Value, ArrayValue]:
|
||||
def value(self) -> T.Union[Binding, ExprValue, ObjectValue, Value, ArrayValue]:
|
||||
return self.children[0]
|
||||
|
||||
@property
|
||||
|
|
|
@ -143,12 +143,13 @@ class Signal(AstNode):
|
|||
|
||||
@property
|
||||
def document_symbol(self) -> DocumentSymbol:
|
||||
detail = self.ranges["detail_start", "detail_end"]
|
||||
return DocumentSymbol(
|
||||
self.full_name,
|
||||
SymbolKind.Event,
|
||||
self.range,
|
||||
self.group.tokens["name"].range,
|
||||
self.ranges["detail_start", "detail_end"].text,
|
||||
detail.text if detail is not None else None,
|
||||
)
|
||||
|
||||
def get_reference(self, idx: int) -> T.Optional[LocationLink]:
|
||||
|
|
|
@ -23,7 +23,7 @@ from blueprintcompiler.gir import ArrayType
|
|||
from blueprintcompiler.lsp_utils import SemanticToken
|
||||
|
||||
from .common import *
|
||||
from .contexts import ExprLiteralCtx, ScopeCtx, ValueTypeCtx
|
||||
from .contexts import ExprValueCtx, ScopeCtx, ValueTypeCtx
|
||||
from .expression import Expression
|
||||
from .gobject_object import Object
|
||||
from .types import TypeName
|
||||
|
@ -112,35 +112,6 @@ class TypeLiteral(AstNode):
|
|||
return get_docs_section("Syntax TypeLiteral")
|
||||
|
||||
|
||||
class ExprLiteral(AstNode):
|
||||
grammar = [Keyword("expr"), Expression]
|
||||
|
||||
@property
|
||||
def expression(self) -> Expression:
|
||||
return self.children[Expression][0]
|
||||
|
||||
@validate("expr")
|
||||
def validate_for_type(self) -> None:
|
||||
expected_type = self.parent.context[ValueTypeCtx].value_type
|
||||
expr_type = self.root.gir.get_type("Expression", "Gtk")
|
||||
if expected_type is not None and not expected_type.assignable_to(expr_type):
|
||||
raise CompileError(
|
||||
f"Cannot convert Gtk.Expression to {expected_type.full_name}"
|
||||
)
|
||||
|
||||
@docs("expr")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExprLiteral")
|
||||
|
||||
@context(ExprLiteralCtx)
|
||||
def expr_literal(self):
|
||||
return ExprLiteralCtx()
|
||||
|
||||
@context(ValueTypeCtx)
|
||||
def value_type(self):
|
||||
return ValueTypeCtx(None, must_infer_type=True)
|
||||
|
||||
|
||||
class QuotedLiteral(AstNode):
|
||||
grammar = UseQuoted("value")
|
||||
|
||||
|
@ -350,7 +321,7 @@ class IdentLiteral(AstNode):
|
|||
if not self.context[ValueTypeCtx].allow_null:
|
||||
raise CompileError("null is not permitted here")
|
||||
elif self.ident == "item":
|
||||
if not self.context[ExprLiteralCtx]:
|
||||
if not self.context[ExprValueCtx]:
|
||||
raise CompileError(
|
||||
'"item" can only be used in an expression literal'
|
||||
)
|
||||
|
@ -410,7 +381,6 @@ class IdentLiteral(AstNode):
|
|||
class Literal(AstNode):
|
||||
grammar = AnyOf(
|
||||
TypeLiteral,
|
||||
ExprLiteral,
|
||||
QuotedLiteral,
|
||||
NumberLiteral,
|
||||
IdentLiteral,
|
||||
|
@ -419,7 +389,7 @@ class Literal(AstNode):
|
|||
@property
|
||||
def value(
|
||||
self,
|
||||
) -> T.Union[TypeLiteral, ExprLiteral, QuotedLiteral, NumberLiteral, IdentLiteral]:
|
||||
) -> T.Union[TypeLiteral, QuotedLiteral, NumberLiteral, IdentLiteral]:
|
||||
return self.children[0]
|
||||
|
||||
|
||||
|
@ -443,6 +413,35 @@ class ObjectValue(AstNode):
|
|||
)
|
||||
|
||||
|
||||
class ExprValue(AstNode):
|
||||
grammar = [Keyword("expr"), Expression]
|
||||
|
||||
@property
|
||||
def expression(self) -> Expression:
|
||||
return self.children[Expression][0]
|
||||
|
||||
@validate("expr")
|
||||
def validate_for_type(self) -> None:
|
||||
expected_type = self.parent.context[ValueTypeCtx].value_type
|
||||
expr_type = self.root.gir.get_type("Expression", "Gtk")
|
||||
if expected_type is not None and not expected_type.assignable_to(expr_type):
|
||||
raise CompileError(
|
||||
f"Cannot convert Gtk.Expression to {expected_type.full_name}"
|
||||
)
|
||||
|
||||
@docs("expr")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExprValue")
|
||||
|
||||
@context(ExprValueCtx)
|
||||
def expr_literal(self):
|
||||
return ExprValueCtx()
|
||||
|
||||
@context(ValueTypeCtx)
|
||||
def value_type(self):
|
||||
return ValueTypeCtx(None, must_infer_type=True)
|
||||
|
||||
|
||||
class Value(AstNode):
|
||||
grammar = AnyOf(Translated, Flags, Literal)
|
||||
|
||||
|
|
|
@ -134,6 +134,11 @@ class XmlOutput(OutputFormat):
|
|||
self._emit_expression(value.expression, xml)
|
||||
xml.end_tag()
|
||||
|
||||
elif isinstance(value, ExprValue):
|
||||
xml.start_tag("property", **props)
|
||||
self._emit_expression(value.expression, xml)
|
||||
xml.end_tag()
|
||||
|
||||
elif isinstance(value, ObjectValue):
|
||||
xml.start_tag("property", **props)
|
||||
self._emit_object(value.object, xml)
|
||||
|
@ -205,8 +210,6 @@ class XmlOutput(OutputFormat):
|
|||
xml.put_text(self._object_id(value, value.ident))
|
||||
elif isinstance(value, TypeLiteral):
|
||||
xml.put_text(value.type_name.glib_type_name)
|
||||
elif isinstance(value, ExprLiteral):
|
||||
self._emit_expression(value.expression, xml)
|
||||
else:
|
||||
if isinstance(value.value, float) and value.value == int(value.value):
|
||||
xml.put_text(int(value.value))
|
||||
|
@ -220,12 +223,6 @@ class XmlOutput(OutputFormat):
|
|||
xml.put_text(
|
||||
"|".join([str(flag.value or flag.name) for flag in value.child.flags])
|
||||
)
|
||||
elif isinstance(value.child, Translated):
|
||||
raise CompilerBugError("translated values must be handled in the parent")
|
||||
elif isinstance(value.child, TypeLiteral):
|
||||
xml.put_text(value.child.type_name.glib_type_name)
|
||||
elif isinstance(value.child, ObjectValue):
|
||||
self._emit_object(value.child.object, xml)
|
||||
else:
|
||||
raise CompilerBugError()
|
||||
|
||||
|
|
|
@ -89,14 +89,14 @@ Example
|
|||
// Cast the result of the closure so blueprint knows it's a string
|
||||
label: bind $format_bytes(template.file-size) as <string>
|
||||
|
||||
.. _Syntax ExprLiteral:
|
||||
.. _Syntax ExprValue:
|
||||
|
||||
Expression Literals
|
||||
-------------------
|
||||
Expression Values
|
||||
-----------------
|
||||
|
||||
.. rst-class:: grammar-block
|
||||
|
||||
ExprLiteral = 'expr' :ref:`Expression<Syntax Expression>`
|
||||
ExprValue = 'expr' :ref:`Expression<Syntax Expression>`
|
||||
|
||||
Some APIs take *an expression itself*--not its result--as a property value. For example, `Gtk.BoolFilter <https://docs.gtk.org/gtk4/class.BoolFilter.html>`_ has an ``expression`` property of type `Gtk.Expression <https://docs.gtk.org/gtk4/class.Expression.html>`_. This expression is evaluated for every item in a list model to determine whether the item should be filtered.
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ Properties
|
|||
|
||||
.. rst-class:: grammar-block
|
||||
|
||||
Property = <name::ref:`IDENT<Syntax IDENT>`> ':' ( :ref:`Binding<Syntax Binding>` | :ref:`ObjectValue<Syntax ObjectValue>` | :ref:`Value<Syntax Value>` ) ';'
|
||||
Property = <name::ref:`IDENT<Syntax IDENT>`> ':' ( :ref:`Binding<Syntax Binding>` | :ref:`ExprValue<Syntax ExprValue>` | :ref:`ObjectValue<Syntax ObjectValue>` | :ref:`Value<Syntax Value>` ) ';'
|
||||
|
||||
Properties specify the details of each object, like a label's text, an image's icon name, or the margins on a container.
|
||||
|
||||
|
|
5
tests/sample_errors/incomplete_signal.blp
Normal file
5
tests/sample_errors/incomplete_signal.blp
Normal file
|
@ -0,0 +1,5 @@
|
|||
using Gtk 4.0;
|
||||
|
||||
Label {
|
||||
notify::
|
||||
}
|
2
tests/sample_errors/incomplete_signal.err
Normal file
2
tests/sample_errors/incomplete_signal.err
Normal file
|
@ -0,0 +1,2 @@
|
|||
5,1,0,Expected a signal detail name
|
||||
4,9,3,Unexpected tokens
|
|
@ -198,7 +198,7 @@ class TestSamples(unittest.TestCase):
|
|||
"adw_breakpoint_template",
|
||||
"expr_closure",
|
||||
"expr_closure_args",
|
||||
"expr_literal_closure",
|
||||
"expr_value_closure",
|
||||
"parseable",
|
||||
"signal",
|
||||
"signal_not_swapped",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue