diff --git a/blueprintcompiler/completions.py b/blueprintcompiler/completions.py index b10ec3e..5d36739 100644 --- a/blueprintcompiler/completions.py +++ b/blueprintcompiler/completions.py @@ -177,15 +177,6 @@ def property_completer(lsp, ast_node, match_variables): docs=prop.doc, detail=prop.detail, ) - elif prop.type.full_name == "Gtk.Expression": - yield Completion( - prop_name, - CompletionItemKind.Property, - sort_text=f"0 {prop_name}", - snippet=f"{prop_name}: expr $0;", - docs=prop.doc, - detail=prop.detail, - ) else: yield Completion( prop_name, diff --git a/blueprintcompiler/formatter.py b/blueprintcompiler/formatter.py index f438675..35da5d2 100644 --- a/blueprintcompiler/formatter.py +++ b/blueprintcompiler/formatter.py @@ -146,10 +146,8 @@ def format(data, tab_size=2, insert_space=True): is_child_type = False elif str_item in CLOSING_TOKENS: - if str_item == "]" and str(last_not_whitespace) != "[": + if str_item == "]" and last_not_whitespace != ",": current_line = current_line[:-1] - if str(last_not_whitespace) != ",": - current_line += "," commit_current_line() current_line = "]" elif str(last_not_whitespace) in OPENING_TOKENS: @@ -193,9 +191,6 @@ def format(data, tab_size=2, insert_space=True): elif prev_line_type in require_extra_newline: newlines = 2 - current_line = "\n".join( - [line.rstrip() for line in current_line.split("\n")] - ) commit_current_line(LineType.COMMENT, newlines_before=newlines) else: # pragma: no cover diff --git a/blueprintcompiler/language/__init__.py b/blueprintcompiler/language/__init__.py index 5eb2b60..e797eaa 100644 --- a/blueprintcompiler/language/__init__.py +++ b/blueprintcompiler/language/__init__.py @@ -41,7 +41,6 @@ from .types import ClassName from .ui import UI from .values import ( ArrayValue, - ExprValue, Flag, Flags, IdentLiteral, diff --git a/blueprintcompiler/language/contexts.py b/blueprintcompiler/language/contexts.py index 6e26048..c5e97b3 100644 --- a/blueprintcompiler/language/contexts.py +++ b/blueprintcompiler/language/contexts.py @@ -79,9 +79,3 @@ class ScopeCtx: for child in node.children: if child.context[ScopeCtx] is self: yield from self._iter_recursive(child) - - -@dataclass -class ExprValueCtx: - """Indicates that the context is an expression literal, where the - "item" keyword may be used.""" diff --git a/blueprintcompiler/language/expression.py b/blueprintcompiler/language/expression.py index e0b4246..f305035 100644 --- a/blueprintcompiler/language/expression.py +++ b/blueprintcompiler/language/expression.py @@ -81,16 +81,6 @@ class LiteralExpr(ExprBase): or self.root.is_legacy_template(self.literal.value.ident) ) - @property - def is_this(self) -> bool: - from .values import IdentLiteral - - return ( - not self.is_object - and isinstance(self.literal.value, IdentLiteral) - and self.literal.value.ident == "item" - ) - @property def literal(self): from .values import Literal @@ -101,15 +91,6 @@ class LiteralExpr(ExprBase): def type(self) -> T.Optional[GirType]: return self.literal.value.type - @validate() - def item_validations(self): - if self.is_this: - if not isinstance(self.rhs, CastExpr): - raise CompileError('"item" must be cast to its object type') - - if not isinstance(self.rhs.rhs, LookupOp): - raise CompileError('"item" can only be used for looking up properties') - class LookupOp(InfixExpr): grammar = [".", UseIdent("property")] @@ -304,9 +285,6 @@ expr.children = [ def decompile_lookup( ctx: DecompileCtx, gir: gir.GirContext, cdata: str, name: str, type: str ): - if ctx.parent_node is not None and ctx.parent_node.tag == "property": - ctx.print("expr ") - if t := ctx.type_by_cname(type): type = decompile.full_name(t) else: @@ -326,8 +304,6 @@ def decompile_lookup( if constant is not None: if constant == ctx.template_class: ctx.print("template." + name) - elif constant == "": - ctx.print("item as <" + type + ">." + name) else: ctx.print(constant + "." + name) return @@ -342,9 +318,6 @@ def decompile_lookup( def decompile_constant( ctx: DecompileCtx, gir: gir.GirContext, cdata: str, type: T.Optional[str] = None ): - if ctx.parent_node is not None and ctx.parent_node.tag == "property": - ctx.print("expr ") - if type is None: if cdata == ctx.template_class: ctx.print("template") @@ -357,9 +330,6 @@ def decompile_constant( @decompiler("closure", skip_children=True) def decompile_closure(ctx: DecompileCtx, gir: gir.GirContext, function: str, type: str): - if ctx.parent_node is not None and ctx.parent_node.tag == "property": - ctx.print("expr ") - if t := ctx.type_by_cname(type): type = decompile.full_name(t) else: diff --git a/blueprintcompiler/language/gobject_object.py b/blueprintcompiler/language/gobject_object.py index 1def15b..54cb297 100644 --- a/blueprintcompiler/language/gobject_object.py +++ b/blueprintcompiler/language/gobject_object.py @@ -28,18 +28,7 @@ from .common import * from .response_id import ExtResponse from .types import ClassName, ConcreteClassName -RESERVED_IDS = { - "this", - "self", - "template", - "true", - "false", - "null", - "none", - "item", - "expr", - "typeof", -} +RESERVED_IDS = {"this", "self", "template", "true", "false", "null", "none"} class ObjectContent(AstNode): diff --git a/blueprintcompiler/language/gobject_property.py b/blueprintcompiler/language/gobject_property.py index 50a7512..b553909 100644 --- a/blueprintcompiler/language/gobject_property.py +++ b/blueprintcompiler/language/gobject_property.py @@ -21,12 +21,13 @@ from .binding import Binding from .common import * from .contexts import ValueTypeCtx -from .values import ArrayValue, ExprValue, ObjectValue, Value +from .gtkbuilder_template import Template +from .values import ArrayValue, ObjectValue, Value class Property(AstNode): grammar = Statement( - UseIdent("name"), ":", AnyOf(Binding, ExprValue, ObjectValue, Value, ArrayValue) + UseIdent("name"), ":", AnyOf(Binding, ObjectValue, Value, ArrayValue) ) @property @@ -34,7 +35,7 @@ class Property(AstNode): return self.tokens["name"] @property - def value(self) -> T.Union[Binding, ExprValue, ObjectValue, Value, ArrayValue]: + def value(self) -> T.Union[Binding, ObjectValue, Value, ArrayValue]: return self.children[0] @property diff --git a/blueprintcompiler/language/values.py b/blueprintcompiler/language/values.py index 5556d99..63cf4fc 100644 --- a/blueprintcompiler/language/values.py +++ b/blueprintcompiler/language/values.py @@ -23,8 +23,7 @@ from blueprintcompiler.gir import ArrayType from blueprintcompiler.lsp_utils import SemanticToken from .common import * -from .contexts import ExprValueCtx, ScopeCtx, ValueTypeCtx -from .expression import Expression +from .contexts import ScopeCtx, ValueTypeCtx from .gobject_object import Object from .types import TypeName @@ -320,12 +319,7 @@ class IdentLiteral(AstNode): if self.ident == "null": if not self.context[ValueTypeCtx].allow_null: raise CompileError("null is not permitted here") - elif self.ident == "item": - if not self.context[ExprValueCtx]: - raise CompileError( - '"item" can only be used in an expression literal' - ) - elif self.ident not in ["true", "false"]: + else: raise CompileError( f"Could not find object with ID {self.ident}", did_you_mean=( @@ -413,35 +407,6 @@ 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) @@ -487,14 +452,6 @@ class ArrayValue(AstNode): range=quoted_literal.range, ) ) - elif isinstance(value.child, Translated): - errors.append( - CompileError( - "Arrays can't contain translated strings", - range=value.child.range, - ) - ) - if len(errors) > 0: raise MultipleErrors(errors) diff --git a/blueprintcompiler/lsp.py b/blueprintcompiler/lsp.py index c4076b4..0659154 100644 --- a/blueprintcompiler/lsp.py +++ b/blueprintcompiler/lsp.py @@ -118,7 +118,6 @@ class LanguageServer: self.client_capabilities = {} self.client_supports_completion_choice = False self._open_files: T.Dict[str, OpenFile] = {} - self._exited = False def run(self): # Read tags from gir files. During normal compilation these are @@ -126,7 +125,7 @@ class LanguageServer: xml_reader.PARSE_GIR.add("doc") try: - while not self._exited: + while True: line = "" content_len = -1 while content_len == -1 or (line != "\n" and line != "\r\n"): @@ -222,14 +221,6 @@ class LanguageServer: }, ) - @command("shutdown") - def shutdown(self, id, params): - self._send_response(id, None) - - @command("exit") - def exit(self, id, params): - self._exited = True - @command("textDocument/didOpen") def didOpen(self, id, params): doc = params.get("textDocument") diff --git a/blueprintcompiler/outputs/xml/__init__.py b/blueprintcompiler/outputs/xml/__init__.py index 5c03761..a21b6fb 100644 --- a/blueprintcompiler/outputs/xml/__init__.py +++ b/blueprintcompiler/outputs/xml/__init__.py @@ -134,11 +134,6 @@ 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) @@ -223,6 +218,12 @@ 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() @@ -244,9 +245,6 @@ class XmlOutput(OutputFormat): raise CompilerBugError() def _emit_literal_expr(self, expr: LiteralExpr, xml: XmlEmitter): - if expr.is_this: - return - if expr.is_object: xml.start_tag("constant") else: diff --git a/docs/reference/expressions.rst b/docs/reference/expressions.rst index 3d523d1..8688ff0 100644 --- a/docs/reference/expressions.rst +++ b/docs/reference/expressions.rst @@ -42,8 +42,8 @@ Expressions are composed of property lookups and/or closures. Property lookups a .. _Syntax LookupExpression: -Lookups -------- +Lookup Expressions +------------------ .. rst-class:: grammar-block @@ -56,8 +56,8 @@ The type of a property expression is the type of the property it refers to. .. _Syntax ClosureExpression: -Closures --------- +Closure Expressions +------------------- .. rst-class:: grammar-block @@ -72,8 +72,8 @@ Blueprint doesn't know the closure's return type, so closure expressions must be .. _Syntax CastExpression: -Casts ------ +Cast Expressions +---------------- .. rst-class:: grammar-block @@ -81,32 +81,7 @@ Casts Cast expressions allow Blueprint to know the type of an expression when it can't otherwise determine it. This is necessary for closures and for properties of application-defined types. -Example -~~~~~~~ - .. code-block:: blueprint // Cast the result of the closure so blueprint knows it's a string - label: bind $format_bytes(template.file-size) as - -.. _Syntax ExprValue: - -Expression Values ------------------ - -.. rst-class:: grammar-block - - ExprValue = 'expr' :ref:`Expression` - -Some APIs take *an expression itself*--not its result--as a property value. For example, `Gtk.BoolFilter `_ has an ``expression`` property of type `Gtk.Expression `_. This expression is evaluated for every item in a list model to determine whether the item should be filtered. - -To define an expression for such a property, use ``expr`` instead of ``bind``. Inside the expression, you can use the ``item`` keyword to refer to the item being evaluated. You must cast the item to the correct type using the ``as`` keyword, and you can only use ``item`` in a property lookup--you may not pass it to a closure. - -Example -~~~~~~~ - -.. code-block:: blueprint - - BoolFilter { - expression: expr item as <$UserAccount>.active; - } + label: bind $my_closure() as \ No newline at end of file diff --git a/docs/reference/objects.rst b/docs/reference/objects.rst index 6f76da6..09f5af8 100644 --- a/docs/reference/objects.rst +++ b/docs/reference/objects.rst @@ -58,7 +58,7 @@ Properties .. rst-class:: grammar-block - Property = `> ':' ( :ref:`Binding` | :ref:`ExprValue` | :ref:`ObjectValue` | :ref:`Value` ) ';' + Property = `> ':' ( :ref:`Binding` | :ref:`ObjectValue` | :ref:`Value` ) ';' Properties specify the details of each object, like a label's text, an image's icon name, or the margins on a container. diff --git a/tests/formatting/comment_in.blp b/tests/formatting/comment_in.blp index 88b825a..32a907c 100644 --- a/tests/formatting/comment_in.blp +++ b/tests/formatting/comment_in.blp @@ -1,4 +1,2 @@ using Gtk 4.0; -//comment -// Trailing whitespace: -// +//comment \ No newline at end of file diff --git a/tests/formatting/comment_out.blp b/tests/formatting/comment_out.blp index 91e647a..d5dca95 100644 --- a/tests/formatting/comment_out.blp +++ b/tests/formatting/comment_out.blp @@ -1,4 +1,2 @@ using Gtk 4.0; // comment -// Trailing whitespace: -// diff --git a/tests/formatting/lists_in.blp b/tests/formatting/lists_in.blp deleted file mode 100644 index 66b37a2..0000000 --- a/tests/formatting/lists_in.blp +++ /dev/null @@ -1,21 +0,0 @@ -using Gtk 4.0; - -Box { - styles [] -} - -Box { - styles ["a"] -} - -Box { - styles ["a",] -} - -Box { - styles ["a", "b"] -} - -Box { - styles ["a", "b",] -} diff --git a/tests/formatting/lists_out.blp b/tests/formatting/lists_out.blp deleted file mode 100644 index 7f1fe4a..0000000 --- a/tests/formatting/lists_out.blp +++ /dev/null @@ -1,31 +0,0 @@ -using Gtk 4.0; - -Box { - styles [] -} - -Box { - styles [ - "a", - ] -} - -Box { - styles [ - "a", - ] -} - -Box { - styles [ - "a", - "b", - ] -} - -Box { - styles [ - "a", - "b", - ] -} diff --git a/tests/formatting/out.blp b/tests/formatting/out.blp index b84c25f..9d9a8b4 100644 --- a/tests/formatting/out.blp +++ b/tests/formatting/out.blp @@ -11,7 +11,7 @@ Overlay { notify::icon-name => $on_icon_name_changed(label) swapped; styles [ - "destructive", + "destructive" ] } diff --git a/tests/sample_errors/expr_item_not_cast.blp b/tests/sample_errors/expr_item_not_cast.blp deleted file mode 100644 index 76a1d89..0000000 --- a/tests/sample_errors/expr_item_not_cast.blp +++ /dev/null @@ -1,5 +0,0 @@ -using Gtk 4.0; - -BoolFilter { - expression: expr item.visible; -} diff --git a/tests/sample_errors/expr_item_not_cast.err b/tests/sample_errors/expr_item_not_cast.err deleted file mode 100644 index f6cf7d4..0000000 --- a/tests/sample_errors/expr_item_not_cast.err +++ /dev/null @@ -1 +0,0 @@ -4,20,4,"item" must be cast to its object type \ No newline at end of file diff --git a/tests/sample_errors/expr_value_assignment.blp b/tests/sample_errors/expr_value_assignment.blp deleted file mode 100644 index 51d778f..0000000 --- a/tests/sample_errors/expr_value_assignment.blp +++ /dev/null @@ -1,5 +0,0 @@ -using Gtk 4.0; - -Label { - label: expr 1; -} diff --git a/tests/sample_errors/expr_value_assignment.err b/tests/sample_errors/expr_value_assignment.err deleted file mode 100644 index 1c7092a..0000000 --- a/tests/sample_errors/expr_value_assignment.err +++ /dev/null @@ -1 +0,0 @@ -4,10,4,Cannot convert Gtk.Expression to string \ No newline at end of file diff --git a/tests/sample_errors/expr_value_closure_arg.blp b/tests/sample_errors/expr_value_closure_arg.blp deleted file mode 100644 index 7f828c4..0000000 --- a/tests/sample_errors/expr_value_closure_arg.blp +++ /dev/null @@ -1,5 +0,0 @@ -using Gtk 4.0; - -BoolFilter { - expression: expr $closure(item as ) as ; -} diff --git a/tests/sample_errors/expr_value_closure_arg.err b/tests/sample_errors/expr_value_closure_arg.err deleted file mode 100644 index b9e19f8..0000000 --- a/tests/sample_errors/expr_value_closure_arg.err +++ /dev/null @@ -1 +0,0 @@ -4,29,4,"item" can only be used for looking up properties \ No newline at end of file diff --git a/tests/sample_errors/expr_value_item.blp b/tests/sample_errors/expr_value_item.blp deleted file mode 100644 index 141c806..0000000 --- a/tests/sample_errors/expr_value_item.blp +++ /dev/null @@ -1,5 +0,0 @@ -using Gtk 4.0; - -BoolFilter { - expression: expr item as