girparser: Provide default constructor for classes.
[vala-lang.git] / vala / valaconstant.vala
blob0c77d07bce2e467791b338b8199784035fc62821
1 /* valaconstant.vala
3 * Copyright (C) 2006-2011 Jürg Billeter
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.
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.
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents a type member with a constant value.
28 public class Vala.Constant : Symbol, Lockable {
29 /**
30 * The data type of this constant.
32 public DataType type_reference {
33 get { return _data_type; }
34 set {
35 _data_type = value;
36 _data_type.parent_node = this;
40 /**
41 * The value of this constant.
43 public Expression? value {
44 get { return _value; }
45 set {
46 _value = value;
47 if (_value != null) {
48 _value.parent_node = this;
53 private string cname;
55 private bool lock_used = false;
57 private DataType _data_type;
59 private Expression _value;
61 /**
62 * Creates a new constant.
64 * @param name constant name
65 * @param type_reference constant type
66 * @param value constant value
67 * @param source_reference reference to source code
68 * @return newly created constant
70 public Constant (string name, DataType? type_reference, Expression? value, SourceReference? source_reference, Comment? comment = null) {
71 base (name, source_reference, comment);
72 if (type_reference != null) {
73 this.type_reference = type_reference;
75 this.value = value;
78 public override void accept (CodeVisitor visitor) {
79 visitor.visit_constant (this);
82 public override void accept_children (CodeVisitor visitor) {
83 type_reference.accept (visitor);
85 if (value != null) {
86 value.accept (visitor);
90 /**
91 * Returns the name of this constant as it is used in C code.
93 * @return the name to be used in C code
95 public string get_cname () {
96 if (cname == null) {
97 cname = get_default_cname ();
99 return cname;
103 * Returns the default name of this constant as it is used in C
104 * code.
106 * @return the name to be used in C code by default
108 public virtual string get_default_cname () {
109 if (parent_symbol == null) {
110 // global constant
111 return name;
112 } else {
113 return "%s%s".printf (parent_symbol.get_lower_case_cprefix ().up (), name);
117 public void set_cname (string value) {
118 this.cname = value;
121 public bool get_lock_used () {
122 return lock_used;
125 public void set_lock_used (bool used) {
126 lock_used = used;
129 public override void replace_expression (Expression old_node, Expression new_node) {
130 if (value == old_node) {
131 value = new_node;
135 public override void replace_type (DataType old_type, DataType new_type) {
136 if (type_reference == old_type) {
137 type_reference = new_type;
141 private void process_ccode_attribute (Attribute a) {
142 if (a.has_argument ("cname")) {
143 cname = a.get_string ("cname");
145 if (a.has_argument ("cheader_filename")) {
146 var val = a.get_string ("cheader_filename");
147 foreach (string filename in val.split (",")) {
148 add_cheader_filename (filename);
154 * Process all associated attributes.
156 public void process_attributes () {
157 foreach (Attribute a in attributes) {
158 if (a.name == "CCode") {
159 process_ccode_attribute (a);
160 } else if (a.name == "Deprecated") {
161 process_deprecated_attribute (a);
162 } else if (a.name == "Experimental") {
163 process_experimental_attribute (a);
168 public override bool check (CodeContext context) {
169 if (checked) {
170 return !error;
173 checked = true;
175 process_attributes ();
177 var old_source_file = context.analyzer.current_source_file;
178 var old_symbol = context.analyzer.current_symbol;
180 if (source_reference != null) {
181 context.analyzer.current_source_file = source_reference.file;
183 context.analyzer.current_symbol = this;
185 type_reference.check (context);
187 if (!check_const_type (type_reference, context)) {
188 error = true;
189 Report.error (source_reference, "`%s' not supported as type for constants".printf (type_reference.to_string ()));
190 return false;
193 if (!external) {
194 if (value == null) {
195 error = true;
196 Report.error (source_reference, "A const field requires a value to be provided");
197 } else {
198 value.target_type = type_reference;
200 value.check (context);
202 if (!value.value_type.compatible (type_reference)) {
203 error = true;
204 Report.error (source_reference, "Cannot convert from `%s' to `%s'".printf (value.value_type.to_string (), type_reference.to_string ()));
205 return false;
208 // support translated string constants for efficiency / convenience
209 // even though the expression is not a compile-time constant
210 var call = value as MethodCall;
211 if (call != null) {
212 var method_type = call.call.value_type as MethodType;
213 if (method_type != null && method_type.method_symbol.get_full_name () == "GLib._") {
214 // first argument is string
215 var literal = call.get_argument_list ().get (0) as StringLiteral;
216 if (literal != null) {
217 value = literal;
218 literal.translate = true;
223 if (!value.is_constant ()) {
224 error = true;
225 Report.error (value.source_reference, "Value must be constant");
226 return false;
229 } else {
230 if (value != null) {
231 error = true;
232 Report.error (source_reference, "External constants cannot use values");
236 if (!external_package && !hides && get_hidden_member () != null) {
237 Report.warning (source_reference, "%s hides inherited constant `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
240 context.analyzer.current_source_file = old_source_file;
241 context.analyzer.current_symbol = old_symbol;
243 active = true;
245 return !error;
248 bool check_const_type (DataType type, CodeContext context) {
249 if (type is ValueType) {
250 return true;
251 } else if (type is ArrayType) {
252 var array_type = type as ArrayType;
253 return check_const_type (array_type.element_type, context);
254 } else if (type.data_type == context.analyzer.string_type.data_type) {
255 return true;
256 } else {
257 return false;