diff --git a/CHANGELOG b/CHANGELOG
index 91f1752..3d11116 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,10 @@
+0.3, in progress:
+
+ * GenericValue added. Used by ExecutionEngine.run().
+ * Build cleanly on OpenBSD, x86-64/amd64 (Laurence Tratt).
+ * Updated documentation.
+
+
0.2.1, 18-Jun-2008:
* Build cleanly with LLVM 2.3 and 2.3svn.
@@ -5,18 +12,18 @@
0.2, 15-Jun-2008:
- * Independent package, need not be unpacked into llvm/bindings
- * Fixed ownership issues with Module/ModuleProvider
+ * Independent package, need not be unpacked into llvm/bindings.
+ * Fixed ownership issues with Module/ModuleProvider.
* Modules, values and types can be stringified, to get their LLVM
- assembly representation
- * Modules and functions can be verified
- * MemoryBuffer and TypeHandle are available
- * ExecutionEngine, TargetData and passes are available
- * Unit tester added (but doesn't test much for now)
- * Python doc string documentation added (still incomplete)
- * Many minor style/cosmetic changes and bug fixes
- * Added documentation as on website into SVN
- * Lots of cleanup
+ assembly representation.
+ * Modules and functions can be verified.
+ * MemoryBuffer and TypeHandle are available.
+ * ExecutionEngine, TargetData and passes are available.
+ * Unit tester added (but doesn't test much for now).
+ * Python doc string documentation added (still incomplete).
+ * Many minor style/cosmetic changes and bug fixes.
+ * Added documentation as on website into SVN.
+ * Lots of cleanup.
0.1, 10-May-2008:
diff --git a/setup.py b/setup.py
index c11e6a7..4812bda 100644
--- a/setup.py
+++ b/setup.py
@@ -26,11 +26,14 @@ def get_llvm_config():
# get from command-line, or use default
lc = 'llvm-config'
- for i in xrange(0, len(sys.argv)):
+ i = 0
+ while i < len(sys.argv):
arg = sys.argv[i]
if arg.startswith('--llvm-config='):
del sys.argv[i]
lc = arg.split('=')[1]
+ else:
+ i += 1
# see if it works
version = _run(lc + ' --version')
@@ -49,7 +52,9 @@ def call_setup(llvm_config):
['core', 'analysis', 'scalaropts', 'executionengine',
'jit', 'native'])
- std_libs = [ 'pthread', 'dl', 'm' ]
+ std_libs = [ 'pthread', 'm' ]
+ if not sys.platform.startswith("openbsd"):
+ std_libs.append("dl")
ext_core = Extension(
'llvm._core',
@@ -60,11 +65,12 @@ def call_setup(llvm_config):
include_dirs = [incdir],
library_dirs = [libdir],
libraries = std_libs + libs_core,
- extra_objects = objs_core)
+ extra_objects = objs_core,
+ extra_link_args = ["-fPIC"])
setup(
name='llvm-py',
- version='0.2.1',
+ version='0.3',
description='Python Bindings for LLVM',
author='Mahadevan R',
author_email='mdevan.foobar@gmail.com',
diff --git a/test/JITTutorial1.py b/test/JITTutorial1.py
new file mode 100644
index 0000000..294380d
--- /dev/null
+++ b/test/JITTutorial1.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+from llvm.core import *
+
+# create a module
+module = Module.new ("tut1")
+
+# create a function type taking 3 32-bit integers, return a 32-bit integer
+ty_int = Type.int (32)
+func_type = Type.function (ty_int, (ty_int,)*3)
+
+# create a function of that type
+mul_add = Function.new (module, func_type, "mul_add")
+mul_add.calling_convention = CC_C
+x = mul_add.args[0]; x.name = "x"
+y = mul_add.args[1]; y.name = "y"
+z = mul_add.args[2]; z.name = "z"
+
+# implement the function
+
+# new block
+blk = mul_add.append_basic_block ("entry")
+
+# IR builder
+bldr = Builder.new (blk)
+tmp_1 = bldr.mul (x, y, "tmp_1")
+tmp_2 = bldr.add (tmp_1, z, "tmp_2")
+
+bldr.ret (tmp_2)
+
+print module
diff --git a/test/JITTutorial2.py b/test/JITTutorial2.py
new file mode 100644
index 0000000..ea1df8e
--- /dev/null
+++ b/test/JITTutorial2.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+from llvm.core import *
+
+# create a module
+module = Module.new ("tut2")
+
+# create a function type taking 2 integers, return a 32-bit integer
+ty_int = Type.int (32)
+func_type = Type.function (ty_int, (ty_int, ty_int))
+
+# create a function of that type
+gcd = Function.new (module, func_type, "gcd")
+
+# name function args
+x = gcd.args[0]; x.name = "x"
+y = gcd.args[1]; y.name = "y"
+
+# implement the function
+
+# blocks...
+entry = gcd.append_basic_block ("entry")
+ret = gcd.append_basic_block ("return")
+cond_false = gcd.append_basic_block ("cond_false")
+cond_true = gcd.append_basic_block ("cond_true")
+cond_false_2 = gcd.append_basic_block ("cond_false_2")
+
+# create a llvm::IRBuilder
+bldr = Builder.new (entry)
+x_eq_y = bldr.icmp (IPRED_EQ, x, y, "tmp")
+bldr.cbranch (x_eq_y, ret, cond_false)
+
+bldr.position_at_end (ret)
+bldr.ret(x)
+
+bldr.position_at_end (cond_false)
+x_lt_y = bldr.icmp (IPRED_ULT, x, y, "tmp")
+bldr.cbranch (x_lt_y, cond_true, cond_false_2)
+
+bldr.position_at_end (cond_true)
+y_sub_x = bldr.sub (y, x, "tmp")
+recur_1 = bldr.call (gcd, (x, y_sub_x,), "tmp")
+bldr.ret (recur_1)
+
+bldr.position_at_end (cond_false_2)
+x_sub_y = bldr.sub (x, y, "x_sub_y")
+recur_2 = bldr.call (gcd, (x_sub_y, y,), "tmp")
+bldr.ret (recur_2)
+
+print module
diff --git a/test/typehandle.py b/test/typehandle.py
new file mode 100644
index 0000000..752b63b
--- /dev/null
+++ b/test/typehandle.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+from llvm.core import *
+
+# create a type handle object
+th = TypeHandle.new(Type.opaque())
+
+# create the struct with an opaque* instead of self*
+ts = Type.struct([ Type.int(), Type.pointer(th.type) ])
+
+# unify the types
+th.type.refine(ts)
+
+# create a module, and add a "typedef"
+m = Module.new('mod1')
+m.add_type_name("struct.node", th.type)
+
+# show what we created
+print m
diff --git a/www/src/example.inc b/www/src/example.inc
index 08b2a2c..f1afb87 100644
--- a/www/src/example.inc
+++ b/www/src/example.inc
@@ -2,8 +2,8 @@
A Simple Function
~~~~~~~~~~~~~~~~~
-Let's create a module containing a single function, corresponding to the
-`C` function:
+Let's create a (LLVM) module containing a single function, corresponding
+to the `C` function:
[C]
source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -23,7 +23,7 @@ source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from llvm import *
from llvm.core import *
-# Create a module.
+# Create an (empty) module.
my_module = Module.new('my_module')
# All the types involved here are "int"s. This type is represented
@@ -128,5 +128,3 @@ And here's the output:
returned 142
-----------------------------------------------------------------------
-That was easy, right?!
-
diff --git a/www/src/examples.txt b/www/src/examples.txt
index 5a33cc4..6f8831f 100644
--- a/www/src/examples.txt
+++ b/www/src/examples.txt
@@ -1,5 +1,35 @@
+Examples and LLVM Tutorials
+===========================
+
Examples
-========
+--------
include::example.inc[]
+LLVM Tutorials
+--------------
+
+The http://www.llvm.org/docs/tutorial/[LLVM tutorials] have been
+ported to llvm-py. Below are the links to the original LLVM tutorial and
+the corresponding Python code using llvm-py:
+
+.Simple JIT Tutorials
+(These were contributed by Sebastien Binet; thanks!)
+
+1. A First Function
+ http://www.llvm.org/docs/tutorial/JITTutorial1.html[LLVM]
+ link:examples/JITTutorial1.py[llvm-py]
+2. A More Complicated Function
+ http://www.llvm.org/docs/tutorial/JITTutorial2.html[LLVM]
+ link:examples/JITTutorial2.py[llvm-py]
+
+
+.Kaleidoscope: Implementing a Language with LLVM
+1. Tutorial Introduction and the Lexer (TODO)
+2. Implementing a Parser and AST (TODO)
+3. Implementing Code Generation to LLVM IR (TODO)
+4. Adding JIT and Optimizer Support (TODO)
+5. Extending the language: control flow (TODO)
+6. Extending the language: user-defined operators (TODO)
+7. Extending the language: mutable variables / SSA construction (TODO)
+8. Conclusion and other useful LLVM tidbits (TODO)
diff --git a/www/src/examples/JITTutorial1.py b/www/src/examples/JITTutorial1.py
new file mode 120000
index 0000000..3d31be9
--- /dev/null
+++ b/www/src/examples/JITTutorial1.py
@@ -0,0 +1 @@
+../../../test/JITTutorial1.py
\ No newline at end of file
diff --git a/www/src/examples/JITTutorial2.py b/www/src/examples/JITTutorial2.py
new file mode 120000
index 0000000..08b251b
--- /dev/null
+++ b/www/src/examples/JITTutorial2.py
@@ -0,0 +1 @@
+../../../test/JITTutorial2.py
\ No newline at end of file
diff --git a/www/src/index.txt b/www/src/index.txt
index d77a217..e9d9e30 100644
--- a/www/src/index.txt
+++ b/www/src/index.txt
@@ -3,15 +3,20 @@ llvm-py: Python Bindings for LLVM
llvm-py provides http://www.python.org/[Python] bindings for
http://llvm.org/[LLVM]. It's goal is to expose enough of LLVM APIs to
-implement a compiler backend or a VM in pure Python. Currently, llvm-py is
-available for LLVM 2.3 and Python 2.5, on Linux/x86. It is expected to
-be usable on various unices, as well as with Python 2.4, with minimal
-changes, if any.
+implement a compiler backend or a VM in pure Python. llvm-py consists of
+Python and C modules that wrap over the native C++/C bindings of LLVM,
+and does not use / have dependencies on "glue utilities" like
+Boost.Python, swig etc.
llvm-py is just hatching. It should be stable enough to start hacking
away, though. Be sure to send in a patch (or shout at the author) if you
miss any specific LLVM API.
+_Availability_: llvm-py is available (as a source package) for LLVM 2.3
+and Python 2.5. It builds on Linux, OpenBSD on i386 and x86-64/amd64.
+It is expected to be usable on various unices, as well as with Python
+2.4 and LLVM 2.3+svn, with minimal changes, if any.
+
News
----
diff --git a/www/src/userguide.txt b/www/src/userguide.txt
index 0086c10..f36610a 100644
--- a/www/src/userguide.txt
+++ b/www/src/userguide.txt
@@ -5,8 +5,6 @@ llvm-py User Guide
=======================================================================
This document is updated frequently (last updated on {localdate}).
Check back often.
-
-You might wish to look over the link:#examples[examples] first.
=======================================================================
@@ -1038,7 +1036,54 @@ methods.
TypeHandle (llvm.core)
~~~~~~~~~~~~~~~~~~~~~~
-TODO
+TypeHandle objects are used to create recursive types, like this linked
+list node structure in C:
+
+[C]
+source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+struct node
+{
+ int data;
+ struct node *next;
+};
+source~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This can be realized in llvm-py like this:
+
+-----------------------------------------------------------------------
+include::../../test/typehandle.py[]
+-----------------------------------------------------------------------
+
+which gives the output:
+
+-----------------------------------------------------------------------
+; ModuleID = 'mod1'
+ %struct.node = type { i32, %struct.node* }
+-----------------------------------------------------------------------
+
+For more details on what is going on here, please refer the LLVM
+Programmer's Manual section
+http://llvm.org/docs/ProgrammersManual.html#TypeResolve["LLVM Type
+Resolution"]. The TypeHandle class of llvm-py corresponds to
+http://www.llvm.org/doxygen/classllvm_1_1PATypeHolder.html[`llvm::PATypeHolder`]
+in C\+\+. The above example is available as
+http://code.google.com/p/llvm-py/source/browse/trunk/test/typehandle.py[test/typehandle.py]
+in the source distribution.
+
+.llvm.core.TypeHandle
+[caption=""]
+=======================================================================
+.Static Constructors
+`new(abstract_ty)`::
+ create a new `TypeHandle` instance, which holds a reference to the
+ given abstract type `abstract_ty`. Typically, the abstract type used
+ is `Type.opaque()`.
+
+.Properties
+`type`::
+ returns the contained type. Typically the `refine` method is called
+ on the returned type.
+=======================================================================
Instructions (llvm.core)
@@ -1095,17 +1140,17 @@ About the llvm-py Project
llvm-py lives at
http://mdevan.nfshost.com/llvm-py/[http://mdevan.nfshost.com/llvm-py/].
-The code (subversion repository) and the issue tracker are hosted on google
-code, at
+The code (subversion repository) and the issue tracker are hosted on the
+Google code hosting service, at
http://code.google.com/p/llvm-py/[http://code.google.com/p/llvm-py/].
-llvm-py is distributed under the new BSD license, the full license
-text is in the file named
+It is distributed under the new BSD license, the full license text is in
+the file named
http://code.google.com/p/llvm-py/source/browse/trunk/LICENSE[LICENSE]
available in the source distribution.
The entire llvm-py website is generated from marked up text files
using the tool http://www.methods.co.nz/asciidoc/[AsciiDoc]. These text
-files and the generated HTML pages are available in the source
+files and the (pre-)generated HTML pages are available in the source
distribution.
llvm-py is an ongoing, live project. Your contributions in any form
diff --git a/www/web/about.html b/www/web/about.html
index a771ff9..9ce2a0e 100644
--- a/www/web/about.html
+++ b/www/web/about.html
@@ -42,7 +42,7 @@ llvm-dev mailing list and irc.oftc.net#llvm (mdevan).
0.3, in progress:
+
+ * GenericValue added. Used by ExecutionEngine.run().
+ * Build cleanly on OpenBSD, x86-64/amd64 (Laurence Tratt).
+ * Updated documentation.
+
+
+0.2.1, 18-Jun-2008:
* Build cleanly with LLVM 2.3 and 2.3svn.
0.2, 15-Jun-2008:
- * Independent package, need not be unpacked into llvm/bindings
- * Fixed ownership issues with Module/ModuleProvider
+ * Independent package, need not be unpacked into llvm/bindings.
+ * Fixed ownership issues with Module/ModuleProvider.
* Modules, values and types can be stringified, to get their LLVM
- assembly representation
- * Modules and functions can be verified
- * MemoryBuffer and TypeHandle are available
- * ExecutionEngine, TargetData and passes are available
- * Unit tester added (but doesn't test much for now)
- * Python doc string documentation added (still incomplete)
- * Many minor style/cosmetic changes and bug fixes
- * Added documentation as on website into SVN
- * Lots of cleanup
+ assembly representation.
+ * Modules and functions can be verified.
+ * MemoryBuffer and TypeHandle are available.
+ * ExecutionEngine, TargetData and passes are available.
+ * Unit tester added (but doesn't test much for now).
+ * Python doc string documentation added (still incomplete).
+ * Many minor style/cosmetic changes and bug fixes.
+ * Added documentation as on website into SVN.
+ * Lots of cleanup.
0.1, 10-May-2008:
@@ -149,7 +156,7 @@ package.
Let's create a module containing a single function, corresponding to the
-C function:
+
Let's create a (LLVM) module containing a single function, corresponding
+to the C function:
from llvm import*from llvm.core import*
-# Create a module.
+# Create an (empty) module.
my_module =Module.new('my_module')# All the types involved here are "int"s. This type is represented
@@ -156,11 +158,77 @@ retval = ee.
returned 142
-
That was easy, right?!
+
+
LLVM Tutorials
+
+
The LLVM tutorials have been
+ported to llvm-py. Below are the links to the original LLVM tutorial and
+the corresponding Python code using llvm-py:
+
Simple JIT Tutorials
+
(These were contributed by Sebastien Binet; thanks!)
+Extending the language: user-defined operators (TODO)
+
+
+
+
+Extending the language: mutable variables / SSA construction (TODO)
+
+
+
+
+Conclusion and other useful LLVM tidbits (TODO)
+
+
+
+
diff --git a/www/web/examples/JITTutorial1.py b/www/web/examples/JITTutorial1.py
new file mode 100644
index 0000000..294380d
--- /dev/null
+++ b/www/web/examples/JITTutorial1.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+from llvm.core import *
+
+# create a module
+module = Module.new ("tut1")
+
+# create a function type taking 3 32-bit integers, return a 32-bit integer
+ty_int = Type.int (32)
+func_type = Type.function (ty_int, (ty_int,)*3)
+
+# create a function of that type
+mul_add = Function.new (module, func_type, "mul_add")
+mul_add.calling_convention = CC_C
+x = mul_add.args[0]; x.name = "x"
+y = mul_add.args[1]; y.name = "y"
+z = mul_add.args[2]; z.name = "z"
+
+# implement the function
+
+# new block
+blk = mul_add.append_basic_block ("entry")
+
+# IR builder
+bldr = Builder.new (blk)
+tmp_1 = bldr.mul (x, y, "tmp_1")
+tmp_2 = bldr.add (tmp_1, z, "tmp_2")
+
+bldr.ret (tmp_2)
+
+print module
diff --git a/www/web/examples/JITTutorial2.py b/www/web/examples/JITTutorial2.py
new file mode 100644
index 0000000..ea1df8e
--- /dev/null
+++ b/www/web/examples/JITTutorial2.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+from llvm.core import *
+
+# create a module
+module = Module.new ("tut2")
+
+# create a function type taking 2 integers, return a 32-bit integer
+ty_int = Type.int (32)
+func_type = Type.function (ty_int, (ty_int, ty_int))
+
+# create a function of that type
+gcd = Function.new (module, func_type, "gcd")
+
+# name function args
+x = gcd.args[0]; x.name = "x"
+y = gcd.args[1]; y.name = "y"
+
+# implement the function
+
+# blocks...
+entry = gcd.append_basic_block ("entry")
+ret = gcd.append_basic_block ("return")
+cond_false = gcd.append_basic_block ("cond_false")
+cond_true = gcd.append_basic_block ("cond_true")
+cond_false_2 = gcd.append_basic_block ("cond_false_2")
+
+# create a llvm::IRBuilder
+bldr = Builder.new (entry)
+x_eq_y = bldr.icmp (IPRED_EQ, x, y, "tmp")
+bldr.cbranch (x_eq_y, ret, cond_false)
+
+bldr.position_at_end (ret)
+bldr.ret(x)
+
+bldr.position_at_end (cond_false)
+x_lt_y = bldr.icmp (IPRED_ULT, x, y, "tmp")
+bldr.cbranch (x_lt_y, cond_true, cond_false_2)
+
+bldr.position_at_end (cond_true)
+y_sub_x = bldr.sub (y, x, "tmp")
+recur_1 = bldr.call (gcd, (x, y_sub_x,), "tmp")
+bldr.ret (recur_1)
+
+bldr.position_at_end (cond_false_2)
+x_sub_y = bldr.sub (x, y, "x_sub_y")
+recur_2 = bldr.call (gcd, (x_sub_y, y,), "tmp")
+bldr.ret (recur_2)
+
+print module
diff --git a/www/web/index.html b/www/web/index.html
index ae154fa..5baee39 100644
--- a/www/web/index.html
+++ b/www/web/index.html
@@ -35,13 +35,17 @@
llvm-py provides Python bindings for
LLVM. It's goal is to expose enough of LLVM APIs to
-implement a compiler backend or a VM in pure Python. Currently, llvm-py is
-available for LLVM 2.3 and Python 2.5, on Linux/x86. It is expected to
-be usable on various unices, as well as with Python 2.4, with minimal
-changes, if any.
+implement a compiler backend or a VM in pure Python. llvm-py consists of
+Python and C modules that wrap over the native C++/C bindings of LLVM,
+and does not use / have dependencies on "glue utilities" like
+Boost.Python, swig etc.
llvm-py is just hatching. It should be stable enough to start hacking
away, though. Be sure to send in a patch (or shout at the author) if you
miss any specific LLVM API.
+
Availability: llvm-py is available (as a source package) for LLVM 2.3
+and Python 2.5. It builds on Linux, OpenBSD on i386 and x86-64/amd64.
+It is expected to be usable on various unices, as well as with Python
+2.4 and LLVM 2.3+svn, with minimal changes, if any.
News
@@ -76,7 +80,7 @@ miss any specific LLVM API.
diff --git a/www/web/license.html b/www/web/license.html
index 9c4b646..64bb49a 100644
--- a/www/web/license.html
+++ b/www/web/license.html
@@ -74,7 +74,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/www/web/userguide.html b/www/web/userguide.html
index fe86bab..bf8a955 100644
--- a/www/web/userguide.html
+++ b/www/web/userguide.html
@@ -49,9 +49,8 @@ window.onload = function(){generateToc(2)}
-
This document is updated frequently (last updated on 25-Jun-2008).
+
This document is updated frequently (last updated on 05-Jul-2008).
Check back often.
#!/usr/bin/env python
+
+from llvm.core import *
+
+# create a type handle object
+th = TypeHandle.new(Type.opaque())
+
+# create the struct with an opaque* instead of self*
+ts = Type.struct([ Type.int(), Type.pointer(th.type) ])
+
+# unify the types
+th.type.refine(ts)
+
+# create a module, and add a "typedef"
+m = Module.new('mod1')
+m.add_type_name("struct.node", th.type)
+
+# show what we created
+print m
For more details on what is going on here, please refer the LLVM
+Programmer's Manual section
+"LLVM Type
+Resolution". The TypeHandle class of llvm-py corresponds to
+llvm::PATypeHolder
+in C++. The above example is available as
+test/typehandle.py
+in the source distribution.
+
+
llvm.core.TypeHandle
+
+
Static Constructors
+
+new(abstract_ty)
+
+
+
+ create a new TypeHandle instance, which holds a reference to the
+ given abstract type abstract_ty. Typically, the abstract type used
+ is Type.opaque().
+
+
+
+
Properties
+
+type
+
+
+
+ returns the contained type. Typically the refine method is called
+ on the returned type.
+
+
+
+
Instructions (llvm.core)
TODO
Basic Block (llvm.core)
@@ -2409,8 +2484,8 @@ methods.
Annotated Examples
A Simple Function
-
Let's create a module containing a single function, corresponding to the
-C function:
+
Let's create a (LLVM) module containing a single function, corresponding
+to the C function:
from llvm import*from llvm.core import*
-# Create a module.
+# Create an (empty) module.
my_module =Module.new('my_module')# All the types involved here are "int"s. This type is represented
@@ -2533,22 +2608,21 @@ retval = ee.
returned 142
-
That was easy, right?!
About the llvm-py Project
llvm-py lives at
http://mdevan.nfshost.com/llvm-py/.
-The code (subversion repository) and the issue tracker are hosted on google
-code, at
+The code (subversion repository) and the issue tracker are hosted on the
+Google code hosting service, at
http://code.google.com/p/llvm-py/.
-llvm-py is distributed under the new BSD license, the full license
-text is in the file named
+It is distributed under the new BSD license, the full license text is in
+the file named
LICENSE
available in the source distribution.
The entire llvm-py website is generated from marked up text files
using the tool AsciiDoc. These text
-files and the generated HTML pages are available in the source
+files and the (pre-)generated HTML pages are available in the source
distribution.
llvm-py is an ongoing, live project. Your contributions in any form
are most welcome. You can checkout the latest SVN HEAD from
@@ -2559,7 +2633,7 @@ reached at mdevan.foobar@gmail.com.