Line data Source code
1 : /* valaconstant.vala
2 : *
3 : * Copyright (C) 2006-2011 Jürg Billeter
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2.1 of the License, or (at your option) any later version.
9 :
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 :
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a type member with a constant value.
27 : */
28 2562483 : public class Vala.Constant : Symbol {
29 : /**
30 : * The data type of this constant.
31 : */
32 : public DataType type_reference {
33 4433044 : get { return _data_type; }
34 1675512 : private set {
35 5258638 : _data_type = value;
36 1675512 : _data_type.parent_node = this;
37 : }
38 : }
39 :
40 : /**
41 : * The value of this constant.
42 : */
43 : public Expression? value {
44 3030270 : get { return _value; }
45 2560946 : private set {
46 2561197 : _value = value;
47 2560946 : if (_value != null) {
48 251 : _value.parent_node = this;
49 : }
50 : }
51 : }
52 :
53 2560945 : private DataType _data_type;
54 :
55 2560945 : private Expression _value;
56 :
57 : /**
58 : * Creates a new constant.
59 : *
60 : * @param name constant name
61 : * @param type_reference constant type
62 : * @param value constant value
63 : * @param source_reference reference to source code
64 : * @return newly created constant
65 : */
66 6185345 : public Constant (string name, DataType? type_reference, Expression? value, SourceReference? source_reference = null, Comment? comment = null) {
67 2560945 : base (name, source_reference, comment);
68 2560945 : if (type_reference != null) {
69 1063455 : this.type_reference = type_reference;
70 : }
71 2560945 : this.value = value;
72 : }
73 :
74 1535470 : public override void accept (CodeVisitor visitor) {
75 1535470 : visitor.visit_constant (this);
76 : }
77 :
78 612100 : public override void accept_children (CodeVisitor visitor) {
79 612100 : type_reference.accept (visitor);
80 :
81 612100 : if (value != null) {
82 186 : value.accept (visitor);
83 : }
84 : }
85 :
86 0 : public override void replace_expression (Expression old_node, Expression new_node) {
87 0 : if (value == old_node) {
88 0 : value = new_node;
89 : }
90 : }
91 :
92 612057 : public override void replace_type (DataType old_type, DataType new_type) {
93 612057 : if (type_reference == old_type) {
94 612057 : type_reference = new_type;
95 : }
96 : }
97 :
98 1160042 : public override bool check (CodeContext context) {
99 1160042 : if (checked) {
100 137862 : return !error;
101 : }
102 :
103 1022180 : checked = true;
104 :
105 1022180 : var old_source_file = context.analyzer.current_source_file;
106 1022180 : var old_symbol = context.analyzer.current_symbol;
107 :
108 1022180 : if (source_reference != null) {
109 1022137 : context.analyzer.current_source_file = source_reference.file;
110 : }
111 1022180 : if (!(parent_symbol is Block)) {
112 : // non-local constant
113 1022157 : context.analyzer.current_symbol = this;
114 : }
115 :
116 1022180 : type_reference.check (context);
117 :
118 1022180 : if (!check_const_type (type_reference, context)) {
119 2 : error = true;
120 2 : Report.error (source_reference, "`%s' not supported as type for constants", type_reference.to_string ());
121 2 : return false;
122 : }
123 :
124 : // check whether constant type is at least as accessible as the constant
125 1022178 : if (!type_reference.is_accessible (this)) {
126 1 : error = true;
127 1 : Report.error (source_reference, "constant type `%s' is less accessible than constant `%s'", type_reference.to_string (), get_full_name ());
128 : }
129 :
130 1022178 : if (!external) {
131 185 : if (value == null) {
132 : // constants from fast-vapi files are special
133 2 : if (source_type != SourceFileType.FAST) {
134 1 : error = true;
135 1 : Report.error (source_reference, "A const field requires a value to be provided");
136 : }
137 : } else {
138 183 : value.target_type = type_reference;
139 :
140 183 : if (!value.check (context) || type_reference.error) {
141 1 : error = true;
142 1 : return false;
143 : }
144 :
145 182 : if (!value.value_type.compatible (type_reference)) {
146 1 : error = true;
147 1 : Report.error (source_reference, "Cannot convert from `%s' to `%s'", value.value_type.to_string (), type_reference.to_string ());
148 1 : return false;
149 : }
150 :
151 : // support translated string constants for efficiency / convenience
152 : // even though the expression is not a compile-time constant
153 181 : unowned MethodCall? call = value as MethodCall;
154 4 : if (call != null) {
155 4 : unowned MethodType? method_type = call.call.value_type as MethodType;
156 5 : if (method_type != null && method_type.method_symbol.get_full_name () == "GLib._") {
157 : // first argument is string
158 1 : var literal = call.get_argument_list ().get (0) as StringLiteral;
159 1 : if (literal != null) {
160 1 : value = literal;
161 1 : literal.translate = true;
162 : }
163 : }
164 : }
165 :
166 181 : if (!value.is_constant ()) {
167 1 : error = true;
168 1 : Report.error (value.source_reference, "Value must be constant");
169 1 : return false;
170 : }
171 :
172 : // check whether initializer is at least as accessible as the constant
173 180 : if (!value.is_accessible (this)) {
174 1 : error = true;
175 1 : Report.error (value.source_reference, "value is less accessible than constant `%s'", get_full_name ());
176 : }
177 : }
178 : } else {
179 1021993 : if (value != null) {
180 1 : error = true;
181 1 : Report.error (source_reference, "External constants cannot use values");
182 : }
183 : }
184 :
185 1022175 : if (!external_package && !hides && get_hidden_member () != null) {
186 0 : Report.warning (source_reference, "%s hides inherited constant `%s'. Use the `new' keyword if hiding was intentional", get_full_name (), get_hidden_member ().get_full_name ());
187 : }
188 :
189 1022175 : context.analyzer.current_source_file = old_source_file;
190 1022175 : context.analyzer.current_symbol = old_symbol;
191 :
192 1022175 : active = true;
193 :
194 1022175 : return !error;
195 : }
196 :
197 1022219 : bool check_const_type (DataType type, CodeContext context) {
198 1022219 : if (type is ValueType) {
199 1022180 : return true;
200 296794 : } else if (type is VoidType || type is PointerType) {
201 2 : return false;
202 296792 : } else if (type is ArrayType) {
203 39 : unowned ArrayType array_type = (ArrayType) type;
204 39 : return check_const_type (array_type.element_type, context);
205 296753 : } else if (type is DelegateType) {
206 2 : unowned DelegateType delegate_type = (DelegateType) type;
207 2 : return !delegate_type.type_symbol.get_attribute_bool ("CCode", "has_target", true);
208 296751 : } else if (type.type_symbol != null) {
209 296751 : return type.type_symbol.is_subtype_of (context.analyzer.string_type.type_symbol);
210 : } else {
211 2 : return false;
212 : }
213 : }
214 : }
|