The scripting_eiffel sample program

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.