| 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.