Line data Source code
1 : /* valaswitchstatement.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 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a switch selection statement in the source code.
27 : */
28 290 : public class Vala.SwitchStatement : CodeNode, Statement {
29 : /**
30 : * Specifies the switch expression.
31 : */
32 : public Expression expression {
33 3632 : get {
34 3632 : return _expression;
35 : }
36 118 : private set {
37 118 : _expression = value;
38 118 : _expression.parent_node = this;
39 : }
40 : }
41 :
42 112 : private Expression _expression;
43 224 : private List<SwitchSection> sections = new ArrayList<SwitchSection> ();
44 :
45 : /**
46 : * Creates a new switch statement.
47 : *
48 : * @param expression switch expression
49 : * @param source_reference reference to source code
50 : * @return newly created switch statement
51 : */
52 336 : public SwitchStatement (Expression expression, SourceReference? source_reference = null) {
53 112 : this.source_reference = source_reference;
54 112 : this.expression = expression;
55 : }
56 :
57 : /**
58 : * Appends the specified section to the list of switch sections.
59 : *
60 : * @param section a switch section
61 : */
62 572 : public void add_section (SwitchSection section) {
63 572 : section.parent_node = this;
64 572 : sections.add (section);
65 : }
66 :
67 : /**
68 : * Returns the list of switch sections.
69 : *
70 : * @return section list
71 : */
72 235 : public unowned List<SwitchSection> get_sections () {
73 235 : return sections;
74 : }
75 :
76 217 : public override void accept (CodeVisitor visitor) {
77 217 : visitor.visit_switch_statement (this);
78 : }
79 :
80 113 : public override void accept_children (CodeVisitor visitor) {
81 113 : expression.accept (visitor);
82 :
83 113 : visitor.visit_end_full_expression (expression);
84 :
85 1269 : foreach (SwitchSection section in sections) {
86 578 : section.accept (visitor);
87 : }
88 : }
89 :
90 6 : public override void replace_expression (Expression old_node, Expression new_node) {
91 6 : if (expression == old_node) {
92 6 : expression = new_node;
93 : }
94 : }
95 :
96 117 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
97 1335 : foreach (SwitchSection section in sections) {
98 609 : section.get_error_types (collection, source_reference);
99 : }
100 : }
101 :
102 109 : public override bool check (CodeContext context) {
103 109 : if (checked) {
104 0 : return !error;
105 : }
106 :
107 109 : checked = true;
108 :
109 109 : if (!expression.check (context)) {
110 1 : error = true;
111 1 : return false;
112 : }
113 :
114 108 : if (expression.value_type == null ||
115 108 : (!(expression.value_type is IntegerType) &&
116 69 : !(expression.value_type is EnumValueType) &&
117 29 : !expression.value_type.compatible (context.analyzer.string_type))) {
118 0 : Report.error (expression.source_reference, "Integer or string expression expected");
119 0 : error = true;
120 0 : return false;
121 : }
122 :
123 : // ensure that possibly owned (string) expression stays alive
124 108 : expression.target_type = expression.value_type.copy ();
125 108 : expression.target_type.nullable = false;
126 :
127 108 : var labelset = new HashSet<string> (str_hash, str_equal);
128 1248 : foreach (SwitchSection section in sections) {
129 570 : section.check (context);
130 :
131 : // check for duplicate literal case labels
132 1896 : foreach (SwitchLabel label in section.get_labels ()) {
133 663 : if (label.expression != null) {
134 591 : string? value = null;
135 591 : if (label.expression is StringLiteral) {
136 134 : value = ((StringLiteral)label.expression).eval ();
137 457 : } else if (label.expression is Literal) {
138 191 : value = ((Literal)label.expression).to_string ();
139 266 : } else if (label.expression.is_constant ()) {
140 265 : value = label.expression.to_string ();
141 : }
142 :
143 1181 : if (value != null && !labelset.add (value)) {
144 1 : error = true;
145 1 : Report.error (label.expression.source_reference, "Switch statement already contains this label");
146 : }
147 : }
148 : }
149 : }
150 :
151 108 : return !error;
152 : }
153 :
154 102 : public override void emit (CodeGenerator codegen) {
155 102 : expression.emit (codegen);
156 :
157 102 : codegen.visit_end_full_expression (expression);
158 :
159 102 : codegen.visit_switch_statement (this);
160 : }
161 : }
|