The REBOL Scripting Language

The Relative Expression-Based Object Language (REBOL) was designed to make it easier to communicate between computers, or between people and computers, using context-dependent sublanguages.


July 01, 2000
URL:http://www.drdobbs.com/embedded-systems/the-rebol-scripting-language/184404172

People who speak English understand messages such as "turn on the light" or "record TV channel 7 at 8 pm." But can your computer understand the same messages? The question is not whether your computer can understand English, but rather, can it understand these specific messages? In other words, is it possible to share a common language with your computer, even if it's not exactly English?

This is the goal of REBOL, short for "Relative Expression-Based Object Language." REBOL was designed to make it easier to communicate between computers, or between people and computers, using context-dependent sublanguages. REBOL is unlike traditional programming languages such as C, Basic, or Java. The language has no keywords and little syntax. Although it can be used for programming, writing functions, and performing processes, its greatest strength is the ability to easily create domain-specific languages or dialects.

In addition, REBOL is a highly polymorphic and reflective language. The former means that the language applies its functions to a wide variety of datatypes in a consistent manner. The latter indicates that the language can be dynamically introspective about itself. This property is quite difficult to obtain in language design, but allows REBOL to be descriptive and self referential. In fact, REBOL is metacircular: It is able to serve as its own metalanguage, eliminating the need for preprocessing and macros. The result is a language with a powerful and dynamic means of expression.

REBOL scripts are machine independent and run on 37 different CPU/OS platforms. The language has several networking protocols built in, including HTTP, FTP, NNTP, SMTP, POP, Finger, Whois, Daytime, and DNS. In addition, it handles multiple proxy servers and can communicate directly at the TCP/IP level. Finally, REBOL is compact, requiring only a 200 KB download; it can be downloaded free of charge from http://www.rebol.com/.

REBOL Programming

REBOL is not a conventional language. It breaks a number of rules. For instance, REBOL has more than 40 datatypes built in (contrasted to languages such as C that have five or six datatypes). This lets you write values such as dates, times, money, e-mail, HTML/XML tags, and URLs directly in a script using a format that is already familiar to you. In addition, the datatypes are always part of the system. You don't need to hunt around for libraries or include files.

This simple script creates a network agent to check a web site every 10 minutes. If the web page fails to download, an e-mail is sent to the webmaster:

forever [

   if error? try [ 

      read http://www.site.dom

   ] [

   send [email protected] 

      "Site is down."

   ]

   wait 0:10


]

This example checks every hour to determine if a web site has changed:

old-sum: checksum read http://www.site.dom

until [

    wait 1:00

    old-sum <> checksum read http://www.site.dom

]

send [email protected] "Web site changed!"

The brackets [] indicate blocks, which can hold both code and data values. They can be of any length and may contain other blocks. The values within a block can be of various datatypes. These values are written in free format, with no significance to spacing or lines. Table 1 shows the available datatypes.

Table 1: Primary REBOL datatypes. (a) Numerical datatypes; (b) character datatypes; (c) block datatypes; (d) word datatypes; (e) function datatypes; (f) object datatypes; (g) special datatypes.

REBOL is a symbolic language. Words are used as both symbols and as variables. When used as symbols, you're not interested in their value, only what they stand for.

A block can be evaluated. This operation looks up the values for words and performs functions. The values can be passed as arguments to functions, and values are returned as results. All operations in REBOL are functions. For instance, you can write:

if time > 11:30 [print "Lunch"]

But you can also write code such as:

condition: (time > 11:30)


action: [print "Lunch"]


if condition action

A variable definition is done with a colon, not an equal (which is used for equality). A variable can hold a function as well as any other type of value.

It is worth noting that REBOL has no keywords and little syntax. This may seem foreign if you know C, Java, or Basic, but these features are important for creating dialects.

As mentioned earlier, REBOL is a highly polymorphic and reflective language. The reflective property can be seen when using the REBOL internal help, which uses function argument specifications to generate help information. For instance, the help lines in Example 1 were generated from the definition of the switch function. This introspective database is also used when generating error messages, as in Example 2.


USAGE:
     SWITCH value cases /default case
DESCRIPTION:
     Selects a choice and evaluates what follows it.
     SWITCH is a function.
ARGUMENTS:
     value -- Value to search for. (Type: any)
     cases -- Block of cases to search. (Type: block)
REFINEMENTS:
     /default
         case -- Default case if no others are found. (Type: any)

Example 1: Help lines in REBOL.


switch 20
   ** Script Error: switch expected cases argument of type: block.
   ** Where: switch 20

Example 2: Generating error messages.

REBOL Data Structuring

REBOL data structures are also formed with blocks. They can contain values of any datatype, including words, and the values may appear in any order. The freedom of order establishes the basis for dialects and will be explained in the next section.

The data held within blocks can be referenced by its position, tag, type, evaluation, and dialect. Referencing by position is most common for groups of fixed-size structured data. For instance, Listing One defines a block of friends and related data. The position determines where information is held. Name is first, age is second, and e-mail is third.

