Branch data Line data Source code
1 : : /*
2 : : * Copyright 2006-2009 Savarese Software Research Corporation
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * https://www.savarese.com/software/ApacheLicense-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include <ssrc/wispers/lua/Properties.h>
18 : :
19 : : __BEGIN_NS_SSRC_WSPR_LUA
20 : :
21 : 3 : void PropertiesToTable::PushValue::operator()(const primitive_property_vector & v) const
22 : : {
23 : 3 : lua_createtable(state, v.size(), 0);
24 : 3 : int i = 1;
25 [ + + ]: 33 : for(primitive_property_vector::const_iterator && it = v.begin(), && end = v.end(); it != end; ++it)
26 : : {
27 : 30 : lua_pushinteger(state, i++);
28 : 30 : boost::apply_visitor(*this, *it);
29 : 30 : lua_settable(state, -3);
30 : : }
31 : 3 : }
32 : :
33 : 62 : void PropertiesToTable::PushValue::operator()(const Properties & properties)
34 : : const
35 : : {
36 : : using NS_SSRC_WSPR_UTILITY::property_type;
37 : 62 : const property_type *v = properties.value();
38 : :
39 [ - + ]: 62 : if(properties.is_leaf()) {
40 [ # # ]: 0 : if(v != 0) {
41 : 0 : boost::apply_visitor(*this, *v);
42 : : } else {
43 : 0 : lua_pushnil(state);
44 : : }
45 : : } else {
46 : 62 : lua_newtable(state);
47 : :
48 [ - + ]: 62 : if(v != 0) {
49 : 0 : boost::apply_visitor(*this, *v);
50 : 0 : lua_setfield(state, -2, "_value");
51 : : }
52 : :
53 : 62 : properties.visit(to_table);
54 : : }
55 : 62 : }
56 : :
57 : 34 : void PropertiesToTable::PushValue::operator()(const property_vector & v) const
58 : : {
59 : 34 : lua_createtable(state, v.size(), 0);
60 : 34 : int i = 1;
61 [ + + ]: 96 : for(property_vector::const_iterator && it = v.begin(), && end = v.end(); it != end; ++it)
62 : : {
63 : 62 : lua_pushinteger(state, i++);
64 : 62 : PropertiesToTable::PushValue::operator()(*it);
65 : 62 : lua_settable(state, -3);
66 : : }
67 : 34 : }
68 : :
69 : 125 : void PropertiesToTable::enter(const std::string key,
70 : : const Properties *properties,
71 : : const bool)
72 : : const
73 : : {
74 : : using NS_SSRC_WSPR_UTILITY::property_type;
75 : 125 : const property_type *v = properties->value();
76 : :
77 [ + + ]: 125 : if(!properties->is_leaf()) {
78 : 13 : lua_newtable(state());
79 : :
80 [ - + ]: 13 : if(v != 0) {
81 : 0 : boost::apply_visitor(push, *v);
82 : 0 : lua_setfield(state(), -2, "_value");
83 : : }
84 : : } else {
85 [ + - ]: 112 : if(v != 0) {
86 : 112 : boost::apply_visitor(push, *v);
87 : : } else {
88 : 0 : lua_pushnil(state());
89 : : }
90 : : }
91 : 125 : }
92 : :
93 : 125 : void PropertiesToTable::leave(const std::string key,
94 : : const Properties *properties,
95 : : const bool)
96 : : const
97 : : {
98 : 125 : lua_setfield(state(), -2, key.c_str());
99 : 125 : }
100 : :
101 : : /**
102 : : * Copies a Lua table into a Properties instance. Tables must either
103 : : * be pure arrays of primitive values, pure arrays of tables, or a
104 : : * zero-length table with key value pairs where all the keys are strings.
105 : : *
106 : : * @param state A pointer to the Lua state containing the table to convert
107 : : * at the top of the stack.
108 : : * @param properties The Properties instance to convert.
109 : : */
110 : 161 : void table_to_properties(lua_State *state, Properties & properties) {
111 : 161 : const size_t size = lua_objlen(state, -1);
112 : :
113 [ + + ]: 161 : if(size == 0) {
114 : 141 : lua_pushnil(state);
115 [ + + ]: 797 : while(lua_next(state, -2)) {
116 : 515 : const int ltype = lua_type(state, -1);
117 : 1030 : const string && key = convert<string>(state, -2);
118 : :
119 : : // TODO: key == "_value" should use set_value(v) instead of set(v, k)
120 [ + + + + : 515 : switch(ltype) {
- ]
121 : : case LUA_TNUMBER:
122 [ + - + - ]: 35 : properties.set(convert<lua_Number>(state, -1), key);
123 : 35 : break;
124 : : case LUA_TBOOLEAN:
125 [ + - + - ]: 4 : properties.set(convert<bool>(state, -1), key);
126 : 4 : break;
127 : : case LUA_TSTRING:
128 [ + - + - : 364 : properties.set(convert<string>(state, -1), key);
+ - + - +
- ]
129 : 364 : break;
130 : : case LUA_TTABLE: {
131 [ + - ]: 112 : Properties *node = properties.create_node(key);
132 [ + - ]: 112 : table_to_properties(state, *node);
133 : : }
134 : 112 : break;
135 : : default:
136 : 0 : break;
137 : : };
138 : :
139 [ + - ]: 515 : lua_pop(state, 1);
140 : : }
141 : : } else {
142 : 20 : lua_pushnil(state);
143 : : // Determine type of array elements (primitive or table).
144 [ + - ]: 20 : if(lua_next(state, -2)) {
145 [ + + ]: 20 : if(lua_istable(state, -1)) {
146 : : Properties *node;
147 : 15 : property_vector & v = properties.create_property_vector();
148 : 15 : v.reserve(size);
149 [ + + ]: 28 : do {
150 [ + - ]: 28 : v.push_back(node = new Properties);
151 : 28 : table_to_properties(state, *node);
152 : 28 : lua_pop(state, 1);
153 : 28 : } while(lua_next(state, -2));
154 : : } else {
155 : : primitive_property_vector & v =
156 : 5 : properties.create_primitive_property_vector();
157 : 5 : v.reserve(size);
158 [ + + ]: 22 : do {
159 : 22 : const int ltype = lua_type(state, -1);
160 [ + - - - ]: 22 : switch(ltype) {
161 [ + - ]: 22 : case LUA_TNUMBER: v.push_back(convert<lua_Number>(state, -1)); break;
162 [ # # ]: 0 : case LUA_TBOOLEAN: v.push_back(convert<bool>(state, -1)); break;
163 [ # # # # : 0 : case LUA_TSTRING: v.push_back(convert<string>(state, -1)); break;
# # ]
164 : 0 : default: break;
165 : : };
166 : 22 : lua_pop(state, 1);
167 : 22 : } while(lua_next(state, -2));
168 : : }
169 : : }
170 : : }
171 : 161 : }
172 : :
173 : : /**
174 : : * This function is a kluge to work around a SWIG library relocation error.
175 : : * For some reason, table_to_properties doesn't resolve when called within
176 : : * a SWIG wrapper function. Removing lua_State* from the function signature
177 : : * allows the function to be located, which then resolves table_to_properties
178 : : * within the same relocation unit instead of crossing module boundaries.
179 : : */
180 : 1 : void swig_table_to_properties(void *state, Properties & properties) {
181 : 1 : table_to_properties(reinterpret_cast<lua_State*>(state), properties);
182 : 1 : }
183 : :
184 : : namespace {
185 : 20 : inline properties_ptr load_properties(lua_State *state, int err)
186 : : SSRC_DECL_THROW(LuaCallError)
187 : : {
188 [ - + ]: 20 : if(err != 0) {
189 [ # # # # ]: 0 : string msg(lua_tostring(state, -1));
190 [ # # ]: 0 : lua_pop(state, 1);
191 [ # # ]: 0 : throw LuaCallError(msg, err);
192 : : }
193 : :
194 : 20 : pcall_nopop(0, LUA_MULTRET, state);
195 : :
196 [ - + ]: 20 : if(!lua_istable(state, -1)) {
197 : 0 : lua_pop(state, 1);
198 : : throw LuaCallError("properties definition does not return table",
199 [ # # # # ]: 0 : LUA_ERRSYNTAX);
200 : : }
201 : :
202 [ + - + - ]: 20 : properties_ptr properties(new Properties);
203 : :
204 [ + - ]: 20 : table_to_properties(state, *properties);
205 [ + - ]: 20 : lua_pop(state, 1);
206 : :
207 : 20 : return properties;
208 : : }
209 : : }
210 : :
211 : 18 : properties_ptr load_properties(lua_State *state, const std::string & filename)
212 : : SSRC_DECL_THROW(LuaCallError)
213 : : {
214 : 18 : int err = luaL_loadfile(state, filename.c_str());
215 : 18 : return load_properties(state, err);
216 : : }
217 : :
218 : 2 : properties_ptr load_string_properties(lua_State *state,
219 : : const std::string & code_str)
220 : : SSRC_DECL_THROW(LuaCallError)
221 : : {
222 : 2 : int err = luaL_loadstring(state, code_str.c_str());
223 : 2 : return load_properties(state, err);
224 : : }
225 : :
226 [ + - + - ]: 18 : __END_NS_SSRC_WSPR_LUA
|