4. Embedding the Interpreter

While running the interpreter is nice, it is not a good example of what Psyche can do. There are more interpreters, and most of them are faster, easier to use, or better in other respects. Psyche's strength lies in embedding the interpreter in a Python program.

Psyche consists of a small number of Python modules. These modules and a short description of them are described in Table 4.1.


Table 4.1: Psyche Modules
Module Purpose
psyche Top level module for Psyche
psyche.analyzers Semantical Analyzers
psyche.ast Nodes for Abstract Syntax Tree
psyche.function Classes for executing Scheme functions
psyche.interpreter The interpreter, the shell and environments
psyche.lexer Lexical Analyzer and Token class
psyche.parser Parser
psyche.schemefct Implementation of Scheme procedures
psyche.types Implementation of Scheme types


4.1 Evaluating Scheme Expressions

Let's start with a small example from the interactive Python shell. In this example we shall create a Scheme interpreter and use it to calculate the square of 5.

Example 4..1   Computing squares
 
Python 2.2.1 (#1, Apr 21 2002, 08:38:44)  
[GCC 2.95.4 20011002 (Debian prerelease)] on linux2 
Type "help", "copyright", "credits" or "license" for more information.
>>> from psyche.interpreter import Interpreter
>>> i = Interpreter()
>>> i.eval('(define (square x) (* x x))')
>>> i.eval('(square 5)')
25
>>> i.eval('(square -1)')
1
>>> i.eval('(square "hello")')
Traceback (most recent call last):
    ...
TypeError: unsupported operand type(s) for *: 'str' and 'str'
>>>

Let's step through this example and see what happens.

The first statement imports the Interpreter into our namespace. The second statement creates an actual Interpreter object and names it i.

The other statements use the eval method to execute Scheme commands. eval is the most interesting method in the Interpreter; it expects a string containing a legal Scheme command, evaluates the command and returns the result of the evaluation.

The third statement evaluates the Scheme command (define...). The fourth and fifth statements again evaluate a Scheme expression, using the square procedure defined in the third statement.

At this point, two interesting observations can be made. Firstly, notice how the interpreter keeps its state; in the fourth and fifth statements, it remembers the definition of square from the third statement.

Secondly, the latter two evaluations print a (correct) return value, while the first evaluation does not. Understanding this requires some knowledge the Scheme specification, which explicitly states the return values of each Scheme command. However, for some commands such as define, the R5RS specifies that the return value is undefined. In these cases, Psyche will return None, which is silently ignored by the Python shell.

The last statement tries to evaluate a Scheme expression resulting in an error. Psyche uses the Python exception handling mechanism to signal errors. In this case, a TypeError is raised.

4.2 Dynamically Constructing Scheme Expressions

Warning: Unfinished

Y. Duppen