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 23using GLib; 24 25/** 26 * Represents a type member with a constant value. 27 */ 28public class Vala.Constant : Symbol { 29 /** 30 * The data type of this constant. 31 */ 32 public DataType type_reference { 33 get { return _data_type; } 34 set { 35 _data_type = value; 36 _data_type.parent_node = this; 37 } 38 } 39 40 /** 41 * The value of this constant. 42 */ 43 public Expression? value { 44 get { return _value; } 45 set { 46 _value = value; 47 if (_value != null) { 48 _value.parent_node = this; 49 } 50 } 51 } 52 53 private DataType _data_type; 54 55 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 public Constant (string name, DataType? type_reference, Expression? value, SourceReference? source_reference = null, Comment? comment = null) { 67 base (name, source_reference, comment); 68 if (type_reference != null) { 69 this.type_reference = type_reference; 70 } 71 this.value = value; 72 } 73 74 public override void accept (CodeVisitor visitor) { 75 visitor.visit_constant (this); 76 } 77 78 public override void accept_children (CodeVisitor visitor) { 79 type_reference.accept (visitor); 80 81 if (value != null) { 82 value.accept (visitor); 83 } 84 } 85 86 public override void replace_expression (Expression old_node, Expression new_node) { 87 if (value == old_node) { 88 value = new_node; 89 } 90 } 91 92 public override void replace_type (DataType old_type, DataType new_type) { 93 if (type_reference == old_type) { 94 type_reference = new_type; 95 } 96 } 97 98 public override bool check (CodeContext context) { 99 if (checked) { 100 return !error; 101 } 102 103 checked = true; 104 105 var old_source_file = context.analyzer.current_source_file; 106 var old_symbol = context.analyzer.current_symbol; 107 108 if (source_reference != null) { 109 context.analyzer.current_source_file = source_reference.file; 110 } 111 if (!(parent_symbol is Block)) { 112 // non-local constant 113 context.analyzer.current_symbol = this; 114 } 115 116 type_reference.check (context); 117 118 if (!check_const_type (type_reference, context)) { 119 error = true; 120 Report.error (source_reference, "`%s' not supported as type for constants".printf (type_reference.to_string ())); 121 return false; 122 } 123 124 if (!external) { 125 if (value == null) { 126 // constants from fast-vapi files are special 127 if (source_type != SourceFileType.FAST) { 128 error = true; 129 Report.error (source_reference, "A const field requires a value to be provided"); 130 } 131 } else { 132 value.target_type = type_reference; 133 134 if (!value.check (context) || type_reference.error) { 135 error = true; 136 return false; 137 } 138 139 if (!value.value_type.compatible (type_reference)) { 140 error = true; 141 Report.error (source_reference, "Cannot convert from `%s' to `%s'".printf (value.value_type.to_string (), type_reference.to_string ())); 142 return false; 143 } 144 145 // support translated string constants for efficiency / convenience 146 // even though the expression is not a compile-time constant 147 unowned MethodCall? call = value as MethodCall; 148 if (call != null) { 149 unowned MethodType? method_type = call.call.value_type as MethodType; 150 if (method_type != null && method_type.method_symbol.get_full_name () == "GLib._") { 151 // first argument is string 152 var literal = call.get_argument_list ().get (0) as StringLiteral; 153 if (literal != null) { 154 value = literal; 155 literal.translate = true; 156 } 157 } 158 } 159 160 if (!value.is_constant ()) { 161 error = true; 162 Report.error (value.source_reference, "Value must be constant"); 163 return false; 164 } 165 } 166 } else { 167 if (value != null) { 168 error = true; 169 Report.error (source_reference, "External constants cannot use values"); 170 } 171 } 172 173 if (!external_package && !hides && get_hidden_member () != null) { 174 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 ())); 175 } 176 177 context.analyzer.current_source_file = old_source_file; 178 context.analyzer.current_symbol = old_symbol; 179 180 active = true; 181 182 return !error; 183 } 184 185 bool check_const_type (DataType type, CodeContext context) { 186 if (type is ValueType) { 187 return true; 188 } else if (type is VoidType || type is PointerType) { 189 return false; 190 } else if (type is ArrayType) { 191 unowned ArrayType array_type = (ArrayType) type; 192 return check_const_type (array_type.element_type, context); 193 } else if (type.type_symbol != null) { 194 return type.type_symbol.is_subtype_of (context.analyzer.string_type.type_symbol); 195 } else { 196 return false; 197 } 198 } 199} 200