dfsm: Add all the missing API reference comments
[bendy-bus:bendy-bus.git] / dfsm / dfsm-ast-expression-unary.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-expression-unary
22  * @short_description: AST unary expression node
23  * @stability: Unstable
24  * @include: dfsm/dfsm-ast-expression-unary.h
25  *
26  * AST unary expression node implementing support for unary operations such as logical negation.
27  */
28
29 #include "config.h"
30
31 #include <glib.h>
32 #include <glib/gi18n-lib.h>
33
34 #include "dfsm-ast-expression-unary.h"
35 #include "dfsm-parser.h"
36 #include "dfsm-parser-internal.h"
37
38 static void dfsm_ast_expression_unary_dispose (GObject *object);
39 static void dfsm_ast_expression_unary_sanity_check (DfsmAstNode *node);
40 static void dfsm_ast_expression_unary_pre_check_and_register (DfsmAstNode *node, DfsmEnvironment *environment, GError **error);
41 static void dfsm_ast_expression_unary_check (DfsmAstNode *node, DfsmEnvironment *environment, GError **error);
42 static GVariantType *dfsm_ast_expression_unary_calculate_type (DfsmAstExpression *self, DfsmEnvironment *environment);
43 static GVariant *dfsm_ast_expression_unary_evaluate (DfsmAstExpression *self, DfsmEnvironment *environment);
44 static gdouble dfsm_ast_expression_unary_calculate_weight (DfsmAstExpression *self);
45
46 struct _DfsmAstExpressionUnaryPrivate {
47         DfsmAstExpressionUnaryType expression_type;
48         DfsmAstExpression *child_node;
49 };
50
51 G_DEFINE_TYPE (DfsmAstExpressionUnary, dfsm_ast_expression_unary, DFSM_TYPE_AST_EXPRESSION)
52
53 static void
54 dfsm_ast_expression_unary_class_init (DfsmAstExpressionUnaryClass *klass)
55 {
56         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
57         DfsmAstNodeClass *node_class = DFSM_AST_NODE_CLASS (klass);
58         DfsmAstExpressionClass *expression_class = DFSM_AST_EXPRESSION_CLASS (klass);
59
60         g_type_class_add_private (klass, sizeof (DfsmAstExpressionUnaryPrivate));
61
62         gobject_class->dispose = dfsm_ast_expression_unary_dispose;
63
64         node_class->sanity_check = dfsm_ast_expression_unary_sanity_check;
65         node_class->pre_check_and_register = dfsm_ast_expression_unary_pre_check_and_register;
66         node_class->check = dfsm_ast_expression_unary_check;
67
68         expression_class->calculate_type = dfsm_ast_expression_unary_calculate_type;
69         expression_class->evaluate = dfsm_ast_expression_unary_evaluate;
70         expression_class->calculate_weight = dfsm_ast_expression_unary_calculate_weight;
71 }
72
73 static void
74 dfsm_ast_expression_unary_init (DfsmAstExpressionUnary *self)
75 {
76         self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, DFSM_TYPE_AST_EXPRESSION_UNARY, DfsmAstExpressionUnaryPrivate);
77 }
78
79 static void
80 dfsm_ast_expression_unary_dispose (GObject *object)
81 {
82         DfsmAstExpressionUnaryPrivate *priv = DFSM_AST_EXPRESSION_UNARY (object)->priv;
83
84         g_clear_object (&priv->child_node);
85
86         /* Chain up to the parent class */
87         G_OBJECT_CLASS (dfsm_ast_expression_unary_parent_class)->dispose (object);
88 }
89
90 static void
91 dfsm_ast_expression_unary_sanity_check (DfsmAstNode *node)
92 {
93         DfsmAstExpressionUnaryPrivate *priv = DFSM_AST_EXPRESSION_UNARY (node)->priv;
94
95         switch (priv->expression_type) {
96                 case DFSM_AST_EXPRESSION_UNARY_NOT:
97                         /* Valid */
98                         break;
99                 default:
100                         g_assert_not_reached ();
101         }
102
103         g_assert (priv->child_node != NULL);
104         dfsm_ast_node_sanity_check (DFSM_AST_NODE (priv->child_node));
105 }
106
107 static void
108 dfsm_ast_expression_unary_pre_check_and_register (DfsmAstNode *node, DfsmEnvironment *environment, GError **error)
109 {
110         DfsmAstExpressionUnaryPrivate *priv = DFSM_AST_EXPRESSION_UNARY (node)->priv;
111
112         dfsm_ast_node_pre_check_and_register (DFSM_AST_NODE (priv->child_node), environment, error);
113
114         if (*error != NULL) {
115                 return;
116         }
117 }
118
119 static void
120 dfsm_ast_expression_unary_check (DfsmAstNode *node, DfsmEnvironment *environment, GError **error)
121 {
122         DfsmAstExpressionUnaryPrivate *priv = DFSM_AST_EXPRESSION_UNARY (node)->priv;
123         GVariantType *child_type;
124         const GVariantType *desired_supertype;
125
126         dfsm_ast_node_check (DFSM_AST_NODE (priv->child_node), environment, error);
127
128         if (*error != NULL) {
129                 return;
130         }
131
132         child_type = dfsm_ast_expression_calculate_type (priv->child_node, environment);
133
134         switch (priv->expression_type) {
135                 case DFSM_AST_EXPRESSION_UNARY_NOT:
136                         desired_supertype = G_VARIANT_TYPE_BOOLEAN;
137                         break;
138                 default:
139                         g_assert_not_reached ();
140         }
141
142         if (g_variant_type_is_subtype_of (child_type, desired_supertype) == FALSE) {
143                 gchar *formal, *actual;
144
145                 formal = g_variant_type_dup_string (desired_supertype);
146                 actual = g_variant_type_dup_string (child_type);
147
148                 g_variant_type_free (child_type);
149
150                 g_set_error (error, DFSM_PARSE_ERROR, DFSM_PARSE_ERROR_AST_INVALID,
151                              _("Type mismatch between the formal and actual parameter to unary operator %u: expects type %s but received type %s."),
152                              priv->expression_type, formal, actual);
153                 return;
154         }
155
156         g_variant_type_free (child_type);
157 }
158
159 static GVariantType *
160 dfsm_ast_expression_unary_calculate_type (DfsmAstExpression *expression, DfsmEnvironment *environment)
161 {
162         DfsmAstExpressionUnaryPrivate *priv = DFSM_AST_EXPRESSION_UNARY (expression)->priv;
163
164         switch (priv->expression_type) {
165                 case DFSM_AST_EXPRESSION_UNARY_NOT:
166                         return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
167                 default:
168                         g_assert_not_reached ();
169         }
170 }
171
172 static GVariant *
173 dfsm_ast_expression_unary_evaluate (DfsmAstExpression *expression, DfsmEnvironment *environment)
174 {
175         DfsmAstExpressionUnaryPrivate *priv = DFSM_AST_EXPRESSION_UNARY (expression)->priv;
176         GVariant *child_value, *unary_value;
177
178         /* Evaluate our sub-expression first. */
179         child_value = dfsm_ast_expression_evaluate (priv->child_node, environment);
180
181         /* Do the actual evaluation. */
182         switch (priv->expression_type) {
183                 case DFSM_AST_EXPRESSION_UNARY_NOT:
184                         unary_value = g_variant_new_boolean (!g_variant_get_boolean (child_value));
185                         break;
186                 default:
187                         g_assert_not_reached ();
188         }
189
190         /* Tidy up and return */
191         g_variant_unref (child_value);
192
193         g_assert (g_variant_is_floating (unary_value) == TRUE);
194         g_variant_ref_sink (unary_value); /* sink reference */
195
196         return unary_value;
197 }
198
199 static gdouble
200 dfsm_ast_expression_unary_calculate_weight (DfsmAstExpression *self)
201 {
202         return dfsm_ast_expression_calculate_weight (DFSM_AST_EXPRESSION_UNARY (self)->priv->child_node);
203 }
204
205 /**
206  * dfsm_ast_expression_unary_new:
207  * @expression_type: the type of expression
208  * @child_node: the expression's child node, or %NULL
209  *
210  * Create a new #DfsmAstExpression of type @expression_type with the given child node.
211  *
212  * Return value: (transfer full): a new AST node
213  */
214 DfsmAstExpression *
215 dfsm_ast_expression_unary_new (DfsmAstExpressionUnaryType expression_type, DfsmAstExpression *child_node)
216 {
217         DfsmAstExpressionUnary *expression;
218         DfsmAstExpressionUnaryPrivate *priv;
219
220         g_return_val_if_fail (DFSM_IS_AST_EXPRESSION (child_node), NULL);
221
222         switch (expression_type) {
223                 case DFSM_AST_EXPRESSION_UNARY_NOT:
224                         /* Valid */
225                         break;
226                 default:
227                         g_assert_not_reached ();
228         }
229
230         expression = g_object_new (DFSM_TYPE_AST_EXPRESSION_UNARY, NULL);
231         priv = expression->priv;
232
233         priv->expression_type = expression_type;
234         priv->child_node = g_object_ref (child_node);
235
236         return DFSM_AST_EXPRESSION (expression);
237 }