You can use the string sink data type to create a destination for string data. OmniMark has several
types of data destinations (or sinks):
string sink function
value string sink function argument
In some cases, these sinks simply direct output to a file, a network, or some other destination. In other cases,
they transform the data in some way as it is output. For instance, the external filter function
jis.writer transforms its output from UTF-8 encoding to JIS encoding. The addition of the
string sink type makes it possible to write such filter functions in internal OmniMark functions.
The string sink data type allows you to write string sink functions that can transform
data as it is sent to a destination.
In the following example, the string sink data type is used to declare a string sink
function, and to declare a parameter of string sink for the function so that it can send the data
that it processes to another sink.
define string sink function uppercase value string sink destination as using output as destination repeat scan #current-input match letter+ => chars output "ug" % chars match [\letter]+ => stuff output stuff again process using output as uppercase #main-output output "Hello World.%n"
In most places in OmniMark the current output scope is active, meaning that you can execute an
output action almost anywhere in your program, and the data will stream to the sink, or sinks, that
are attached to the current output scope. Because a string sink function is itself a destination for data,
however, the current output scope is not active inside a string source function unless you explicitly
establish it.
In the example above the sink #main-output is passed to the function as the string
sink parameter destination. The using output as qualifier is then used inside
the function to establish the current output scope for the function.
You can write a string sink function that consumes its input and does not send it to another sink,
but if you want to send the data on to another sink, you must establish a current output scope in the function
before you perform an output action. It is an error to perform an output when the current output
scope is not active.
String sink functions operate in a streaming fashion. This means that the string sink function runs
as a coroutine with the process that produces the data it consumes. For instance, in this program,
process using output as uppercase #main-output do xml-parse scan "war-and-peace.xml" output "%c" done
the output of the parse is streamed incrementally to the uppercase function (just as it would have been streamed
incrementally to #main-output if that was used as the output destination directly). The uppercase
function, in turn, streams its output incrementally to its current output scope, which is
#main-output.
Notice that a string sink function does not receive the data that it consumes from a parameter of
the function. Because a string sink function instantiates a sink, it can only be called where a sink
expression is expected, that is, anywhere that you could use a regular OmniMark sink, such as an open stream or
#main-output. In the example above, the uppercase function is used with using
output as to establish it as the current output scope of the program. All data output within the scope of
the using output as statement will therefore be streamed to the uppercase function.
Because a sink is an active consumer of data, you cannot declare a variable of type string sink.
You can use string sink only to declare a string sink function or a string
sink parameter for a function. A string sink parameter must be a value parameter.
An external string sink function can be used anywhere a built-in OmniMark sink, such as
#main-output or file <filename> can be used. However, an internal string sink
function cannot be used with the output-to statement or with the open...as
statement. Internal sinks are always bound to a scope that feeds data to them.
Modifiers can be specified when using an instance of the string sink data type. However, if the
string sink is defined by an internal function, the referents-allowed and
referents-displayed modifiers cannot be specified.
Once a string sink is established, the following actions can be applied to it:
Actions put and output are used to feed textual data into the sink, and the action
signal can be used to send control signals to the sink coroutine.
You can use a return action, without a value, to end a string sink function, or you can
simply allow the function to end. There is no operational difference between the two, except that no part of
function body will be executed after the return is executed.
return is therefore useful if you want to end the function within a conditional construct.
Alternatively, you can throw an exception from a string sink function. If the exception is not caught
within the function itself, it will propagate to the scope where the function was called from.
When a string sink function ends, the execution of its producer will be halted. Only the always clauses
in the producer's scope will be run after that. In the similar situation when the body of a scope consuming a
string source ends or throws before consuming the entire source, the source will be halted. In either case, the
program execution then proceeds after the scope where the string sink or string source function was
called. The following program, for example,
define string sink function consume-first-line as do scan #current-input match (any-text ** "%n") => line put #main-output line done process using output as consume-first-line do output "My mistress' eyes are nothing like the sun;%n" output "Coral is far more red than her lips' red;%n" done output "If snow be white, why then her breasts are dun;%n"only outputs these two lines:
My mistress' eyes are nothing like the sun; If snow be white, why then her breasts are dun;
The string sink data type replaces the output type, which was used for declaring external output functions, and is now deprecated.
The external output function declaration:
define external output function ...
is deprecated in favor of the external string sink function declaration:
define external string sink function ...
The value output parameter declaration:
define external function foo value output destination
is deprecated in favor of the value string sink parameter declaration:
define external function foo value string sink destination