1/* valaswitchlabel.vala
2 *
3 * Copyright (C) 2006-2010  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 switch label in the source code.
27 */
28public class Vala.SwitchLabel : CodeNode {
29	/**
30	 * Specifies the label expression.
31	 */
32	public Expression expression {
33		get { return _expression; }
34		set {
35			_expression = value;
36			_expression.parent_node = this;
37		}
38	}
39
40	public weak SwitchSection section {
41		get { return (SwitchSection) parent_node; }
42	}
43
44	private Expression _expression;
45
46	/**
47	 * Creates a new switch case label.
48	 *
49	 * @param expr   label expression
50	 * @param source reference to source code
51	 * @return       newly created switch case label
52	 */
53	public SwitchLabel (Expression expr, SourceReference? source = null) {
54		expression = expr;
55		source_reference = source;
56	}
57
58	/**
59	 * Creates a new switch default label.
60	 *
61	 * @param source reference to source code
62	 * @return       newly created switch default label
63	 */
64	public SwitchLabel.with_default (SourceReference? source = null) {
65		source_reference = source;
66	}
67
68	public override void accept (CodeVisitor visitor) {
69		visitor.visit_switch_label (this);
70	}
71
72	public override void accept_children (CodeVisitor visitor) {
73		if (expression != null) {
74			expression.accept (visitor);
75
76			visitor.visit_end_full_expression (expression);
77		}
78	}
79
80	public override bool check (CodeContext context) {
81		if (checked) {
82			return !error;
83		}
84
85		checked = true;
86
87		if (expression != null) {
88			var switch_statement = (SwitchStatement) section.parent_node;
89
90			// enum-type inference
91			var condition_target_type = switch_statement.expression.target_type;
92			if (expression.symbol_reference == null && condition_target_type != null && condition_target_type.type_symbol is Enum) {
93				var enum_type = (Enum) condition_target_type.type_symbol;
94				foreach (var val in enum_type.get_values ()) {
95					if (expression.to_string () == val.name) {
96						expression.target_type = condition_target_type.copy ();
97						expression.symbol_reference = val;
98						break;
99					}
100				}
101			}
102
103			if (!expression.check (context)) {
104				error = true;
105				return false;
106			}
107
108			if (!expression.is_constant ()) {
109				error = true;
110				Report.error (expression.source_reference, "Expression must be constant");
111				return false;
112			}
113			if (!expression.value_type.compatible (switch_statement.expression.value_type)) {
114				error = true;
115				Report.error (expression.source_reference, "Cannot convert from `%s' to `%s'".printf (expression.value_type.to_string (), switch_statement.expression.value_type.to_string ()));
116				return false;
117			}
118		}
119
120		return true;
121	}
122
123	public override void emit (CodeGenerator codegen) {
124		codegen.visit_switch_label (this);
125	}
126}
127