Listing One
  friends: [
          "Bob"   24 [email protected]
          "Sally" 28 [email protected]
          "Julie" 30 [email protected]
  ]
  foreach [name age email] friends [
          send email reform ["Hi" name "How's it going?"]
  ]

Referencing data by tag is useful if the order of the data is irregular or contains entries of variable length, as in Listing Two. Words are used as tags to mark specific values. The words are not used as variables; they are just markers (similar to how XML tags its data). Similar to tags, datatypes can be used to reference specific items. Listing Three shows how you would find all e-mail addresses to send friends a quick hello.

Listing Two

friends: [
        name "Bob" "Marker" age 24
        name "Sally"
                age 28
                email [email protected]
                phone #777-555-1111
        name "Julie" "Lober"
                email [email protected]
                site http://www.juliesite.dom
                city "New York"
]
while [friends: find friends 'name] [
        friends: next friends
        print first friends
]
friends: head friends

Listing Three
while [friends: find friends email!] [
        send first friends "Quick hello!"
        friends: next friends
]

Another method of referencing data requires evaluation of the data block in order to set variables to specific values. Here each value is assigned to a variable. This is done when the block is evaluated, as in Listing Four.

Listing Four

friends: [
        [name: "Bob Marker" age: 24]
        [name: "Sally"
                age: 28
                email: [email protected]
                phone: #777-555-1111
        ]
        [name: "Julie Lober"
                email: [email protected]
                site: http://www.juliesite.dom
                city: "New York"
        ]
]
foreach person friends [
        set [name age email phone site city] none
        do person
        print name
]

The extra line that sets all the variables to none is done to allow code to determine if the variable was actually set in the block. Not all variables may be present in each block. (The scope of these variables can be global or local to a function or object.)

Dialects

A REBOL dialect is a set of data structuring rules that lets you define specific meaningful sequences of REBOL words or data. Dialects are created in REBOL using the language's data structures, symbols, and native functions. Any sequence of values that must be interpreted through special code is considered a dialect. Listings One through Three are dialects because they require user code to interpret their structure. Listing Four is not a dialect, because it is actual code.

A dialect is defined as a specialized grammar that shares REBOL's common set of datatypes. A dialect is not specified as character patterns, but rather as datatype patterns within REBOL. Dialects are normally created by a programmer who understands the details of a specific domain. For instance, you can create a home control dialect that lets you send this message to your home:

Turn on porch light at 7:30 pm

Your home computer would interpret the message by running a REBOL dialect that understands actions like "turn on," objects like "porch light," and times like "7:30 pm."

There is no limit to the number or sophistication of the dialects that can be created. It is common practice for programmers to create sublanguages to better express and describe solutions. Chip designers, civil engineers, stock brokers, statisticians, financiers, travel agents, and other professionals have created their own specialized languages to become more productive within their specific domains. Other dialect examples are in Example 3. These dialects can become more involved and sophisticated depending on the requirements of the domain, as in Example 4.


Buy 10.5 gallons of gas at $1.42 each
Sell 100 shares of "Acme" at $4.55 per share
Display "river" image in center of screen
Turn right 2 miles after "Perkins Road" exit

Example 3: Dialect examples.

Search for flight from SFO to JFK
         prefer "American" or "United"
         departs 1-June-2000
         arrives before 10:30PM
         priced less than $450

or:

Buy 1000 shares of "Acme" symbol ACME
         at or below $4.60
         expires on 6-June-2000
         account #ACN-456-987
         confirm with [email protected]

Example 4: More complex examples.

These examples are wordy in order to make them look more like English; however, REBOL should not be mistaken for English. It is not. The similarity to English is done to make dialects easier for users. Messages can be written in a more concise format if necessary. For instance, Listing Five shows dialect lines that are used to describe a graphical user interface in REBOL/View with its consumer interface dialect (CID is one of several user-interface dialects). Rather than use extra words, the meaning of each line is known from the words and datatypes that are used, such as text strings, numbers, image files, colors, blocks, and so on.

Listing Five

