Search This Blog

Friday, May 20, 2011

Scripting in OS X with Squirrel

I have been working on a new product, part of which requires a server application to run on a Macintosh - at least for now.  The other part of the application runs on an iPhone and/or iPad.

I needed a way to create programming scripts to control certain aspects of the product, i.e., changing the products functionality in the field without rebuilding the code.  To accomplish this I am use a scripting language called Squirrel.

Over the last decade or so I have used a number of languages for scripting among them Chicken which is a Scheme-based Lisp.  Chicken worked well for most things but, alas, the Lisp syntax with its bizillions of parends is really too much to take over the long haul - even with editors that help out by doing the balancing for you.

Squirrel comes as two small directories of C++ code.  One for the main language and compiler, one for a series of standard "libraries" that support things like file I/O, math and so on.  While there are plenty of scripting languages out there (JavaScript, Lua, Chicken, etc. etc.) all of these appear to be much larger than Squirrel - larger in the sense of more files, more complexity, more build issues, and so on.

Squirrel consists of about a dozen .CPP files for the main language, compiler and runtime and another half dozen or so for the standard library.  Not bad when you consider what you get (from the web site):

 - Open Source MIT license
 - dynamic typing
 - delegation
 - classes & inheritance
 - higher order functions
 - lexical scoping
 - generators
 - cooperative threads(co-routines)
 - tail recursion
 - exception handling
 - automatic memory management (CPU bursts free; mixed approach ref counting/GC)
 - both compiler and virtual machine fit together in about 7k lines of C++ code.
 - optional 16bits characters strings
 - lambda functions

Lambda-functions, threads and generators in 7K lines of code - a geeks delight for sure.

When checking out the site I did not see a Mac or iOS port.  Since these are the features I needed I decided to port it to both.

Now the target system (Mac and iOS) have some peculiar issues.  The Mac is either a 64-bit or 32-bit OS and iOS requires both a arm and i386 version (arm for the physical phones and i386 (32-bit) for the iPhone/iPad simulator you use for virtual testing.  This means four different libraries, eight if you build for debug and release.

So I set about porting - which took zero time since - despite no Mac/iOS being listed on the squirrel web site - the code just built and ran (a standard Makefile is provided so all you have to do is cd into the top level and type "make").

More work (which posted about here) was required to get things to link.

(At this point I have to say the XCode 4 is not quite ready for prime time.  It does work but its so ridiculously confusing to use its almost to frustrating to deal with.  But more on this another time...)

Once I had the libraries working for the various platforms I set about doing some basic testing - making sure that for both Mac and iOS I could call and run Squirrel .nut files from running Mac and iOS applications.  This also worked without any hitches right out of the box.

The next tricky thing to do was to integrate the build environment.  As I described in the last post the only way I could get that to work in XCode 4 was to put Squirrel into a library (.a) file.

Now on the iPhone/Mac platforms there are multiple languages you can use: C, C++, and Objective-C among the main ones.  Both the GCC 4.2 and the LLVM GCC 4.2 support all languages on both platforms.  However, I was somewhat concerned about mixing these all together.

It turns out that the only really tricky part is adding a "-libstdc++" to the "Linker Flags" section of the build page in either XCode 3.2 or 4 after you create and add a squirrel .a library.  Squirrel is built with C++ and hence requires this. 

However, beyond that I had no other operational problems.  It was easy enough to create both .c and .m files and to call into the Squirrel code from both.  (I suspect that this is more to do with GCC/LLVM than Apple.)

At this point I have put together an extensive set of code surrounding Squirrel for my application and I must say that other than some minor documentation issues and a small change to Squirrel it all went great.

Squirrel is designed for gaming and my application, which has realtime aspects to it, should work well with its architecture.

I did make on change to Squirrel - the compiler, which can compile .nut files into the VM or into .cnut (compiled .nut) files, takes a lexer function as a parameter.  You pass the compiler a user pointer when you call it and the lexer function is repeated called with this parameter so you can handle all of your own lexing issues.  For example, in my case, I wanted a way to include certain symbols and constants from .h and other files without having to duplicate them.

The only issue I found so far was that the compiler error function, which the user can also define, is not called with the user pointer - which means that if you are augmenting the lexer the compiler error function cannot know the state of your lexer.   I changed Squirrel to make the user pointer a parameter to the compiler error function - hopefully this change will make its way into the official code base.

Documentation-wise I really didn't have too much trouble.  The only part so far that I have found unclear is the difference between assigning to local and global variables (using '=' versus '<-').  There was some forum help for this but I think adding some extra documentation around this would be helpful.

(I do have one question at this point, however.  The issue of reentrancy.  My guess is that for a given Squirrel VM you cannot have more than one active outside OS thread or event loop simultaneously active, i.e., say I have one VM and two events invoking Squirrel functions through the C API.  I have to assume that these would need to be synchronized though the documentation and web site are not clear on this.)

In my .m and .c code I am able to call into Squirrel and easily access class instances and invoke members which makes the functionality I need very simple and straight forward.

While I have most of this also working for iOS I have not completely tested it - though since much of my code runs on both platforms and based on what i have seen so far I do not expect any problems.

Squirrel was written by Alberto Demichelis and I have to say that over all this is an excellent effort.  The language is fairly intuitive, powerful (supporting much of what you can do in Lisp without the ugliness), and straight forward to learn.  The provided .CPP code is clean and straightforward - I added my extra user pointer to the compiler after about 10 minutes of work.  (From his resume it looks like Alberto is just one talented guy - basically completely self taught.)

The license is MIT Open source (linked from the Squirrel web site: "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.") which means that there isn't much required to make use of it in a commercial product.

My hat is off to Alberto on this one.

No comments:

Post a Comment