# Section 8.16.1.9:
$TEXT_CURSOR

###### abstract class $TEXT_CURSOR{ELT, STP} < $CURSOR{ELT, STP}

#### Formal Definitions

This abstract class defines a state component which is a set of all instantiations of objects of any class sub-typing from this class in addition to the vdm model types used wherever this class name is used. Note that SAME has to be an instantiated class, not an abstract one.

types
SAME = object_type ;
$TEXT_CURSOR_ELT_STP = set of object_type ;
Pred = ELT -> BOOL
state
multi : $TEXT_CURSOR_ELT_STP
inv multi_types ==
forall obj in set multi_types & sub_type($TEXT_CURSOR_ELT_STP,obj)

NOTE | See the important note about vdm state in the notes on vdm-sl usage in this specification.

This abstract class defines the features required by a text cursor in addition to those inherited from $CURSOR, introducing features which permit the extraction and skipping of text components, lines, etc.

#### Auxiliary Functions

Several of the post-conditions in this class refer to substrings of some string which contain no line marks. The following functions and predicate are provided to define this. It is used in several places in the following definitions.

lmark () res : STP
post res = CHAR_STR.str(LIBCHARS.Line_Mark(STP.index_lib(buffer)))
space () res : ELT
post res = CHAR_CODE.char(LIBCHARS.Space(STP.index_lib(buffer)))
no_line_marks(str : STP) res : BOOL
pre true
post forall idx1, idx2 in inds str &
idx2 - idx1 = len lmark
and str(idx1, ..., idx2) <> lmark)

#### Reader Routines

