This is the programmer guide for Latte, the Language for Transforming Text.

Copyright © 1998 Zanshin Inc.

The contents of this file are subject to the Zanshin Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License.  You should have received a copy of the License with Latte; see the file COPYING.  You may also obtain a copy of the License at <http://www.zanshin.com/ZPL.html>.

Documents distributed under the License are distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License for the specific language governing rights and limitations under the License.

The Original Code is Latte.

The Initial Developer of the Original Code is Zanshin, Inc.

This product includes software developed by the University of California, Berkeley and its contributors.

This is the programmer guide for Latte, the Language for Transforming Text.

Introduction
************

This document describes the programming interface to the Latte library. Latte is the Language for Transforming Text.  With the Latte library it is possible to write programs that process Latte-formatted documents, e.g. to translate them into other formats.  One such translator program, latte-html, converts Latte files into HTML files.  It comes with Latte, and its implementation will serve as an instructional tool throughout this manual.

Regrettably, this document is not yet complete.  Until it is, programmers interested in using the Latte library should contact latte-dev@zanshin.com for information and assistance.

Latte processing overview
*************************

To process a file of Latte input, the caller creates a reader and a visitor.  The reader is responsible for parsing the input into a variety of data structures and evaluating those structures.  The visitor is responsible for performing the desired processing on the results.

Each top-level expression recognized by the reader is immediately evaluated and then ``visited'' by the visitor.  (The action of the visitor in latte-html is to evaluate the expression, adjust the resulting text according to certain HTML rules, and then output it.)

Latte_Reader
************

 -- Constructor: Latte_Reader (istream &STREAM, const shstring &FILENAME)
 -- Constructor: Latte_Reader (istream &STREAM, const shstring &FILENAME, Latte_Activation &ACTIVATION)

     Constructs a new Latte_Reader.  Input is from STREAM.  The name of the stream is FILENAME (used in error messages and to set the Latte variable \__FILE__).  The optional argument ACTIVATION contains variable bindings; if omitted, a new global activation is created and populated with some intrinsic global definitions (presently only \__latte-version__).

 -- Latte_Reader member fn: void install_standard_definitions ()

     Populates the reader's activation with the standard intrinsic variable definitions, primarily the definitions of Latte's built-in functions.

 -- Latte_Reader member fn: void process (Latte_Visitor &VISITOR)

     Consumes the input and processes it using VISITOR.

Latte_Obj
*********

Calling Latte_Reader::process() creates a series of Latte_Obj trees that are then handed to a Latte_Visitor. Latte_Obj is an abstract base class for a rich variety of subclasses.

Latte_Obj has a collection of virtual functions for testing which subclass an object belongs to.

 -- Latte_Obj virtual member fn: Latte_Assignment * as_assignment ()
 -- const Latte_Assignment *: as_assignment () const

     If this is a Latte_Assignment, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_Boolean * as_boolean ()
 -- const Latte_Boolean *: as_boolean () const

     If this is a Latte_Boolean, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_Group * as_group ()
 -- const Latte_Group *: as_group () const

     If this is a Latte_Group, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_List * as_list ()
 -- const Latte_List *: as_list () const

     If this is a Latte_List, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_Nested * as_nested ()
 -- const Latte_Nested *: as_nested () const

     If this is a Latte_Nested, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_Operator * as_operator ()
 -- const Latte_Operator *: as_operator () const

     If this is a Latte_Operator, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_Param * as_param ()
 -- const Latte_Param *: as_param () const

     If this is a Latte_Param, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_Str * as_str ()
 -- const Latte_Str *: as_str () const

     If this is a Latte_Str, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_Tangible * as_tangible ()
 -- const Latte_Tangible *: as_tangible () const

     If this is a Latte_Tangible, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_VarRef * as_varref ()
 -- const Latte_VarRef *: as_varref () const

     If this is a Latte_VarRef, returns it, else returns NULL.

 -- Latte_Obj virtual member fn: Latte_WsNode * as_wsnode ()
 -- const Latte_WsNode *: as_wsnode () const

     If this is a Latte_WsNode, returns it, else returns NULL.

Every Latte object has a boolean value and a numeric value.

 -- Latte_Obj virtual member fn: bool bool_val () const

     Returns the boolean value of this.  By the default implementation, the boolean value of every Latte object is true except for an empty Latte_List or Latte_Group, and except for a false-valued Latte_Boolean.  (This does not prevent defining a new subclass that overrides bool_val() and creates new false Latte values.)

 -- Latte_Obj virtual member fn: Latte_Number_t numeric_val () const

     Returns the numeric value of this.  By the default implementation, the numeric value of every Latte object is zero except for Latte_Str objects whose strings can be parsed as numbers. (This does not prevent defining a new subclass that overrides numeric_val() and creates new Latte objects with non-zero numeric values.)

     The type Latte_Number_t is either long or double, depending on an option given when Latte is compiled.  If the preprocessor symbol ENABLE_FLOATING_POINT (in latte-conf.h) is defined, then Latte_Number_t is double, otherwise it's long.

 -- Latte_Obj member fn: Refcounter<Latte_Obj> eval (Latte_Activation &ACTIVATION)

     Evaluates this in the scope of ACTIVATION and returns the result.  Every Latte object evaluates to some Latte object; by the default implementation, most simply evaluate to themselves.

     Note, eval() is not a virtual member function.  To define a new subclass with different evaluation rules, override do_eval(), not eval().

 -- Latte_Obj virtual member fn: bool self_evaluating () const

     Returns true if this will definitely evaluate to itself when eval() is called; returns false if this may not evaluate to itself.

 -- Latte_Obj virtual member fn: void visit (Latte_Visitor &VISITOR)

     ``Visit'' this with VISITOR.  This calls visitor.visit_FOO() where FOO is one of assignment, boolean, closure, group, list, nested, operator, param, varref, wsnode, and str, depending on which Latte_Obj subclass this belongs to.

