VASmalltalk – Calling Smalltalk from Lua

Ok, now the other way around – and its getting more interesting:

We call a Lua program from Smalltalk and then we want to call a Smalltalk based function from that running Lua script. As you may know from other external libraries: a callback from an external code into Smalltalk is only allowed, if the callout from Smalltalk to the external code has been done in a synchronous way. Otherwise the system WILL crash !

And this example only works under Linux (Unix), simply because the Windows version of VASmalltalk only allows “stdcall” calling convention for EsEntryPoints. The Unix based versions only support “cdecl” calling conventions and this is the convention Lua expects. You will notice – if running these examples under Windows – that the system will crash. The Smalltalk function will be called in Windows (you can set a breakproint …), but when returning to Lua is simply crashes.

But now back to the example …

We define a function within Smalltalk as in the example before and leave out the Lua specific code. Just to give you an idea, what the Smalltalk method should return:

functionF: luaPointer
  | x y |

  ... some code missing ...

  ^(x * x * y sin) / (1-x)

and the Lua code looks like …

x = 4.0;
y = 2.0;
result = 0.0;
result = smalltalkFunction(x, y);

The overall idea in this example is: use the defined method, make it fixed, get the EsEntryPoint for that method and somehow let Lua know about the EsEntryPoint address – and then let us see, how this all works together …🙂.

As you might see: the (Smalltalk-)function (Lua is calling) takes two numerical parameters: “x” and “y”. We have to check the parameters within the called Smalltalk function. And here is the full source code of the Lua-oriented Smalltalk method:

functionF: pointerToLuaState
  | x y luaInterface n |

  "We create a Lua Interpreter with the status delivered with the parameter"	
  luaInterface := MSKLuaLibrary newLua: pointerToLuaState.
	
  "number of arguments. Should be 2: x and y"
  n := luaInterface getTop.
	
  "We check the number of arguments and the types of the arguments"
  ^((n=2) 
      and:[ (luaInterface isNumber:1) 
             and:[ luaInterface isNumber: 2 ]])
     ifTrue:[
       "retrieve both arguments from stack"
       x := luaInterface toNumber: 1.
       y := luaInterface toNumber: 2.
       "push the result on top of the Lua stack"
       luaInterface 
         pushNumber: ((x * x * y sin) / (1.0 - x)).		
       "the return value of this method are the number of results
        on top of the Lua stack
       "
       1 					
   ]
   ifFalse:[
     "we leave the error path out ..."			
   ].

And here you see how Lua aware C functions have to be written. As all Lua functions you might return several results and these are pushed (by the function) on the Lua stack. The return value of the C function are the number of results values pushed on the Lua stack.

Ok, we have the Smalltalk function, but how do we make all this runnable. Well first we define an instance of EsEntryPoint:

createEntryPoint
  "^ Returns an unbind entry point for the receiver ...."
^EsEntryPoint
   receiver: self
   selector: #functionF:
   callingConvention: 'c'
   arrayBased: false
   parameterTypes: #(uint32)
   returnType: #int32

And now the Smalltalk-code to glue all stuff together:

"we create a new instance of the Lua Interpreter"
luaInterpreter := MSKLuaLibrary newLua.
"we tell this interpreter about our exported Smalltalk
 function and how it is named in the Lua environement"
luaInterpreter
  registerEsEntryPoint: MSKLuaTestCase createEntryPoint as: 'smalltalkFunction'.
"we execute the Lua code - see above"
luaInterpreter
  doFile: './example03.lua'.
"and query the result of global variable 'result', where we
 expect the result of the called Smalltalk function"
result := 
 luaInterpreter
   getGlobalNamed: 'result' ;
   toNumber: -1.
Transcript cr ; show: 'Result :', result asString

and you get in the Smalltalk Transcript window:

Result :-4.84958627640364

There are some limitations in all this work:

-> callbacks from Lua to Smalltalk only work under Linux (Unix)
-> it only works with synchronous call outs from Smalltalk to Lua

But after all it may give you an idea how powerful this all can be …

This entry was posted in Smalltalk and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s