summaryrefslogtreecommitdiff
path: root/codegen/valagvaluemodule.vala
blob: 8b4dbbc66e08d82be4a223c860bd3b8ea87ddce6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* valagvaluemodule.vala
 *
 * Copyright (C) 2019  Rico Tzschichholz
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Rico Tzschichholz <ricotz@ubuntu.com>
 */

public class Vala.GValueModule : GAsyncModule {
	public override void visit_cast_expression (CastExpression expr) {
		unowned DataType? value_type = expr.inner.value_type;
		unowned DataType? target_type = expr.type_reference;

		if (expr.is_non_null_cast || value_type == null || gvalue_type == null
		    || value_type.type_symbol != gvalue_type || target_type.type_symbol == gvalue_type
		    || get_ccode_type_id (target_type) == "") {
			base.visit_cast_expression (expr);
			return;
		}

		generate_type_declaration (expr.type_reference, cfile);

		// explicit conversion from GValue
		var ccall = new CCodeFunctionCall (get_value_getter_function (target_type));
		CCodeExpression gvalue;
		if (value_type.nullable) {
			gvalue = get_cvalue (expr.inner);
		} else {
			gvalue = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (expr.inner));
		}
		ccall.add_argument (gvalue);

		if (value_type.is_disposable ()) {
			var temp_var = get_temp_variable (value_type, true, expr, false);
			emit_temp_var (temp_var);
			var temp_ref = get_variable_cexpression (temp_var.name);
			ccode.add_assignment (temp_ref, get_cvalue (expr.inner));

			// value needs to be kept alive until the end of this block
			temp_ref_values.insert (0, get_local_cvalue (temp_var));
		}

		CCodeExpression rv;
		if (target_type is ArrayType) {
			var temp_var = get_temp_variable (target_type, true, expr, false);
			emit_temp_var (temp_var);
			var temp_ref = get_variable_cexpression (temp_var.name);
			ccode.add_assignment (temp_ref, ccall);
			rv = temp_ref;

			// null-terminated string array
			var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
			len_call.add_argument (rv);
			append_array_length (expr, len_call);
		} else if (target_type is StructValueType) {
			var temp_var = get_temp_variable (new PointerType (target_type), true, expr, false);
			emit_temp_var (temp_var);
			var temp_ref = get_variable_cexpression (temp_var.name);
			ccode.add_assignment (temp_ref, ccall);
			rv = temp_ref;

			// default value to fallback to
			var temp_value = create_temp_value (target_type, true, expr, true);
			var ctemp = get_cvalue_ (temp_value);

			var holds = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_HOLDS"));
			holds.add_argument (gvalue);
			holds.add_argument (new CCodeIdentifier (get_ccode_type_id (target_type)));
			var cond = new CCodeBinaryExpression (CCodeBinaryOperator.AND, holds, rv);
			var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
			warn.add_argument (new CCodeConstant ("\"Invalid GValue unboxing (wrong type or NULL)\""));
			var fail = new CCodeCommaExpression ();
			fail.append_expression (warn);
			fail.append_expression (ctemp);
			rv = new CCodeConditionalExpression (cond, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, rv), fail);
		} else {
			rv = ccall;
		}

		set_cvalue (expr, rv);
	}

	public override CCodeExpression get_value_getter_function (DataType type_reference) {
		var array_type = type_reference as ArrayType;
		if (type_reference.type_symbol != null) {
			return new CCodeIdentifier (get_ccode_get_value_function (type_reference.type_symbol));
		} else if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) {
			// G_TYPE_STRV
			return new CCodeIdentifier ("g_value_get_boxed");
		} else {
			return new CCodeIdentifier ("g_value_get_pointer");
		}
	}

	public override CCodeExpression get_value_setter_function (DataType type_reference) {
		var array_type = type_reference as ArrayType;
		if (type_reference.type_symbol != null) {
			return new CCodeIdentifier (get_ccode_set_value_function (type_reference.type_symbol));
		} else if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) {
			// G_TYPE_STRV
			return new CCodeIdentifier ("g_value_set_boxed");
		} else {
			return new CCodeIdentifier ("g_value_set_pointer");
		}
	}

	public override CCodeExpression get_value_taker_function (DataType type_reference) {
		var array_type = type_reference as ArrayType;
		if (type_reference.type_symbol != null) {
			return new CCodeIdentifier (get_ccode_take_value_function (type_reference.type_symbol));
		} else if (array_type != null && array_type.element_type.type_symbol == string_type.type_symbol) {
			// G_TYPE_STRV
			return new CCodeIdentifier ("g_value_take_boxed");
		} else {
			return new CCodeIdentifier ("g_value_set_pointer");
		}
	}
}