Latte_Tangible
==============

Latte_Nested
============

Other Latte_Obj subclasses
==========================

Latte_Visitor
*************

 -- Latte_Visitor virtual member fn: void visit_assignment (Latte_Assignment &ASSIGNMENT)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Assignment.  The default implementation does nothing.

 -- Latte_Visitor virtual member fn: void visit_boolean (Latte_Boolean &BOOLEAN)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Boolean.  The default implementation does nothing.

 -- Latte_Visitor virtual member fn: void visit_closure (Latte_Closure &CLOSURE)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Closure.  The default implementation does nothing.

 -- Latte_Visitor virtual member fn: void visit_group (Latte_Group &GROUP)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Group.  The default implementation recursively calls Latte_Obj::visit() on each member of GROUP in order.

 -- Latte_Visitor virtual member fn: void visit_list (Latte_List &LIST)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_List.  The default implementation recursively calls Latte_Obj::visit() on each member of LIST in order.

 -- Latte_Visitor virtual member fn: void visit_nested (Latte_Nested &NESTED)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Nested.  The default implementation calls Latte_Obj::visit() on the Latte_Obj contained within NESTED.

 -- Latte_Visitor virtual member fn: void visit_operator (Latte_Operator &OPERATOR)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Operator.  The default implementation does nothing.

 -- Latte_Visitor virtual member fn: void visit_param (Latte_Param &PARAM)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Param.  The default implementation does nothing.

 -- Latte_Visitor virtual member fn: void visit_str (Latte_Str &STR)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_Str.  This function is ``pure virtual'' in Latte_Visitor; there is no default implementation, and subclasses are required to override it.

     In latte-html, the LatteHtml_HtmlVisitor class supplies an implementation of visit_str() that works as follows:

       * It calls Latte_Visitor::suggest_wstate() to determine the proper whitespace to emit before the string;

       * It emits the suggested whitespace;

       * If the whitespace included two or more newlines, and if processing is not presently inside a call to {\pre ...}, it emits the HTML paragraph tag <p>;

       * If processing is presently inside a call to {\html ...}, it emits the string literally; otherwise it emits each character of the string one at a time, converting <, >, &, and " to &lt;, &gt;, &amp;, and &quot;, respectively.

 -- Latte_Visitor virtual member fn: void visit_varref (Latte_VarRef &VARREF)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_VarRef.  The default implementation does nothing.

 -- Latte_Visitor virtual member fn: void visit_wsnode (Latte_WsNode &WSNODE)

     Called by Latte_Obj::visit() when the Latte_Obj is actually a Latte_WsNode.  The default implementation notes the whitespace contained in WSNODE for possible use in subsequent calls to suggest_wstate(); then it calls Latte_Obj::visit() on the nested object within WSNODE.

Whitespace and file locations
*****************************

Shared strings
**************

Miscellaneous details
*********************

Reference counting
==================

Debug log
=========

Restorer
========

A Restorer is an object that holds a reference to some variable, and a value for that variable.  It assigns the value to the variable when it goes out of scope.

Its name comes from the fact that it's usually used to restore the value of a variable that has been temporarily changed for the duration of some function.  For example, here's how Latte_Obj::eval() keeps track of its recursion depth:

     static unsigned int depth = 0;
     Restorer<unsigned int> depth_restorer(depth);

     ++depth;

     ...
     val = do_eval(activation);
     ...

At the end of the function, depth is restored to the value it had before the ++depth statement.  This is more reliable than

     ++depth;

     ...
     val = do_eval(activation);
     ...

     --depth;

since do_eval() may throw an exception which could cause the --depth to be skipped.  A Restorer, on the other hand, will restore the old value even when the scope ends because of an exception.

 -- Constructor: Restorer<T> (T &VAR)

     Constructs a new Restorer on a variable of type T.  The current value of VAR is recorded.  When this Restorer is destructed, that value is assigned back to VAR.

 -- Constructor: Restorer<T> (T &VAR, const T &NOW, const T &LATER)

     Alternative constructor that immediately assigns to VAR the value NOW, and that assigns LATER to VAR when the Restorer is destructed.

Writing new Latte applications
******************************