15.11 The Jaql User Environment
The role of a query language is to take a user query and produce results. You can create a simple graphical user environment where users of your language can develop queries, issue them, and see the results. The heart of such an environment has two text areas: one for user queries and one for results. The environment also needs a button to tell the environment to execute the query and a second button to clear the result area. The sample code for this package includes the class JaqlUe , which provides an interactive user environment for applying Jaql queries to the Chip data model. The code for this user interface is tangential to the subject of writing parsers, but all the code is on the CD included with this book.
The code in sjm.examples.query separates its handling of user interaction into two classes: JaqlUe and JaqlMediator . The JaqlUe class is responsible for the creation of Swing components . It also contains the main() method that launches the user interface. The JaqlMediator class controls the interaction of the Swing components. This class implements ActionListener , and it defines the action method that executes when the user presses the Go! button, as Figure 15.16 shows.
Figure 15.16. A Jaql user environment sequence. The objects in this diagram collaborate to recognize a user's text query and create a corresponding Query object.
When the user clicks the Go! button, a JaqlMediator object receives notification that action is required. The mediator uses a JaqlParser object to parse the user's query. As the parse proceeds, the parser adds select terms, class names , and comparisons to a QueryBuilder object.
After the parse, the mediator asks the builder to build, passing it a ChipSource object as a source of axioms. The builder creates and returns a Query object. The mediator asks this object for proofs and appends the results to the results area in the user environment.
15.11.1 Exception Handling
When the user presses the Go! button, the mediator constructs a QueryBuilder object, passing it a ChipSpeller object to use for spell checking. The spell check relies on the exception handling of JaqlMediator to display the proper error message. When the Jaql parser sees a class name , its ClassNameAssembler object passes the class name to the QueryBuilder object. The query builder checks for a class of this name using the ChipSpeller object, throwing an UnrecognizedClassException if the entered class name is unknown. The JaqlMediator . actionPerformed() method catches this exception and appends it to the output text area.
Chapter 11, "Extending the Parser Toolkit," explains how Track objects throw a runtime exception when a sequence begins but does not complete. The use of tracks in lieu of normal sequences greatly aids a user who is struggling to enter a proper query.
The select sequence and the three comma-separated lists in the Jaql parser use tracks to help diagnose the source of input errors. For example, if the user forgets the word from ,
select ChipName, PricePerBag chip where Oil = "Coconut"
The user environment prints
After : select ChipName , PricePerBag Expected: from Found : chip
15.11.3 Handling Abject Failure
Tracks work only after the track begins. If the user enters text that the Jaql parser cannot parse at all, the JaqlMediator object detects the failure. In this case, the mediator expresses the problem that it cannot parse the input. For example, if the user enters
How do I use this?
the JaqlMediator object displays
Cannot parse input text.