summaryrefslogtreecommitdiff
path: root/vala/valawithstatement.vala
diff options
context:
space:
mode:
authorNick Schrader <nick.schrader@mailbox.org>2020-03-27 13:12:09 -0300
committerRico Tzschichholz <ricotz@ubuntu.com>2020-05-23 10:34:00 +0200
commit31d30658306f15160775e9a125b0dad4ab155332 (patch)
tree1e039d62a4c59b7b3c31c9136b2c2eb7db2237c2 /vala/valawithstatement.vala
parentf1f776027ceb376b6faca17625799f6bd2ea66d2 (diff)
downloadvala-31d30658306f15160775e9a125b0dad4ab155332.tar.gz
Add support for "with" statementwip/issue/327
Create data-type scoped blocks Fixes https://gitlab.gnome.org/GNOME/vala/issues/327
Diffstat (limited to 'vala/valawithstatement.vala')
-rw-r--r--vala/valawithstatement.vala150
1 files changed, 150 insertions, 0 deletions
diff --git a/vala/valawithstatement.vala b/vala/valawithstatement.vala
new file mode 100644
index 000000000..f873e600c
--- /dev/null
+++ b/vala/valawithstatement.vala
@@ -0,0 +1,150 @@
+/* valawithtatement.vala
+ *
+ * Copyright (C) 2020 Nick Schrader
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Nick Schrader <nick.schrader@mailbox.org>
+ */
+
+public class Vala.WithStatement : Block {
+ /**
+ * Expression representing the type of body's dominant scope.
+ */
+ public Expression expression {
+ get { return _expression; }
+ private set {
+ _expression = value;
+ _expression.parent_node = this;
+ }
+ }
+
+ /**
+ * Specifies the with-variable.
+ */
+ public LocalVariable? with_variable { get; private set; }
+
+ /**
+ * The block which dominant scope is type of expression.
+ */
+ public Block body {
+ get { return _body; }
+ private set {
+ _body = value;
+ _body.parent_node = this;
+ }
+ }
+
+ Expression _expression;
+ Block _body;
+
+ public WithStatement (LocalVariable? variable, Expression expression, Block body, SourceReference? source_reference = null) {
+ base (source_reference);
+ this.with_variable = variable;
+ this.expression = expression;
+ this.body = body;
+ }
+
+ public override void accept (CodeVisitor visitor) {
+ visitor.visit_with_statement (this);
+ }
+
+ public override void accept_children (CodeVisitor visitor) {
+ if (expression.symbol_reference == with_variable) {
+ expression.accept (visitor);
+ }
+
+ if (with_variable != null) {
+ with_variable.accept (visitor);
+ }
+
+ body.accept (visitor);
+ }
+
+ bool is_object_or_value_type (DataType? type) {
+ if (type == null) {
+ return false;
+ } else if (type is PointerType) {
+ var pointer_type = (PointerType) type;
+ return is_object_or_value_type (pointer_type.base_type) && expression is PointerIndirection;
+ } else {
+ return type is ObjectType || type is ValueType;
+ }
+ }
+
+ public override bool check (CodeContext context) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ if (!expression.check (context)) {
+ error = true;
+ return false;
+ }
+
+ if (!is_object_or_value_type (expression.value_type)) {
+ error = true;
+ Report.error (expression.source_reference, "with statement expects an object or basic type");
+ return false;
+ }
+
+ var local_var = expression.symbol_reference as LocalVariable;
+ if (with_variable != null || local_var == null) {
+ if (with_variable == null) {
+ local_var = new LocalVariable (expression.value_type.copy (), get_temp_name (), expression, source_reference);
+ } else {
+ local_var = with_variable;
+ }
+ body.insert_statement (0, new DeclarationStatement (local_var, source_reference));
+ }
+ with_variable = local_var;
+
+ var old_symbol = context.analyzer.current_symbol;
+ owner = context.analyzer.current_symbol.scope;
+ context.analyzer.current_symbol = this;
+
+ if (!body.check (context)) {
+ error = true;
+ }
+
+ context.analyzer.current_symbol = old_symbol;
+
+ return !error;
+ }
+
+ public override void emit (CodeGenerator codegen) {
+ if (expression.symbol_reference == with_variable) {
+ expression.emit (codegen);
+ }
+ body.emit (codegen);
+ }
+
+ public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+ if (source_reference == null) {
+ source_reference = this.source_reference;
+ }
+ expression.get_error_types (collection, source_reference);
+ body.get_error_types (collection, source_reference);
+ }
+
+ public override void get_defined_variables (Collection<Variable> collection) {
+ if (expression.symbol_reference != with_variable) {
+ collection.add (with_variable);
+ }
+ }
+}