REBOL |
Internet Communications LanguageTM |
REBOL/View 1.0 (Beta)
User's Guide
Version 0.9
(1-February-2000)
Positions and Sizes
Displaying Faces
Face Feelings
Events
Iterated Faces
Body Facet Object
Edge Facet Object
Font Facet Object
Paragraph Facet Object
Feel Facet Object
REBOL/View is built on top of REBOL/Core 2.2 and includes the new features listed below:
Pair Type | The coordinate pair (x,y) datatype. Used to describe screen positions, offsets, and sizes (such as 500x200). |
Image Type | The datatype that holds RGB images that are ready for display. |
Event Type | Holds information that represents user input events. It is normally read from an event port and contains mouse position, mouse buttons, keyboard input, and timestamp. |
Parse Block | The additional parsing functions. It is used for writing dialects, such as the Consumer Interface Dialect (CID) that is a component of View. |
Image Processors |
The image processing routines currently include:
Note: Some of these may have reduced functionality for the beta release. |
JPEG, GIF, BMP | Graphic format decoders. |
Face Compositor | The primary module for displaying and layering face content in a window. Also includes mouse tracking and face visual effects (such as wipes and flies). |
Font Handler | Used to load fonts and draw them on the display. Also provides sizing functions for text strings. |
Event Handler | Provides information about the mouse position, button positions, keys pressed, timing, etc. Communicates through a port, allowing queuing, waiting, clearing, and other related functions. |
CI Dialect | REBOL's standard Consumer Interface Dialect distributed with View. |
Auto Installer | Installs REBOL/View into the operating system. Performs necessary configuration to allow REBOL content to launch automatically (from file icons or the browser). Installation is almost transparent to the user and has no impact on the systems operation. On systems with Internet access, REBOL registers itself at www.REBOL.com through the network or dial-up. |
Demo Linkage | A built-in script that access REBOL's server to run demos, grab documentation, register, etc. |
REBOL/View provides a powerful method of creating interfaces using a two-dimensional graphical compositing system. Although this system allows for a wide variety of graphical user interface designs to be implemented, it remains straightforward when compared with traditional approaches. In addition, REBOL/View is highly portable and will be released on many of the same platforms as REBOL/Core.
In REBOL, there are two ways to build graphical interfaces. The easiest way is to use a dialect that accepts simple descriptions and converts them to their underlying graphical objects. The other way is to define the necessary graphical objects directly. Both have advantages. For most applications, using a dialect produces the most results with the least effort. However, some types of special interfaces and behaviors can only be created by directly specifying the objects.
For instance, using a graphical interface dialect (such as CID, the Consumer Interface Dialect, which is covered in another document), specify a window with higher level description such as:
backdrop %mountains.jpgtitle "Image File Viewer"across button "First" [list: head list] button "Next" [list: next list] button "Back" [list: back list] button "Last" [list: back tail list]
Note that this is still REBOL code, but it is a dialect of REBOL. There can be many such dialects. For instance, dialects will be designed depending on the purpose of the interface, such as the folder/icon framework of a computer desktop, the scene orientation of a TV set-top box, the slide transition model of a presentation engine, the touch screen of a kiosk, the playfield style of a video game, and the restricted display area of a handheld device.
The ability for such dialects to allow a simple, flexible, and incremental description of content is the same characteristic that allowed HTML to become rapidly accepted by users. In such dialects there are defaults for everything. A user can easily extend and enhance the display, and almost any description should render a display, even if it's not precisely what the user expected.
By contrast, the fundamental graphical objects of REBOL do not describe elements such as buttons, text boxes, sliders, fields, areas, etc. Instead, they specify the attributes of an area of the screen such as its color, image, position, size, feel (mouse events), etc.
For instance, making an object directly with a simple image can be shown with the code:
image-face: make face [ offset: 0x0 size: 1000x1000 body: make body [ image: load %backdrop.jpg effect: 'fit ] edge: none ]
This requires much more detail for each display object when compared to the dialect. However, it provides a greater degree of control over the attributes of each of these objects. The display objects provide the powerful building blocks upon which a wide range of graphical metaphors can be built. Each interface consists of a tree of graphical objects that describe the content and attributes of their spatial areas.
There is only one type of graphical display object in REBOL. It is called a face. A typical user interface is constructed from a number of such faces, each of which may provide a different look and feel depending on its attributes. Each face may include an image, text, and a set of image processing commands.
The attributes of a face are called facets. They include location, size, color, image, font, style, paragraph format, rendering effects, feeling, and other information. Some of the more detailed facets, such as fonts, bodies, edges, and paragraph attributes, are objects themselves. This allows the reuse of specific object characteristics by sharing them between many display objects. For example, a group of buttons often use the same body, edge, font, and paragraph attributes. As a result, a natural object-oriented method of specification simplifies new display object specification.
A face may include one or more sub-faces. These sub-faces are positioned relative to their parent face. This is called a pane, because an entire group of faces can be repositioned simply by changing the position of the parent face. Within a pane, faces are drawn in the order in which they are listed. In addition, each sub-face can have sub-faces of its own; hence, a tree of graphical objects are formed, each of which is positioned relative to its parent. This is the hierarchy used by the internal compositing system.
A face can be iterated to create a number of virtual faces. For instance, when displaying a list of ten buttons, each of the buttons does not need to be created as a separate object. If the buttons only differ by a few facets (such as position, text, and action taken on selection), a model face can be created and iterated for its other position. This is useful when creating scrolling lists of files and other data sets that share the same appearance.
The simplest example program is one that displays a single string. To make this happen, make a face that defines the string to display, then pass that face to the view function. In fine REBOL tradition, this takes just one line:
view make face [text: "Hello World!"]
The facets of what is displayed will be determined by the system default set in the face object used here. Hence, the string is displayed in the Helvetica font in the center of the window. Any of the face facets can be modified and override the defaults. Some of these facets are sub-objects themselves. To modify them, make new objects that inherit the property of the old objects. This is simple to do within the context of the face object:
view make face [ text: "Hello World!" font: make font [color: 200.10.10] ]
The above example will display the string in red. Following is an example that will display it in large letters:
view make face [ text: "Hello World!" font: make font [size: 32 color: 200.10.10] ]
To put a colored box around the text of a specific size in a given position on the display:
view make face [ text: "Hello World!" offset: 100x100 size: 200x50 body: make body [color: 10.10.100] font: make font [size: 32 color: 200.10.10] ]
Of course, a face object also may be defined with these facets, then used as the basis for further changes:
box-face: make face [ offset: 100x100 size: 200x50 body: make body [color: 10.10.100] edge: make edge [color: 250.200.50] font: make font [size: 32 color: 200.10.10] ]view make box-face [text: "Hello World!"]
To add a border edge to the box:
view make box-face [ text: "Hello World!" edge: make edge [color: 250.200.50] ]
To bevel the edge and bold the text:
view make box-face [ text: "Hello World!" edge: make edge [effect: 'bevel] font: make font [style: 'bold] ]
Note that the inheritance of the facets is happening at multiple levels. The box-face facets as well as the edge and font facet objects are being cloned. Provide only the required differences rather than respecifying the object. This inheritance has been happening from the beginning. To see the default font facets for the standard face, type:
probe face/font
As a final example, here is the box-face with an image backdrop for its body:
view make box-face [ text: "Hello World!" body: make body [image: load %carlwave.jpg effect: 'image] font: make font [style: 'bold shadow: 3x3] ]
The standard face object is defined in system/standard/face as:
face: make object! [ offset: 0x0 ; position (position of window) size: 100x100 ; width & height (dimension of window) span: none ; offset to next area (scaling factor) pane: none ; sub-face or block of surfaces text: none ; face text (window name) data: none ; user defined data field body: object! ; describes the body area edge: object! ; describes the edge border font: object! ; describes the font attributes para: object! ; describes the paragraph attributes feel: object! ; the functional behavior of the face ]
This is also defined as the global word face for convenience.
Following is a more detailed description of the object fields of a face:
Face Object Definition | ||
offset | pair |
The X-Y position of the face relative to its parent face. If scaled coordinates are being used, then offset will be the scaled value. Example: offset: 10x10 |
size | pair |
The width and height of the face's area. It is the size of the basic body of the face, and by default clipping will be performed to prevent internal graphics (including text) from spilling outside this area. Example:
|
span | pair |
For the top level face, span specifies the range of the coordinate system. For instance, providing 10000x10000 specifies the lower right corner of the display to be that coordinate. For all other faces, span specifies the offset for each iterative face when an auto iteration is being performed. Example:
|
pane | face block |
A face or block of faces that are located relative to the face and displayed within its bounds. Example of single child display object:
Example of multiple child display objects:
|
text | value |
A string (or any other value, such as a number) to be displayed within the face. The string may be a single word or an entire paragraph. The font, color, size, alignment, and other attributes of the text are determined by the font and para facets. Example:
|
data | value | An open variable storing other information about the face. Strictly, data is not required because the face object can be extended with additional fields when necessary. |
body | object | The attributes of the body area. It includes its color, image, and special effects. This object's attributes are explained below. |
edge | object | The attributes of the edge area. It includes color, image, special effects, and the size of the edge. This object's attributes are explained below. |
font | object | The attributes of the font used for text display. It includes the font name, style, size, color, offset, space, align, valign, angle, shadow, and outline. This object's attributes are explained below. |
para | object | The attributes of the paragraph used for text. Includes the origin, margin, indent, tabs, edit, wrap, scroll, and filter. This object's attributes are explained below. |
feel | object | Three functions that define the behavior of the face. The functions are evaluated at various times during the rendering, selection, and "hovering" over a face. This object's attributes are explained below. |
The facets span, pane and text can be set to none to be ignored. More detailed information about the facet objects can be found in the tables shown later.
The position of a face can be specified relative to its parent. The size of the area it will occupy can also be provided. In the "Hello World" example above, a single face is defined within the main window face. Its offset is relative to the main window, as shown in the following diagram:
The default coordinate system for the offset is pixels; however, a virtual coordinate system can be provided to make the display resolution independent. This allows the same display to be made smaller or larger for other types of devices such as televisions or hand-helds LCDs. More about this later.
For panes, the same positioning method is used for the pane's face, then each of the pane's sub-faces are located relative to that position:
This allows free relocation of the pane face and all of its sub-faces will move along with it. In many cases a pane will not provide any additional graphics, but will be used for grouping face objects.
In the examples above, the view function was used to display a face. It is a simple mezzanine function that is provided to construct the top-level face, display it, and processes events. If the face passed to view contains a pane of sub-faces, they will all be shown at the same time and the display will come to life.
The view function picks default values for the size, position, and title of the main display window. The values can be overridden with refinements:
view/size face 800x600view/offset/size face 0x0 800x600view/title face "Hello World Example"
Alternately, a top-level face object can be constructed and the show function (below) used to display it. Refer to the source code for view for more detail.
The lower-level function for showing a face is show. For a single display calling show is unnecessary because all of the faces within the panes will be shown from the beginning. However, when adding or modifying faces in the existing display, call show again on that face or on any of its parent faces to refresh it. Note that only faces that have been added to the pane of another face can be displayed. If show is called on a face that has not been added to the panes of the interface, it will be ignored.
If you show a face that is a pane and it contains a block of other faces, they will all be displayed together. Of course, it is possible that a face may not be displayed if it falls outside of the parent face (it is clipped) or is obscured by another face.
A face is removed from the display with the hide function. This is done to remove a single face or an entire pane of faces. Before making major changes to a pane, hide the parent object before modifying its pane block. This prevents stray user-interface events from interacting with the faces while modifying the pane.
The feel of a face is its behavior in response to mouse input. You can control what happens to a face each time it is drawn, hovered over, or selected. The feel object within a face defines the functions to be used.
The redraw function is called immediately before a face is displayed. This allows a face to dynamically alter any of its facets prior to being displayed. This is how screen interacters (buttons, choices, etc.) reflect their current state to the user. For example, a button might be displayed as either up or down depending on the state of a variable that has been set. The redraw variable should be set to none if no function is needed. This speeds up the interface by not calling needless functions.
The over function is called whenever the mouse pointer passes over the face. This function can be used to provide user feedback by changing the appearance of the face. For instance, hot text will change color as the mouse passes over it.
The engage function is called whenever the face has been selected by the mouse button. This function typically performs some type of action based on the selection. This function is called also when the mouse is moved off the face with the mouse button being held down, and it is called again when the mouse returns to the face with the button down, as well as when the button is released. These combinations allow the state of the face to change depending on the actions of the mouse.
Events are mouse and keyboard actions that take place inside a face. These events consist of mouse movements and clicks as well as keyboard input. Events are processed by the do-events function that is normally called after setting up the initial faces and showing them with view.
The first thing do-events does is open an events port using the 'events scheme:
event-port: open [scheme: 'event]
This defines event-port as a type of port called an event port. All events taking place in the displayed REBOL/View window faces are queued in event-port. Each event queued is an individual event of the type event!.
After opening the event port, the do-events function next accesses the event port defined to event-port in a forever loop in which it does the following:
The do-events function is a mezzanine and can be viewed using source:
source do-events
do-events: func [/local event-port event][
event-port: open [scheme: 'event]
forever [
wait event-port
event: first event-port
if event/type = 'quit [break]
do event
if all [
value? 'main-view-face
main-view-face
next-pane <> main-view-face/pane
] [
main-view-face/pane: next-pane
show main-view-face
]
]
close event-port
event
]
It is intended to be redefined by the user to handle events as needed. It is best to handle events inside a forever loop.
Each event queued in the event port contains information about the event. This information is accessible by
using the refinements supported by the event! datatype. The following table explains each of these refinements:
Event Refinements | |
/type |
Returns event type. The event types are:
|
/offset |
Returns the mouse cursor offset relative to the REBOL/View window. The offset returned has different meaning depending on the event type:
|
/char | Returns the ASCII character relative to the event. With 'key events, this will return the character
pressed that triggered the event. The only exceptions to this rule are the arrow keys Up, Down, Left and Right
along with the End and Home keys. These key events are handled internally by REBOL for changing the caret position
in edit windows. The key events may still be accessed using the /code refinement. For the events 'down, 'up and 'move, the character returned is always #"^@", which is represented in REBOL as a null character. |
/code | Returns a word representation of an Up, Down, Left, Right, End or Home key in a 'key event when pressed; the word representations are 'up, 'down, 'left, 'right, 'end or 'home, respectively. This value defaults to none otherwise. |
/control | Returns a logic value, true or false, depending on whether or not the control key was pressed when the event was sent. This works with the events 'up, 'down, 'move and 'key. |
/shift | Returns a logic value, true or false, depending on whether or not the shift key was pressed when the event was sent. This works with the events 'up, 'down, 'move and 'key. |
/time | Returns the time stamp of the event. |
Events can be examined and actions determined based on the event type, offset, ,character code, time and whether or not the control or shift key was depressed at the time the event was generated.
For example, to see if the event is a mouse click, check the event type using the /type refinement inside the forever loop:
forever [
wait event-port
event: first event-port
if event/type = 'down [ ... ]
...
]
Following is a conceptual example of checking for multiple types of events:
forever [
wait event-port
event: first event-port
switch event/type [
down [ ... ]
up [ ... ]
key [ ... ]
quit [ break ]
]
....
]
Events handled in do-events are handled at the global level. No matter what face the event takes place in, it will be possible to handle the event in do-events. To process events focused on a specific face, use a face's feel object to process the event. This is done by using do on events, as noted under step 4 of do-events' forever loop above (do event). When an event is evaluated using do, REBOL's internal event handling figures out what face the event took place in and activates event handlers inside that face's feel object.
Every face has a default feel object with three words defined to none. These words, collectively
referred to as feelings, are redraw, engage and over and relate to specific events
that occur in the face. Feelings can be defined as functions to create actions based on events occurring within
the face. The following table relates these events to their feeling counterparts with a little explanation:
Face Feeling Event Association | |
redraw |
Called every time the face is redrawn. This is called with two arguments:
Conceptual example: new-face: make face [ ... feel: make feel [ redraw: func [face [object!] offset [pair!]] [ ... ] ] ] |
engage |
Called when a mouse click occurs in the face. This is called with three arguments:
Conceptual example:
... feel: make feel [ engage: func [ face [object!] action [word!] event [event!] ] [ ... ] ] ] |
over |
Called when the mouse cursor is over the face. This is called with three arguments:
Conceptual example:
|
Each of the feelings listed above take as their first argument its own face object. This allows the feeling to modify its face object before reshowing it with show. When show is called within a feeling function on the face passed to the feeling, that face and its sub faces will be refreshed in the REBOL/View window. Here's a simple conceptual example of this:
...
over: func [face [object!] over? [logic!] offset [pair!]] [
either over? [
face/text: "Mouse Is OVER This Face!"
] [
face/text: "Mouse is AWAY From This Face!"
]
show face
]
....
If a face's offset is changed before reshowing it, the face will be moved to that new offset in the REBOL/View window upon calling show.
The face feelings can be looked at using probe. This example shows the default:
probe face/feel
make object! [
redraw: none
engage: none
over: none
]
It is not practical to specify every face that is to be displayed. For instance, in the case of a file list or email inbox, there may be numerous identical faces that vary by content and position. In such cases these faces can be generated dynamically through iteration.
To create an iterated view the pane variable, which is normally set to a face or block, is instead set to a function. This function will be called by the system to supply the pane face or block during the iteration process. This is done whenever the system needs to identify the faces that make up the iterated view, which is during display rendering or event processing.
A number of the facets of a face are complex enough that they are best described with objects. Another advantage of using objects is that they can be incrementally refined with inheritance.
The body is the primary area used in the face. It may be flat, shaded, patterned, rendered (such as a gradient
fill), an image, a tiled image, or an effect image.
Body Attributes | ||
color | tuple |
The color of the body. If an image is specified, this indicates the tint that should be applied to the body. The primary color specified for the area. How it is applied depends on what type of rendering is being performed. For flat shading, it is the fill color. For transparency colorizing, textures, gradients, it is the primary hue. Note that there are times when multiple colors might be needed; they can be specified in the effect arguments. Example:
|
image | image |
An image to use for the body. The image will be scaled as needed to fit the face. Example
|
effect | word block |
What effect to use to render the image or face background. A number of image processing effects will be available. For instance, a gradient can be used on a flat color or an image. Specifies one or more rendering operations to be executed to create the final image. Operations include tinting, texturing, gradients, filters, etc. |
The edge is a rectangular subframe that borders (inside) a body. It is used for image borders, button edges,
tables, special framing, etc. It is composited with the body and has the same attributes as a body.
Edge Attributes | ||
color | tuple |
The color of the edge. Example:
|
image | image |
An image to use for the edge. The edge is placed behind the body. Example:
|
effect | word block |
An effect used to render the edge. Refer to body/effect. Identical to body render, except processing may or may not be performed on the rectangle obscured by the body. |
size | pair |
The pixel thickness of edge as an x/y offset. The x offset refers to the thickness of the vertical borders (left and right) while the y offset the horizontal borders (top and bottom). Example:
|
Following are the standard text style attributes.
Font Attributes | ||
name | word string block |
The name of the font. (A list of font names may also be used.) |
style | word block |
The style of the font (plain, bold, italic, etc.) |
size | integer | The size of the font. |
color | tuple | The text color of the font. |
offset | tuple | Padding. |
space | pair | Spacing between characters and between lines. The X value adds to the spacing between characters. Positive values expand the text, negative values condense it. The Y value has a similar effect on line spacing. |
angle | integer | The baseline angle of the text in degrees. |
align | word | The alignment (left, center, right, justify) |
valign | word | The vertical alignment (left, center, right, justify) |
tabs | integer block |
Tab spacing can be specified as a repeating fixed distance (integer) or at specific locations on a line as a block of integers. |
shadow | pair block |
Specification of a shadow effect. (requires offset, percentage, color) |
outline | integer block |
Specification of an outline effect. (requires size, color) |
Paragraph facet object attributes are applied to entire paragraphs of text for control of spatial formatting.
They only apply to text rendered within areas, hence are not used for free-form text:
Paragraph Attributes | ||
origin | pair | Offsets the text origin from the left top of the bounding area. This is needed because the bounding area might be sized for reasons other than the proper positioning of text (e.g. for an image size or graphic). |
margin | pair | Prevents text from entering a region on the right and bottom of the area. If text enters this area, word wrapping will occur. Necessary for the same reasons as origin. |
indent | pair | Offsets the origin of a new paragraph’s first line. The X value can be used to indent or exdent (negative value) the start of the line. The Y value is used only to add extra spacing between paragraphs. It is ignored for the first paragraph. |
tabs | integer block |
Tab spacing can be specified as a repeating fixed distance (integer) or at specific locations on a line (a list of integers). |
edit? | logic | Indicates that the text can be edited. Used for editable string fields. |
wrap? | logic | Indicates that word wrapping is desired. |
scroll? | logic | Indicates that scrolling is desired. |
filter | func | Filters that are applied to text during edit mode. A function that can be used to prevent specific types of characters from being entered. |
The behavioral function part of a face.
Feel Attributes | ||
redraw | func | A function called before a face is drawn. |
over | func | A function called when the select button is up and the mouse has moved over the face. Most of the time, nothing happens, but a special effect can be made to provide user with feedback. |
engage | func | A function called when the select button goes up, down, off, or back on a face. |
The feel facet object is explained in greater detail under the subsection Events.
This datatype represents a coordinate pair (x,y). A pair! value is specified as <number>x<number>, such as 100x100. REBOL translates pair! values directly:
probe type? 200x200 pair!
Pairs can be viewed by their individual coordinates using traditional REBOL means:
p: 640x480 probe first p 640 probe second p 480
All pair values support the /x and /y refinements. They allow the viewing and manipulation of individual pair coordinates.
Viewing individual coordinates:
probe p/x 640 probe p/y 480
Modifying individual coordinates:
p/x: 800 p/y: 600 probe p 800x600
To determine if a value is a pair! datatype, use the pair? function:
probe pair? 400x200 true probe pair? p true
This datatype represents any loaded image. If an image's format is not supported by REBOL, it will fail to load. Use load to load an image file into REBOL.
Defining a word as an image:
img: load %bay.jpg
Once an image is loaded, it will be of the type image!:
probe type? img image!
To determine if a value is a image! datatype, use the image? function:
probe image? img true
Refer to the section above about Events.
Blocks are parsed similar to strings. A set of grammar rules that specify the order of expected values. However, unlike parsing strings, don't be concerned with characters, spaces, or line termination. Parsing of blocks is done at the value level, making the grammar rules easier to specify and operation much faster.
Block parsing is the easiest way to create dialects in REBOL. Dialects are sub-languages of REBOL that use the same lexical form for all datatypes but allow a different ordering of the values within a block. That is, the values do not need to conform to the normal order required by REBOL (that of function argument ordering). Dialects are able to provide greater expressive power for specific domains of use. For instance, the parser rules themselves are specified as a dialect of REBOL. So are function argument specifications.
A few concise examples help illustrate parsing of blocks.
block: [when 10:30] print parse block ['when 10:30] print parse block ['when time!] parse block ['when set time time! (print time)]
Note that a specific word can be matched by using its literal word in the rule (as in the case of 'when). A datatype can be specified rather than a value, as in the time! lines above. In addition, a variable can be set to a value with the set operation.
Alternates can be used as with strings:
rule: [some [ 'when set time time! | 'where set place string! | 'who set persons [word! | block!] ]]
This rules allows the information to be entered in any order:
parse [ who Fred where "Downtown Center" when 9:30 ] rule print [time place persons]
The example could have used variable assignment, but it illustrates how to provide alternate input ordering.
Here's another example that evaluates the results:
rule: [ set count integer! set str string! (loop count [print str]) ] parse [3 "great job"] rule parse [3 "hut" 1 "hike"] [some rule]
Finally, here is a more advanced example:
rule: [ set action ['buy | 'sell] set number integer! 'shares 'at set price money! (either action = 'sell [ print ["income" price * number] total: total + (price * number) ][ print ["cost" price * number] total: total - (price * number) ] ) ] total: 0 parse [sell 100 shares at $123.45] rule print ["total:" total] total: 0 parse [ sell 300 shares at $89.08 buy 100 shares at $120.45 sell 400 shares at $270.89 ] [some rule] print ["total:" total]
Most of the same parse operations and formats that are available for strings are also allowed for blocks.
| - alternate rule [block] - sub-rule (paren) - evaluate a REBOL expression
none - match nothing opt - zero or one time some - one or more times any - zero or more times 12 - repeat pattern 12 times 1 12 - repeat pattern 1 to 12 times 0 12 - repeat pattern 0 to 12 times
skip - skip a value (or multiple if repeat given) to - advance input to a value or datatype thru - advance input thru a value or datatype
set - set the next value to a variable copy - copy the next match sequence to a variable
word - look-up value of a word word: - mark the current input series position :word - set the current input series position
In addition, a specific value can be matched when parsing blocks. For instance:
"fred" - matches to the string "fred" %data - matches to the file name %data 10:30 - matches to the time 10:30 1.2.3 - matches to the tuple 1.2.3
This can be done for any datatype with the exception of integers, which are reserved for use as repeat counters. (However, the integers can still be matched; see below.)
In addition to match against a word, specify the word as a literal:
'name 'when 'empty
A value of any given datatype can be matched by specifying the datatype name. For example:
string! - any quoted string time! - any time date! - any date tuple! - any tuple
Don't forget the "!" that is part of the datatype name or an error will be created.
The parse operations not allowed for blocks are those that deal with specific characters. For instance, a match cannot be specified to the first letter of a word or string, nor to spacing or line termination.
When parsing a block, if a sub-block is found, it will be treated as a single value of the block! datatype. However, to parse a sub-block, invoke the parser recursively on the sub-block.
The into function provides this ability. It expects that the next value in the input block is a sub-block to be parsed. This is as if a block! has been provided. If it is not a block then it will fail the match and look for alternates or exit the rule. If it is a block, the parser rule that follows the into function will be used to begin parsing the sub-block. It is processed in the same way as a sub-rule.
rule: [date! into [string! time!]] data: [10-Jan-2000 ["Ukiah" 10:30]] print parse data rule
All of the normal parser operations can be applied to the into function.
rule: [ set date date! set info into [string! time!]] ] data: [10-Jan-2000 ["Ukiah" 10:30]] print parse data rule print info rule: [date! copy items 2 into [string! time!]] data: [10-Jan-2000 ["Ukiah" 10:30] ["Rome" 2:45]] print parse data rule probe items
REBOL Technologies is very interested in the problems found. To report a bug, use the feedback script included with this release. Start REBOL/View, then enter:
do %feedback.r
If your REBOL system is configured to send email, the script will prompt you for information, then email your information directly to our support department.
Alternately, send an email message (no HTML or enclosures). Please write a subject line that describes the problem. Write something like "making blocks does not work" rather than just "bug". Email:
feedback@REBOL.com
We will send an automatic confirmation of each report. If you don't get the confirmation, then we may not have received your email or the return address is incorrect.
Be sure to give us a simple example of the problem within the bug report. If it occurs in a large script, edit it down to just the bug. Please don't send large files.
Also, be sure to include the version number as is printed in the title banner. It indicates not only the version and revision, but also the update number and the platform (OS). From the REBOL language you can obtain the version number with:
print REBOL/version