Fixed problem in DeviceSettings::strParam, returned wrong string
[avr-sim.git] / src / script / VM.cpp
blobaff9d58940392f6c6c7077d061a3d8ec4fc18bf8
1 #include "VM.h"
2 #include "ScriptException.h"
3 #include <iostream>
4 #include <assert.h>
6 extern "C" {
7 #include <lua50/lua.h>
8 #include <lua50/lauxlib.h>
9 #include <lua50/lualib.h>
12 namespace script {
13 #ifdef LUA_DEBUG
14 static void LineHook(lua_State *L, lua_Debug *ar) {
15 std::cerr << ar->currentline << std::endl;
18 static void CallHook(lua_State *L, lua_Debug *ar) {
19 std::cerr << ar->source << ' ' << ar->name << std::endl;
21 #endif
23 VM::VM() {
24 assert( (None == LUA_TNONE) && (Nil == LUA_TNIL) &&
25 (Boolean == LUA_TBOOLEAN) && (LightUserData == LUA_TLIGHTUSERDATA) &&
26 (Number == LUA_TNUMBER) && (String == LUA_TSTRING) &&
27 (Table == LUA_TTABLE) && (Function == LUA_TFUNCTION) &&
28 (UserData == LUA_TUSERDATA) && (Thread == LUA_TTHREAD) );
30 lua = lua_open();
31 if( lua == 0 )
32 throw ScriptException("Failed to initialize Lua virtual machine");
34 lua_pushstring(lua, "_ERRORMESSAGE");
35 lua_pushlightuserdata(lua, this);
36 lua_pushcclosure(lua, printError, 1);
37 lua_settable(lua, LUA_GLOBALSINDEX);
39 lua_register(lua, "trace", printMessage);
41 static const luaL_reg lualibs[] = {
42 {"base", luaopen_base},
43 {"table", luaopen_table},
44 {"io", luaopen_io},
45 {"string", luaopen_string},
46 {"math", luaopen_math},
47 {"debug", luaopen_debug},
48 // {"loadlib", luaopen_loadlib},
49 {NULL, NULL}
52 const luaL_reg *lib = lualibs;
53 for(; lib->func; lib++) {
54 lib->func(lua); /* open library */
55 lua_settop(lua, 0); /* discard any results */
58 #ifdef LUA_DEBUG
59 lua_sethook(lua, CallHook, LUA_MASKCALL, 0);
60 lua_sethook(lua, LineHook, LUA_MASKLINE, 0);
61 #endif
64 VM::~VM() {
65 if( lua != 0 ) {
66 lua_settop(lua, 0);
67 lua_close(lua);
68 lua = 0;
72 void VM::compileFile(const char *name) {
73 if( lua_dofile(lua, name) )
74 throw ScriptException("Failed to compile script file");
77 void VM::compileSource(const std::string & src) {
78 if( lua_dostring(lua, src.c_str()) )
79 throw ScriptException("Failed to compile script string");
82 void VM::compileSource(const char *buffer, int size) {
86 void VM::gc() {
87 lua_setgcthreshold(lua, 0); // collected garbage
90 bool VM::next(int index) {
91 if( ! lua_istable(lua, index) )
92 throw ScriptException("Tried to use next() on a non-table object");
94 return (0 != lua_next(lua, index));
97 void VM::pop(int n /*= 1*/) {
98 lua_pop(lua, n);
101 void VM::setTable(int index) {
102 if( lua_istable(lua, index) == 0 )
103 throw ScriptException("Tried to use object as table");
105 lua_settable(lua, index);
108 void VM::setTableRaw(int index) {
109 if( lua_istable(lua,index) == 0 )
110 throw ScriptException("Tried to use object as table");
112 lua_rawset(lua, index);
115 void VM::setTableRawI(int index, int n) {
116 if( lua_istable(lua, index) == 0 )
117 throw ScriptException("Tried to use object as table");
119 lua_rawseti(lua, index, n);
122 void VM::call(int args, int results) {
123 if( lua_isfunction(lua, -args - 1) == 0 )
124 throw ScriptException("Called invalid script function\n");
126 lua_pushliteral(lua, "_ERRORMESSAGE");
127 lua_gettable(lua, LUA_GLOBALSINDEX); // get traceback function
128 lua_insert(lua, 1);
130 int errnr = lua_pcall(lua, args, results, 1);
131 if( errnr != 0 ) {
132 if( err.empty() ) {
133 const char *msg = lua_tostring(lua, -1);
134 if( msg == 0 )
135 msg = "(error with no message)";
137 lua_pop(lua, 1);
138 throw ScriptException(msg);
139 } else {
140 throw ScriptException(err);
144 lua_remove(lua, 1);
147 void VM::registerClass(const char *name, const script::Table & table) {
148 lua_pushstring(lua, name);
149 lua_getref(lua, table.ref);
150 lua_settable(lua, LUA_GLOBALSINDEX);
153 void VM::unregisterClass(const char *name) {
154 lua_pushstring(lua, name);
155 lua_pushnil(lua);
156 lua_settable(lua, LUA_GLOBALSINDEX);
159 void VM::getGlobal(const std::string & name) {
160 lua_getglobal(lua, name.c_str());
163 void VM::getGlobal(const char *name) {
164 lua_getglobal(lua, name);
167 void VM::setGlobal(const std::string & name) {
168 lua_setglobal(lua, name.c_str());
171 void VM::setGlobal(const char *name) {
172 lua_setglobal(lua, name);
175 void VM::pushValue(int index) {
176 lua_pushvalue(lua, index);
179 void VM::pushNil() {
180 lua_pushnil(lua);
183 void VM::pushNumber(float x) {
184 lua_pushnumber(lua, x);
187 void VM::pushBoolean(bool b) {
188 lua_pushboolean(lua, b);
191 void VM::pushString(const std::string & str) {
192 lua_pushstring(lua, str.c_str());
195 void VM::pushString(const char *str) {
196 lua_pushstring(lua, str);
199 void VM::pushTable(const script::Table & tab) {
200 assert( lua == tab.lua );
202 if( tab.ref >= 0 )
203 lua_getref(lua, tab.ref);
204 else
205 lua_pushnil(lua);
208 void VM::pushCFunction(CFunction f) {
209 lua_pushcclosure(lua, f, 0);
212 void VM::pushCClosure(CFunction f, int n) {
213 lua_pushcclosure(lua, f, n);
215 void VM::remove( int index ) {
216 lua_remove(lua, index);
219 int VM::getType(int index) const {
220 return lua_type(lua, index);
223 const char *VM::getTypeName(int type) const {
224 return lua_typename(lua, type);
227 bool VM::isType(int index, VM::Type type) const {
228 return ( lua_type(lua, index) == type );
231 bool VM::isCFunction(int index) const {
232 return ( lua_iscfunction(lua, index) != 0 );
235 bool VM::isFunction(int index) const {
236 return ( lua_type(lua, index) == LUA_TFUNCTION );
239 bool VM::isNil(int index) const {
240 return ( lua_type(lua, index) == LUA_TNIL );
243 bool VM::isNumber(int index) const {
244 return ( lua_type(lua, index) == LUA_TNUMBER );
247 bool VM::isString(int index) const {
248 return ( lua_type(lua, index) == LUA_TSTRING );
251 bool VM::isTable(int index) const {
252 return ( lua_type(lua, index ) == LUA_TTABLE );
255 bool VM::isUserData(int index) const {
256 return ( lua_type(lua, index) == LUA_TUSERDATA );
259 bool VM::isBoolean(int index) const {
260 return ( lua_type(lua, index) == LUA_TBOOLEAN );
263 bool VM::isEqual(int index1, int index2) const {
264 return ( lua_equal(lua, index1, index2) != 0 );
267 bool VM::isLess(int index1, int index2) const {
268 return ( lua_lessthan(lua, index1, index2) != 0 );
271 int VM::stackSpace() const {
272 //return luaL_stackspace(lua);
273 return 0;
276 bool VM::toBoolean(int index) const {
277 if( lua_type(lua, index ) != LUA_TBOOLEAN )
278 throw ScriptException("Tried to use non-boolean as boolean");
280 return lua_toboolean(lua, index);
283 float VM::toNumber(int index) const {
284 if( lua_type(lua, index ) != LUA_TNUMBER )
285 throw ScriptException("Tried to use non-number as number");
287 return lua_tonumber(lua, index);
290 const char *VM::toString(int index) const {
291 if( ! lua_isstring(lua, index) )
292 throw ScriptException("Tried to use non-string as string");
294 return lua_tostring(lua, index);
297 script::Table VM::toTable(int index) const {
298 if ( ! lua_istable(lua, index) )
299 throw ScriptException("Tried to use non-table as table");
300 lua_pushvalue(lua, index);
302 script::Table tab;
303 tab.lua = lua;
304 tab.ref = lua_ref(lua, true);
305 return tab;
308 VM::CFunction VM::toCFunction(int index) const {
309 if( lua_iscfunction(lua, index) == 0 )
310 throw ScriptException("Tried to use non C-function as C-function");
312 return lua_tocfunction(lua, index);
315 void *VM::toUserData(int index) const {
316 if( lua_isuserdata(lua, index) == 0 )
317 throw ScriptException("Tried to use object as user data");
319 return lua_touserdata(lua, index);
322 int VM::top() const {
323 return lua_gettop(lua);
326 void VM::stackTrace(int level, std::string & trace) const {
327 lua_Debug ar;
328 // memset(&ar, 0, sizeof(ar));
329 if( ! lua_getstack(lua, 1 + level, &ar) ) {
330 trace = "";
331 return;
334 if( ! lua_getinfo(lua, "Snl", &ar) ) {
335 trace = "";
336 return;
339 char str[512];
340 sprintf(str, "at %s(%s:%i)", ar.name, ar.source, ar.currentline);
341 trace.assign(str);
344 int VM::printError(lua_State* lua) {
345 assert( lua_isstring(lua, -1) );
346 assert( lua_isuserdata(lua, lua_upvalueindex(1)) );
348 const char *msg = lua_tostring(lua, -1);
349 VM *vm = (VM *)lua_touserdata(lua, lua_upvalueindex(1));
350 vm->err = msg;
352 // get stack trace
353 const short MAX_LEVEL = 20;
354 std::string trace[MAX_LEVEL];
355 short level = 0;
356 for( ; level < MAX_LEVEL ; ++level ) {
357 vm->stackTrace(level, trace[level]);
358 if( trace[level] == "" )
359 break;
361 if( level == 0 )
362 vm->err = vm->err + "\nStack trace:";
363 vm->err = vm->err + "\n\t " + trace[level];
366 // debug output
367 /* std::cerr << msg << std::endl;
368 if( level > 0 ) {
369 std::cerr << "Stack trace:";
370 for ( int i = 0 ; i < level ; ++i )
371 std::cerr << trace[i] << std::endl;
374 return 0;
377 int VM::printMessage( lua_State* lua ) {
378 assert( lua_isstring(lua, 1) );
380 const char *msg = lua_tostring(lua, 1);
382 // get caller
383 lua_Debug ar;
384 // memset(&ar, 0, sizeof(ar));
385 lua_getstack(lua, 1, &ar);
386 lua_getinfo(lua, "Snl", &ar);
388 // debug output
389 std::cerr << "script: " << msg << " at "
390 << ar.source << ar.currentline << std::endl;
392 return 0;
395 void VM::getRef(int ref) {
396 lua_getref(lua, ref);
399 int VM::ref(bool lock) {
400 return lua_ref(lua, lock);
403 void VM::unref(int ref) {
404 lua_unref(lua, ref );