The following reader routines correspond to some components of the internal state of a cursor object. They are defined in relation to the textual concept of lines and of comments (as in some programming language source text.

- line_no : CARD - The text string cursor model contains the notion of lines of text separated by line marks. The model itself, however, does not ascribe any particular value to the current line. Incrementation of the value is done automatically on detection of a line mark during scanning.
- comment_start : STP - This string models the token used when scanning to indicate the start of a region of comment (rather than 'normal' text).
- comment_end : STP - if this component is set then comment is expected to occur in properly nested regions, otherwise if it is the empty string then a region of comment terminates at the next line mark.

#### reset_line

This routine enables the value to be set for later incrment as scanning is done. No checking of validity is possible.

reset_line | (
| val : CARD
| )

##### Formal Signature

reset_line(self : SAME, val : CARD)

##### Pre-condition

pre true

##### Post-condition

postline_no = val

This routine resets the value of the current line in the buffer to the given value. Control of this value is not defined by the scanner.

#### is_line_mark

The cultural context in which the program is executing determines the end of a text line (usually operating system dependent in practice) which is to be taken as a line mark. This predicate returns true if the cursor is currently positioned at a line mark.

is_line_mark | : BOOL

##### Formal Signature

is_line_mark(self : SAME) res : BOOL

##### Pre-condition

Since this routine is a predicate, the pre-condition is vacuously true.

##### Post-condition

post let test = self(index, ..., (index + len lmark)) in
res = (lmark = test)

This predicate returns true if and only if the cursor is positioned at a line mark as determined by the buffer cultural context.

#### set_comment_start

This routine sets the start of comment token to be the single element given until a further call of this or the other set_comment_start operation.

set_comment_start | (
| val : ELT
| )

##### Formal Signature

set_comment_start(self : SAME, val : ELT)

##### Pre-condition

pre true

##### Post-condition

post comment_start = [val]

This routine sets the value of the comment start to be the single element given.

#### set_comment_start

This routine sets the start of comment token to be string given until a further call of this or the other set_comment_start operation.

set_comment_start | (
| val : STP
| )

##### Formal Signature

set_comment_start2(self : SAME, val : STP)

##### Pre-condition

pre true

##### Post-condition

post comment_start = val

This routine sets the value of the comment start to be the string given.

#### set_comment_end

This routine sets the end of comment token to be the single element given until a further call of this or the other set_comment_start operation.

set_comment_end | (
| val : ELT
| )

##### Formal Signature

set_comment_end(self : SAME, val : ELT)

##### Pre-condition

pre true

##### Post-condition

post comment_start = [val]

This routine sets the value of the comment end to be the single element given.

#### set_comment_end

This routine sets the end of comment token to be string given until a further call of this or the other set_comment_start operation.

set_comment_end | (
| val : STP
| )

##### Formal Signature

set_comment_end2(self : SAME, val : STP)

##### Pre-condition

pre true

##### Post-condition

post comment_end = val

This routine sets the value of the comment end to be the string given.

#### skip_comment

Providing that the next element(s) in the buffer are a start comment token then this feature skips to the element beyond the end of the comment and returns true.

skip_comment | : BOOL

##### Formal Signature

skip_comment(self : SAME) res : BOOL

##### Pre-condition

Since this routine is a predicate, the pre-condition is vacuously true.

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let startidx = (index~ + 1) in
let test = self(startidx, ..., (startidx + len comment_start)) in
res = ((test = comment_start)
and not is_done
and (len comment_end = 0
and is_line_mark(self))
or (let endidx = (index - len comment_end) in
let finish = self(endidx, ..., (endidx + len comment_end)) in
(finish = comment_end)))
or (has_error(self)
and index = index~)

This predicate returns true if and only if the next item in the buffer is the start of a comment and the cursor is positioned after the end of that comment, otherwise false is returned and the cursor position has not been changed.

#### skip_space

This feature advances the cursor past all spaces in the string up to the occurrence of a non-space element or to the end of the string if there are no remaining non-space elements. Note that a comment is treated in this feature as a single space element. The encoding used for a space depends on the repertoire and encoding of the buffer string.

skip_space |

##### Formal Signature

skip_space(self : SAME)

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in
(forall elem in set elems skipped &
elem = space
and (is_done
or (buffer(index + 1) <> space))

This routine advances the cursor past all space elements (including a comment as a single space) or to the end of the string if all remaining elements are spaces.

#### skip_space

This version of the space skipping feature advances the cursor past all space elements (treating a comment as a space) before returning self. Note that the enocding which represents a space depends on the enocding and repertoire of the buffer string.

skip_space | : SAME

##### Formal Signature

skip_space2(self : SAME) res : SAME

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in
(forall elem in set elems skipped &
elem = space
and (is_done
or (buffer(index + 1) <> space))
and res = self

This routine advances the cursor over all space elements (treating a comment as a single space). Note that the space element is defined for the culture encoding and repertoire of the buffer string. Self is then returned.

#### skip_over_line

This feature advances the cursor past all of the elements in the buffer up to and including the next end of line mark - or the end of the string if that occurs first.

skip_over_line |

##### Formal Signature

skip_over_line(self : SAME)

##### Pre-condition

pre true

##### Post-condition

post let head = buffer(1, ..., index~) in
let head ^ skipped ^ lm = buffer(1, ..., index) in
no_line_marks(skipped)
and (index = len self
or lm = lmark)

This routine advances the cursor past the next line mark (if any) in the buffer or up to the end of the string, whichever occurs first.

#### skip_word

This feature advances the cursor past all non-spaces in the string up to the occurrence of a space element or to the end of the string if there are no remaining space elements. The encoding used for a space depends on the repertoire and encoding of the buffer string.

skip_word |

##### Formal Signature

skip_word(self : SAME)

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in
(forall elem in set elems skipped &
elem <> space
and (is_done
or (buffer(index + 1) = space))

This routine advances the cursor past all non-space elements or to the end of the string if no remaining elements are spaces.

#### skip_word

This version of skipping advances the cursor past all non-space elements up to but not including the next space element before returning self.

skip_word | : SAME

##### Formal Signature

skip_word2(self : SAME) res : SAME

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in
(forall elem in set elems skipped &
elem <> space
and (is_done
or (buffer(index + 1) = space))
and res = self

This routine advances the cursor up to, but not including the next space element. Self is then returned.

#### skip_to

This feature advances the cursor past all of the elements in the buffer up to but not including the next occurrence of the argument - or the end of the string if that occurs first.

skip_to | (
| str : STP
| )

##### Formal Signature

skip_to5(self : SAME, str : STP)

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in (forall idx1, idx2 in inds skipped &
idx2 - idx1 = len str
and skipped(idx1, ..., idx2) <> str)
and (is_done
or (buffer(index, ..., (index + len str)) = str))

This routine advances the cursor up to (but not beyond)the next occurrence of the argument string or to the end of the line if this occurs first.

#### skip_to

This feature advances the cursor past all of the elements in the buffer up to but not including the next occurrence of the argument - or the end of the string if that occurs first before returning self.

skip_to | (
| str : STP
| ) : SAME

##### Formal Signature

skip_to6(self : SAME, str : STP) res : SAME

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in (forall idx1, idx2 in inds skipped &
idx2 - idx1 = len str
and skipped(idx1, ..., idx2) <> str)
and (is_done
or (buffer(index, ..., (index + len str)) = str))
and (res = self)

This routine advances the cursor up to (but not beyond)the next occurrence of the argument string or to the end of the line if this occurs first before returning self.

#### skip_over

This feature advances the cursor past all of the elements in the buffer up to and including the next occurrence of str in the buffer - or the end of the string if that occurs first.

skip_over | (
| str : STP
| )

##### Formal Signature

skip_over5(self : SAME, str : STP)

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in let hw_mark = len skipped - len str in
(forall idx1, idx2 in inds skipped(1, ...,hw_mark) &
idx2 - idx1 = len loc_lm
and skipped(idx1, ..., idx2) <> str)
and (is_done
or (skipped(hw_mark, ..., len skipped) = str))

This routine advances the cursor up to (but not beyond)the next occurrence of the argument string or to the end of the line if this occurs first.

#### skip_over

This feature advances the cursor past all of the elements in the buffer up to and including the next occurrence of str in the buffer - or the end of the string if that occurs first.

skip_over | (
| str : STP
| ) : SAME

##### Formal Signature

skip_over6(self : SAME, str : STP) res : SAME

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post let head = buffer(1, ..., index~) in
let head ^ skipped = buffer(1, ..., index) in let hw_mark = len skipped - len str in
(forall idx1, idx2 in inds skipped(1, ...,hw_mark) &
idx2 - idx1 = len loc_lm
and skipped(idx1, ..., idx2) <> str)
and (is_done
or (skipped(hw_mark, ..., len skipped) = str))
and (res = self)

This routine advances the cursor up to (but not beyond)the next occurrence of the argument string or to the end of the line if this occurs first before returning self.

#### get_char

This feature is the scanning primitive for a cursor character. Successive calls scan the string item by item advancing the cursor one character for each call.

get_char | : ELT

##### Formal Signature

get_char(self : SAME) res : ELT

##### Pre-condition

pre true

##### Post-condition

post res = self(index)

This routine returns the character currently indicated by the cursor (or void if the complete string has been scanned) and then advances the cursor. It is an error if the cursor cannot be advanced.

#### get_line_mark

This feature requires that the cursor is positioned at a line mark in the buffer. This is moved over and returned. Note that the line mark is dependent on the execution environment.

skip_over_line |

##### Formal Signature

get_line_mark(self : SAME) res : STP

##### Pre-condition

pre is_line_mark(self)

##### Post-condition

post (index = index~ + len lmark)
and res = lmark

This routine advances the cursor over the next line mark which is retrieved and returned.

#### get_word

This feature scans the string, retrieving elements until the first occurrence of a space character or the end of the string has been reached.

get_word | : STP

##### Formal Signature

get_word(self : SAME) res : STP

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post res = buffer((index~ + 1), ..., index)
and (forall elem in set elems res &
elem <> space)
and (is_done
or buffer(index + 1) = space

This routine scans the string from the current element, retrieving characters up to either the first space character or the end of the string has been reached.

#### get_word

This feature scans the string, retrieving elements until either a space is reached, the count is exceeded or the end of the string, whichever occurs first.

get_word | (
| count : CARD
| ) : STP

##### Formal Signature

get_word2(self : SAME, count : CARD) res : STP

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post res = buffer((index~ + 1), ..., index)
and (forall elem in set elems res &
elem <> space)
and (is_done
or (index - index~ = count)
or buffer(index + 1) = space

This routine returns the string starting at the current element until either the given count is reached or a space is detected or until the end of the string, whichever occurs first.

#### get_upto_char

This feature scans the string seeking for the given element value. If found then the string between the start index and the position reached is returned, otherwise an error condition is set.

get_upto_char | (
| elem : ELT
| ) : STP

##### Formal Signature

get_upto_char(self : SAME, elem : ELT) res : STP

##### Pre-condition

pre true

##### Post-condition

Note the use of the has_error feature here. This is inherited from the patent class $CURSOR.

post (self(index) = elem
and (res = self(index~, ..., index))
and forall elt in set elems res &
elt <> elem)
or has_error(self)

This routine returns the string starting at the current element until either the element with the value elem is reached or the end of the string, whichever occurs first. It is an error if elem is not detected before the end of the string. The contents of the value returned is not specified if an error has occurred.

#### get_upto

This feature scans the string seeking for an element for which the predicate argument returns true. If found then the string between the start index and the position reached is returned, otherwise an error condition is set.

get_upto | (
| predicate : ROUT{ELT} : BOOL
| ) : STP

##### Formal Signature

get_upto4(self : SAME, predicate : Pred) : res : STP

##### Pre-condition

pre true

##### Post-condition

Note the use of the has_error feature here. This is inherited from the patent class $CURSOR.

post (predicate(self(index))
and (res = self((index~ + 1), ..., index))
and forall elt in set elems res &
not predicate(elt))
or has_error(self)

This routine returns the string starting at the current element until an element satisfying the predicate is reached or the end of the string, whichever occurs first. It is an error if a suitable element is not detected before the end of the string. The contents of the value returned is not specified if an error has occurred.

#### get_str

This feature returns the string sequence from the current position up to and including the next occurrence of a line mark (if any).

get_str | : STP

##### Formal Signature

get_str(self : SAME) : res : STP

##### Pre-condition

pre true

##### Post-condition

Note that this makes use of the feature is_done which is specified in the parent class $CURSOR.

post (res = self((index~ + 1), ..., index)
and (let head ^ tail be st len tail = len lmark in
no_line_marks(head)
and (is_done
or tail = lmark))

This routine returns the string starting at the current element up to and including the next line mark (if any).

#### get_upto_cut

This feature scans the string seeking for an element which is in the string argument - which is considered as a set of elements rather than a sequence. If found then the string between the start index and the position reached is returned, otherwise an error condition is set.

get_upto_cut | (
| cut_set : STP
| ) : STP

##### Formal Signature

get_upto_cut(self : SAME, cut_set : STP) res : STP

##### Pre-condition

pre true

##### Post-condition

Note the use of the has_error feature here. This is inherited from the patent class $CURSOR.

post (self(index) in set elems cut_set
and (res = self((index~ + 1), ..., index))
and forall elt in set elems res &
elt not in set elems cut_set)
or has_error(self)

This routine returns the string starting at the current element until an element is found which is equal to one of the elements in the argument string considered as a set of elements is reached or the end of the string, whichever occurs first. It is an error if such an element is not detected before the end of the string. The contents of the value returned is not specified if an error has occurred.

#### get_upto_cut

This feature scans the string seeking for an element which is in the string argument - which is considered as a set of elements rather than a sequence. If found then the string between the start index and the position reached is returned, otherwise an error condition is set.

get_upto_cut | (
| cut_set : STP
| start : CARD
| ) : STP

##### Formal Signature

get_upto_cut2(self : SAME, cut_set : STP, start : CARD) : res : STP

##### Pre-condition

pre true

##### Post-condition

Note the use of the has_error feature here. This is inherited from the parent class $CURSOR.

post (self(index - 1) in set elems cut_set
and (res = self((index~ + 1), ..., index))
and forall elt in set elems res(start - 1, ..., (len res - 1)) &
elt not in set elems cut_set)
or has_error(self)

This routine returns the string starting at the current element extending up to and including the first element found which is equal to one of the elements in the argument string considered as a set of elements or the end of the string, whichever occurs first. It is an error if such an element is not detected before the end of the string. The contents of the value returned is not specified if an error has occurred.

#### current_line

This feature, irrespective of the current cursor position on the current line of the buffer, returns the entire line up to and including the next occurrence of a line mark (if any).

current_line | : STP

##### Formal Signature

current_line(self : SAME) : res : STP

##### Pre-condition

pre true

##### Post-condition

post let start : CARD be st
(let preceding ^ head = self(start, ..., index~) in
((start = 1
and preceding = [])
or preceding = lmark)
and no_line_marks(head)) in
let previous = self(start, ..., index~) in
let rest ^ test = self((index~ + 1), ..., index) be st
((index = len self
and test = [])
or test = lmark)
and no_line_marks(rest) in
res = previous ^ rest ^ test

This routine returns the string which is the entire current line in the buffer - from beginning to end - including the end of line mark.

#### line!

This iterator provides a facility for 'parsing' text line by line, yielding logical lines excluding escaped line marks, comment and initial blanks. It provides a similar facility to the class SOURCE in respect of arbitrary text strings. The out argument is the number of the first (non-escaped) line in the string buffer.

line! | (
once | escape : ELT
out | line_num : CARD
| ) : SAME

##### Formal Signature

Note that the formal name of the iter has been changed to replace the exclamation mark iter symbol to a name acceptable to vdm tools.

line_iter(self : SAME, escape : ELT) res : STP * CARD

##### Pre-condition

pre

##### Post-condition

This post-condition makes use of the history concept from vdm++ (see the vdm dialect notes).

post let loc_res : STP = ??? in
res = mk_(create(loc_res),line_no)
and history = history~ + res

[TODO work out what to put on place of the ??? above!]

##### Quit condition

For quit actions see the specification of the quit statement.

errs QUIT : index = len self -> quit

This iter yields a string cursor for a new buffer which has been composed by assembling one or more source lines from the buffer for self into a logical line. This is done by omitting comment lines and stripping unwanted line marks at the end as necessary. The iter then returns a new string cursor indexed at the first non-space element of the line found.

| Language Index |  | Library Index |  | String Index

Comments or enquiries should be made to Keith Hopper. Page last modified: Monday, 27 November 2000. |