8b4dbbc66e08d82be4a223c860bd3b8ea87ddce6
[roobuilder] / src / codegen / valagvaluemodule.vala
1 /* valagvaluemodule.vala
2  *
3  * Copyright (C) 2019  Rico Tzschichholz
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  *      Rico Tzschichholz <ricotz@ubuntu.com>
21  */
22
23 public class Vala.GValueModule : GAsyncModule {
24         public override void visit_cast_expression (CastExpression expr) {
25                 unowned DataType? value_type = expr.inner.value_type;
26                 unowned DataType? target_type = expr.type_reference;
27
28                 if (expr.is_non_null_cast || value_type == null || gvalue_type == null
29                     || value_type.type_symbol != gvalue_type || target_type.type_symbol == gvalue_type
30                     || get_ccode_type_id (target_type) == "") {
31                         base.visit_cast_expression (expr);
32                         return;
33                 }
34
35                 generate_type_declaration (expr.type_reference, cfile);
36
37                 // explicit conversion from GValue
38                 var ccall = new CCodeFunctionCall (get_value_getter_function (target_type));
39                 CCodeExpression gvalue;
40                 if (value_type.nullable) {
41                         gvalue = get_cvalue (expr.inner);
42                 } else {
43                         gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner));
44                 }
45                 ccall.add_argument (gvalue);
46
47                 if (value_type.is_disposable ()) {
48                         var temp_var = get_temp_variable (value_type, true, expr, false);
49                         emit_temp_var (temp_var);
50                         var temp_ref = get_variable_cexpression (temp_var.name);
51                         ccode.add_assignment (temp_ref, get_cvalue (expr.inner));
52
53                         // value needs to be kept alive until the end of this block
54                         temp_ref_values.insert (0, get_local_cvalue (temp_var));
55                 }
56
57                 CCodeExpression rv;
58                 if (target_type is ArrayType) {
59                         var temp_var = get_temp_variable (target_type, true, expr, false);
60                         emit_temp_var (temp_var);
61                         var temp_ref = get_variable_cexpression (temp_var.name);
62                         ccode.add_assignment (temp_ref, ccall);
63                         rv = temp_ref;
64
65                         // null-terminated string array
66                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
67                         len_call.add_argument (rv);
68                         append_array_length (expr, len_call);
69                 } else if (target_type is StructValueType) {
70                         var temp_var = get_temp_variable (new PointerType (target_type), true, expr, false);
71                         emit_temp_var (temp_var);
72                         var temp_ref = get_variable_cexpression (temp_var.name);
73                         ccode.add_assignment (temp_ref, ccall);
74                         rv = temp_ref;
75
76                         // default value to fallback to
77                         var temp_value = create_temp_value (target_type, true, expr, true);
78                         var ctemp = get_cvalue_ (temp_value);
79
80                         var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
81                         holds.add_argument (gvalue);
82                         holds.add_argument (new CCodeIdentifier (get_ccode_type_id (target_type)));
83                         var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, rv);
84                         var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
85                         warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
86                         var fail = new CCodeCommaExpression ();
87                         fail.append_expression (warn);
88                         fail.append_expression (ctemp);
89                         rv = new CCodeConditionalExpression (cond, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, rv), fail);
90                 } else {
91                         rv = ccall;
92                 }
93
94                 set_cvalue (expr, rv);
95         }
96
97         public override CCodeExpression get_value_getter_function (DataType type_reference) {
98                 var array_type = type_reference as ArrayType;
99                 if (type_reference.type_symbol != null) {
100                         return new CCodeIdentifier (get_ccode_get_value_function (type_reference.type_symbol));
101                 } else if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) {
102                         // G_TYPE_STRV
103                         return new CCodeIdentifier ("g_value_get_boxed");
104                 } else {
105                         return new CCodeIdentifier ("g_value_get_pointer");
106                 }
107         }
108
109         public override CCodeExpression get_value_setter_function (DataType type_reference) {
110                 var array_type = type_reference as ArrayType;
111                 if (type_reference.type_symbol != null) {
112                         return new CCodeIdentifier (get_ccode_set_value_function (type_reference.type_symbol));
113                 } else if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) {
114                         // G_TYPE_STRV
115                         return new CCodeIdentifier ("g_value_set_boxed");
116                 } else {
117                         return new CCodeIdentifier ("g_value_set_pointer");
118                 }
119         }
120
121         public override CCodeExpression get_value_taker_function (DataType type_reference) {
122                 var array_type = type_reference as ArrayType;
123                 if (type_reference.type_symbol != null) {
124                         return new CCodeIdentifier (get_ccode_take_value_function (type_reference.type_symbol));
125                 } else if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) {
126                         // G_TYPE_STRV
127                         return new CCodeIdentifier ("g_value_take_boxed");
128                 } else {
129                         return new CCodeIdentifier ("g_value_set_pointer");
130                 }
131         }
132 }