1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "squirrel/squirrel_util.hpp"
18
19#include <config.h>
20
21#include <stdio.h>
22#include <sqstdaux.h>
23#include <sqstdblob.h>
24#include <sqstdmath.h>
25#include <sqstdstring.h>
26#include <stdarg.h>
27
28#include "squirrel/script_interface.hpp"
29#include "supertux/game_object.hpp"
30#include "util/log.hpp"
31
32std::string squirrel2string(HSQUIRRELVM v, SQInteger i)
33{
34 std::ostringstream os;
35 switch (sq_gettype(v, i))
36 {
37 case OT_NULL:
38 os << "<null>";
39 break;
40 case OT_BOOL: {
41 SQBool p;
42 if (SQ_SUCCEEDED(sq_getbool(v, i, &p))) {
43 if (p)
44 os << "true";
45 else
46 os << "false";
47 }
48 break;
49 }
50 case OT_INTEGER: {
51 SQInteger val;
52 sq_getinteger(v, i, &val);
53 os << val;
54 break;
55 }
56 case OT_FLOAT: {
57 SQFloat val;
58 sq_getfloat(v, i, &val);
59 os << val;
60 break;
61 }
62 case OT_STRING: {
63 const SQChar* val;
64 sq_getstring(v, i, &val);
65 os << "\"" << val << "\"";
66 break;
67 }
68 case OT_TABLE: {
69 bool first = true;
70 os << "{";
71 sq_pushnull(v); //null iterator
72 while (SQ_SUCCEEDED(sq_next(v,i-1)))
73 {
74 if (!first) {
75 os << ", ";
76 }
77 first = false;
78
79 //here -1 is the value and -2 is the key
80 os << squirrel2string(v, -2) << " => "
81 << squirrel2string(v, -1);
82
83 sq_pop(v,2); //pops key and val before the nex iteration
84 }
85 sq_pop(v, 1);
86 os << "}";
87 break;
88 }
89 case OT_ARRAY: {
90 bool first = true;
91 os << "[";
92 sq_pushnull(v); //null iterator
93 while (SQ_SUCCEEDED(sq_next(v,i-1)))
94 {
95 if (!first) {
96 os << ", ";
97 }
98 first = false;
99
100 //here -1 is the value and -2 is the key
101 // we ignore the key, since that is just the index in an array
102 os << squirrel2string(v, -1);
103
104 sq_pop(v,2); //pops key and val before the nex iteration
105 }
106 sq_pop(v, 1);
107 os << "]";
108 break;
109 }
110 case OT_USERDATA:
111 os << "<userdata>";
112 break;
113 case OT_CLOSURE:
114 os << "<closure>";
115 break;
116 case OT_NATIVECLOSURE:
117 os << "<native closure>";
118 break;
119 case OT_GENERATOR:
120 os << "<generator>";
121 break;
122 case OT_USERPOINTER:
123 os << "userpointer";
124 break;
125 case OT_THREAD:
126 os << "<thread>";
127 break;
128 case OT_CLASS:
129 os << "<class>";
130 break;
131 case OT_INSTANCE:
132 os << "<instance>";
133 break;
134 case OT_WEAKREF:
135 os << "<weakref>";
136 break;
137 default:
138 os << "<unknown>";
139 break;
140 }
141 return os.str();
142}
143
144void print_squirrel_stack(HSQUIRRELVM v)
145{
146 printf("--------------------------------------------------------------\n");
147 SQInteger count = sq_gettop(v);
148 for (int i = 1; i <= count; ++i) {
149 printf("%d: ",i);
150 switch (sq_gettype(v, i))
151 {
152 case OT_NULL:
153 printf("null");
154 break;
155 case OT_INTEGER: {
156 SQInteger val;
157 sq_getinteger(v, i, &val);
158 printf("integer (%d)", static_cast<int>(val));
159 break;
160 }
161 case OT_FLOAT: {
162 SQFloat val;
163 sq_getfloat(v, i, &val);
164 printf("float (%f)", static_cast<double>(val));
165 break;
166 }
167 case OT_STRING: {
168 const SQChar* val;
169 sq_getstring(v, i, &val);
170 printf("string (%s)", val);
171 break;
172 }
173 case OT_TABLE:
174 printf("table");
175 break;
176 case OT_ARRAY:
177 printf("array");
178 break;
179 case OT_USERDATA:
180 printf("userdata");
181 break;
182 case OT_CLOSURE:
183 printf("closure(function)");
184 break;
185 case OT_NATIVECLOSURE:
186 printf("native closure(C function)");
187 break;
188 case OT_GENERATOR:
189 printf("generator");
190 break;
191 case OT_USERPOINTER:
192 printf("userpointer");
193 break;
194 case OT_THREAD:
195 printf("thread");
196 break;
197 case OT_CLASS:
198 printf("class");
199 break;
200 case OT_INSTANCE:
201 printf("instance");
202 break;
203 case OT_WEAKREF:
204 printf("weakref");
205 break;
206 default:
207 printf("unknown?!?");
208 break;
209 }
210 printf("\n");
211 }
212 printf("--------------------------------------------------------------\n");
213}
214
215SQInteger squirrel_read_char(SQUserPointer file)
216{
217 std::istream* in = reinterpret_cast<std::istream*> (file);
218 int c = in->get();
219 if (in->eof())
220 return 0;
221 return c;
222}
223
224void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
225{
226 if (SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
227 throw SquirrelError(vm, "Couldn't parse script");
228}
229
230void compile_and_run(HSQUIRRELVM vm, std::istream& in,
231 const std::string& sourcename)
232{
233 compile_script(vm, in, sourcename);
234
235 SQInteger oldtop = sq_gettop(vm);
236
237 try {
238 sq_pushroottable(vm);
239 if (SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue)))
240 throw SquirrelError(vm, "Couldn't start script");
241 } catch(...) {
242 sq_settop(vm, oldtop);
243 throw;
244 }
245
246 // we can remove the closure in case the script was not suspended
247 if (sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
248 sq_settop(vm, oldtop-1);
249 }
250}
251
252HSQUIRRELVM object_to_vm(HSQOBJECT object)
253{
254 if (object._type != OT_THREAD)
255 return nullptr;
256
257 return object._unVal.pThread;
258}
259
260/* EOF */
261