ePolyglot: Examination and development of multilanguage programming using Eiffel, Python, and Haskell | ||
---|---|---|
Prev | Chapter 12. Scripting Eiffel with Python | Next |
What we've done is create a version of Python that understands our Eiffel extension module in a native way. Here's the source that went into creating our custom interpreter:
Example 12-2. Source code for the scripting_eiffel sample program
The CALLED_FROM_PYTHON class, again
class CALLED_FROM_PYTHON creation make feature make is --dummy creation feature do end print_message is do std_output.put_string( "Hello, calling-eiffel-from-python world!%N" ) end print_integer_addition( a, b : INTEGER ) is do std_output.put_string( a.to_string + " + " + b.to_string + "=" + (a+b).to_string ) end end |
The TEST class, our root object
class TEST creation make feature make is do end create_a : CALLED_FROM_PYTHON is do create Result.make end end |
Note some departures from our last program, particularly the TEST class. The make procedure does absolutely nothing--it just returns control back to the caller. Similarly, we include a create_a feature to simplify creation of the CALLED_FROM_PYTHON object that we'll script with Python. And the script?
Example 12-3. The test.py script
__doc__ = """ Exists only to test our ability to call Eiffel methods from Python. Note that for this example, the 'python extension module' is created as a static library that is linked by a custom Python interpreter. There's probably a better way, but the shared library creation was crashing any time stdout was referenced. """ import eiffel_glue import python_shadows if __name__ == "__main__" : eiffel_glue.initialize_eiffel_runtime( 0, "NULL" ) print "Eiffel runtime initialized with root object " + eiffel_glue.cvar.eiffel_root_object print "\ncreating a 'CALLED_FROM_PYTHON' object" a = python_shadows.eiffel_CALLED_FROM_PYTHON( eiffel_glue.test_create_a( eiffel_glue.cvar.eiffel_root_object ) ) print "A sample CALLED_FROM_PYTHON object was created with pointer " + a.swig_pointer print "\nPrinting a message using the CALLED_FROM_PYTHON.print_message feature" a.print_message() print "\nPrinting integer additiong using the" print "CALLED_FROM_PYTHON.print_integer_addition feature" a.print_integer_addition( 1, 42 ) print |
You'll note that the above script looks a little different--and that's because it, not our Eiffel root class, represents the main program. Note the creation of a as an eiffel_object and its use in the script, producing the following output:
Example 12-4. Output of the test.py script
[vputz@yak_prime scripting_eiffel]$ ./python test.py Eiffel runtime initialized with root object _80de978_void_p creating a 'CALLED_FROM_PYTHON' object A sample CALLED_FROM_PYTHON object was created with pointer _80de9a0_void_p Printing a message using the CALLED_FROM_PYTHON.print_message feature Hello, calling-eiffel-from-python world! Printing integer additiong using the CALLED_FROM_PYTHON.print_integer_addition feature 1 + 42=43 |
Note that to execute the interpreter, I had to specifically use the python interpreter located in the current directory (not the default). But it works--and even more interestingly, works interactively as well:
Example 12-5. Interactive use of exposed Eiffel features
[vputz@yak_prime scripting_eiffel]$ ./python Python 1.5.2 (#1, Sep 17 1999, 20:15:36) [GCC egcs-2.91.66 19990314/Linux (egcs- on linux-i386 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> import eiffel_glue >>> eiffel_glue.initialize_eiffel_runtime( 0, "NULL" ) >>> import python_shadows >>> a = python_shadows.eiffel_CALLED_FROM_PYTHON( eiffel_glue.test_create_a( eiffel_glue.cvar.eiffel_root_object ) ) >>> a.print_message() Hello, calling-eiffel-from-python world! >>> a.print_integer_addition( 1, 42 ) 1 + 42=43 >>> [vputz@yak_prime scripting_eiffel]$ |
We've come a long way--we've exposed Python to Eiffel, including easy manipulation of Python objects through Eiffel shadow classes, and finally come full circle to the point where we can interactively manipulate Eiffel classes and Eiffel objects from within Python. Note that in this simple example our interaction with the Eiffel runtime was short enough that garbage collection did not collect our orphaned CALLED_FROM_PYTHON object, and users are reminded to implement some sort of bookkeeping on the Eiffel side if they really wish to script Eiffel entirely from Python.
Only one more element remains to add to the mix, and its inclusion was somewhat rocky. The following two chapters detail our only somewhat successful efforts to add Haskell to the mix.