view layout 640x480 [
    backdrop %trees.jpg
    title "Network Tester"
    text {Test that your network configuration is working
            by clicking on relevant buttons below.}
    pad 20
    text "Network Tests:" yellow
    button "DNS"    [read dns://www.rebol.com]
    button "Whois"  [read whois://[email protected]]
    button "Finger" [read finger://[email protected]]
    button "Time"   [read daytime://10.5.5.2]
    button "SMTP"   [send [email protected] "Test"]
    button "POP"    [read pop://user:[email protected]]
    button "HTTP"   [read http://www.rebol.com]
]

In addition to user-defined dialects, REBOL has several built-in dialects. The specification of a function and its arguments is done in a dialect of REBOL that accepts argument names, their acceptable datatypes, description strings, functional refinements, and more. Listing Six shows the append function specification. Other dialects are used in REBOL for the secure and parse functions.

Listing Six

append: func [
        {Appends a value to the tail of a series.}
        series [series! port!] {Series to append to}
        value {Value to append}
        /only {Appends a block value as a block}
]

Defining Dialects

A dialect can be formal or informal. A formal dialect requires a grammar be provided to the parse function. An informal dialect requires no such specification. Listings One through Three are informal dialects. To specify a formal dialect, grammar rules are provided to the parse function. Listing Seven is a stock trade and its dialect.

Listing Seven

trade: [
        Sell 100 shares of "Acme" at $4.55 per share
]
stock-dialect: [
        set action ['sell | 'buy]
        set shares integer! 'shares 'of
        set company string! 'at
        set price money! 'per 'share
]
parse trade stock-dialect

The stock dialect is a block that defines the rules of the grammar for the stock dialect. These rules are actually a dialect of REBOL, so the values within it have a different meaning than they would in normal REBOL code.

The first line indicates that a variable should be set to hold either the word "sell" or "buy." The vertical bar separates the alternates. Whichever is found will be set to the action variable. If neither is found, then the parse function will return immediately with a false value. This is similar to the standard Backus Naur Form (BNF) grammar specifications used to specify most languages and protocols. The remaining lines set other values for the number of shares, company name, and price per share. The words that begin with a tick (single quote) are literal words and must appear as specified within the grammar. Many of these words can be made optional by using the opt keyword, as in Listing Eight. This new grammar allows all of the stock trades in Listing Nine. Listing Ten is the code that calls the parse function with the grammar rules and prints the result.

Listing Eight
set action ['sell | 'buy]
set shares integer! opt 'shares opt 'of
set company string! 'at ['below | 'above | none]
set price money! opt ['per 'share]

Listing Nine
Sell 100 shares of "Acme" at $4.55 per share
Sell 100 shares "Acme" at $4.55 per share
Sell 100 shares "Acme" at above $4.55 per share
Sell 100 of "Acme" at $4.55 per share
Sell 100 of "Acme" at below $4.55
Sell 100 "Acme" at $4.55

Listing Ten

either parse trade stock-dialect [
        print [action shares company price]
][
        print "stock trade error"
]

Simple Network Dialect

The stock dialect parses the trade, but does nothing other than print the result. Most of the time, you'll want to associate specific actions to parts of a dialect. The dialect in Listing Eleven defines a simple network command language that can move web pages between systems and send a progress report to a network manager. This is a complete script example that includes a REBOL header.

Listing Eleven

REBOL [
    Title: "Dr. Dobb's Example"
    Date: 28-Mar-2000
    Version: 1.0.2
    Needs: [core 2.3.0]
]
commands: [
    manager is [email protected]
    access with ftp://user:[email protected]/pages

    inform "beginning update..."
    download %index.html
    download %sitemap.html to %oldsitemap.html

    upload %new-index.html to %index.html
    upload %logo.jpg
    notify "home page has been updated"

    quit
]
net-dialect: [
    'manager opt 'is set who email!
    'access opt 'with set site url!
    some [
        'download file-rule
              (print ["Downloading:" src]
              write/binary dest read/binary site/:src)
        | 'upload file-rule
              (print ["Uploading:" src]
              write/binary site/:dest read/binary src)
        | 'notify set message string! (send who message)
        | 'inform set message string! (print message)
        | 'quit (quit)
        | here: (print ["Unknown:" mold here] halt)
    ]
]
file-rule: [set src file! ['to set dest file! | none (dest: src)]]
if error? try [parse commands net-dialect][
    send who "Script failed"
]


The block of commands holds actions that the net dialect block parses with specified grammar rules. In addition, there is a file rule that is used within the net dialect block. The parse function is called with error handling (the try function) just in case a mistake is not caught by the dialect grammar. This script can easily be modified to load the command block from other files.

Conclusion

Communication is the exchange and interpretation of information. To communicate, we need to share a common language. However, in many cases we are dealing with a specific domain, where a dialect can provide greater productivity, easier maintenance, and quicker time-to- market. There are examples in the world around us from VCRs to toasters and from home control to automobile engines that can benefit from this approach. This becomes even more essential in today's distributed computing environment, where complexity and size of software solutions have created serious development barriers. Within these specific domains, REBOL provides a powerful tool for breaking through that code barrier.


Carl is the founder of REBOL Technologies and one of the designers of the Amiga operating system. He can be contacted at [email protected]. Jul00: The REBOL Scripting Language


switch 20
   ** Script Error: switch expected cases argument of type: block.
   ** Where: switch 20

Example 2: Generating error messages.

Jul00: The REBOL Scripting Language


Buy 10.5 gallons of gas at $1.42 each
Sell 100 shares of "Acme" at $4.55 per share
Display "river" image in center of screen
Turn right 2 miles after "Perkins Road" exit

Example 3: Dialect examples.

Jul00: The REBOL Scripting Language


Search for flight from SFO to JFK
         prefer "American" or "United"
         departs 1-June-2000
         arrives before 10:30PM
         priced less than $450

or:

Buy 1000 shares of "Acme" symbol ACME
         at or below $4.60
         expires on 6-June-2000
         account #ACN-456-987
         confirm with [email protected]

Example 4: More complex examples.

Jul00: The REBOL Scripting Language

Table 1: Primary REBOL datatypes. (a) Numerical datatypes; (b) character datatypes; (c) block datatypes; (d) word datatypes; (e) function datatypes; (f) object datatypes; (g) special datatypes.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.