One of the benefits of having a first-class referent type is that there is no more need to keep all active referents in the single built-in shelf referents
. We can instead export the type itself and let the user keep the track of her referents in the way most appropriate for the problem at hand. That also frees the user from the obligation to invent a unique name for each referent.
Here's a new version of the insert-neighbour-links
example that makes use of first-class referents:
global markup-referent-buffer section-referents variable define markup source function insert-neighbour-links (value markup source sections) as using output as resolve-referents into #current-output do markup-parse sections new section-referents output "%c" using output as section-referents lastmost output "" done element "section" local markup-element-event link initial { create-element-event (declared-elements of target-dtd){"link"} attributes { attribute "id" with key "link-end" } } increment section-count using output as section-referents lastmost do signal throw #markup-start link output "Section " || "d" % number of section-referents || ": %v(title)" signal throw #markup-end link done signal throw #markup-start #current-markup-event output section-referents [number of section-referents - 1] when number of section-referents > 1 output new section-referents output #content signal throw #markup-end #current-markup-event
The new version does not name its referents. It instead uses the section-referents
shelf to store and access them.
Another possibility would be to skip the use of markup-referent-buffer
in favour of a purpose-built subtype of markup-future
. This can be useful in situations where the referent value cannot be easily calculated at any one time.
The insert-neighbour-links
example has been rather simplistic so far. For example, it assumes that the section identifier and title could be fetched from two attributes of a single element. Suppose instead that the referent value must be combined from two different child elements named <id>
and <title>
. In that case, we cannot construct the final referent value in any of the three element rules, we can only provide its pieces.
The solution is simply to provide the pieces of the final referent value as we obtain them. We don't need to combine them into the full referent value until the resolution time anyway, when the function resolved
will be invoked. We can override this function to put the referent value together as follows:
declare record section-referent extends markup-future field integer number field string id field markup-buffer title define overriding markup source function resolved value section-referent section as do when section:number != 0 local markup-element-event link initial { create-element-event (declared-elements of target-dtd){"link"} attributes { section:id with key "link-end" } } signal throw #markup-start link output "Section " || "d" % section:number || ": " || section:title signal throw #markup-end link done
Note that an uninitialized section-referent
, whose number
field is not set, resolves to an empty string.
The insert-neighbour-links
filter now needs to be adjusted to work with the special section-referent
instances instead of the generic markup-referent-buffer
ones. The following will work:
define markup source function insert-neighbour-links (value markup source sections) as using output as resolve-referents into #current-output do markup-parse sections output "%c" done global section-referent previous-section global section-referent current-section global section-referent next-section element "section" set current-section to next-section set current-section:number to previous-section:number + 1 set next-section to new section-referent {} signal throw #markup-start #current-markup-event output previous-section || next-section || #content signal throw #markup-end #current-markup-event set previous-section to current-section element "id" when parent is "section" set current-section:id to "%c" element "title" when parent is "section" using output as current-section:title output #content