dfsm: Add all the missing API reference comments
[bendy-bus:bendy-bus.git] / dfsm / dfsm-ast-statement-assignment.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * D-Bus Simulator
4  * Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk>
5  * 
6  * D-Bus Simulator is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * D-Bus Simulator is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with D-Bus Simulator.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * SECTION:dfsm-ast-statement-assignment
22  * @short_description: AST assignment statement node
23  * @stability: Unstable
24  * @include: dfsm/dfsm-ast-statement-assignment.h
25  *
26  * AST assignment statement implementing support for assigning new values to variables and structures of variables.
27  */
28
29 #include "config.h"
30
31 #include <glib.h>
32 #include <glib/gi18n-lib.h>
33
34 #include "dfsm-ast-statement-assignment.h"
35 #include "dfsm-parser.h"
36 #include "dfsm-parser-internal.h"
37
38 static void dfsm_ast_statement_assignment_dispose (GObject *object);
39 static void dfsm_ast_statement_assignment_sanity_check (DfsmAstNode *node);
40 static void dfsm_ast_statement_assignment_pre_check_and_register (DfsmAstNode *node, DfsmEnvironment *environment, GError **error);
41 static void dfsm_ast_statement_assignment_check (DfsmAstNode *node, DfsmEnvironment *environment, GError **error);
42 static void dfsm_ast_statement_assignment_execute (DfsmAstStatement *statement, DfsmEnvironment *environment, DfsmOutputSequence *output_sequence);
43
44 struct _DfsmAstStatementAssignmentPrivate {
45         DfsmAstDataStructure *data_structure; /* lvalue */
46         DfsmAstExpression *expression; /* rvalue */
47 };
48
49 G_DEFINE_TYPE (DfsmAstStatementAssignment, dfsm_ast_statement_assignment, DFSM_TYPE_AST_STATEMENT)
50
51 static void
52 dfsm_ast_statement_assignment_class_init (DfsmAstStatementAssignmentClass *klass)
53 {
54         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
55         DfsmAstNodeClass *node_class = DFSM_AST_NODE_CLASS (klass);
56         DfsmAstStatementClass *statement_class = DFSM_AST_STATEMENT_CLASS (klass);
57
58         g_type_class_add_private (klass, sizeof (DfsmAstStatementAssignmentPrivate));
59
60         gobject_class->dispose = dfsm_ast_statement_assignment_dispose;
61
62         node_class->sanity_check = dfsm_ast_statement_assignment_sanity_check;
63         node_class->pre_check_and_register = dfsm_ast_statement_assignment_pre_check_and_register;
64         node_class->check = dfsm_ast_statement_assignment_check;
65
66         statement_class->execute = dfsm_ast_statement_assignment_execute;
67 }
68
69 static void
70 dfsm_ast_statement_assignment_init (DfsmAstStatementAssignment *self)
71 {
72         self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, DFSM_TYPE_AST_STATEMENT_ASSIGNMENT, DfsmAstStatementAssignmentPrivate);
73 }
74
75 static void
76 dfsm_ast_statement_assignment_dispose (GObject *object)
77 {
78         DfsmAstStatementAssignmentPrivate *priv = DFSM_AST_STATEMENT_ASSIGNMENT (object)->priv;
79
80         g_clear_object (&priv->expression);
81         g_clear_object (&priv->data_structure);
82
83         /* Chain up to the parent class */
84         G_OBJECT_CLASS (dfsm_ast_statement_assignment_parent_class)->dispose (object);
85 }
86
87 static void
88 dfsm_ast_statement_assignment_sanity_check (DfsmAstNode *node)
89 {
90         DfsmAstStatementAssignmentPrivate *priv = DFSM_AST_STATEMENT_ASSIGNMENT (node)->priv;
91
92         g_assert (priv->data_structure != NULL);
93         dfsm_ast_node_sanity_check (DFSM_AST_NODE (priv->data_structure));
94
95         g_assert (priv->expression != NULL);
96         dfsm_ast_node_sanity_check (DFSM_AST_NODE (priv->expression));
97 }
98
99 static void
100 dfsm_ast_statement_assignment_pre_check_and_register (DfsmAstNode *node, DfsmEnvironment *environment, GError **error)
101 {
102         DfsmAstStatementAssignmentPrivate *priv = DFSM_AST_STATEMENT_ASSIGNMENT (node)->priv;
103
104         dfsm_ast_node_pre_check_and_register (DFSM_AST_NODE (priv->data_structure), environment, error);
105
106         if (*error != NULL) {
107                 return;
108         }
109
110         dfsm_ast_node_pre_check_and_register (DFSM_AST_NODE (priv->expression), environment, error);
111
112         if (*error != NULL) {
113                 return;
114         }
115 }
116
117 static void
118 dfsm_ast_statement_assignment_check (DfsmAstNode *node, DfsmEnvironment *environment, GError **error)
119 {
120         DfsmAstStatementAssignmentPrivate *priv = DFSM_AST_STATEMENT_ASSIGNMENT (node)->priv;
121         GVariantType *lvalue_type, *rvalue_type;
122
123         /* Check the sub-nodes first .*/
124         dfsm_ast_node_check (DFSM_AST_NODE (priv->data_structure), environment, error);
125
126         if (*error != NULL) {
127                 return;
128         }
129
130         dfsm_ast_node_check (DFSM_AST_NODE (priv->expression), environment, error);
131
132         if (*error != NULL) {
133                 return;
134         }
135
136         /* Check that the l-value can actually be assigned to: it has to be a data structure with leaf nodes which are only variables (apart from
137          * dictionary keys, which can have any type). */
138         if (dfsm_ast_data_structure_is_variable (priv->data_structure) == FALSE) {
139                 g_set_error (error, DFSM_PARSE_ERROR, DFSM_PARSE_ERROR_AST_INVALID,
140                              _("Non-variable data structure as the l-value of an assignment: "
141                                "only data structures consisting of only variables may be assigned to."));
142
143                 return;
144         }
145
146         /* Check the types of the l- and r-values are compatible. */
147         lvalue_type = dfsm_ast_data_structure_calculate_type (priv->data_structure, environment);
148         rvalue_type = dfsm_ast_expression_calculate_type (priv->expression, environment);
149
150         if (g_variant_type_is_subtype_of (rvalue_type, lvalue_type) == FALSE) {
151                 gchar *expected, *received;
152
153                 expected = g_variant_type_dup_string (lvalue_type);
154                 received = g_variant_type_dup_string (rvalue_type);
155
156                 g_variant_type_free (lvalue_type);
157                 g_variant_type_free (rvalue_type);
158
159                 g_set_error (error, DFSM_PARSE_ERROR, DFSM_PARSE_ERROR_AST_INVALID,
160                              _("Type mismatch for assignment: expected l-value type %s but received r-value type %s."), expected, received);
161
162                 return;
163         }
164
165         g_variant_type_free (lvalue_type);
166         g_variant_type_free (rvalue_type);
167 }
168
169 static void
170 dfsm_ast_statement_assignment_execute (DfsmAstStatement *statement, DfsmEnvironment *environment, DfsmOutputSequence *output_sequence)
171 {
172         DfsmAstStatementAssignmentPrivate *priv = DFSM_AST_STATEMENT_ASSIGNMENT (statement)->priv;
173         GVariant *rvalue;
174
175         /* Evaluate the rvalue */
176         rvalue = dfsm_ast_expression_evaluate (priv->expression, environment);
177         g_assert (rvalue != NULL);
178
179         /* Perform the assignment */
180         dfsm_ast_data_structure_set_from_variant (priv->data_structure, environment, rvalue);
181
182         g_variant_unref (rvalue);
183 }
184
185 /**
186  * dfsm_ast_statement_assignment_new:
187  * @data_structure: data structure being assigned to (lvalue)
188  * @expression: expression to be evaluated for assignment (rvalue)
189  *
190  * Create a new #DfsmAstStatement for an assignment of @expression to @data_structure.
191  *
192  * Return value: (transfer full): a new AST node
193  */
194 DfsmAstStatement *
195 dfsm_ast_statement_assignment_new (DfsmAstDataStructure *data_structure, DfsmAstExpression *expression)
196 {
197         DfsmAstStatementAssignment *statement;
198         DfsmAstStatementAssignmentPrivate *priv;
199
200         g_return_val_if_fail (DFSM_IS_AST_DATA_STRUCTURE (data_structure), NULL);
201         g_return_val_if_fail (DFSM_IS_AST_EXPRESSION (expression), NULL);
202
203         statement = g_object_new (DFSM_TYPE_AST_STATEMENT_ASSIGNMENT, NULL);
204         priv = statement->priv;
205
206         priv->data_structure = g_object_ref (data_structure);
207         priv->expression = g_object_ref (expression);
208
209         return DFSM_AST_STATEMENT (statement);
210 }
211
212 /**
213  * dfsm_ast_statement_assignment_get_variable:
214  * @self: a #DfsmAstStatementAssignment
215  *
216  * Gets the variable being assigned to in the assignment (i.e. the l-value of the assignment).
217  *
218  * Return value: (transfer none): variable being assigned to
219  */
220 DfsmAstDataStructure *
221 dfsm_ast_statement_assignment_get_variable (DfsmAstStatementAssignment *self)
222 {
223         g_return_val_if_fail (DFSM_IS_AST_STATEMENT_ASSIGNMENT (self), NULL);
224
225         return self->priv->data_structure;
226 }
227
228 /**
229  * dfsm_ast_statement_assignment_get_expression:
230  * @self: a #DfsmAstStatementAssignment
231  *
232  * Gets the expression being evaluated and assigned in the assignment (i.e. the r-value of the assignment).
233  *
234  * Return value: (transfer none): unevaluated form of the expression being evaluated and assigned
235  */
236 DfsmAstExpression *
237 dfsm_ast_statement_assignment_get_expression (DfsmAstStatementAssignment *self)
238 {
239         g_return_val_if_fail (DFSM_IS_AST_STATEMENT_ASSIGNMENT (self), NULL);
240
241         return self->priv->expression;
242 }