Line data Source code
1 : /* valalockstatement.vala
2 : *
3 : * Copyright (C) 2009 Jiří Zárevúcky
4 : * Copyright (C) 2006-2010 Jürg Billeter
5 : * Copyright (C) 2006-2007 Raffaele Sandrini
6 : *
7 : * This library is free software; you can redistribute it and/or
8 : * modify it under the terms of the GNU Lesser General Public
9 : * License as published by the Free Software Foundation; either
10 : * version 2.1 of the License, or (at your option) any later version.
11 :
12 : * This library is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * Lesser General Public License for more details.
16 :
17 : * You should have received a copy of the GNU Lesser General Public
18 : * License along with this library; if not, write to the Free Software
19 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 : *
21 : * Authors:
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : * Jiří Zárevúcky <zarevucky.jiri@gmail.com>
24 : */
25 :
26 : using GLib;
27 :
28 : /**
29 : * Represents a lock statement.
30 : *
31 : * {{{ lock (foo); }}} or {{{ lock (foo) { ... } }}}
32 : *
33 : * If the statement is empty, the mutex remains locked until a corresponding
34 : * {@link Vala.UnlockStatement} occurs. Otherwise it's translated into a
35 : * try/finally statement which unlocks the mutex after the block is finished.
36 : */
37 73 : public class Vala.LockStatement : CodeNode, Statement {
38 : /**
39 : * Expression representing the resource to be locked.
40 : */
41 : public Expression resource {
42 306 : get { return _resource; }
43 55 : private set {
44 136 : _resource = value;
45 55 : _resource.parent_node = this;
46 : }
47 : }
48 :
49 : /**
50 : * The statement during its execution the resource is locked.
51 : */
52 : public Block? body {
53 214 : get { return _body; }
54 55 : private set {
55 81 : _body = value;
56 55 : if (_body != null) {
57 26 : _body.parent_node = this;
58 : }
59 : }
60 : }
61 :
62 55 : private Expression _resource;
63 55 : private Block _body;
64 :
65 165 : public LockStatement (Expression resource, Block? body, SourceReference? source_reference = null) {
66 55 : this.body = body;
67 55 : this.source_reference = source_reference;
68 55 : this.resource = resource;
69 : }
70 :
71 55 : public override void accept (CodeVisitor visitor) {
72 55 : resource.accept (visitor);
73 55 : if (body != null) {
74 26 : body.accept (visitor);
75 : }
76 55 : visitor.visit_lock_statement (this);
77 : }
78 :
79 0 : public override void replace_expression (Expression old_node, Expression new_node) {
80 0 : if (resource == old_node) {
81 0 : resource = new_node;
82 : }
83 : }
84 :
85 55 : public override bool check (CodeContext context) {
86 55 : if (body != null) {
87 26 : if (!body.check (context)) {
88 3 : return false;
89 : }
90 :
91 : // if the statement isn't empty, it is converted into a try statement
92 26 : var fin_body = new Block (source_reference);
93 26 : fin_body.add_statement (new UnlockStatement (resource, source_reference));
94 :
95 26 : var try_stmt = new TryStatement (body, fin_body, source_reference);
96 27 : if (body.tree_can_fail) {
97 1 : var catch_body = new Block (source_reference);
98 1 : catch_body.add_statement (new ThrowStatement (new ReferenceTransferExpression (new MemberAccess.simple ("_lock_error_")), source_reference));
99 1 : var catch_clause = new CatchClause (new ErrorType (null, null), "_lock_error_", catch_body, source_reference);
100 1 : catch_clause.error_type.value_owned = true;
101 1 : try_stmt.add_catch_clause (catch_clause);
102 : }
103 :
104 26 : var block = new Block (source_reference);
105 26 : block.add_statement (new LockStatement (resource, null, source_reference));
106 26 : block.add_statement (try_stmt);
107 :
108 26 : var parent_block = (Block) parent_node;
109 26 : parent_block.replace_statement (this, block);
110 :
111 26 : return block.check (context);
112 : }
113 :
114 29 : if (checked) {
115 0 : return !error;
116 : }
117 :
118 29 : checked = true;
119 :
120 29 : resource.check (context);
121 :
122 : /* resource must be a member access and denote a Lockable */
123 29 : if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) {
124 1 : error = true;
125 1 : resource.error = true;
126 1 : Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
127 1 : return false;
128 : }
129 :
130 : /* parent symbol must be the current class */
131 28 : if (resource.symbol_reference.parent_symbol != context.analyzer.current_class) {
132 1 : error = true;
133 1 : resource.error = true;
134 1 : Report.error (resource.source_reference, "Only members of the current class are lockable");
135 1 : return false;
136 : }
137 :
138 : /* parent class must not be compact */
139 27 : if (context.analyzer.current_class.is_compact) {
140 1 : error = true;
141 1 : resource.error = true;
142 1 : Report.error (resource.source_reference, "Only members of the non-compact classes are lockable");
143 1 : return false;
144 : }
145 :
146 26 : ((Lockable) resource.symbol_reference).lock_used = true;
147 :
148 26 : return !error;
149 : }
150 :
151 26 : public override void emit (CodeGenerator codegen) {
152 26 : resource.emit (codegen);
153 26 : codegen.visit_lock_statement (this);
154 : }
155 : }
|