Assume a toy source language with an if-statement (see figure 3):
class TOY_IFTHEN inherit TOY_LANG creation make feature exp, stat: TOY_LANG; ... end
The corresponding pretty-print element could be:
class PP_IFTHEN
inherit PP_LANG
creation make
feature
pexp, pstat: PP_LANG;
make (e, s : PP_LANG) is
do
pexp:=e;
pstat:=s;
end
display is
do
io.putstring ("IF ");
pexp.display
io.putstring (" THEN ");
pstat.display;
io.putstring (" END")
io.new_line;
end;
Now we need the specialized function that maps an if-statement to its pretty-print element.
class PRETTY_FUNCTION_IFTHEN
inherit FUNCTION[TOY_IFTHEN, PP_IFTHEN]
creation make
feature
genFunc: GEN_FUNC[TOY_LANG, PP_LANG];
make(s: GEN_FUNC[TOY_LANG, PP_LANG]) is
do
genFunc:=s
end;
infix "@"(ift: TOY_IFTHEN) :
PP_IFTHEN is
do
!PP_IFTHEN!Result.make
(genFunc @ ift.exp,
genFunc @ ift.stat)
end;
end
The creation argument of type GEN_FUNC specifies the generic
function to be used for evaluation of subcomponents (exp and
stat). Its generic4 parameters denote the
function type to be going from TOY_LANG to
PP_LANG.
The method for function application (@) simply creates the pretty-print element while supplying the results of recursively evaluating the subcomponents (exp and stat).
The client code for performing a full interpretation is:
source: TOY_LANG;
pp_structure: PP_LANG;
pretty_functions: PP_FUNCTIONS;
prettyPrint: GEN_FUNC[TOY_LANG,
PP_LANG];
...
!!pretty_functions.init;
!!prettyPrint.make (pretty_functions);
pp_structure:=prettyPrint @ source;
pp_structure.display;
...
Prior to its usage, a function package must be initialized by calling init. Then, a generic function (prettyPrint) is created by suppling a pretty-print function package (pretty_functions)5. Next, the generic function is applied to the source structure, yielding a target structure (pp_structure). The semantics are finally produced by invoking (display) on the target structure.
A concrete function package appears as follows:
class PP_FUNCTIONS
inherit FUNCTIONS[TOY_LANG, PP_LANG]
creation init
feature
init is
local
pf_var: PF_VAR;
pf_assign: PF_ASSIGN;
pf_ifthen: PF_IFTHEN;
prettyPrint: GEN_FUNC[TOY_LANG,
PP_LANG]
do
make(3);
!!prettyPrint.make(Current);
!!pf_var;
!!pf_assign.make(prettyPrint);
!!pf_ifthen.make(prettyPrint);
put(pf_var, "TOY_VAR");
put(pf_assign, "TOY_ASSIGN");
put(pf_ifthen, "TOY_IFTHEN")
end;
end
Each concrete package inherits from an abstract function package class which,
in turn, inherits from HASH_TABLE:
deferred
class FUNCTIONS[SOURCE, TARGET]
inherit HASH_TABLE[
FUNCTION[SOURCE, TARGET],
STRING]
feature
init is deferred end;
end
So, make(3) initializes the function package to a hash table with three entries. Next, a generic function is created in order to serve as the creation argument for the three specialized function prototypes. The function to print variables (pf_var) does not need to recursively evaluate subcomponents, ergo it does not require a generic function for its creation. Note that the Current argument in the creation of the generic function causes the very function package that is currently being initialized to become the argument for the generic function that is supplied to the specialized functions. Finally, the specialized function prototypes are put into the hash table using their corresponding source element class names as keys.
Therefore, the application method of the generic function definition --
class GEN_FUNC[SOURCE, TARGET]
inherit FUNCTION[SOURCE, TARGET];
INTERNAL;
creation make
feature
functions: FUNCTIONS [SOURCE, TARGET];
make (fs: like functions) is
do
functions:=fs
end;
infix "@" (source: SOURCE): TARGET is
do
Result:=
clone(functions.item
(class_name(source))
) @ source
end;
end
-- can simply access the class name of the source element (method
class_name is inherited from the system class
INTERNAL), use it to retrieve the correct specialized function
prototype (call item on the function package)6, and then apply a cloned exemplar
to its own argument. Instead of a hash table we also could have used a
dictionary or even a type case switching statement in order to achieve
dispatching on the type of arguments.