Permalink
Switch branches/tags
Nothing to show
Find file Copy path
5186 lines (4398 sloc) 243 KB

Red Language Specification - draft

Table of Contents

1. Introduction

1.1. Purpose

The purpose of this document is to systematically describe the lexical/syntactic and semantic rules of the Red programming language, and thus to be the authoritative document for:

  • verifying implementation conformity

  • tracking changes in the language design, including why changes were made

  • acting as a reference for tests

In as much as feasible, and in order to avoid duplication, existing pieces of official documentation will be referred to. A list of those can be found in section 18.

Because of the wealth of built-in functions that Red makes available, combined with the numerous optional facilities ("refinements") that these functions have, it is not possible to give an exhaustive treatment of Red’s functionality. Red allows quite detailed information about a function’s operation to be documented within the function specification, and this should be consulted in order to be able to use any function optimally. See section 13.6.

This document is not intended to be used in order to learn the language (tutorial); for that purpose sufficient materials can be found using the Red Wiki at https://github.com/red/red/wiki .

1.2. Conventions

In this document, technical terms — whether in general use or specific to the Red language — will be written in italics when first used and sometimes also on some subsequent occasions. Values from the Red language, grammatical categories, rule numbers and Unicode Code Point numbers will be written in monospace font.

Rules have a code in the form: Letter + 3 digits. The number is an incremental counter. The prefix letter can be:

  • S: for lexical and syntactic rules.

  • E: for evaluation rules.

2. Overview

2.1. Characterization

Red is a next-generation programming language strongly inspired by Rebol, but with a broader field of usage thanks to its native-code compiler, from system programming to high-level scripting and cross-platform reactive GUI, while providing modern support for concurrency. Red has its own complete cross-platform toolchain, featuring two compilers, an interpreter and a linker, not depending on any third-party library. Once complete, Red will be self-hosted.

The concurrency part is far from being implemented, mention it here?

2.2. Red toolchain

A program written in Red is intended to be executed on a target computer. To that end, it will be submitted to the Red toolchain which is a program executing on a host computer; this computer may be, but need not be identical to the target computer. In case the two are identical, the program execution may take the form of interpretation, i.e. the effect of the program is the result of the toolchain’s operation itself. In either case, the execution may occur through compilation, i.e. the toolchain produces a program in a lower-level language (e.g. machine code) suitable for execution on the target computer. The toolchain is to be constructed such that the effect of the program is the same whether it is executed through interpretation or compilation. A further facility of the toolchain is that it provides one or more interactive consoles, i.e. visual interfaces which accept program fragments and display the result of evaluating them (REPL or Read Evaluate Print Loop).

Information about the installation and usage of the toolchain can be found in the README file of the Red repository on Github. This repository contains the full source code of the toolchain, which may be said to be the final authority on what the Red language is.

2.3. Values and types

An important property of Red is that any Red program is a sequence of Red values, i.e. code and data are a priori indistinguishable. In other words, Red is homoiconic. Thus, execution of a Red program is tantamount to evaluating each of its constituent values in turn, according to the evaluation rules. Each Red value has a type and the types themselves are also values of the language. The type of each value can be determined either lexically (single values), or syntactically (grouped values).

2.4. Words, contexts and binding

A special category of values is formed by words, that play a similar role to identifiers and keywords of other languages. Red does not have identifiers nor keywords: as will be explained in more detail below, any word may refer to another value in some context. The word is said to be bound to, or in the context. Evaluation of a word yields the value it refers to. The evaluation rules given below will state, amongst others, how words can come to refer to values in the course of program execution.

A large number of words are pre-defined to refer to certain values in the global context, notably to built-in functions, types (type names conventionally end in !) and constants such as the truth values: true and false, as well as none ("nil" or "null" in other languages). See section 14 for the complete list.

2.5. Dialects

Red makes available a large number of different value types. The evaluation rules stated below describe the interpretation of these values when they occur in a Red program which, as stated before, is nothing more or less than a sequence of values. The users may furthermore use and interpret Red values, when considered as data, in ways of their own, and thus create dialects or Domain Specific Languages (DSLs). Implementing the interpretation of dialects in Red is greatly facilitated by the parse facility (see section 13.2).

In fact, Red itself contains a number of dialects where blocks of data are interpreted in a specific way; this includes the preprocessor dialect, the parse dialect, the visual interface dialect (VID), which also uses the draw dialect and the shape dialect, the various spec dialects involved in defining vectors, images, bitsets, objects, errors, maps, functions and routines, furthermore the compose dialect and the system dialect (Red/System).

Red/System is on the one hand a language of its own: it is a C-level language with memory pointer support and a very basic and limited set of datatypes. Programs written in Red/System can be compiled and executed using the toolchain. As a dialect of Red its purpose is to provide low-level system programming capabilities, and it serves both as a tool to build Red’s runtime library and as intermediate language for the compiler to generate machine code from. The elements of a Red/System program are lexically the same as Red values. Red/System is specified in a separate document (see section 18).

3. Structure of Red programs

3.1. Textual structure

For submission to the Red toolchain, a Red program must be prepared as a text file. This may contain any Unicode Code Points, encoded using the UTF-8 scheme.

As a first operation of the toolchain, the text file will be subjected to lexical analysis which will break the text up in a series of lexemes, i.e. textual representations of Red single values, interspersed with grouping tokens. The grouping tokens should occur in properly nested pairs, and are the following: ( ), [ ], #( ), #[ ]. A sequence of lexemes enclosed in matching grouping tokens represents a Red grouped value of a certain type, and this construct may again be enclosed in grouping tokens etc. Note that the token pairs " ", #" ", { }, #{ } and < > each delimit a single value, they are not grouping tokens.

As a rule, lexemes must be separated from each other and from grouping tokens by one or more whitespace characters. In the Red source text, whitespace characters are space (U+0020), tab (U+0009), line feed (U+000A), carriage return (U+000D), next line (U+0085) and non-breaking space (U+00A0). Consequently, Red program texts are free form, i.e. neither their arrangement in separate lines, nor their formatting with indentation and the like, has any significance for their interpretation.

This is most certainly short of some whitespace values, please correct See also issue #2492

In certain cases, where there can be no ambiguity, the requirement for whitespace between values can be relaxed. For example, it is possible to omit whitespace between two consecutive block! values and between word! values and block! values. These examples are all syntactically valid:

     either x = 1["OK"]["NOK"]
     either x = 1  ["OK"]     ["NOK"]
     either x = 1 [
         "OK"
     ] [
         "NOK"
     ]

Comments, which have no significance for the operation of the program, may be placed following a semicolon ; until the end of an input line (end-of-line comment), or they may follow the word comment and be formulated as a single Red value — most usefully a series of characters enclosed in " " or { } — or a series of Red values enclosed in [ ].

A well-formed Red program begins with a prologue which may contain metadata for the toolchain and/or the reader. The relevant data will be described in section 17. Note that, although Red text is in general case-insensitive (barring exceptions noted in section 5), the first three letters of the prologue must be literally R e d.

3.2. Formal grammar

A formal grammar corresponding to the above presentation is given below. This omits the separation by whitespace, and the presence of end-of-line comments. As usual, * means zero or more instances of the non-terminal. In the grammar fragments of subsequent sections of this document, o will stand for an optional instance. Other characters outside non-terminals stand for themselves, with the understanding that, if they immediately precede or follow a non-terminal, they are part of the produced lexeme. The comment to any production rule, which starts after the ; on the line, states the type of the single or grouped values generated by this rule. The significance of the types is found in section 4.1. Any non-terminal that is not further defined in this grammar is explained in the individual sub-sections of section 5. Those sections will also introduce the <symbol-literal>, which by itself is not a lexeme, and therefore does not generate a value of the language. Its use is in explaining the common characteristics of several lexemes, namely <word-literal>, <refinement-literal> and <issue-literal>, see sections 5.2.5 and 5.2.15/16.

S100

program structure

<program>  ::= <prologue> <value>*
<prologue> ::= Red [ <value>* ]
<value>    ::= <lexeme> | <group>
<lexeme>   ::= <integer-literal>                        ; integer!
             | <float-literal>                          ; float!
             | <integer-literal>% | <float-literal>%    ; percent!
             | <integer-literal>x<integer-literal>      ; pair!
             | <time-literal>                           ; time!
             | <date-literal>                           ; date!
             | <tuple-literal>                          ; tuple!
             | <word-literal>                           ; word!
             | '<word-literal>                          ; lit-word!
             | <word-literal>:                          ; set-word!
             | :<word-literal>                          ; get-word!
             | <refinement-literal>                     ; refinement!
             | <issue-literal>                          ; issue!
             | <char-literal>                           ; char!
             | <string-literal>                         ; string!
             | <file-literal>                           ; file!
             | <url-literal>                            ; url!
             | <email-literal>                          ; email!
             | <tag-literal>                            ; tag!
             | <binary-literal>                         ; binary!
             | <path-literal>                           ; path!
             | '<path-literal>                          ; lit-path!
             | <path-literal>:                          ; set-path!
             | :<path-literal>                          ; get-path!

    <group>    ::= <paren-literal>
             | <block-literal>
             | <map-literal>
             | <constructor>
    <paren-literal> ::= ( <value>* )                    ; paren!
    <block-literal> ::= [ <value>* ]                    ; block!
    <map-literal> ::=   #( <value>* )                   ; map! (even number of values only)
    <constructor> ::=   #[ <value>* ]                   ; reserved for general typed value constructor

3.3. Expressions and evaluation order

At a semantic level, the constituents of a Red program are not values but expressions. An expression groups one or more values, and may be formed in three ways: as an application of a (prefix) function, as an infix expression which uses an operator, or as a binding of a word to refer to a value.

The statement made earlier: "execution of a Red program is tantamount to evaluating each of its constituent values in turn, according to the evaluation rules" can therefore be refined to: "execution of a Red program is tantamount to evaluating each of its constituent expressions in turn, according to the evaluation rules", with expression being construed as the largest sequence of values conforming to the following definition:

S101

expressions

<expression>      ::= <operand>
                    | <expression> <op> <operand>
<operand>         ::= <value>
                    | <prefix-function> <argument>*
                    | <word-literal>: <expression>
<argument>        ::= <expression>

Here <op> is an expression which evaluates to an operator, i.e. an op! value representing an infix function of two arguments, and <prefix-function> is an expression which evaluates to a prefix function (value of type action! native! function! or routine!). The number of expressions (arguments) following a prefix function is strictly dependent on the function value and is known as the arity of the function value. Binding is expressed by a <word-literal>: (set-word! value) followed by an <expression>. See further the evaluation rules given in section 7. Evaluation of the operands of operators has precedence over function application and binding; also, as suggested in rule S101, operators are strictly left associative, there is no precedence between any two operators. The fact that the arguments of a function simply follow the function itself (they are not enclosed in parentheses) means that, for the reader to understand a program, knowledge of the arity of functions is necessary. Evaluation order can of course be influenced by the use of parentheses, given the evaluation rule for values of paren! type (see section 7.3.4).

Some basic examples:

1 + 2 3 + 4                ; 6 values, 2 expressions
1 + 2 * 3                  ; result is 9, not 7
1 + (2 * 3)                ; result is 7
pick copy "abc" 1          ; 1 is argument to pick, since copy has 1 argument itself
copy/part "abc" 2          ; with the "refinement" /part, copy now has 2 arguments
mod x 2 + 1                ; mod has 2 arguments; this will be interpreted as mod x 3
1 + mod x 2                ; this is what was probably meant
(mod x 2) + 1              ; another way  of writing that
1 + a: 2                   ; result is 3, a now refers to 2

In what follows, terms like <integer-literal> will be used to refer to lexemes; to indicate the corresponding values, terms like "value of type integer! ", " integer! value" or plain "integer" will be used. Also, in grammar fragments, on the right-hand side of the ::= sign, terms like <integer> will stand for " <expression> evaluating to an integer! value" etc., while decorated non-terminals like <true-block> will stand for <block> etc.

4. Types

4.1. Type list

The full list of types of the languages is given below, with an explanation of the usage of their values.

type values and usage

datatype!

types of the language (first class values)

typeset!

sets of types

none!

single value: none, i.e. a value belonging to none of the other types

logic!

true or false

char!

characters (Unicode Code Points)

integer!

integer numbers

float!

floating point (decimal) numbers

percent!

floating point numbers expressed as a percentage

time!

time intervals or points in time, stored as a floating point number of seconds

date!

dates according to the Gregorian calendar, optionally with time of day and timezone

pair!

2-dimensional coordinates or size

tuple!

e.g. colors in RGB or other scheme, IPv4 addresses

word!

identifiers that can be bound

lit-word!

quoted (unevaluated) words

set-word!

words to be given a value to refer to

get-word!

words to be evaluated

refinement!

indicates optional argument of function

issue!

literal identifiers

handle!

opaque integers for communication with operating system

block!

ordered collections of values of any type (polymorphic array), may also be used as unordered collections (sets)

hash!

blocks with quick access

paren!

differs from block in behaviour under evaluation

path!

specifying optional arguments in function calls, selection of components of composite values

lit-path!

quoted (unevaluated) paths

set-path!

for setting a component of a composite value

get-path!

paths to be evaluated

vector!

ordered sequences of values of identical type, which can be char! or integer! (8/16/32 bits), percent! or float! (32/64 bits); default: 32 bits for char! or integer! and 64 bits otherwise

string!

sequences of characters (Unicode Code Points)

file!

files or directories (folders)

url!

URLs

tag!

tags in the sense of HTML, XML etc.

email!

email addresses

binary!

sequences of bytes

image!

2-dimensional arrays of pixels (RGBA values stored in 4 bytes for each pixel, row first)

bitset!

sequences of logic! values, used e.g. to model sets of non-negative integers, such as Unicode Code Points

map!

collections of pairs of values where the first value in each pair functions as key for retrieval of the second; keys are restricted to types in scalar!, any-word! and any-string!

object!

collections of word-value pairs with a context in which the words (also called fields) are bound, and are referring to the corresponding values; objects are capable of triggering asynchronous events in response to changes in their components, thus enabling reactive programming; objects have a class property associated with them

error!

specialized objects representing error conditions

port!

specialized objects for communicating with external resources

native!

pre-defined functions with built-in evaluation according to special rules

action!

pre-defined polymorphic functions of one or two arguments with built-in evaluation

op!

operators, i.e. infix functions of two arguments, each one is derived from a native!, action!, function! or routine! value

function!

user-defined functions; as with native! and action! values, function! values may have optional arguments, indicated by refinements

routine!

user-defined functions with body in Red/System code

unset!

single value indicating the absence of a usable value

event!

representations of external activity

TBD
point!
closure!
ref!
struct!
library!

4.2. Type categories

As seen in the previous section, Red has a rather large number of different types. For a better understanding of their nature and that of their values, it is useful to make a number of distinctions into different categories.

  • textual representation: types having lexically/syntactically representable values or not

  • internal storage: direct types vs indirect types and function types

  • internal structure of values: atomic types vs composite types

  • reflectivity: types with values that admit reflection or not

  • evaluation: passive types, decaying types, active types, function types

  • implementation of built-in functions: parent types

4.2.1. Types according to their textual representation

Not all types listed have lexically or syntactically determined values. Those that have not may have their values generally be represented in programs by expressions of the form make <type> <spec>, where <type> is an expression that evaluates to a type name or to a value of the desired type, and <spec> is an <expression> whose value is interpreted by the make function as appropriate for the given type. This is explained in detail in section 5.3. An alternative, syntactical representation, will be offered for a number of types (or all??) in the form of construction syntax #[<type> <spec>].

4.2.2. Direct/Indirect/Function types

Red values are internally stored using value slots of uniform size. Values of direct types fit completely into one such slot; for values of indirect types, which have a variable number of components, the slot stores a pointer to a further storage area that holds the components of the value. As a consequence, when a word is made to refer to a value of indirect type or such a value is supplied as actual argument to a function, the components of this value may be changed through operations on the word or the function formal argument. In order to prevent this, values of indirect types must be explicitly copied before being transmitted as argument or having a word refer to them. The built-in function copy will do this. If the components themselves are of indirect type, copy will not copy their components, unless the function refinement /deep is used.

A third category to be distinguished is that of function types, where pointers to the argument list and the body are stored in the slot.

4.2.3. Atomic/Composite types

Values of certain types have components which may be extracted and/or changed using a variety of facilities which will be specified below under evaluation. Such types are called composite and the others are atomic. All indirect types are composite, but the converse is not true: some direct types are also composite. In Red, values of atomic types are immutable, and values of composite types are mutable.

4.2.4. Types that admit reflection

Values of some types have (internal) properties of interest to the user which may usefully be exposed. E.g. the set of words from the word/value pairs making up an object may be retrieved by the built-in function words-of. Likewise, the argument spec of a function may be retrieved by spec-of.

We should perhaps consider context? or rather context-of as a reflector also

4.2.5. Types according to the evaluation of their values

  • Values of passive types evaluate to themselves. The great majority of types belong to this category.

  • Values of decaying types are quoted instances of other values. They evaluate to the unquoted value.

  • Values of active types are bound to a context, their binding can be retrieved to yield the value referred to.

  • Values of function types, when evaluated, result in the application of the function to its arguments.

Detailed rules for the evaluation in these various cases are given in section 7.

4.2.6. Parent types

The notion of parent type arises in the implementation of actions, i.e. pre-defined polymorphic functions of up to two arguments with built-in evaluation, e.g. add, subtract, copy, find, etc. The implementation uses a dispatch table which contains a pointer to a specific run-time function for each allowed combination of action and type of first argument. These functions are grouped by the type to which they apply. Now for any action/type combination, such function may be designated as inherited from the parent type, and in this way two or more types may share the same implementation for that action. In this approach, there are two pseudo-types defined, which function as parent types from which to inherit: they are symbol! for types related to word! and series! for types related to block! and string!. A further pseudo-type context! provides implementation of context-related functionality (see sections 2.4 and 6).

4.2.7. Overview table

type value representation1 storage atomic/composite reflection? evaluation parent type

datatype!

using words

direct

atomic

N

passive

typeset!

using make

direct

atomic

N

passive

none!

using words

direct

atomic

N

passive

logic!

using words

direct

atomic

N

passive

char!

lexical

direct

atomic

N

passive

integer!

integer!

lexical

direct

atomic

N

passive

float!

lexical

direct

atomic

N

passive

percent!

lexical

direct

atomic

N

passive

float!

time!

lexical

direct

composite

N

passive

float!

date!

lexical

direct

composite

N

passive

pair!

lexical

direct

composite

N

passive

tuple!

lexical

direct

composite

N

passive

word!

lexical

direct

atomic

Y

active

symbol!

lit-word!

lexical

direct

atomic

Y

decaying

word!

set-word!

lexical

direct

atomic

Y

active

word!

get-word!

lexical

direct

atomic

Y

active

word!

refinement!

lexical

direct

atomic

Y2

passive

word!

issue!

lexical

direct

atomic

Y2

passive

word!

handle!

using words

direct

atomic

N

passive

integer!

block!

syntactic

indirect

composite

N

passive

series!

hash!

using make

indirect

composite

N

passive

block!

paren!

syntactic

indirect

composite

N

active

block!

path!

lexical

indirect

composite

N

active and function

block!

lit-path!

lexical

indirect

composite

N

decaying

path!

set-path!

lexical

indirect

composite

N

active

path!

get-path!

lexical

indirect

composite

N

active

path!

vector!

using make

indirect

composite

N3

passive

string!

string!

lexical

indirect

composite

N

passive

series!

file!

lexical

indirect

composite

N

passive

url!

url!

lexical

indirect

composite

N

passive

string!

tag!

lexical

indirect

composite

N

passive

string!

email!

lexical

indirect

composite

N

passive

string!

binary!

lexical

indirect

composite

N

passive

string!

image!

using make

indirect

composite

N

passive

series!

bitset!

using make

indirect

composite

N

passive

map!

syntactic

indirect

composite

Y

passive

object!

using make

indirect

composite

Y

passive

error!

using make

indirect

composite

Y

passive

object!

port!

using make

indirect

composite

Y

passive

object!

native!

using words

function

atomic

Y

function

action!

using words

function

atomic

Y

function

native!

op!

using words

function

atomic

Y

function

native!

function!

using make

function

atomic

Y

function

routine!

using routine

function

atomic

Y

function

function!

unset!

using make

direct

atomic

N

passive

event!

using words

direct

composite

N

passive

Notes:

  1. Values of all types may be represented using make, except those of datatype! native! action! routine! handle! and event!

  2. See REP #14

  3. See REP #12

TBD
point!
closure!
ref!
struct!
library!

4.3. Type hierarchy

For the convenience of the user, certain typesets have been pre-defined which group related types. These will notably be used for indicating the allowed types of arguments to polymorphic functions. E.g. power takes two arguments whose types are both in the typeset number!. Note that there is a typeset series! which covers the same types that have the pseudo-type series! as parent type. Note further that there is not a one-to-one correpondence between this (semantic) hierarchy and the implementation hierarchy implied by the assignment of parent types.

any-type!
|--internal!
|  |--unset!
|--default!
   |--external!
   |  |--event!
   |--immediate!
   |  |--datatype!
   |  |--typeset!
   |  |--none!
   |  |--logic!
   |  |--scalar!
   |  |  |--char!
   |  |  |--number!
   |  |  |  |--integer!
   |  |  |  |--any-float!   <---- see issue #2565
   |  |  |     |--float!
   |  |  |     |--percent!
   |  |  |--time!
   |  |  |--date!
   |  |  |--pair!
   |  |  |--tuple!
   |  |--all-word!
   |  |  |--any-word!
   |  |  |  |--word!
   |  |  |  |--lit-word!
   |  |  |  |--set-word!
   |  |  |  |--get-word!
   |  |  |--refinement!
   |  |  |--issue!
   |  |--handle!
   |--series!
   |  |--any-block!
   |  |  |--any-list!
   |  |  |  |--block!
   |  |  |  |--hash!
   |  |  |  |--paren!
   |  |  |--any-path!
   |  |     |--path!
   |  |     |--lit-path!
   |  |     |--set-path!
   |  |     |--get-path!
   |  |--vector!
   |  |--any-string!
   |  |  |--string!
   |  |  |--file!
   |  |  |--url!
   |  |  |--tag!
   |  |  |--email!
   |  |--binary!
   |  |--image!
   |--bitset!
   |--map!
   |--any-object!
   |  |--object!
   |  |--error!
   |  |--port!
   |--any-function!
      |--native!
      |--action!
      |--op!
      |--function!
      |--routine!

TBD
point!
closure!
ref!
struct!
library!

The built-in function type? will yield the type of a value. It has a refinement /word which will yield the type as a word! value. For every pre-defined type and typeset there is a built-in function which will test if a value is of that type (or a type in that typeset). These functions have the name of the type(set) with the ! replaced by ?.

Examples:

type? 1        -> integer!
integer? 1     -> true
number? 1.0    -> true

5. Values

5.1. Introduction

The types whose names are mentioned in rule S100 (integer! to map!) are the only ones that have lexically or syntactically determined values. Values that are not lexically or syntactically determined may generally be represented in programs with the help of the built-in function make. This is one of three related means that Red provides in order to produce new values:

  • creating them with the help of other ones (built-in function make)

  • converting values to related ones of other types (built-in function to)

  • changing their type without changing their content (built-in function as)

All three built-in functions have two arguments: <target> and <spec>, where <target> evaluates to a type (datatype! value) or to a value (prototype) of the desired type and <spec> is interpreted as appropriate for the given type.

Both make and to are trivially defined if the type of their <spec> argument is the same as (the type of) their <target> argument; for indirect types, a copy is made of the value of <spec>.

For several types, the available values are referred to by words at program start: none! has none, logic! has true = yes = on and false = no = off, and datatype! has all the valid type names pre-defined (no further datatypes can be defined by the user); likewise native!, action! and op! have all the built-in functions and operators pre-defined (values of type action! and native! cannot be made by the user, but new infix operators can be). Values of types event! and handle!, that are used to communicate with the operating system, can only be represented by words that are arguments to functions handling this communication.

Mention general typed value constructor #[ <type> <value>* ] See also REP #9

The following sub-sections will specify the lexical structure resp. the <spec> argument of the make, to and as function for values of each of the types as appropriate. For convenience, the <target> argument is specified in evaluated form when it is a <type>, and the <spec> argument is presented as a <block-literal> when it is important to show the components of the block. It should be remembered, however, that make, to and as do evaluate their arguments, so that any <expression> which evaluates to a type or a block is allowed in the relevant argument positions.

In the following rules, the sign ° signifies an optional element.

5.2. Lexical structure of values

5.2.1. integer!

S111

An <integer-literal> is written as an integer number from -231 to 231-1 in decimal notation. Leading zeroes are allowed, as well as ' signs between digits, for separation. A + sign is allowed but not compulsory. Hexadecimal notation, eg FFh, is omitted as this is under discussion

Examples: 123 -123 +0001 1'000

5.2.2. float!

S112

A <float-literal> is written as a floating point number in the range of the IEEE 754 binary64 format, in decimal notation. As an alternative to the dot . as decimal point, a comma , may be used. Leading zeroes are allowed, as well as ' signs between digits, for separation. A + sign is allowed but not compulsory. No zero is needed before the decimal point when the absolute value is smaller than 1.0. The number may be followed by E or e with an integer exponent on base 10. Leading zeroes are allowed in the exponent, and a + sign is allowed but not compulsory. Note that in this case, no decimal point is required, and that ' signs between digits are not allowed.

Examples: 1.23 -0,5 .5 +010.20 1E9 1E-9

For the special numbers positive and negative infinity, and for the "not a number" value, the following literals are used: 1.#INF, -1.#INF, 1.#NaN and -1.#NaN. The latter two are equivalent representations for a single value. More information on the handling of these special numbers, including negative zero, is to be found in the additional documentation (see section 18).

5.2.3. time!

S113
<time-literal> ::= <Red-time> | +<Red-time> | -<Red-time>
<Red-time> ::= <hours>:<minutes> | <hours>:<minutes>:<seconds> | <hours>:<minutes>:<seconds>.<decimals> |
               <minutes>:<seconds>.<decimals>

where <hours> <minutes> <seconds> and <decimals> may each be any unsigned <integer-literal> (leading zeroes are allowed, carry is performed as appropriate when the minutes and/or the integer part of the seconds are outside the normal range 0..59).

Examples: 10:20 10:20:30.456 20:30.5 -1:00:00

5.2.4. tuple!

S114

A <tuple-literal> is written as 3 to 12 integer! values in the range 0..255 separated by dots .

Examples: 192.168.1.2 (an IPv4 address), 255.255.128 (an RGB value)

For a list of pre-defined words referring to RGB values see section 14.1.5.

5.2.5. word!

S115

A <word-literal> is a restricted form of <symbol-literal>.

A <symbol-literal> is written as one or more characters from the entire Unicode range excluding control characters (notably Unicode sets C0, C1), whitespace characters and the following set: / \ ^ , [ ] ( ) { } " # $ % @ : ;. The following punctuation characters from the ASCII subset are allowed: ! & ' * + - . < = > ? _ ` | ~. Symbols, i.e. instances of <symbol-literal> are case-insensitive, i.e. changing any letter in the symbol into the corresponding upper- or lower-case variant does not create a different symbol in terms of the equality operator = (see section 5.8.1). As stated above (section 3.2), a symbol is not a value of the language. Its use is in explaining the common characteristics of values of several types, namely word!, refinement! section 5.2.15 and issue! section 5.2.16

A <word-literal> is a <symbol-literal> that does not begin with 0-9 or '. However, the combination <> may only occur on its own, and <…​> with any characters in between the < and > character is a value of type tag! (see section 5.2.11).

Examples: abc Abc ABC + <> integer! last-item? ; the first three are equal word! values.

1a is not a <word-literal>; <p> is a <tag-literal>.

5.2.6. char!

S116
<char-literal> :: = #"<single-character>"
<single-character> ::= <viewable-character> | <escaped-character> | <hexadecimal-codepoint>
<escaped-character> :: =  ^(null) | ^@ | ^(back) | ^(tab) | ^- | ^(line) | ^/ | ^(page) | ^(esc) |
              ^" | ^^ |  ^(del) | ^~ | ^A | ^B | ... | ^Z | ^[ | ^\ | ^] | ^_
<hexadecimal-codepoint> :: = ^(<hex-number>)

where <hex-number> consists of 2 to 6 hexadecimal digits 0-9 A-F a-f.

A <char-literal> must be a valid single Unicode code point, i.e. an integer in the range 0 to 10FFFF (hexadecimal notation).

A <viewable character> is, in most cases, simply a displayable character. For example, e, é, or 😀. When a displayable character requires two or more graphemes to display it, each grapheme requires a separate Red character. For example, when é is encoded in its two character decomposed form e (U+0065) followed by the combining ´ (U+0301) they cannot be considered a single char! value, and programs must explicitly handle their interpretation.

The correspondence between the escaped characters and Unicode Code Points is given in the table below.

Named Form Short Form Character Code Point Pre-defined word(s)

#"^(null)

#"^@"

null

U+0000

null

#"^(back)"

#"^H"

backspace

U+0008

#"^(tab)"

#"^I" #"^-"

horizontal tab

U+0009

tab

#"^(line)"

#"^J" #"^/"

line feed

U+000A

lf, newline

#"^(page)"

#"^L"

form feed

U+000C

#"^(esc)"

#"^["

escape

U+001B

escape

#"^(del)"

#"^~"

delete

U+007F

#"^""

" (double quote)

U+0022

dbl-quote

#"^^"

^ (caret)

U+005E

#"^A" - #"^]"

control characters

U+0001 - U+001D

#"^_"

control character

U+001F

For more pre-defined words referring to characters see section 14.1.1.

Note that code point U+001E cannot be represented by #"^^" as expected, since that is already taken for caret. Note also that ^ will be ignored in front of any single character with which it does not form (the beginning of) an <escaped-character> or <hexadecimal-codepoint>. Thus e.g. ^3 yields the same as 3.

Examples: #"A" #"^/" #"^(0A)"

5.2.7. string!

S117
<string-literal> ::= "<single-character>*" | {<single-character>*}

where <single-character> is defined in rule S116

When the <string-literal> is delimited by " " it must not contain unescaped new-line characters U+000A, U+0085, U+2028 and U+2029. When the <string-literal> is delimited by { } it may contain unescaped new-line characters and any " as well as nested { } pairs, but any unpaired { or } character that is part of the <string-literal> must be escaped by preceding it with ^. Within a <string-literal>, the same remark holds for ^ as noted above for a <char-literal>.

Examples:

"abc^/def"
{abc +
def}

5.2.8. file!

S118

A <file-literal> is written as % followed by one or more non whitespace characters, or by zero or more characters enclosed in " " in which case whitespace characters except line feed and next line may be included. The interpretation of this value is operating system dependent, but escaped characters of the form %<hex-byte> (see section 5.2.12) are accepted, except when " " are used. The % character itself needs to be escaped as %25.

5.2.9. url!

S119

A <url-literal> is written as three or more non whitespace characters, of which at least one : which must not be the first or last character. The remarks in the previous section on escaped characters apply.

5.2.10. email!

S120

An <email-literal> is written as two or more characters containing one @ but not beginning with it. The remarks in section 5.2.8 on escaped characters apply.

5.2.11. tag!

S121

A <tag-literal> is written as one or more characters, not starting with <, = or >, enclosed in < >. Characters " and ' are allowed but must each be properly paired. Within such pair, the other one may occur freely, thus "…​'…​" and '…​"…​' are allowed.

5.2.12. binary!

S122
<binary-literal> ::= 2#{<base2-byte>*} | #{<hex-byte>*} | 16#{<hex-byte>*} | 64#{<base64-char>*}

where <base2-byte> is a group of 8 digits 0 or 1, <hex-byte> is two hexadecimal characters 0-9 A-F a-f and <base64-char> is a single character from the set A-Z a-z 0-9 + /; the individual elements within the #{ } brackets (<base2-byte>, <hex-byte> or <base64-char>) may be separated from the brackets and from each other by whitespace.

Examples:

2#{00000001 00000010 00000011}
#{ 01 02 03 }
64#{AQID}

In order to help convert between the 3 representations (base2, base16 and base64), the built-in functions debase and enbase have been defined. They each have a refinement /base with an argument of 2, 16 or 64 (default).

Examples:

enbase #{010203}           -> "AQID"
enbase/base #{010203} 2    -> "000000010000001000000011"
debase "AQID"              -> #{010203}

Note that enbase will also take a string! value as argument; it will be UTF-8 encoded into a binary! value before being converted.

5.2.13. path!

S123
<path-literal> ::= <path-head>/<selector>
<path-head> ::= <word-literal> | <path-literal>
<selector> ::= <integer-literal> | <word-literal> | :<word-literal> | <paren>

Examples:

list/1/2
system/view/screens/2
list/:i
list/(i + 1)
copy/part

5.2.14. date!

A date! value comprises day, month and year numbers as well as, optionally, a time of day stored as a UTC time value with optional timezone information. The year number ranges from -214 to 214-1, but in literals it must lie between -9999 and 9999. Other values may be constructed using make or to (see sections 5.3.13 and 5.4.13). The UTC time is a non-negative time! value and the timezone is a signed time! value which varies between -15:45 and +15:45 in multiples of 0:15 (note that actual timezones vary between -12:00 and +14:00).

A date! value without time specified has time and timezone components none and is conceptually different from a date! value with time and timezone components 0:00; the former will be displayed as date-only, the latter will have time and timezone displayed; for computations, the former will effectively have time and timezone 0:00.

A <date-literal> may use a native Red format, or a subset of the representation defined by the ISO 8601 date and time standard.

S135
<date-literal> ::= <Red-date> | <Red-date>/<time> | <Red-date>T<time> | <ISO-date>T<time>
<Red-date> ::=  <year><sep><month><sep><day> | <day><sep><month><sep><year> |
                <day><sep><month><sep><short-year>
<sep> ::= / | -
<ISO-date> ::= <yyyy><mm><dd> | <yyyy>-W<ww> | <yyyy>-W<ww>-<d> | <yyyy>-<ddd>
<time> ::= <Red-time><zone>° | <ISO-time><zone>°
<ISO-time> ::= <hh><mm> | <hh><mm><ss> | <hh><mm><ss>.<decimals>
<zone> ::= Z | <sign><hours> | <sign><hours>:<minutes> | <sign><hh><mm>
<sign> ::= + | -

Date representation

The <year> part is a 3- or 4-digit number with an optional - sign. Years between -99 and 99 may be expressed using leading zeroes. The <short-year> part is an unsigned 1- or 2-digit number which is interpreted in the current (21st) century if it is smaller than 50, or in the previous (20th) century otherwise.

The <month> part is either a 1- or 2-digit unsigned number, or one of the month names which are stored in system/locale/months (both the full names and the first 3 characters of each name are allowed, and they are case-insensitive). For the default locale, these names are:

January February March April May June July August September October November December

The <day> part is a 1- or 2-digit unsigned number.

The separator <sep> must be the same in both positions. With a negative year in last position it is recommended to use / rather than -.

The <yyyy> part is an unsigned 4-digit number indicating the year, the <mm> and <dd> parts are unsigned 2-digit numbers indicating the month and day. The <ww> part is an unsigned 2-digit number indicating the week number as defined by the ISO 8601 standard, with the <d> part a single digit 1 to 7 for the day of the week (1 = Monday). When <d> is absent, the default is 1. The <ddd> part is an unsigned 3-digit number indicating the day of the year (1 to 366).

The combination of year, month and day is checked for validity.

Time representation

For <Red-time> see rule S113. The <hh> <mm> and <ss> parts are 2-digit unsigned numbers indicating the hours, minutes and seconds respectively. For <decimals> see rule S113.

The time of day is in the 24-hour system and is used modulo 24:00 with a possible carry resulting in increasing the date. Note that it represents local time.

The timezone may be represented as in rule S113, with <hours> being a 1- or 2-digit number, and <minutes> having 2 digits, or in the ISO time format. The meaning of Z is 0:00. The value is used modulo 16:00 and is rounded down in multiples of 00:15.

Note that all dates are understood to be in the (proleptic) Gregorian calendar. This has particular significance for the check on the validity of the date 29-Feb, since the leap years are computed according to that calendar both for present and future, but also for all past years, including before 1582 AD.

Examples: 20170705T175800Z, 5-Jul-2017/19:58+2:00 ; these values are equal.

5.2.15. refinement!

S136
<refinement-literal> ::= /<symbol-literal>

For <symbol-literal> see section 5.2.5.

A <refinement-literal> may contain a digit 0-9 or ' as first character after the /. However, the combinations /<> and /<…​> with any characters in between the < and > character will be lexically analyzed as the word / followed by the word <> resp. a value of type tag! (see section 5.2.11).

Note that one of the main uses of refinement values is in indicating optional arguments of functions. As will be seen in section 5.3.8, these optional arguments are of the restricted form /<word-literal>.

Examples: /abc /Abc /ABC /1a ; the first three are equal refinement! values.

5.2.16. issue!

S137
<issue-literal> ::= #<symbol-literal>

For <symbol-literal> see section 5.2.5.

An <issue-literal> may contain a digit 0-9 or ' as first character after the #. However, the combinations #<> and
#<…​> with any characters in between the < and > character are not allowed.

Examples: #abc #Abc #ABC #10FFFF ; the first three are equal issue! values.

5.3. Creation of values (make)

For some types, the values can only be introduced in a program as a result of the make function. This section deals first of all with the types for which that is the case, and with map! which has a "parallel" syntactic form of its own. The make function can also be used to construct values of other types. This is dealt with in the latter part of the section.

Note that make routine! is forbidden; values of type routine! should be made by invoking the built-in function routine which raises an error if called from the interpreter. As noted before (section 4.2.7) values of type datatype!, native!, action!, handle! and event! may not be made using make.

In this section, non-terminals like <integer> do not stand for a literal integer but for a value (to be evaluated) of integer! type etc. Note also that, as stated above, the first argument of make does not have to be a datatype! value; if it is a value of another type, that type is taken to be the desired type. This is not made explicit in the following rules, except in the case of make object! where an object! value as second argument has a different interpretation.

Furthermore, non-terminals like <typeset-name> stand for a bound <word-literal> referring to a typeset! value etc.

For all types in series! except image!, and for map!, make is defined with a <spec> which is an integer! or float! value: the float! value is truncated; the integer or truncated number is used to create an empty series! or map! value with storage for the given number of components reserved. For vector!, the components are initialized (see section 5.3.3).

5.3.1. typeset!

S124
<typeset> ::= make typeset! [<typeset-element>*]
<typeset-element> ::= <typeset-name> | <datatype-name>

Examples:

number!: make typeset! [integer! float! percent!]
scalar!: make typeset! [char! number! time! date! pair! tuple!]

Note that an empty typeset is allowed (make typeset! [ ]).

5.3.2. hash!

S125
<hash> ::= make hash! <block>

The contents of the <block> are copied (not deeply).

5.3.3. vector!

S126
<vector> ::= make vector! <vector-spec>
<vector-spec> ::= <block> | [ <type-and-size> <block>]
<type-and-size> ::= char! 8 | char! 16 | char! 32 |
                    integer! 8 | integer! 16 | integer 32! |
                    float! 32 | float! 64 | percent! 32 | percent! 64

The components of the <block> should all have the same type char!, integer!, float! or percent!. If <type-and-size> are omitted, type is deduced from the contents of <block>, and size is the default size (32 bits for char! and integer!, 64 bits otherwise). If <block> is empty, the assumed type is integer! of size 32.

Note that make vector! <integer> and make vector! <float> produce a vector of integers of size 32, initialized to 0, in contrast to the general behaviour of make series! <integer> and make series! <float> (see the beginning of section 5.3). See REP #13

Examples:

make vector! []
make vector! [integer! 16 [1 2 3]]
make vector! [#"a" #"b" #"c"]`

5.3.4. image!

S127
<image> ::= make image! <image-spec>
<image-spec> ::= <pair> | [<pair> <tuple> <binary>°] | [<pair> <binary> <binary>°]

An image! value stores a sequence of RGBA (color + transparency) values for pixels, using 4 bytes in 1 word for each pixel, as follows: B in bits 0..7, G in bits 8..15, R in bits 16..23, A in bits 24..31. When extracting a single pixel (see also section 5.6), these values are encoded in a 4-element tuple! value as follows: the first 3 elements are R, G and B, and the last element is 255 - A. When setting a single pixel, a 3 or 4-element tuple has to be specified. Elements beyond the 4th are ignored, if there are 3 elements, A has the default value of 255 (fully opaque).

If <image-spec> is <pair>, the image is created with the given dimensions, and with all pixels having color 255.255.255 and transparency 255. If a <tuple> is specified, it should have 3 or 4 elements; any more are ignored. These elements determine the color and transparency of all pixels, in the manner as stated above. An <integer> is not allowed See issue 2883 If a single <binary> is specified, this should contain the sequence of colors of all pixels (three bytes per pixel, in the order R, G, B, stored by horizontal line). The number of triplets should match the image size, more bytes are ignored, fewer bytes are supplemented with bytes {00} for 0. The transparency for all pixels is set to 255. The second <binary>, if present, contains the transparency values (one byte per pixel, in the same ordering). Again, the number of bytes should match the image size. More are ignored, fewer are supplemented with bytes #{FF} for 255. If the previous item in the specification was a 4-element tuple, this <binary> is ignored.

Examples:

make image! 200x300, make image! [200x300 255.0.0]
make image! [2x2 #{FFFFFFCCCCCCBFBFBF0C0C0C} #{FFFFFFFF}]

5.3.5. bitset!

S128
<bitset> ::= make bitset! <binary> | make bitset! <bitset-spec> | charset <bitset-spec>
<bitset-spec> ::= <integer> | <char> | <string> | [<bit-position>*] | [not <bit-position>*]
<bit-position> ::= <integer> | <char> | <string> | <char> - <char> | <integer> - <integer>

A <binary> produces a bitset! value that is bit-by-bit equal to the binary! value. The difference between binary! and bitset! is that binary! values have components that are integers 0..255, with 1-origin index, while bitset! values have components that are logic! values (true = 1, false = 0), with 0-origin index. The built-in function charset is defined as shorthand for make bitset!, except that <binary> is not allowed as its argument. The <bitset-spec> that is an integer! value produces an "empty" bitset (all bits set to false) of size the nearest multiple of 8. In all other cases the <bitset-spec> provides a list of bit-position numbers, or ranges of them, that are to be set to true. The <char> is interpreted as the Unicode Codepoint number. A string! value is interpreted as the collection of all its component characters. Note that an integer! value used as <bit-position> should be non-negative, but need not be a valid Unicode Codepoint number. The length of the bitset is computed as the smallest multiple of 8 needed to fit the highest bit number (0-origin). An "empty" bitset created by charset [ ] is 8 bits (one byte) long. A <bitset-spec> that is a block starting with not produces the bit-by-bit complement of the bitset produced by the following bit-position numbers, while actually storing only these bit-positions. See issue #2609

Examples:

make bitset! 16
charset "abc"
charset [#"A" - #"Z" #"a" - #"z"]

The built-in function complement? will test if the bitset is a complemented one, i.e. if its complement is what is actually stored.

5.3.6. object!

S129
<object> ::= make object! <object-spec> | object <object-spec> | context <object-spec> |
             make <expression> <object-spec>
<object-spec> ::= <block>

The built-in functions object and context will invoke make object! on their argument. The <expression> must evaluate to a value of type object!.

If the first argument to make is object! this creates a new object as follows. A new context is created and associated to the object. The words of the new context (i.e. the fields of the object) are the words of all the set-word! values that are (first-level) components of the <object-spec>. The corresponding values are set to the unset value. The <object-spec> is bound to this context (see section 6.3.6). The bound block is then executed. See issue #3362 The class property of the newly created object is set to a unique integer.

If the first argument to make is an object! value, it serves as prototype. A new object is created whose associated context is a copy of the prototype’s context. The set-word! values that are (first-level) components of the <object-spec> are added to this context if they are not already present in that context. The <object-spec> is then treated as in the previous case. If there are no new fields, the class property of the new object is copied from the prototype; the new object is then said to be derived from the prototype. Otherwise, the new object receives a new class value.

Within the expressions making up the values of the fields of an object, the word self refers to the object as a whole, unless that word has been defined as a field of the object.

Two field names have special significance: on-change* and on-deep-change*. These should be defined as functions; on-change* will be called whenever any field of the object changes its value; on-deep-change* will be called whenever a component of a series or object value which is the value of a field, or a (sub-)component of that field — at any level of nesting — changes its value. In order to permit the triggering of the latter function, all series and object values have an owned property which may be set using the modify function. These facilities are used by the toolchain for the purposes of implementing the reactivity feature (see section 13.4) and hence for the implementation of the GUI system (see section 13.3). Detailed information about the implementation details may be found in the documents referred to in section 18.

An additional built-in function construct <spec> creates an object, but without executing the <spec> block. It has a refinement /with to specify a base object which will be extended with the (unevaluated) set-word/value pairs in <spec>; if any set-word in <spec> is the same as a field name of the base object, the associated value will replace the original field value. The words true yes on false no off and none will be evaluated to their logic! or none! value, except if the refinement /only is specified.

The built-in function extend takes an object! value as first argument and a set of key-value pairs as second argument of type block! hash! or map!. It will add the keys that are not present in the map, with their values, and replace the values for those keys that are already present. The keys and values are not evaluated. It is not yet implemented

5.3.7. error!

S130
<error> ::= make error! <error-spec>
<error-spec> ::= <integer> | <block> | <string>

For the fields of an error! value, and the structure of the error repertoire (system/catalog/errors) see section 12.1.

If the <error-spec> is an integer! value, it is used to find values for the type and id fields of the error! value which result in the code with that integer! value. The values of these two fields are then bound as described in section 12.1.

If the <error-spec> is a block! value, it should either contain two word! values which will be used for the type and id value of the intended error! value, or it should be an <object-spec> containing at least type: and id: fields, and possibly arg1 arg2 arg3 fields; in the former case, the type and id values will be bound as described in section 12.1; in the latter case, the <block> will be treated as described under rule S129; note that also in this case, the <block> will be executed.

Except in the case where an <object-spec> is provided, any fields other than type and id cannot be set by make. They should be set afterwards.

If the <error-spec> is a string! value, this will be used as arg1 for the error with type: 'user id: 'message.

Note that error! values all have class = 1.

5.3.8. function!

S131
<function> ::= make function! [<function-spec> <function-body>] | func <function-spec> <function-body> |
               has [<argument>*] <function-body> | does <function-body> | function <function-spec> <function-body>
<function-spec> ::= [<docstring>° <argument-spec> <return-spec>°]
<docstring> ::= <string>
<argument-spec> ::= <argument>* <optional-arguments>*
<argument> ::= <argument-name> <argument-doc>° | <argument-name> [<typeset-element>*] <argument-doc>°
<argument-name> ::= <word-literal> | '<word-literal> | :<word-literal>
<argument-doc> ::= <string>
<optional-arguments> ::= <function-refinement> <argument-doc>° <argument>*
<function-refinement> ::= /<word-literal>
<return-spec> ::= return: [<typeset-element>*] <docstring>°
<function-body> ::= <block>

For <typeset-element> see rule S124. Note that both in the <argument-spec> and the <return-spec> any <typeset-name> must refer to a pre-defined typeset value (see section 4.3). User-defined typesets may not be mentioned. See issue #3285

The <docstring> may be used to document the purpose and working of the function. Each <argument-doc> may be used to document the purpose and usage of the associated <argument>. In this connection, the <word-literal> of the <function-refinement> is also considered an <argument>. When present, the type(set)s specified for an <argument> will be used to check the type of the actual argument supplied. Otherwise, default! will be assumed. Likewise, when present, the type(set)s of the <return-spec> will be used to check the type of the result. The <word> s of the <argument> s following the <function-refinement>, if any, are to be matched with actual arguments, if the function application (see rule E110) specifies the corresponding <selector> (see rule S123). In that case, the actual argument corresponding to the selector is true, whereas otherwise both that argument and the optional arguments are none. The optional argument /local is conventionally used to list the local words of the function. It is normally put after any other optional arguments (in fact the built-in help function expects this to be the case). It is not usual, although not forbidden, to supply actual arguments for these local words.

The built-in function func is defined as shorthand for make function!. The built-in function has is defined as shorthand for a function without other arguments than local words, thus has [<arguments>] <block> is equivalent to func [/local <arguments>] <block>. The built-in function does is defined as shorthand for func [ ] <block> (no arguments at all). The built-in function function is similar to func, but it adds all set-words and words from iterators (e.g. foreach <word> and repeat <word>) found in the body to the list of local arguments.

5.3.9. routine!

S132
<routine> ::= routine <routine-spec> <routine-body>
<routine-spec> ::= [<docstring>° <routine-argument>* <locals>° <routine-return>°]
<routine-argument> ::= <word> <argument doc>° | <word> [<type-literal>] <argument-doc>°
<locals> ::= /local <routine-argument>*
<routine-return> ::= return: [<type-literal>]
<type-literal> ::= any-type! | <type-name>
<routine-body> ::= <block>

For <docstring> and <argument-doc> see rule S131. Note that routines do not have optional arguments, except /local. Note also that arguments and return spec must have a single type specified. If the argument has no type specified, any-type! is assumed. The <type-name> must be integer! float! or logic!, or one that has a Red/System struct! alias defined that describes a value slot of that type.see issue #2642 The <routine-body> must contain valid Red/System code.

Values of type routine! may not occur in programs submitted to the interpreter, and in programs submitted to the compiler, they may only occur preceded by a set-word (<word-literal>:).

The construction of routines requires a fairly deep knowledge of the Red runtime system and the representation and storage of argument and result values.

5.3.10. op!

S133
<op> ::= make op! <prefix-function>

For <prefix-function> see rule S101.

In contrast to action! and native! values which cannot be made by means of make, the user may create new infix functions of two arguments (operators), using make op!. The <prefix-function> should have exactly two arguments and no optional arguments, except possibly /local.

Example: &&: make op! func [a b][all [a b]].

5.3.11. map!

A map! value can be produced both as grouped value and by make. The specification is the same in both cases.

S134
<map> ::= #(<map-spec>) | make map! [<map-spec>]
<map-spec> ::= <key-value-pair>*
<key-value-pair> ::= <key><value>

Each <key> should be a value of a type in scalar!, any-word!, any-string! or binary!. All keys should be unique. If identical keys are encountered in the <map-spec> the value corresponding to the last one encountered is taken. Keys of any type within any-word! that do not differ in their symbol are considered identical for this purpose. See issue #2577

Note that values of logic! and none! type are not allowed as keys. Nevertheless true, false and none may occur in <key> position. Since the constituents of <map-spec> are not evaluated, these words will be treated as word! values. The same is true if they occur in <value> position.

The built-in function extend takes a map! value as first argument and a set of key-value pairs as second argument of type block!, hash! or map!. It will add the keys that are not present in the map, with their values, and replace the values for those keys that are already present. The keys and values are not evaluated.

5.3.12. port!

S135
<port> ::= make port! <port-spec>
<port-spec> ::= TBD

Note that port! values all have class = 2.

5.3.13. Other types

  • Making integer! values from logic! values: true → 1, false → 0 See issue #2644

  • Making logic! values from number! values: 0/0.0/0% → false, all else → true

  • Making a url! value from an any-list! value: the components (at least one is required) may be of any type; they will be form ed; the first component is assumed to be the protocol (e.g. http) and the second one, if any, to be the server address (e.g. www.red-lang.org); if the third one is an integer! value, this is assumed to be the port number (e.g. 80), otherwise the third and any following components are assumed to constitute the file path including — if the last one is an issue! value — a fragment.

  • Making a date! value from an any-list! value: the block should have 3 to 7 components; if any of them is a word! value, the value it refers to will be retrieved. The first 3 components should be of integer! type and are interpreted as year, month, day, or day, month, year if the first value is smaller than 100. Negative years may only occur in third position. If there are 4 or 5 components, the 4th should be a time! value for the time of day; a 5th component should be an integer! or time! value for the timezone. If there are 6 or 7 components, the 4th, 5th and 6th components should be hours (integer!), minutes (integer!), seconds (integer! or float!) for the time of day; a 7th component should be an integer! or time! value for the timezone. All values are checked for validity, and over- and under-flow in the date and time (e.g. 32 1 2017 ⇒ 1-Feb-2017 and 3 -10 0 ⇒ 02:50:00) is not allowed. The timezone value is treated as in <date-literal> (see section 5.2.14).

  • For the following types, make operates in the same way as to (see next section): none! char! float! percent! time! pair! any-word! refinement! issue! unset!.

5.4. Conversion of values (to)

Conversion is possible for selected combinations of source and target type. The list given below is meant to be exhaustive. A summary table is available elsewhere (see section 18).

Note that for each type that may occur as target type, there is a built-in function defined as shorthand: to-integer <spec> for to integer! <spec> etc.

5.4.1. Target types none! and unset!

The functions to-none and to-unset yield a none! resp. unset! value for any argument value.

5.4.2. Target type logic!

The function to-logic yields true for any argument value except false and none. Note that to logic! 0 yields true whereas make logic! 0 yields false! See issue #2645

5.4.3. Target types in any-string!

The function to-string yields the same result as the built-in function form (see section 11.1.1) except for

  • unset! and none! values: conversion is not allowed

  • binary! values: these will be decoded as UTF-8

  • any-list! values: the function will apply form to each component and concatenate the results

Note that to-string and form omit the "decoration", i.e. the : resp. ' for any-word! and any-path! values. But see issue #3409

The functions to-file, to-email and to-tag will perform the same conversion and yield a result of the appropriate type. The function to-url will operate analogously for none! and binary! values; a block! value has the same interpretation as for the make url! function.

5.4.4. Target types in any-list!

The function to-block yields a block with the argument as single component except for

  • string! values: first applies load (see section 11.1.1) and applies to-block to the result

  • typeset! values: yields a block with the individual types

  • any-block! and vector! values: yields a block with the components

  • any-object! and map! values: yields the same as body-of

The functions to-paren etc. will perform the same conversion and yield a result of the appropriate type.

5.4.5. Target type integer!

The function to-integer is defined for

  • any-float! and time! values: truncates the floating point value (seconds in the case of time!) towards 0

  • char! values: yields the Unicode Code Point number

  • binary! values: interprets the first 4 bytes as an integer (two’s complement notation) if there are fewer than 4 bytes, #{00} bytes are prepended before conversion

  • issue! values: interprets up to 8 characters, if possible, as a hexadecimal number; further characters are ignored; if the number of characters is odd and less than 8, the last one is ignored

  • string! values: yields the result of load or an error

  • date! values: yields the Unix epoch time value (see e.g. https://en.wikipedia.org/wiki/Unix_time) based on the time component adjusted to UTC; because of the limitations on integer values the date should be between 13-Dec-1901/20:45:52 and 19-Jan-2038/3:14:07; see also to-date below

5.4.6. Target types in any-float! and time!

The function to-float is defined for

  • integer! values: yields the corresponding float! value

  • time! values: yields the number of seconds

  • char! values: yields the Unicode Code Point number as float! value

  • binary! values: interprets the first 8 bytes as a floating point number (IEEE 754 binary64 format) if there are fewer than 8 bytes, #{00} bytes are prepended

  • string! values: yields the result of load or an error

  • any-list! values: these should contain two components of type integer! or float! the result is the first number times 10 to the power of the truncated second number

The function to-percent will perform the same conversions and yield a value of type percent!.

The function to-time will do the same and yield a time! value; in this case, the any-list! argument should contain one to three values; the first an integer! value for the hours; the second, if present, an integer! value for the minutes; and the third, if present, an integer! or float! value for the seconds.

5.4.7. Target type char!

The function to-char is defined for

  • number! values: yields the Unicode Code Point with the (truncated) number

  • binary! values: assumes UTF-8 encoding; decodes as many bytes as necessary to obtain a Unicode Code Point

  • any-string! values: yields the first character

5.4.8. Target type pair!

The function to-pair is defined for

  • number! values: yields the pair with two components equal to the (truncated) number

  • any-list! values: these should contain two integer! or float! values; yields the pair wih the (truncated) numbers as components

Note that a similar built-in function as-pair of two arguments is defined, which creates a pair out of the arguments.

5.4.9. Target type tuple!

The function to-tuple is defined for

  • binary! values: yields the first 12 bytes or fewer as tuple components; if only 1 or 2 bytes are present, components 0 are added

  • string! values: yields the result of load or an error

  • any-list! values: these should contain only integer! or float! values in the range 0..255; yields the first 12 components or fewer as tuple components; if only 1 or 2 values are present, components 0 are added

5.4.10. Target type binary!

The function to-binary is defined for

  • integer! and any-float! values: yields the corresponding 4 resp. 8 byte binary value

  • char! values: yields the 1 to 4 byte binary value corresponding to the Unicode Code Point number

  • tuple! values: yields the 3 to 12 bytes binary value corresponding to the tuple components

  • bitset! values: yields the corresponding binary value

  • string! values: yields the UTF-8 encoded binary value

  • any-list! values: these should contain only integer! or float! values; the binary equivalents are concatenated, using as few bytes as needed for each integer! value and 8 bytes for each float! value

  • image! values: yields a binary value with 4 bytes for each pixel

5.4.11. Target types in any-word!, refinement! and issue!

The function to-word is defined for:

  • char! values: makes a word! value with that single character

  • logic! and datatype! values: yields the word that refers to the value

  • string! values: yields the result of load or an error

The functions to-lit-word etc. perform the same conversions and yield the result as a value of the appropriate type.

Note that to-word none does not yield the word none, it raises an error.

5.4.12. Target type image!

The function to-image is defined for object! values that are faces i.e. derived from the face! object which describes a window in the Red GUI system. It yields the face such as it would be rendered on the screen, as an image! value. See further the documentation of the GUI system (reference in section 18).

5.4.13. Target type date!

The function to-date is defined for integer! values which are interpreted as Unix epoch time, i.e. the difference in number of seconds between midnight on 1 January 1970 and the desired date and time. This number can be both positive and negative and because of the limitation of integer numbers will yield dates between 13-Dec-1901/20:45:52 and 19-Jan-2038/3:14:07. Furthermore, it is defined for any-list! values which have the same interpretation as for make date! (see section 5.2.14) except that in this case, over- and under-flow are allowed and taken into account.

5.4.14. Additional conversion functions

  • to-hex takes an integer argument and produces the hexadecimal equivalent as a 16 character issue! value, with leading zeroes if needed

  • to-local-date returns the date with local zone

  • to-UTC-date returns the date with UTC zone

  • as-pair takes two integer arguments and combines them into a pair! value, thus as-pair x y is equivalent to to-pair reduce [x y]

  • as-color takes three integer arguments 0..255 and makes a tuple! value representing a color (RGB)

  • as-rgba does the same with four arguments, with additional transparency (RGBA)

  • as-ipv4 also has four arguments, and suggests an IPv4 address interpretation of the tuple

  • hex-to-rgb converts an issue! value representing a color with each component as one or two hexadecimal digits, to an equivalent tuple! value

  • uppercase and lowercase will work on values of type char! and any-string! and convert them to upper case or lower case respectively; they use the Unicode 7.0 case folding table (only character pairs with status C and S)

  • to-local-file converts a Red file path to the local system file path and to-red-file converts a local system file path to a Red file path (see section 11.3.2

5.5. Casting of values (as)

The casting facility applies to most of the series! types, and makes use of the fact that values of several different but related types have their component values stored in identical fashion. Therefore a change of type can be performed without copying any component values. Two groups of related types are involved: block!, paren!, any-path! on the one hand, and any-string! on the other. The type of the second argument should be in the same group as the (type of the) first argument. The result is a new value of the desired type, pointing to the components of the old value. Note the absence of hash! from the first group, explained by the fact that hash! values are stored differently from other any-block! values.

5.6. Components of values

Composite values can have their components extracted and changed by various means.

5.6.1. Indexing

Values that are sequences (with types in series! and bitset!) admit indexing by integers. As explained earlier, components of series! values are indexed from 1, while components of bitset! values are indexed from 0.

Built-in functions for indexing are pick for extraction and poke for changing, with the following specifications:

pick <source> <index>
poke <destination> <index> <value>

where <index> evaluates to a value of permitted index type given the type of <source> resp. <destination> and <value> evaluates to a value for the component type of <destination>.

Values of type integer! are permitted as <index> for all sequences. Additionally, for programming convenience, values of series! types may be indexed by logic! values, where true yields the first component and false the second component. Also, for pick, bitsets admit indexing by characters, strings and blocks (interpreted as in <bitset-spec>, see section 5.3.5), with the result being true if the component(s) with the corresponding Unicode Code Point number(s) is/are all true. For poke, the bitset component(s) thus indexed will (all) be set to the given <value> (true or false). In this connection if should be noted that, although the components of a value of type bitset! are of type logic!, with poke it is allowed to use values of any other type, where 0 and none set the bit to false, and all other values (including 0.0 and 0%) set the bit to true. Finally, images may also be indexed by pairs as coordinates, with the index being computed in accordance with the row-oriented storage of the pixels.

Path expressions may also be used. The correspondence is as follows:

pick <source> <index> <==> <source>/<index>
poke <destination> <index> <value> <==> <destination>/<index>: <value>

Here <source> and <destination> must be a <path-head>, see rule S113. The <index> must be a single value or an expression of an allowed type. Note that for lexical reasons, a char!, string! or pair! value used as index in path expressions must be enclosed in parentheses. A block! value is not allowed in this position, not even in parentheses, and neither is a logic! value. Note also that selecting a component which is a value of type any-function! by means of a path expression will evaluate the component, and thus lead to its application, whereas selection by pick will not. See issue #3482

Note further that path expressions cannot be used to index file! and url! values, as these path expressions will be interpreted as "extending" the file or url path, as explained in section 7.3.5.

Values of the direct types time!, date!, pair! and tuple! also admit component selection by "indexing". In the case of tuple! values, this indexing treats the tuple as a sequence. In the other cases, the indexes are defined to correspond to named components, which can therefore also be used in selection by "key" (see next section). The correspondences are as follows:

  • for time! values: 1 ~ hour 2 ~ minute 3 ~ second

  • for date! values: 1 ~ date 2 ~ year 3 ~ month 4 ~ day 5 ~ zone 6 ~ time 7 ~ hour 8 ~ minute 9 ~ second 10 ~ weekday 11 ~ yearday = julian 12 ~ timezone 13 ~ week 14 ~ isoweek

  • for pair! values: 1 ~ x (horizontal dimension, left to right) and 2 ~ y (vertical dimension, top to bottom).

The built-in functions first, second, third, fourth and fifth are defined as pick <expression> 1 etc.

Indexing with values outside the allowed range lead to an error for values of direct type, both in case of extraction and changing, and also for values of indirect type in case of changing; on component extraction of values of indirect type an index out of range yields a none result. See issues #3516 and #3517

5.6.2. Selection by "key"

This is possible for values that are sequences (with types in series!, but not bitset!), and for values of types object!, error!, port! and map!. A restricted facility also exists for values of type time!, date!, pair!, email!, image! and event!.

Built-in functions for selection are select for extraction and put for changing, with the following definitions:

select <source> <key>
put <destination> <key> <value>

The semantics are different in the two main cases (sequences vs. objects/maps).

  • For extraction in sequences, a case-insensitive find action is performed on the components using the key, which should be a single value of a type allowable for find, or a sequence of such values, and the result is the component after the first occurrence of the key (single or sequence) if found, and none otherwise.

  • For extraction in the other types, which contain key/value pairs, the result is the value corresponding to the given key. If there is no such key in a map! value the result is none; in case of an object!, port! or error! value the result is an error.

  • For changing a value in sequences, the key should be of a type in scalar!, any-string!, any-word! or binary!, and the destination should be of a type in any-block!. See issue #1960 If the find action in unsuccessful, both the key and the corresponding value are appended to the destination; otherwise, the value after the found key is replaced.

  • For changing a value in maps, the key should likewise be of a type in scalar!, any-string!, any-word! or binary!. Again, if the find action in unsuccessful, both the key and the corresponding value are added to the map; otherwise, the value associated with the found key is replaced. Setting a map component to none removes the component and its key from the map.

  • For changing a value in objects, the key should be a word that is a valid field name, and the value of that field is replaced; otherwise, an error is raised. An additional facility, for setting all components of an object is provided by the set function with an object! first argument, and a block of component values as second argument. If the second argument is none, all components will be set to none.

  • Fields of error! values cannot be set.See issue #2554

  • Fields of port! values TBD

Path expressions may also be used for selection. The correspondence is as follows:

select <source> <key> <==> <source>/<key>
put <destination> <key> <value> <==> <destination>/<key>: <value>

The same lexical restrictions apply as noted above for indexing. Also in this case, selecting a component which is a value of type any-function! by means of a path expression will evaluate the component, and thus lead to its application, whereas selection by select will not. See issue #3482

Values of type time!, date!, pair!, email! and image! also admit component selection by specific words, and values of type event! have this as the only way of selection. However, here the selection is only possible by <path> and <path>: expressions, not by select and put. The allowed values of the keys for each of these types are stored in system/catalog/accessors.

In case of time!, date!, email!, image! and event!, the result is obtained by performing a certain calculation, as follows.

Extracting a component:

  • time! values: given the stored number of seconds, the hour and minute components are the result of finding the whole number of 3600 seconds in the total, and then the whole number of 60 seconds in the remainder; the second component is what remains after that (this is a float! value)

  • date! values: the date year month day zone time hour minute and second components are extracted either directly or as in the case of time!; the timezone component is equal to the zone component on extraction; the others are the result of a calculation: the weekday component is a number between 1 and 7 (1 = Monday), the yearday component is the ordinal number of the date in the current year (1 = first of January), the week component is the week number according to a casual definition (week starts on Sunday, first week starts on January 1st), and the isoweek component is the week number according to the ISO 8601 standard;

  • email! values: the user component is the part before the @ and the host component is the part after the @; both are of type string!

  • image! values: the size component is the pair! value that holds the dimensions, the argb, rgb and alpha components are the binary! sequences of ARGB, RGB and A values respectively

  • event! values: the components, which are explained in the Red GUI documentation (see section 18) are calculated in an OS-dependent way

Setting a component:

  • time! values: the hour, minute and second components can be individually set and will replace the values they had before

  • date! values: the date, year, month, day, hour, minute, second and zone components can be set directly; the value for the time component (which can be negative) is used modulo 24:00 with adjustment of the date; the same holds for the resulting time when any of the values of the hour, minute and second components is changed; setting the timezone component results in a date! value with the corresponding zone component and a changed time component such that the UTC time value is unchanged; setting the week or isoweek component results in a date! value having the date of the first day in the indicated week; setting the weekday component results in a date! value with the corresponding date in the same week; setting the time component to none will ensure that the time and timezone components will not be displayed, and that for computations they have the value 0:00

  • email! values: the user and host component values should be supplied as strings

  • image! values: the size component cannot be set; the other components can be set to a binary! value of the required length; if the value is shorter, bytes #{00} are appended; if the value is longer, the remainder is ignored; a tuple! value can also be supplied, its components will be used for each pixel; if an integer! value is supplied, its 4 bytes will be similarly used see issue #2883

  • event! values: only the type component can be set to a word! value

Selection by a key of the wrong type or wrong value leads to an error.

5.6.3. Overview table

type index values built-in functions key values or types built-in functions

time!

1 2 3

pick

hour minute second

date!

1 .. 14

pick

date year month day zone time hour minute second weekday yearday julian timezone week isoweek

pair!

1 2

pick

x y

tuple!

1 .. 12

pick

any-block!

integer! logic!1

pick poke

any-type!

select put

vector!

integer! logic!1

pick poke

char! integer! float!2

select3

string!

integer! logic!1

pick poke

char! any-string! binary!

select3

email!

integer! logic!1

pick poke

char! any-string! binary! host user

select3

file! url!

integer!1 logic!1

pick poke

char! any-string! binary!

select3

binary!

integer! logic!1

pick poke

integer! char! any-string! binary!

select3

image!

integer! pair!

pick poke

size rgb alpha argb

bitset!

integer! char! string! block!

pick poke

map!

scalar! any-word! any-string! binary!

select put

object!

word!

select put

error!

code type id arg1 arg2 arg3 near where stack

select

port!

spec scheme actor awake state data

select put(TBD)

event!

type face window offset key picked flags away? down? mid-down? alt-down? aux-down? ctrl? shift?

Notes:

  1. not in path expressions

  2. See issue #2625

  3. See issue #1960

5.7. Reflection on values

Values of some types have (internal) properties of interest to the user which may usefully be exposed.

This concerns first of all any-word! values for which information on their binding may be obtained by means of two built-in functions: context? and index?. These are explained in section 6.2. See REP #14.

The function complement? is described in section 5.3.5.

The function face? tests if an object is derived of the face! object which is explained in section 13.3.

Functions on vector! values have been requested see REP #12

For values of types date! email! event! image! pair! time! which admit component selection by "key" (see section 5.6.2), the allowed key values are available from system/catalog/accessors which is a block of pairs <type-name><block of key words>.

For values of type object!, error!, port! and map!, which consist of key/value pairs, the collection of keys, that of values, and the set of key/value pairs may each be obtained as a block by means of the built-in functions words-of values-of and body-of. For convenience, keys-of is defined as synonym for words-of. In addition, for objects there is the property class-of which yields the unique number that is given to each object that is created from a <spec>, and is inherited by objects derived from it (see rule S129). This property is 1 for error! values, and 2 for port! values.

For any-function! values, one can obtain the full <argument-spec> through the built-in function spec-of and the list of formal argument names through the function words-of not yet implemented. For function! and routine! values, there is in addition the function body-of which yields the function/routine body.

All functions <property>-of <expression> are shorthand for the general function reflect <expression> <property> e.g. words-of <expression> is defined as reflect <expression> 'words.

For series! values, the property owned has been defined which is notably used by the reactivity facility (see section 13.4). This property can only be obtained by reflect <expression> 'owned. see issue #1957

Note that the help built-in function is typically making good use of these reflection facilities.

5.8. Comparison of values

Red has the following operators and corresponding native! functions for comparison of two values. Each of these operators/functions allows arguments of any type, although in most cases the comparison may only yield true if the two types are the same. Exceptions will be noted below. The equality functions, i.e. the first four, are defined for all types of the arguments. They always yield a value of type logic!, never an error. The others (the ordering ones) are only defined for certain combinations of types and yield an error otherwise. Also this will be noted.

operator native function

=

equal?

==

strict-equal?

=?

same?

<>

not-equal?

<

lesser?

<=

lesser-or-equal?

>

greater?

>=

greater-or-equal?

5.8.1. Equality comparisons

The strictest equality test is same? which yields true only if the two values are of the same type and the two value slots (see section 4.2.2) have identical content. For values of direct types this comes down to simple equality, but for values of other types it is quite possible to be equal but not the same (e.g. two strings of identical content, but one a string literal and the other the result of decoding a binary! value).

For two values to succeed the strict-equal? test, they have to be of the same type and also have exactly the same value, i.e. not have the differences allowed for the equal? test.

The equal? test ignores case differences in the spelling of words (values of types in all-word!) and strings (values of types in any-string!), and in the case of floating point numbers, a very small difference (1 in 1016) in actual value.See also issue #2658

For values of any-block! type, the strict-equal? and equal? tests apply pairwise to the components. For any-object! the requirements are identity of field names and (strict) equality of field values. If the components or field values are also of any-block! or any-object! type, there is recursion involved, with cycle detection. For values of vector! type, these tests also apply pairwise to the components. In addition, the component type (char! integer! float! or percent!) must be the same, but the component size in bits may be different.

In all cases, for the equal? and not-equal? test, the requirement of equal type is relaxed for several combinations of types of the two values.

  • char! and integer! See issue #2650

  • integer! float! and percent!

  • any-word! and refinement! (note the absence of issue!)

  • any-string!

  • any-object! See issue #2657

If the combination of types of the two values is not allowed as detailed above, the not-equal? test will yield true and the other three equality tests will yield false.

Note that the function find uses an equality test which differs from strict-equal? in that it ignores case differences in values of types in any-word! and any-string! (see section 9.2).

5.8.2. Ordering comparisons

The following cases can be distinguished:

  • straightforward numerical ordering: char! integer! float! percent! time! and date!

  • lexicographic ordering (case sensitive): pair! tuple! any-word! refinement! issue! vector! any-string! binary! and bitset!; with pairs, the y component is tested before the x component

  • lexicographic ordering (with recursion and cycle detection): any-block! and object!; for objects, the numbers of fields are compared first, and if they are unequal, the field contents are not tested further

  • no comparison: datatype! typeset! none! logic! image! map! error! port! function! routine! action! native! op! handle! event! and unset!.

As a rule, for ordering comparisons the types of the two values have to be the same. See issue #2662 For vector! values, the component type (char! integer! float! or percent!) must also be the same (the size in bits of the components may differ).

For some combinations of types this requirement is relaxed, in the same manner as for equality comparisons.

If the combination of types of the two values is not allowed as detailed above, or if no comparison is defined, the comparison will raise an error.

6. Words, contexts and binding

6.1. Words

Red uses words (values of type word!) to access values in much the same way that other languages use variables. However, in Red, words do not "store" values. Rather, a word refers to a value in some context. i.e. evaluating the word in that context yields the value. The word is said to be bound to, or in the context. Since functions, including built-in functions and operators, are also values in Red, the words that refer to these values appear to work like keywords in other languages.

Thus all word! values have two important properties in this regard: their symbol, that is their spelling (disregarding case), and the context they are bound to. Something words do not have is a restriction on what values they can refer to. In Red, values are strongly typed, but words, when used like variables or keywords, are not.

For practical purposes, words are internally represented by three items: a pointer to a context, an index in a symbol table which contains the symbol, and an index in the context which facilitates retrieving the value the word refers to. Each occurrence of a word carries these three items individually, and each occurence of a word with the same symbol can therefore be bound to a different context, and refer to a different value. Values of types lit-word! set-word! and get-word! (these types form typeset any-word! with word!) have the same binding as the word with the same symbol. Values of types refinement! and issue!, although not bindable, may share that same symbol.

6.2. Contexts

A context in Red is a collection of word/value pairs. The words in this collection are all different, and the values are the values the words refer to. One can think of it as a table composed of two columns, where the first is a list of unique symbols and the second contains a corresponding value for each. Each word that is bound in this context has its symbol and the value it refers to, positioned in a row of the table. The value can be retrieved by finding the symbol, or by using an index (row number) in the table. Note that such tables actually exist in the implementation as values of an internal pseudo-type.

There is one global context containing all words that have passed lexical analysis as well as those that have been pre-defined in the toolchain, and which refer to values such as built-in functions and constants. Words in the global context that are not pre-defined, are considered "unset", which is a special kind of value, distinct from none.

In addition to the global context, any number of contexts may exist during program execution. Every object (value of type object!) gives rise to a context, containing the field-name/value pairs of the object. From an implementation viewpoint, an object is just a combination of a context and a class. Every error (value of type error!) is a specialized object, and therefore also has a context associated with it. Every function (value of type function!) also gives rise to a context, which contains the pairs of formal argument name and actual argument value to be used by the body of the function when it is executed.

The user may access the context of a word reflectively through the built-in function context? which can be applied to any word and will yield the context the word is bound to. Since contexts themselves are not values of a type of the language, they are yielded in the form of an object or function as the case may be. If the word is an argument or refinement of a function (value of type function!), the context is yielded as that function. The context of a word which is a field name of an error value is yielded as an object having the same field names and values as the error. The context of a word which is not a field name of an object is the global context, and is thus yielded as the object system/words. Otherwise, the context is yielded as the object of which the word is a field name. The index of a word in its context may be obtained through the built-in function index?.

6.3. Binding

Words are bound to contexts as a result of:

  • lexical analysis

    • notably when the program containing the words is submitted to the toolchain

    • or through application of the built-in load function

    • or when a string representing some values, including words, is submitted to the REPL

  • applying the built-in set function

  • evaluating an expression consisting of a set-word! value followed by another expression

  • evaluating a make object! <spec> construct

  • making an error! value

  • applying a function to its arguments

  • applying the built-in bind function

  • applying the built-in in function

Details of the binding process in these cases are given in the following sub-sections.

Note that a word bound to a context does not necessarily have a value. The built-in function value? tests if it does.

6.3.1. Lexical analysis

Every lexeme that is recognized in the source text as representing a value of a type in any-word!, either by the operation of the toolchain or — at runtime — by the load function, is bound to the global context, and will initially refer to the unset value in that context.

6.3.2. Setting words to values

The evaluation of <word-literal>: <expression> is treated in rule E105. Equivalent to this is the application of the built-in function set: <word-literal>: <expression> ~ set '<word-literal> <expression>.

The counterpart to set is unset: this will make the word argument refer to the unset value.

6.3.3. Object creation

This is treated in rule S129.

6.3.4. Making an error! value

This is treated in rule S130 and in section 12.1.

6.3.5. Function application

This is treated in rule E110.

6.3.6. Built-in bind function

The built-in function bind has two arguments: a value of type any-word! or a block containing, amongst others, such values, and a context.

For brevity, values of type any-word! will be called "words" in the rest of this section. The function will try to change the binding of a single word or of all words in the block, and will return the (modified) word or block. It will treat words at any depth within the block and its sub-blocks (including values of type paren! path! lit-path! set-path! get-path! and hash!).

For each word to be treated it will search for the presence of an equally spelled word in the given context, which is supplied in the form of a word (whose context will be used), or of an object or error value or a function. If an equally spelled word is found, the function bind will change the context of the treated word to that given context and will adapt the index of the word; otherwise, the word is left untouched.

With the /copy refinement the block! argument will be deep-copied before it is modified.

A major application of this function is the binding of the formal arguments of a function, as they occur within the function body, to the context which contains the actual argument values. See evaluation rule E110.

6.3.7. Built-in in function

The built-in function in has two arguments: an object!,error! or port! value and a word.

It will bind the word to the object, error or port context, and yield the word thus bound as result.

The following equivalence may be observed, where o is an object with field f:

:o/f <==> get in o 'f

7. Evaluation rules

General remark: operator application has precedence over application of other functions and over set-word target evaluation. Note that in Red all operators (values of type op!) are binary infix functions. See further rule E112.

The operation of the toolchain will result in the evaluation of the Red source text presented to it. The user can, at runtime, achieve evaluation of a (fragment of) Red source, i.e. Red data, by invoking the built-in function do (see section 7.6).

7.1. Passive types

E100

For all values of passive types evaluation yields the value itself. This is called the identity rule.

Note that block! is one of the passive types. Thus evaluation of a block leaves the block unchanged. The term execution of a block will be used to indicate sequential evaluation of the components of the block; the result of this execution is the result of the last evaluation, if any, and the unset value otherwise. See also section 7.5.

7.2. Decaying types

These are lit-word! and lit-path!.

E101

Evaluating a lit-word! value results in its word! counterpart.

E102

Evaluating a lit-path! value results in its path! counterpart.

The built-in function quote will yield its argument, which may be of any type, without evaluating it. In particular quote <word-literal> is equivalent to '<word-literal>, and quote <path-literal> is equivalent to '<path-literal>.

7.3. Active types

7.3.1. word! type

E103

Evaluating a word! value proceeds as follows:

  1. Determine the context to which the word is bound.

  2. Obtain the value that the word refers to in this context.

  3. Determine the type of this value.

    1. If the type is unset! raise an error.

    2. If the type is in any-function! apply the function (see rules E110-114).

    3. Otherwise, the result is the value referred to.

Note: there are cases in which a <word> is not to be evaluated, e.g. when it occurs as <key> or <value> in a <map-spec>, or when it is an actual argument to a function where the formal argument is a lit-word!. In these cases, all predefined words, in particular true false and none will be interpreted as word! values rather than as logic! or none! values. To represent values of the desired type in such cases one may use the generalized value construction syntax: #[true], #[false], #[none].

The built-in function get with a word! argument applies the above rule except when the type of the value referred to is in any-function! in which case no function application occurs. Moreover, with the refinement /any no error occurs if the word! value refers to the unset value.

7.3.2. get-word! type

E104

Evaluating a get-word! value proceeds as follows:

  1. Determine the context to which the word is bound.

  2. Obtain the value that the word refers to in this context and yield this as result.

Note that the difference with evaluating a word! value is that no errors are raised and that a function value is not applied but is itself yielded as result.

7.3.3. set-word! type

E105

Evaluating a set-word! value outside an <object-spec> or a <map-spec> has the effect that the <word> in its context is made to refer to the value obtained by evaluating the next expression. An error occurs if no expression is following or if the value obtained is unset. The result of the evaluation is the value obtained from the expression. As a consequence, set-words may be "chained", thus: a: b: c: 1 is equivalent to a: (b: (c: 1)) and thus to a: 1 b: 1 c: 1.

As stated before, the alternative to <word-literal>: <expression> is set <word-literal> <expression> which is a special case of set <word> <expression>. The built-in function set has a refinement /any which will ensure that no error occurs if the expression yields the unset value.

7.3.4. paren! type

E106

The evaluation of a paren! value proceeds by the evaluation of its component values. The result is the value obtained from the last evaluation. This is similar to the execution of a block. The following table compares parens and blocks.

expression          result of evaluation    comment
[1 + 2 3 + 4]         [1 + 2 3 + 4]         block! is passive type
do [1 + 2 3 + 4]      7                     do forces execution
(1 + 2 3 + 4)         7                     paren! is active type
quote (1 + 2 3 + 4)   (1 + 2 3 + 4)         quote inhibits evaluation

7.3.5. path! type

Recall the structure of path! values:

(S123)
    <path-literal> ::= <path-head>/<selector>
    <path-head> ::= <word-literal> | <path-literal>
    <selector> ::= <integer> | <word-literal> | :<word-literal> | <paren>
E107

The evaluation of a path! value proceeds as follows:

  1. Start with the first path component. Evaluate this <path-head>, which is a <word>, as per rule E103.

  2. If there is no next element which is a <selector>, use the value of the <path-head> as intermediate result and go to step 4.

    1. Otherwise, determine the type of the evaluated <path-head>.

    2. If the result is a value of composite type (except file! and url!), and there is a next element which is a <selector>, this will yield a component of the composite value as described in step 3.

    3. If the result is of file! or url! type and there are one or more next elements each of which is a <selector>, the result is a new file or url composed as <path-head>/<selector>/…​

    4. If the result is a value of any-function! type, each following <selector>, if any, should be an actual refinement of the function, i.e a word! value, corresponding to one <function-refinement> present in the <argument-spec> of the function. Apply the combination of the result and the actual refinements according to the rules for values of function types (see section 7.4).

    5. Otherwise, the path is in error.

  3. Determine the type of the <selector>.

    1. If the <selector> is a <get-word> or a <paren>, evaluate it first, use the value obtained as <selector> and go to the beginning of step 3.

    2. If the <selector> is an <integer>, and the composite type is not map! or any-object!, the intermediate result is the component of the composite value at the index given by the integer! value (0-origin for bitset! values, 1-origin for values of all other composite types).

    3. If the composite type is any-object! and the <selector> is not a <word> the path is in error.

    4. If the composite type is map! and the <selector> is not of a type in scalar! any-word! any-string! or binary! the path is in error.

    5. If the <selector> is a <word>, and the composite value is of direct type, image!, email! or event!, an intermediate result is obtained as explained in section 5.6.2.

    6. If the composite value is of indirect type (except image! and email!), an intermediate result is obtained by applying the built-in function select with as arguments the composite value and the <selector>.

    7. Otherwise, the path is in error.

    8. If a further <selector> is present, use the intermediate result just obtained as evaluated <path-head> and go to step 2.

  4. Determine the type of the intermediate result just obtained.

    1. If the type is unset! raise an error and yield the unset value as result.

    2. If the type is in any-function! apply the function (see rules E110-114).

    3. Otherwise, the result is the intermediate result just obtained.

The built-in function get with a path! argument applies the above rule except when the type of the value referred to by the <path-head> is in any-function!. If there isn’t any <selector>, no function application occurs, and the result is the function value. If there is a <selector>, an error is raised. Moreover, with the refinement /any no error occurs if the path! value refers to the unset value.

7.3.6. get-path! type

See also rule E107.

E108

The evaluation of a get-path! value proceeds as follows:

  1. Start with the first path component. Evaluate this <path-head>, which is a <word>, as per rule E103.

  2. If there is no next element which is a <selector>, use the value of the <path-head> as intermediate result and go to step 4.

    1. Otherwise, determine the type of the evaluated <path-head>.

    2. If the result is a value of composite type (except file! and url!), and there is a next element which is a <selector>, this will yield a component of the composite value as described in step 3.

    3. If the result is of file! or url! type and there are one or more next elements each of which is a <selector>, the result is a new file or url composed as <path-head>/<selector>/…​

    4. If the result is a value of any-function! type, no following <selector> is allowed and the result is the function value.

    5. Otherwise, the path is in error.

  3. Determine the type of the <selector>.

    1. If the <selector> is a <get-word> or a <paren>, evaluate it first, use the value obtained as <selector> and go to the beginning of step 3.

    2. If the <selector> is an <integer>, and the composite type is not map! or any-object!, the intermediate result is the component of the composite value at the index given by the integer! value (0-origin for bitset! values, 1-origin for values of all other composite types).

    3. If the composite type is any-object! and the <selector> is not a <word> the path is in error.

    4. If the composite type is map! and the <selector> is not of a type in scalar! any-word! any-string! or binary! the path is in error.

    5. If the <selector> is a <word>, and the composite value is of direct type, image!, email! or event!, an intermediate result is obtained as explained in section 5.6.2.

    6. If the composite value is of indirect type (except image! and email!), an intermediate result is obtained by applying the built-in function select with as arguments the composite value and the <selector>.

    7. Otherwise, the path is in error.

    8. If a further <selector> is present, use the intermediate result just obtained as evaluated <path-head> and go to step 2

  4. Determine the type of the intermediate result just obtained.

    1. If the type is unset! yield the unset value as result.

    2. Otherwise, the result is the intermediate result just obtained.

7.3.7. set-path! type

E109

The evaluation of a set-path! value proceeds as follows:

  1. Start with the first path component. Evaluate this <path-head>, which is a <word>, as per rule E103.

  2. If there is no next element which is a <selector>, use the value of the <path-head> as intermediate result and go to step 4.

    1. Otherwise, determine the type of the evaluated <path-head>.

    2. If the result is a value of composite type (except file! and url!), and there is a next element which is a <selector>, proceed to step 3.

    3. Otherwise, the path is in error.

  3. Determine the type of the <selector>.

    1. If the <selector> is a <get-word> or a <paren>, evaluate it first, use the value obtained as <selector> and go to the beginning of step 3.

    2. If the <selector> is an <integer>, and the composite type is not map! or any-object!, the intermediate result is composite value at the index given by the integer! value (0-origin for bitset! values, 1-origin for values of all other composite types).

    3. If the composite type is any-object! and the <selector> is not a <word> the path is in error.

    4. If the composite type is map! and the <selector> is not of a type in scalar! any-word! any-string! or binary! the path is in error.

    5. If the <selector> is a <word>, and the composite value is of indirect type (except any-object! map! image! and email!), the intermediate result is the composite value at the index found by applying the built-in function find with as arguments the composite value and the <selector>.

    6. If the <selector> is a <word>, and the composite value is of direct type, image! or email!, an intermediate result is obtained which is the component found as as explained in section 5.6.2.

    7. If the composite value is of type object! or map!, the intermediate result is the key/value pair whose key is the <selector>

    8. Otherwise, the path is in error.

    9. If a further <selector> is present, use the component at the index just determined, respectively the value of the key/value pair as evaluated <path-head> and go to step 2

  4. Replace the component at the index determined, respectively the value of the key/value pair, by the value obtained by evaluating the next expression. An error occurs if no expression is following or if the value obtained is unset. The result of the evaluation is the value obtained. As a consequence, set-paths may be "chained", also with set-words, thus: a/b/c: d/e/f: g: 1 is equivalent to a/b/c: 1 d/e/f: 1 g: 1.

Moreover, the alternative to <path-literal>: <expression> is set <path-literal> <expression> which is a special case of set <path> <expression>. The built-in function set has a refinement /any which will ensure that no error occurs if the expression yields the unset value.

7.4. Function types

Evaluation of a value of any-function! type involves application to its arguments, if any, and this together with any actual refinements (word! values that are found as <selector> in a path! value whose <path-head> evaluates to the any-function! value). Exceptions to this rule are:

  • if the value is the result of component selection by pick or select (see section 5.6)

  • if the value is argument to the do function (section 7.6)

In these cases the function will not be applied (passive evaluation).

Recall the basic structure of the <argument-spec>, which is valid, with some limitations, for all values of any-function! type except op! values:

(S121)
<argument-spec> ::= <argument>* <optional-argument>*
<argument> ::= <argument-name> | <argument-name> [<typeset-element>*]
<argument-name> ::= <word> | '<word> | :<word>
<optional-argument> ::= <function-refinement> <argument>*
<function-refinement> ::= /<word>

TBD: apply

7.4.1. function! type

E110

The application of a function! value (also called function call or function application) proceeds as follows:

  1. If the function does not have any arguments (optional or not), execute the body of the function to yield the result of the function.

  2. If the function has any arguments (optional or not), create a context specific to this function value, with all the words (including values of type lit-word! get-word! and refinement!) occurring in the <argument-spec>. Make all these words initially refer to none.

    1. Evaluate as many subsequent expressions as needed to obtain values corresponding to the non-optional arguments, except: When the <argument-name> is a '<word>, then if the next value is a :<word> or :<path> or <paren>, evaluate this to fetch the value it refers to; else pass the next value as-is. If the <argument-name> is :<word>, do not evaluate the corresponding expression but yield its first <value> as-is; do not raise an error if this value is unset. See issue #2622 Make the <word> of each <argument name> refer to the corresponding value. Check the type of each value against the type(set)s specified for the argument.

    2. If actual refinements are present, match each of them with the corresponding <function-refinement> in the <argument-spec>. Make the <word> of the <function-refinement> refer to true. Furthermore, process each <argument> following the <function-refinement> as in the previous sub-step, evaluating the necessary expressions and inserting the values obtained in the context.

    3. Bind the body of the function to the context (see section 6.3.6).

    4. Execute the body of the function to yield the result of the function. Check the type of the resulting value against the type(set)s specified with return:, if any.

Note that the order of the expressions to be supplied for the optional arguments is dictated by the order of the actual refinements present, not by the order of the <function-refinement> s in the <argument-spec>.

7.4.2. action! type

E111

As stated before, the definitions of the actions are fixed at the start of the toolchain’s operation. No new actions can be made by the user. In fact, during initialization of the toolchain, each action name (word! value) is made to refer to an action! value that consists of a spec similar to the <argument-spec> of a function, and an action number. Also, a table is prepared that contains the addresses of the primary Red/System functions that handle the actions, indexed by the action number (their names are the action names followed by *). Subsequently, a dispatch table (action table) is prepared that contains entries for each combination of action number and type of first argument for which the action is defined. As suggested before, this initialization will fill the entry with the address of a Red/System function handling the action for this combination, or with the address already determined for the combination of action and parent type of the given type (inheritance).

The application of an action! value then proceeds as follows:

  1. From the action number, determine the <argument-spec> of the action.

  2. Evaluate one or two expressions corresponding to the non-optional arguments. Evaluate expressions as needed for the optional arguments corresponding to the refinements specified, if any, and determine default values for the others.

  3. Call the primary Red/System function that handles the action with all the arguments in standard order. This will do the following:

    1. Determine the type of the first argument and look up the appropriate entry in the dispatch table.

    2. Call the Red/System function that the entry refers to, with all the arguments

    3. This Red/System function will check the type of the second argument, if any, and determine its operation on the basis of the (combination of the) argument type(s).

As with function! evaluation, the order of the expressions to be supplied for the optional arguments is dictated by the order of the actual refinements present, not by the order of the <function-refinement> s in the <argument-spec>.

7.4.3. op! type

E112

A value of op! type is always derived from a value of another any-function! type: function! action! native! or routine!. Moreover, an op! value always has exactly two arguments and no refinements. Therefore, the application proceeds as for the function etc. it is derived from, with the expression that precedes the op! value corresponding to the first argument and the expression following the op! value corresponding to the second one.

7.4.4. native! type

E113

As stated before, the definitions of the native functions are fixed at the start of the toolchain’s operation. No new natives can be made by the user. In fact, during initialization of the toolchain, each native name (word! value) is made to refer to a native! value that consists of a spec similar to the <argument-spec> of a function, and a native number. Also, a table is prepared that contains the addresses of the Red/System functions that implement the native functions, indexed by the native number (their names are the native names followed by *).

The application of a native! value then proceeds as follows:

  1. From the native number, determine the <argument-spec> of the native function.

  2. Evaluate as many expressions as correspond to the non-optional arguments. Evaluate expressions as needed for the optional arguments corresponding to the refinements specified, if any, and determine default values for the others.

  3. Call the primary Red/System function that handles the native function with all the arguments in standard order. This will call upon the full repertoire of runtime functions, notably the interpreter for executing the blocks of the control functions (if, either, repeat etc.).

As with function! evaluation, the order of the expressions to be supplied for the optional arguments is dictated by the order of the actual refinements present, not by the order of the <function-refinement> s in the <argument-spec>.

7.4.5. routine! type

Recall the basic structure of <routine-spec>:

(S132)
<routine-spec> ::= [<routine-argument>* <locals>° <routine-return>°]
<routine-argument> ::= <word> | <word> [<type-literal>]
<locals> ::= /local <routine-argument>*
<routine-return> ::= return: [<type-literal>]
E114

Values of routine! type may not occur in programs submitted to the interpreter.

When compiling, the toolchain will convert the routine into a Red/System function as follows:

  1. The <routine-spec> is converted into a Red/System function specification block by changing every Red type mentioned in it, except integer! logic! and float! to the corresponding Red/System struct! alias that describes the value slot, thus string! becomes red-string! etc.

  2. A routine argument or return without a type is given Red/System alias red-value! which corresponds to any-type!.

  3. The <routine-body> (which is a block of Red values) becomes the body of this Red/System function, and will be treated as Red/System code.

The function thus constructed becomes part of the intermediate Red/System code that the toolchain produces internally for compilation into machine code, and the application of the function will proceed according to the Red/System rules. The conversion of the argument types enables the function to correctly deal with the Red argument values. Likewise a returned value, if any, will have its correct Red type if the function correctly sets the Red/System struct! value.

Note that the precise mechanism for argument and return value passing is not described here.

7.5. Blocks: reduction and selective evaluation

As stated before, evaluation of a block leaves it unchanged. Execution of a block is the term used to indicate sequential evaluation of the expressions in the block, yielding as a result the result of the last evaluation, if any, and the unset value otherwise. Two built-in functions are available to evaluate expressions in a block and preserve the results in a block: reduce and compose.

The built-in function reduce applied to a block yields a new block, with as components all the results of evaluating the block’s constituent expressions, in the same order; arguments of type any-function! are not evaluated though.

Examples:

reduce [1 + 2 3 + 4]        ->  [3 7]             ; reduction
do [1 + 2 3 + 4]            ->  7                 ; compare with execution

Applied to an argument of type any-function, reduce yields the argument unevaluated; for other non-block types, reduce yields the result of evaluating the argument.

Examples:

reduce :+                     -> make op! [...]   ; not evaluated, therefore not applied
a: 1 reduce a                 -> 1

It is also possible to selectively evaluate the block’s expressions: the built-in function compose will only evaluate those components that are of type paren!. With refinement /deep,compose will also act on nested blocks. With refinement /only, compose will evaluate a block as a block, instead of yielding its constituent expressions separately.

Example:

compose [1 + 2 (3 + 4)]          ->  [1 + 2 7]     ; evaluation only within parens
compose [[(1 + 2)] (3 + 4)]      ->  [[(1 + 2)] 7] ; inner blocks are untouched
compose [([1 + 2]) (3 + 4)]      ->  [1 + 2 7]     ; evaluation of a block yields the components
compose/only [([1 + 2]) (3 + 4)] ->  [[1 + 2] 7]   ; with /only, a block stays a block
compose/deep [[(1 + 2)] (3 + 4)] ->  [[3] 7]       ; with /deep, inner parens are also evaluated

Applied to an argument of any other type, compose yields the same result as reduce.

The functions reduce and compose have a refinement /into with an argument of type any-block!; if present, the components of the result will be inserted into this target.

The built-in function collect will execute the block which is its argument and yield a new block as result which contains as components all values resulting from expressions that are argument to the function keep invoked inside the argument block.

Example:

collect [repeat i 10 [if even? i [keep i ** 2]]] -> [4 16 36 64 100]

The function collect also has a refinement /into, with a series! value as argument; if present, the collected components will be inserted into this series.

The shortcut evaluation functions any and all have a block as argument; they will evaluate the expressions one by one; any will stop at the first one whose value is not false or none and yield that as result; if there is no such expressions it will yield none; all will stop at the first one which is false or none and yield none as a result; if there is no such one it will yield the result of evaluating the last one. Note that any [ ] and all [ ] both yield none.

7.6. Function do

The built-in function do will evaluate its argument, which may be of any type, as follows:

  1. if the argument is a block! value, the block will be executed as described in section 7.1

  2. if the arument is a path! value, the path will be evaluated as described in section 7.3.5

  3. if the argument is a string! value, the built-in function load (see section 11.1.1) will be invoked on the string, and do will be invoked on the result

  4. if the argument is a url! or file! value, this should contain a text which is a valid Red program (see section 3); the text string will be obtained by read (see section 11.3.1) and the previous step will be taken

  5. if the argument is an error! value, the error will be raised (see section 12.1.2)

  6. for an argument of type op!, the application of do is not implemented

  7. otherwise, the argument will be evaluated according to the appropriate rule of section 7; note that resulting values of type function!, native!, action! and routine! will not be applied.

8. Numerical and logical computation

As stated in section 3.3, operators i.e. values of type op! are strictly left associative, and there is no precedence between any two operators. Evaluation order can of course be influenced by the use of parentheses.

8.1. Basic arithmetic operations

Red makes available the usual arithmetic operations through + - * / as operators and their prefix counterparts: add subtract multiply divide. In addition, there are operators and prefix functions for exponentiation (** or power), modulo (// or modulo) and remainder (% or remainder). Enquiry functions are: sign? positive? negative? zero? even? odd? NaN?. The unary minus function is only represented by a prefix function negate, not by an operator, since these have always two arguments. Lastly, there are functions for rounding a number (round) and for determining the absolute value of a number (absolute), the maximum and minimum of two numbers (max min), and the sum and average of a set of numbers (sum and average).

The arity (number of arguments) and the argument and result types for these functions are as follows.

function arity operand 1 type operand 2 type result type

+ - * / // %

2

scalar! vector!

scalar! vector!

see next table

**

2

number!

integer! float!

integer!1 float!

NaN?

1

number!

logic!

sign?

1

number! time!

integer!2

positive? negative?

1

number! time!

logic!

zero?

1

number! char! time! pair! tuple!

logic!

even? odd?

1

number! char! time!

logic!

negate

1

number! time! pair!

same as operand3

absolute round    

1      

number! time! pair!

             

same as operand3

max min            

2      

scalar!            

scalar!        

same as greatest/smallest operand
(operand 1 if equal)

sum

1

any-list!4 vector!

same as individual numbers
(refer to table below if not all numbers have the same type)

average

1

any-list!4 vector!

float! percent!5

Notes:

  1. result type is integer! only if both operands are integer, and the result value fits in 32 bits; otherwise result type is float!

  2. result is -1 0 or 1

  3. see REP #10

  4. components must be of type number!

  5. result type is percent! if sum is of that type, otherwise float!

The result types for the 6 arithmetic operations + - * / // % are detailed in the following table. When no result type is mentioned, all 6 operations are forbidden. Individual restrictions are mentioned through notes 1 to 10. The operations on values of type pair! tuple! and vector! take place component-by-component. When the two operand types are different, the result type is determined as (in decreasing order of precedence):

  • the higher dimension type

  • the higher precision type

  • the type of operand 1

operand 2 →
operand 1
char! integer! float! percent! time! date! pair! tuple! vector!

char!

char!1

char!1

char!1

vector!1,6

integer!

integer!1

integer!

float!

float!

time!

date!9

pair!1,2

tuple!1,2,3

vector!1,6

float!

float!1

float!

float!

float!

time!

pair!

tuple!

vector!

percent!

percent!

percent!

percent!

time!

pair!1,2

tuple!1,2,3

vector!1,6

time!

time!

time!

time!

time!4,5

date!9

date!

date!8

date!8

integer!10

pair!

pair!1

pair!1

pair!1

pair!1

tuple!

tuple!1

tuple!1

tuple!1

tuple!1,11

vector!

vector!1,6

vector!1,6

vector!1,6

vector!1,7

Notes:

  1. modulo not allowed

  2. divide not allowed

  3. subtract not allowed

  4. divide has float! result

  5. multiply not allowed

  6. result has element type of vector operand see also issue #2216

  7. operand 1 and 2 must have same element type

  8. only add/subtract allowed

  9. only add allowed

  10. only subtract allowed; result is number of days, ignoring any time components; for exact difference use built-in function difference

  11. with tuples of unequal length, the shortest one is extended with values 0

The difference between the modulo and remainder functions is as follows:

  • for positive first argument, the result of both is the positive remainder of division by the second argument

  • for negative first argument, the result of modulo is the positive remainder, and the result of remainder is the negative remainder

The results of division by zero are as follows:

  • any integer divided by 0 gives an error

  • any non-zero non-integer number divided by 0 0.0 or 0% gives positive or negative infinity

  • 0 0.0 or 0% divided by 0.0 or 0% gives "not a number"

  • computing modulo and remainder with 0 0.0 or 0% as second operand gives an error

More information on the handling of the special numbers positive and negativity infinity and "not a number" is to be found in the additional documentation (see section 18).

Note that round has a number of refinements:

/to             => Return the nearest multiple of the scale parameter
   scale    [number!] "Must be a non-zero value"
/even          => Halves round toward even results
/down          => Round toward zero, ignoring discarded digits. (truncate)
/half-down     => Halves round toward zero
/floor         => Round in negative direction
/ceiling       => Round in positive direction
/half-ceiling  => Halves round in positive direction

The functions max min on arguments of type pair! and tuple! are applied on a component-by-component basis (tuples must be of equal length). See issue #3395 These functions are also defined for series! arguments. See section 9.3.

8.2. Higher mathematical functions

This concerns first of all the familiar functions exp for raising e = 2.718281828459045 to a power, the logarithms log-e log-2 log-10, and the square root sqrt. Furthermore the trigonometric functions sin cos tan asin acos atan atan2, and the functions random and checksum.

The arity (number of arguments) and the argument and result types for these functions are as follows. Result types are only indicated if different from argument types.

function arity argument type(s) result type

exp log-e log-2 log-10 sqrt

1

number!

float!

sin cos tan asin acos atan

1

float!

atan2

2

float!

random

1

logic! scalar!

checksum

2

binary! string! file! word!

binary!

Notes: all trigonometric functions take an argument in radians, except atan2 which takes two float! arguments representing y and x coordinates. The function random yields a random value between zero and its argument value or one of false and true for logic!; for pair! and tuple! values it operates per component; it is also defined for series! arguments (see section 9.3). The word! argument to checksum indicates the method; allowed are MD5 SHA1 SHA256 SHA384 SHA512 CRC32 TCP ADLER32 hash.

8.3. Set-theoretical functions

The following functions operate on values that can be conceived as representing sets of other values; this concerns some series types: block! hash! string!, as well as bitset! and typeset!.

The functions intersect union difference and exclude have two arguments of one of the types mentioned, and yield a result of the same type. The function unique has one argument of type block! hash! string!, and again yields a result of the same type. The operation of these functions follows from their names.

Note that the function difference is also defined on two date! values; in this case it yields a time! value as the result of subtracting one date with its time from the other.

8.4. Bitwise functions

The following functions operate on the bit patterns underlying Red values of suitable types.

The function complement yields the bit-by-bit complement, thus for integers it yields the two’s complement, e.g. complement 2 is -3. The operators and or xor with prefix counterparts and~ or~ xor~ operate bit-by-bit on their arguments.

Three bit-shift operators are defined on integers, with positive integer shift count:

  • << for left shift: highest bits are shifted out, zero bits are added to the right

  • >> for right shift: lowest bits are shifted out, highest bit is duplicated

  • >>> for "logical" shift: lowest bits are shifted out, zero bits are added to the left

These operators have their equivalent in three routines: shift-left, shift-right and shift-logical which in their turn call upon a single native function shift (default: right shift) with refinements /left and /logical.

The arity (number of arguments) and the argument and result types for these functions are as follows.

function arity argument type(s)

complement

1

integer! bitset! typeset! binary!1

and or xor

2

integer! char! pair! tuple! bitset! typeset! binary! vector!

<< >> >>>

2

integer!

Note:

  1. see REP #10

Note further that and or and xor on values of type bitset! and typeset! yield the same result as intersect union and difference (see previous section).

8.5. Logical functions

The bitwise functions complement and or xor are also applicable to logic! values; on these values, not is equivalent to complement. On values of other types, not will always yield false except on none, where it will yield true.

Note that and or xor evaluate both their arguments. In many programming situations, it is preferable to use the shortcut evaluation functions any and all, which only evaluate subsequent arguments if an earlier one is false or none for any or not none (i.e.true) for all. See section 7.5.

9. Operations on values of indirect types

9.1. Introduction

This concerns series, bitsets, maps, objects and errors.

As explained earlier, series in Red, as values of indirect types, have their components stored contiguously, but separately from the value slot that stores the "series value" itself. This value slot only contains the following information: a pointer to the components storage, and the current index. The components storage itself keeps track of the length of the series i.e. the index of the last component.

Bitsets are stored similarly to series, but have a restricted number of operations.

Maps, objects and errors all have fields, and share a number of operations, although there are also differences to be taken into account.

9.2. Series: positioning and navigation

The following functions of a series value yield a new series value with the index modified, but pointing to the same components:

function new index

head <series>

1

tail <series>

length + 1

at <series> <integer>

(index calculated from <expression>)

skip <series> <integer>

current index + (offset calculated from <expression>)

next <series>

current index + 1

back <series>

current index - 1

find <series> <expression>

index of first occurrence of (component or sub-series)

For image! values, a pair! value is also allowed. This will be converted to a regular index, taking into acount that image pixels are stored row-wise. The <expression> argument of find may be a single component value or a sub-series, or (in the case of any-string! series) a bitset! value representing a choice of values. This function is not defined on image! values. For testing occurrences it uses an equality test which differs from strict-equal? only by not being case-sensitive for values of types in any-string! and any-word!.

For all series, if the index becomes smaller than 1 or greater than length + 1, it will be fixed at 1 or length + 1.

If find on a series does not have a match, its result is none. The function is also defined on values of type bitset! (with <expression> of type char!, string!, integer! or block! of integers), typeset! (with <expression> of type datatype!) and any-object! and map! (with <expression> evaluating to a field value). The result of find in these cases is true if there is a match, and false otherwise.

Furthermore, if the <series> argument is of type any-block! except hash! and the <expression> is of type datatype! the result is the <series> at the index of the first occurrence of a component of that type. See REP #29

Note that find has a rich set of refinements:

/part     => Limit the length of the search
    length   [number! series!]
/only     => Treat a series search value as a single value
/case     => Perform a case-sensitive search
/same     => Use "same?" as comparator
/any      => TBD: Use * and ? wildcards in string searches
/with     => TBD: Use custom wildcards in place of * and ?
    wild     [string!]
/skip     => Treat the series as fixed size records
    size     [integer!]
/last     => Find the last occurrence of value, from the tail
/reverse  => Find the last occurrence of value, from the current index
/tail     => Return the tail of the match found, rather than the head
/match    => Match at current index only and return tail of match

The following enquiry functions are available: head? tail? length? index?. The function empty? is a synonym for tail?. The built-in function offset? yields the difference of the index? values of its two series! arguments.

Note: for programming convenience, the functions length? and empty? (but not tail?) accept none as an argument, yielding none as result.

The function length? is also defined for values of type bitset!, tuple! and map!.

All series operations are defined for port! values??

9.3. Series: extraction and modification of components

The following built-in functions have been described in section 5.6: pick poke select put first second third fourth fifth.

The function select has the same set of refinements as find (see previous section) with the exception of /tail and /match.

The function last <series> is defined as pick back tail <series> 1.

These functions create a new series value, pointing to new components:

function result

copy <series>

copy of the series

extract <series> <integer>

copy of the series with 1st component and every nth following one

split <series> <delimiter>

a block of sub-strings split at the delimiter(s)

Note that copy make a shallow copy, i.e. inner series are not copied. To also copy these inner series, use the refinement`/deep`.

The function extract has a refinement /into, with a series! argument; if present, this series is the target for the resulting components.

For split, the <series> must be of type any-string!, and the <delimiter> may be a single character, a string or — in order to represent a choice of characters — a bitset.

The function copy is also defined on values of type bitset!, map!, object!, error! and port!.

The following functions modify the series in place, i.e. they modify the series value slot to point to the changed series. With the exception of take and alter, their result is the changed series itself. These functions are not defined on image! values.

function operation resulting position of series

reverse <series>

order of components reversed

at head

sort <series>

components in increasing/decreasing order

at head

random <series>

components in random order

at head

clear <series>

components removed till tail

at tail

remove <series>

current component removed

unchanged, i.e. before next component

take <series>

current component removed

(unchanged, result is component value)

change <series> <expression>

current component replaced
by value of <expression>

after current component

replace <series> <pattern>
<expression>

components equal to <pattern>
replaced by value of <expression>

at head

alter <series> <expression>

if value of expression in <series>
it is removed, else appended

(at head, result is true if appended, else false)

insert <series> <expression>

value of <expression> inserted
before current component

before current component

append <series> <expression>

value of expression inserted at tail

at head

repend <series> <expression>

reduced value of expression inserted at tail

at head

trim <series>

spaces removed from string
or none from block or hash value

at head

pad <series>

string padded on right side with spaces

at head

The function reverse is also defined on values of type pair! and tuple!, but in these cases it does not modify the value in place, yielding instead a new value.See issue #3379

The function clear is also defined on values of type bitset! and map!. In the first case it yields a bitset of the same size with all bits cleared, in the second case an empty map.

The functions append and insert are also defined on values of type bitset!. The effect of both is to set the bits corresponding to the argument (a value of type char!, string!, integer! or block! of integers).

The function sort is only defined on values of type string! binary! vector! block! hash! paren!. Since it has quite a number of options, here is the full specification:

DESCRIPTION:
     Sorts a series (modified); default sort order is ascending.
     SORT is an action! value.
ARGUMENTS:
     series       [series!]
REFINEMENTS:
     /case        => Perform a case-sensitive sort.
     /skip        => Treat the series as fixed size records.
        size         [integer!]
     /compare     => Comparator offset, block or function.
        comparator   [integer! block! any-function!]
     /part        => Sort only part of a series.
        length       [number! series!]
     /all         => Compare all fields.
     /reverse     => Reverse sort order.
     /stable      => Stable sorting.
RETURNS:
     [series!]

The following functions take two series as arguments:

function operation result and position

swap

swap components at current positions

first series, at head see also issue #1961

move

remove current component of first series and
insert it before current component of second one

first series, before next component

max

compare series lexicographically

greater series, before current component

min

compare series lexicographically

smaller series, before current component

Also these functions are not defined on image! values.

Note: for programming convenience, the following functions take none as argument, yielding none as result: clear find length? remove select take.

The function modify is used to change the owned property of a series value (see section 5.3.6 and section 5.7). It has three arguments: the series value, the word 'owned, and a block of the owner object and field name, or the value none.

All series operations are defined for port! values??

9.4. Operations on bitsets

The following operations on bitsets have been described in earlier sections: complement? (5.3.5), pick poke (5.6), intersect union difference exclude (8.3) and complement and or xor (8.4). The following built-in functions are also defined on bitsets, with the following semantics:

function operation

insert <bitset> <bitset-spec>

set the bit(s) at the indicated position(s) to true

append <bitset> <bitset-spec>

idem

remove/part <bitset> <bitset-spec>

set the bit(s) at the indicated position(s) to false

clear <bitset>

set all bits to false

negate <bitset>

complement

copy <bitset>

yield a copy of the bitset

find <bitset> <bitset-spec>

yield true if the indicated bit(s) is/are all set

length? <bitset>

yield the number of bits reserved for the bitset

For <bitset-spec> see section 5.3.5. If this is a block, it may not contain not.

9.5. Operations on maps

The following operations on maps have been described in section 5.6: put select. The following built-in functions are also defined on maps, with the following semantics:

function operation

clear <map>

remove all key-value pairs from the map

copy <map>

yield a copy of the map

extend <map> <items>

add key-value pairs from <items> (a block, hash or map)
replacing the value if the corresponding key is already present

find <map> <value>

yield true if key indicated by <value> exists, else none
<value> must be of type scalar!, any-word! or any-string!

length? <map>

yield the number of key-value pairs

9.6. Operations on objects and errors

The following operations on objects have already been described: put select (section 5.6), object context construct extend (section 5.3.7) and in (section 6.3.7). Of these, in and select are also defined on errors.

The following built-in functions are also defined on objects and errors, with the following semantics:

function operation

copy <any-object>

yield a copy of the object or error

find <any-object> <word>

yield true if key indicated by <word> exists, else none

10. Control

10.1. Selective execution

The following functions enable conditional execution of one or more block: if unless either case switch. The definitions may be presented as follows:

<if>          ::= if <condition> <true-block>
<unless>      ::= unless <condition> <false-block>
<either>      ::= either <condition> <true-block> <false-block>
<case>        ::= case [ <case-alt>* ] | case/all [ <case-alt>* ]
<case-alt>    ::= <condition> <true-block>
<switch>      ::= switch <expression> [ <switch-alt>* ]
                  | switch/default <expression> [ <switch-alt>* ] <default-block>
<switch-alt>  ::= <label> <true-block> | <label> <switch-alt>
<condition>   ::= <expression>
<label>       ::= <value>

The <condition> is evaluated and is satisfied unless it yields false or none, except for unless, where the condition should yield false or none.

With refinement /all, all conditions of the <case> are tested; otherwise testing stops after the first one that is satisfied, if any.

The <label> values of the <switch> are not evaluated. The selection condition is satisfied at the first alternative where the value of the <expression> is equal to a <label>. With refinement /default, the <default-block> will be executed if none of the conditions is satisfied.

The functions if unless case and switch without /default yield none if no condition is satisfied.

10.2. Repeated execution (loops)

The available constructs are the following:

<forever>     ::= forever <body-block>
<while>       ::= while <condition-block> <body-block>
<until>       ::= until <condition-block>
<loop>        ::= loop <integer> <body-block>
<repeat>      ::= repeat <word> <integer> <body-block>
<foreach>     ::= foreach <counter> <series> <body-block>
<forall>      ::= foreach <word> <body-block>
<remove-each> ::= remove-each <counter> <series> <condition-block>
<counter>     ::= <word> | <block>

Semantics:

  • forever: the <body-block> is executed until an exception is encountered (see section 12).

  • while: the <condition-block> is executed and if does not yield false or none, the <body-block> is executed after which the <condition-block> is again executed etc.

  • until: the <condition-block> is executed as long as it does not yield false or none.

  • loop: the <body-block> is executed an integer number of times.

  • repeat: the <body-block> is executed repeatedly with the <word> assuming values from 1 to the integer. Note that the <word> is not local to the loop, i.e. there is no separate context for the repeat loop.

  • foreach: the <counter> may be a word or a block of words. The <body-block> is executed repeatedly with the word(s) being set to subsequent components of the series. The word(s) are again not local to the loop.

Example:

foreach [name phone] ["John" "123-4567" "Mary" "345-6789"] [print [name phone]]
  • forall: the <body-block> is executed repeatedly starting with the word referring to the head of the series; on each subsequent iteration the word will refer to the series at the next position (see next function in section 9.2).

Example:

b: [1 2 3 4 5 6]
forall b [if odd? b/1 [prin b/2]]

this will print 246

  • remove-each: the <condition-block> is executed on each iteration, with the word(s) of the <counter> being set as in foreach. If the condition is satisfied, the component(s) of the series currently referred to by the word(s), is/are removed from the series.

The result of forever is that of the exception that causes its interruption. For the other functions, unless an exception has occurred, the result is the unset value for while and remove-each, and the result of the execution of the body for the remaining ones.

10.3. Interrupting execution

The built-in functions break continue exit return are described in section 12.

The built-in functions halt and quit or q stop the execution of the program. Difference?? The built-in function quit-return delivers its integer argument as status code back to the Operating System.

10.4. Special execution cases

The built-in function comment ignores its argument and yields the unset value as result. It is mostly used to insert multi-line comments, with a multi-line string as argument or to "comment out" blocks of code. Care has to be taken that the argument is a lexically and syntactically valid single Red expression, even though it will not be evaluated.

The built-in function also has two arguments. It evaluates both one after the other, and yields the result of the first one, using get/any.

11. Input/output

This section deals with communication between programs and external resources, and with the related conversion of data between various representations. Red currently has a basic set of functions to work directly with external resources represented as files (values of type file!, which includes directories or folders as they may be called) and as network locations or urls (values of type url!). For more general handling of resources, Red will have ports (values of type port!). This facility will model external resources uniformly as URIs (Uniform Resource Identifiers), which will include files and urls as special cases. The basic I/O functions are completely described in section 11.3 below. The port approach is being described, as it evolves, in section 11.4.

11.1. Conversion of data

11.1.1. Conversion from/to textual representation

The built-in function load will convert textual input (or its binary UTF-8 encoded equivalent), specified as its argument, to one or more values by calling upon the lexical/syntactic analysis facilities of the toolchain. The result is either one value or a block of values.

There are three mechanisms for converting values to readable strings: the built-in function form will produce a basic representation intended for human readers, the built-in function mold will produce a representation that mirrors the source code of the value, while its variant mold/all will produce a representation that can be read back by load to yield the original value. As stated in section 5.4.3 the operation of form is the same as that of to-string with the exception of argument types unset! none! binary! and any-list!. Especially values of the last group of types, as well as values of types vector! and object! merit special attention since the are converted to strings showing the essentials without conserving type information.

Examples:

load "1"                  -> 1                      ; string analyzed as representing an integer
load "1 + 2"              -> [1 + 2]                ; load produces a block for more than one value
load "[1 2 3]"            -> [1 2 3]                ; one (grouped) value detected
load #{5B31203220335D}    -> [1 2 3]                ; same input as binary value

form ()                   -> ""                     ; unset! value
form #{414243}            -> "#{414243}"            ; to-string gives "ABC"
form [1 2 3]              -> "1 2 3"                ; block brackets omitted
form quote (1 2 3)        -> "1 2 3"                ; parens also omitted
form make hash! [1 2 3]   -> "1 2 3"                ; hash property not shown
form make vector! [1 2 3] -> "1 2 3"                ; vector property not shown
form object [a: 1]        -> "a: 1"                 ; object property not shown
mold [1 2 3]              -> "[1 2 3]"              ; load is guaranteed to recognize this
mold make hash! [1 2 3]   -> "make hash! [1 2 3]"   ; hash property conserved
mold make vector! [1 2 3] -> "make vector! [1 2 3]" ; vector property conserved

The built-in function save will apply mold to the expression which is its second argument. If the destination specified as its first argument is a string, it will append the result of mold to that string. If the destination is a binary! value, it will first create a UTF-8 encoded binary! value out of the result of mold and append that value to the destination . See issue #2668

For any-list! values the user can control the way they are presented by mold, by instructing it to insert line feed characters (U+000A) before selected components. The built-in function new-line with an any-list! first argument will set a new-line marker in the value slot of the current component of its argument (if the second argument evaluates to true) or clear this marker if the second argument evaluates to false.

Example:

b: [1 2 3 4]
forall b [new-line b true]
print mold b

gives

[
    1
    2
    3
    4
]

The state of the new-line marker may be tested with the built-in function new-line? which has an any-list! argument, and yields true or false.

11.1.2. Conversion from/to other representations

The built-in functions load and save each have an /as refinement with a word! argument: the value none indicates Red code (Red data) and makes load and save operate as already described; other values implemented are png jpeg bmp gif; for each of these values load will accept binary data in the indicated format and yield an image! value, and save will take an image! value and produce the encoded binary value. The necessary decoding and encoding routines are stored in system/codecs. This is a block of pairs: <word><object>, where the <word> indicates the encoding e.g. jpeg, and the corresponding <object> has the following content:

key value type content

title

string!

(not filled in)

name

word!

'JPEG

mime-type

block!

[image/jpeg]

suffixes

block!

[%.jpg %.jpeg %.jpe %.jfif]

encode

routine!

routine [img [image!] where [any-type!]][…​]

decode

routine!

routine [data [any-type!]][…​]

Note that conversion between "raw" binary data (values of type binary!) and strings is quasi automatic if the binary data uses UTF-8 character encoding: to-binary <string> and to-string <binary> will perform the necessary encoding/decoding.

11.1.3. Full specification of load and save

Because of their importance, the complete specification of the built-in functions load and save is given here.

USAGE:
     LOAD source
DESCRIPTION:
     Returns a value or block of values by reading and evaluating a source
     LOAD is a function! value
ARGUMENTS:
     source       [file! url! string! binary!]
REFINEMENTS:
     /header      => TBD
     /all         => Load all values, returns a block. TBD: Don't evaluate Red header
     /trap        => Load all values, returns [[values] position error]
     /next        => Load the next value only, updates source series word
        position     [word!] "Word updated with new series position"
     /part        =>
        length       [integer! string!]
     /into        => Put results in out block, instead of creating a new block
        out          [block!] "Target block for results"
     /as          => Specify the type of data; use NONE to load as code
        type         [word! none!] "E.g. json, html, jpeg, png, etc"

USAGE:
     SAVE where value
DESCRIPTION:
     Saves a value, block, or other data to a file, URL, binary, or string
     SAVE is a function! value
ARGUMENTS:
     where        [file! url! string! binary! none!] "Where to save"
     value         "Value(s) to save"
REFINEMENTS:
     /header      => Provide a Red header block (or output non-code datatypes)
        header-data  [block! object!]
     /all         => TBD: Save in serialized format
     /length      => Save the length of the script content in the header
     /as          => Specify the format of data; use NONE to save as plain text
        format       [word! none!] "E.g. json, html, jpeg, png, redbin etc"

11.2. Printing

The built-in function prin will take an expression and send a string to the standard output device. If the expression is not a block, the string is the result of applying form to the result of evaluating the expression; in the case of a block, the individual expressions it contains are evaluated and converted by form and separated by single spaces. The built-in function print calls prin and outputs a line feed afterwards.

The built-in function probe will call mold and then print, and yield its argument as a result. This is useful for debugging intermediate results; note that print itself will yield the unset value.

Examples:

print [1 + 2 3 + 4]    ; prints "3 7" and yields unset
probe [1 + 2 3 + 4]    ; prints "[1 + 2 3 + 4]" and yields [1 + 2 3 + 4]

11.3. Basic I/O

This section describes the current state of implementation of I/O facilities which work directly with files and urls. More general facilities will be provided by ports, see section 11.4.

11.3.1. File and URL I/O

The built-in function read will read a string from a file on an external device which is indicated by a file! or url! value as its argument. The content is assumed to be UTF-8 encoded unless the refinement /as is used, which has a word! argument indicating the character encoding What is allowed??. When translating input code points to Red character values, a carriage return character (U+000D) when followed by a line feed character (U+000A) is ignored, but if it occurs without a following line feed it is treated as if it were a line feed. If the refinement /lines is used, the content will be split into lines at the line feed character. If the refinement /binary is used, the content will be read as a binary! value and not be decoded.

The built-in function load also accepts a file! or url! value indicating a text or binary file. It will read the content of the file and treat it as indicated above.

The built-in function write will send a string or binary! value which is its second argument to a file on an external device which is indicated by a file! or url! value as its first argument. If the second argument is not a string or binary! value, it will first be passed to mold. The resulting string will be UTF-8 encoded (as by to-binary) unless the refinement /as is used, which has a word! argument indicating the character encoding What is allowed??. If the refinement /append is used the output will be written at the end of the file. If the refinement /lines is used, and the value to be written is a block, the components of the block will be written with a line feed after every component. The refinement /binary ensures that a line feed character (LF, U+000A) present in the source is not translated to an OS-specific character combination (e.g. CRLF, U+000D + U+000A) but is output as a single LF.

The built-in function save also accepts a file! or url! value indicating a text or binary file. It will send its result to that file.

The built-in function query accepts a file! value and yields the date and time (UTC) of the last modification of the file or directory, as a date! value.

The functions load-thru and read-thru are used for disk-cached remote file access. They work in the same way as their normal counterparts, except that the retrieved file is cached locally, so on their next access, the locally cached copy will be used. The cache folder used by the *-thru functions is indicated by system/options/thru-cache.

11.3.2. File system functions

A file! value may indicate either a file or a directory (some Operating Systems call this a folder). The conventions for Red file names are:

  • the device name, if any, and the names in the directory hierarchy are separated by a / character (some operating systems use the \ character for the same purpose)

  • a file name starting with a / character represents an absolute path, otherwise the path is relative to the current working directory

  • a file name ending in a / character represents a directory

  • the abbreviations . for current directory and .. for one level higher directory are honored; the built-in function clean-path will do the necessary substitutions (normalization)

The built-in function to-local-file translates a Red file! value into the appropriate string for the target OS. The built-in function to-red-file will take a string indicating a file in the target OS and produce the equivalent Red file! value. These functions will not do normalization.

Examples:

to-local-file %/C/Projects/Red/programs/ -> "C:\Projects\Red\programs\"
to-red-file "C:\Projects\Red\programs\"  -> %/C/Projects/Red/programs/

The current working directory is stored in system/options/path.

The following built-in functions deal with the file system:

  • exists? will yield true if the file indicated by its file! argument exists in the file system, and false otherwise

  • exists-thru? operates the same with respect to the thru-cache (see section 11.5)

  • suffix? yields the suffix (extension) of a file, or none if there is no suffix

  • size? will yield the size of the file in bytes

  • dir? will yield true if the file indicated by its`file!` argument is a directory and false otherwise

  • dirize will add a trailing / to its file! argument if needed

  • what-dir will yield the current working directory as a file! value

  • cd or change-dir will set the current working directory to the argument which may be a file!, word! or path! value; the argument will first be normalized

  • pwd will print the current working directory

  • list-dir will list the contents of the directory that is its argument (type file! word! or path!) in as many columns as will fit the screen; it has a refinement /col to specify the number of columns; it also has several near-synonyms: ls and dir will call list-dir without refinement and ll will call it with 1 column specified; all three will use the current working directory if they are called with no argument; note that read <directory> will yield a block with the content of the directory

  • make-dir will create the directory that is indicated by its file! argument; if this contains more than one directory level, and the /deep refinement is specified, the intermediate directory or directories will also be created

  • clean-path will normalize its file! argument to an absolute path where . and .. are eliminated

  • normalize-dir will invoke clean-path and prefix the current working directory if the file path indicated by its argument (word! path! or file!) is relative, and invoke dirize afterwards

  • split-path will take a file! argument and yield a block of two file! values: the last file or directory in the path, preceded by the directory containing that file or directory (or %./ if the argument was a single file or directory)

  • path-thru will return the local disk cache path of a remote file indicated by its url! argument (see section 11.3.1)

  • delete will take a file! argument and delete the file or directory indicated; the result is true if the operation was succesful, and false otherwise

  • request-file will invoke an interactive file requestor and yield a file! value or a block of file! values

  • request-dir will do the same for directories

11.4. Ports

Ports represent a generalization of files and urls. They implement the concept of Uniform Resource Identifier (URI), as defined in RFC3986, and the various operations on the resources represented by URIs; the functionality offered by ports will be more complete than the basic I/O currently provided.

11.4.1. Port components

Ports, i.e.values of type port!, are specialized objects with a fixed number of fields, that contain the necessary information for handling the communication with a wide variety of external resources.

As also shown in section 5.6 the fields are:

name type

spec

object!

scheme

word! object!

actor

native! object!

awake

state

object!

data

A prototype port value is contained in system/standard/port. The significance of the fields is as follows:

  • The spec field is an object representing a resource. The fields of this object correspond to the components of an URI as detailed in RFC3986. The type of resource, which RFC3986 calls its scheme, is represented by the scheme field of the spec object.

  • The scheme field of the port is initially a word! value equal to the scheme field of the spec object`; during operation it is replaced by an object whose keys are the names of the various actor functions like open, read, rename etc., and whose field values are these actor functions that operate on resources with this particular scheme.

  • The actor field TBD

  • The awake field TBD

  • The state field is an object containing state information

  • The data field TBD

The various objects containing the actor functions for the different schemes are stored in system/schemes, a block of word/object pairs. New schemes may be added to system/schemes by calling register-scheme with as arguments the name of the scheme and its content.

The fields of the spec object are:

name type content

scheme

word!

e.g. http, udp, file, mailto

user-info

host

string!

e.g "domain.com"

port

integer!

e.g. 8080

path

file!

target

file!

query

string!

fragment

string!

ref

url! string!

the source of the above fields

All fields except scheme may be none. A prototype object is contained in system/standard/url-parts

A function exists to construct the spec object for a URI given a Red value of type url! or string!: decode-url. It follows RFC3986 with some simplifications. For a file! value, the spec object will have the field scheme set to file and the fields path and target to the directory (folder) and file name within the directory respectively.

A prototype state object is contained in system/standard/port-state

11.4.2. Port operations

The following I/O operations (functions) are defined on ports:

function description

create

Send port a create request

open

Opens a port

open?

close

Closes a port

query

read

write

update

modify

rename

delete

As stated above, these functions are implemented for the various schemes by actors.

A number of these functions also accept a file!, url! or block! argument; the corresponding port! value will be constructed from the file or url respectively as indicated above; the block! should contain key/value pairs as for an object.

Also defined for values of port! type are all functions that are defined for values of series types.

11.5. Other functions

11.5.1. Console functions

The console prompt and the string preceding the result of the user input are available as system/console/prompt and system/console/result. Their initial values are ">> " and "== " respectively.

The built-in function ask will print its argument at the console prompt and wait for user input until a line feed (U+000A) is received; the string before the line feed will be yielded as result.

The built-in function input is shorthand for ask "". See REP #11

The built-in function read-clipboard will return the clipboard content as a string and write-clipboard with a string argument will set the clipboard content.

11.5.2. Browse

The function browse with a url! of file! argument will open the system default browser at the URL that is indicated by its url! argument, or invoke the system file manager for the file that is indicated by its file! argument.

12. Exceptions

Two kinds of exceptions (exceptional situations which disturb the normal evaluation process) may be distinguished: error exceptions or errors, which arise in the course of evaluation because of inappropriate (combinations of) values, and user exceptions that are raised or "thrown" on conditions determined by the user. An intermediate case is the user error which is also raised on conditions determined by the user but which is treated like an error value. To this end, Red defines a dedicated error group "User error" (see below), but the user may also extend the error repertoire with other error groups, specialized for their application.

12.1. Errors

12.1.1. Composition

Errors are values of type error! that can be produced as a result of any evaluation; they are specialized objects with a fixed number of fields, that contain the necessary information for identifying the nature and the place of the error. A prototype error value is contained in system/standard/error. As also shown in section 5.6 the fields are:

name type content

code

integer!

unique identifying number

type

word!

characterizes a group of errors

id

word!

identifier for the error within the group

arg1

any-type!

additional information for the error message

arg2

any-type!

further additional information

arg3

any-type!

still further additional information

near

block!

program fragment

where

any-type!

value whose evaluation triggered the error

stack

integer!

machine address

Any field except type and id can also be none. If arg1 is none arg2 and arg3 will also be none; likewise, if arg2 is none, arg3 will also be none.

The type field may contain one of the following words: throw note syntax script math access user internal.

There is initially a fixed repertoire of errors; identifying information and (parametrized) error messages for each possible error are stored in the object system/catalog/errors. This has the following sub-objects, whose field names correspond to the contents of the type field of the error value and which group related errors:

system/catalog/errors/…​ code field type field

throw

0

"Throw Error"

note

100

"note"

syntax

200

"Syntax Error"

script

300

"Script Error"

math

400

"Math Error"

access

500

"Access Error"

user

800

"User Error"

internal

900

"Internal Error"

As indicated in the table, each of the sub-objects has two fixed fields: code which contains the base number for the codes of the individual errors, and type which is a string that can be used in forming the error message; this serves to sufficiently characterize the group. Each sub-object has furthermore a number of fields, whose names correspond to the id field of the error value, and which identify the individual error. E.g. the math group has fields zero-divide, overflow and positive. The contents of each of these fields is either a string, which is a complete error message, or a block of strings and instances of :arg1, :arg2 and :arg3, which needs to be bound to the context of the error value, in order for the values of arg1 to arg3 to be inserted; the block then can be used to construct the error message. The full list of possible errors is shown in section 16.

When the error value is produced, the word which is the value of its type field is bound such that it refers to the sub-object whose field name is that word; also, the word which is the value of id field is bound such that it refers to the error message (string or block) within that sub-object whose field name is that word. See issue #2633 Thus the following code will produce the full message information for an error value, say err:

either err/arg1                             ; test if insertion is necessary
[
    reduce bind (get err/id) (in err 'id)   ; yields a block of strings and values
][
    get err/id                              ; yields a string
]

Note the use of the in built-in function to obtain the context of the error value.

Examples:

system/catalog/errors/math is an object! of value:
     code             integer!  400
     type             string!   "Math Error"
     zero-divide      string!   "attempt to divide by zero"
     overflow         string!   "math or number overflow"
     positive         string!   "positive number required"
system/catalog/errors/access is an object! of value:
     code             integer!  500
     type             string!   "Access Error"
     cannot-open      block!    ["cannot open:" :arg1]
     invalid-utf8     block!    ["invalid UTF-8 encoding:" :arg1]
     no-connect       block!    ["cannot connect:" :arg1 "reason: timeout"]

The code for each individual error is the base number + the ordinal number of the error in the sub-object (0-origin), e.g. for no-connect it is 502.

Because the catalog is an object like any other, the user may extend it with their own error groups which can then be raised as described below. An example follows:

; add at end, using the next available code
last-type: last keys-of system/catalog/errors
new-code: system/catalog/errors/:last-type/code + 100

system/catalog/errors: make system/catalog/errors [
    my-exceptions: make object! [
        code: new-code
        type: "My Exception"
        WRONG_DOCUMENT_ERR:            [:arg1]
        NO_MODIFICATION_ALLOWED_ERR:   ["field" :arg1 "is read-only"]
    ]
]

In this example, care is taken to set the code field to a value that is not yet used. Of course the name of the sub-object must also be different from an existing one.

12.1.2. Raising and interception

Errors are normally raised by the compiled code or by the interpreter, as the case may be, but they can also be raised by calling the built-in function cause-error. The raising of an error will break off program execution, unless it is intercepted by try or attempt.

The built-in function try <block> will execute the block and if there is an error, it will yield that error value; otherwise it will yield the value resulting from the execution. The built-in function attempt <block> will apply try and if the result is an error value, it will yield none.

12.2. User exceptions

In contrast to errors, a user exception is not a value of the language, but a call of a built-in function, which interrupts program execution and may cause resumption at another place in the code, or result in breaking off the execution like an unintercepted error does.

Three types of user exceptions exist:

  • interruption of repeated execution (loops)

  • interruption of function body execution

  • "throws"

12.2.1. Interruption of loops

Red has a number of loop constructs which cause repeated execution of a block (see section 10.2). In each of these, the block (loop body) may contain calls of the built-in functions break and continue. A call of break will interrupt execution of the body and resume directly after it. The result of break and thus of the evaluation of the loop is the unset value. A call of break/return <expression> will yield the value of the <expression> as a result of evaluating the loop. A call of continue will interrupt execution of the body and resume at the end of the body, potentially resulting in further cycles of execution. Calls of these functions outside a loop body raise an error.

12.2.2. Interruption of function body execution

A call of the built-in function exit will interrupt execution of the function body and resume in the code directly after the call. The result of exit is the unset value. A call of the built-in function return <expression> will also interrupt execution and yield the value of the <expression> as a result of the function body execution. Calls of these functions outside a function body raise an error.

12.2.3. Throws

A throw is a call of the built-in function throw <expression> which will interrupt execution and resume just after a corresponding call of the built-in function catch, yielding the value of the <expression> as a result.

A catch, i.e. a call of the built-in function catch <block>, will execute the block and if there are no throws during the execution, it will yield the result of the execution as a value. If within the block, including within the body of any function called within the block, to any depth, there is a throw, the result of the catch will be the value yielded by this throw.

For more control, throw has a refinement /name with a word! argument. Correspondingly, catch has a refinement /name with as argument a word or a block of words. A named throw will only be reacted on by a named catch which has (amongst others) this name as argument, or by a catch without a name. Other encompassing catch calls will let it pass through.

If a throw is not caught by a catch, it will result in an error.

12.2.4. Interception by try and attempt

The built-in function try (see section 12.1.2) has a refinement /all, allowing it to catch all possible forms of exceptions, including break, continue, exit and return misuses as well as uncaught throws. The built-in function attempt, which calls try, has a refinement safer which causes it to use try/all.

13. Additional facilities

13.1. Preprocessor

The Red preprocessor is a dialect of Red, enabling transformation of Red source code using a specific layer on top of regular Red language code. Transformations are achieved by inlining preprocessor keywords (called directives) inside Red source code.

These directives will be processed:

  • when the Red source code is compiled

  • when the Red source code is executed by the do built-in function with a file! argument

  • when the expand-directives built-in function is called on a block! value

The preprocessor is invoked after the lexical/syntactic analysis phase, so it processes Red values, and not the source code in text form.

Directive categories:

  • conditional directives: include code depending on the result of an expression

  • control directives: control the behavior of the preprocessor.

  • macros: transform code using functions, enables more complex transformations

Directives are denoted by specific issue! values (starting with a # character).

When a directive is processed, it is replaced by the resulting value it returns (some directives do not return anything, so they are just removed). That is how transformations of source code is achieved.

Note: Red/System has its own preprocessor, which is similar, but low-level and applied to the source code in text form.

Further explanations are provided in separate documentation; see section 18.

13.2. Parse

The parse dialect is an embedded Domain Specific Language for parsing input series using grammar rules. It is an enhanced member of the Top Down Parsing Languages (TDPL) family. Parse’s common usages are for checking, validating, extracting and modifying input data and for implementing embedded and external DSLs.

Parse’s core principles are:

  • advance input series by matching grammar rules until top-level rule failure (returning false) or input exhaustion (returning true)

  • ordered choices (e.g. in ["a" | "ab"] rule, the second one will never succeed)

  • rules composability (unlimited)

  • limited backtracking: only input and rules positions are backtracked, other changes remain

  • two modes: string-parsing (for example: external DSL) or block-parsing (for example: embedded DSL)

Further explanations are provided in separate documentation; see section 18.

13.3. GUI System

The Red/View component is a graphic user interface system for the Red programming language. The design goals are:

  • data-oriented, minimal API

  • tree of objects as programming interface

  • realtime or deferred synchronization between the object tree and the display system

  • make two-way binding trivial to support

  • ability to have different backends, across different platforms

  • support OS, third-party and custom widget sets

  • low performance overhead

The virtual tree is built using face objects, i.e. objects derived from the standard object face!. Each face object maps to a graphic component on the display in a two-way binding. The built-in function view takes a face object as argument and displays it together with all face objects depending on it. Face objects can be made directly by the user (make <object> …​) or created by using the Visual Interface Dialect (VID) which allows to specify each graphic element to display. VID code is processed by the layout function.

Draw is a dialect (DSL) that provides a simple declarative way to specify 2D drawing operations. Such operations are expressed as lists of ordered commands (using blocks of values), which can be freely constructed and changed at run-time. Draw blocks can be rendered directly as an image! value using the draw built-in function, or as a part of a graphic element created by view/layout.

Further explanations are provided in separate documentation; see section 18.

13.4. Reactivity

Red objects are capable of triggering asynchronous events in response to changes in their components, thus enabling reactive programming.

The most prominent application of this in the toolchain is in the GUI engine where the face! objects are reactors.

Further explanations are provided in separate documentation; see section 18.

The operation of these functions is dependent on the particular Operating System (OS) running on the target computer.

The following functions allow interaction with the set of environment variables that most Operating Systems maintain:

  • list-env will yield a map! value with string keys and values for all variables for the current process

  • get-env with a string or word argument will yield the current value of the named variable

  • set-env with a string or word argument and a string value as second argument will set the named variable to the value, or unset it if the second argument in none

The function now yields the current date and time as a Red date! value. For its refinements see section 5.2.14.

The function wait with a number! or time! argument will wait for the specified time or number of seconds.

The function call will execute an OS shell command to run another process. Its argument is a string! value representing a shell command or a file! value representing an executable file.

13.6. Help facilities

These facilities owe much to the homoiconicity of Red, and to the systematic use of docstrings (see section 5.3.8).

An overview of available facilities is obtained by typing help at the console. This gives the following output:

    Use HELP or ? to view built-in docs for functions, values
    for contexts, or all values of a given datatype:

        help append
        ? system
        ? function!

    To search for values by name, use a word:

        ? pri
        ? to-

    To also search in function specs, use a string:

        ? "pri"
        ? "issue!"

    Other useful functions:

        ??     - Display a word and its value
        probe  - Print a molded value
        source - Show a function's source code
        what   - Show a list of known functions or words
        about  - Display version number and build date

14. Pre-defined words list

14.1. Constants

For convenience, the values are indicated.

14.1.1. Characters

See also section 5.2.6

    comma         #","
    CR            #"^(0D)"
    dbl-quote     #"^""
    dot           #"."
    escape        #"^["
    lf            #"^/"
    newline       #"^/"
    null          #"^@"
    slash         #"/"
    sp            #" "
    space         #" "
    tab           #"^-"

14.1.2. Floating point numbers

See also sections 5.2.2 and 8.2

    pi            3.141592653589793
    false
    no     = false
    off    = false
    true
    on     = true
    yes    = true
    none

14.1.4. Strings

    crlf              "^(0D)^(0A)"
    font-fixed        "Consolas"
    font-sans-serif   "Arial"
    font-serif        "Times"

14.1.5. Tuples

These are RGB color values (see also section 5.3.4)

    aqua              40.100.130
    beige             255.228.196
    black             0.0.0
    blue              0.0.255
    brick             178.34.34
    brown             139.69.19
    coal              64.64.64
    coffee            76.26.0
    crimson           220.20.60
    cyan              0.255.255
    forest            0.48.0
    glass             0.0.0.255
    gold              255.205.40
    gray              128.128.128
    green             0.255.0
    ivory             255.255.240
    khaki             179.179.126
    leaf              0.128.0
    linen             250.240.230
    magenta           255.0.255
    maroon            128.0.0
    mint              100.136.116
    navy              0.0.128
    oldrab            72.72.16
    olive             128.128.0
    orange            255.150.10
    papaya            255.80.37
    pewter            170.170.170
    pink              255.164.200
    purple            128.0.128
    reblue            38.58.108
    rebolor           142.128.110
    Red               255.0.0
    sienna            160.82.45
    silver            192.192.192
    sky               164.200.255
    snow              240.240.240
    tanned            222.184.135
    teal              0.128.128
    transparent       0.0.0.255
    violet            72.0.90
    water             80.108.142
    wheat             245.222.129
    white             255.255.255
    yello             255.240.120
    yellow            255.255.0

14.2. Datatypes and typesets

14.2.1. Datatypes

See also section 4.1

    action!
    binary!
    bitset!
    block!
    char!
    datatype!
    date!
    email!
    error!
    event!
    file!
    float!
    function!
    get-path!
    get-word!
    handle!
    hash!
    image!
    integer!
    issue!
    lit-path!
    lit-word!
    logic!
    map!
    native!
    none!
    object!
    op!
    pair!
    paren!
    path!
    percent!
    point!
    port!
    refinement!
    routine!
    set-path!
    set-word!
    string!
    tag!
    time!
    tuple!
    typeset!
    unset!
    url!
    vector!
    word!

14.2.2. Typesets

See also section 4.3

    all-word!
    any-block!
    any-float!   <---- see issue #2565
    any-function!
    any-list!
    any-object!
    any-path!
    any-string!
    any-type!
    any-word!
    default!
    external!
    immediate!
    internal!
    number!
    scalar!
    series!

14.3. Functions

The functions are classified by functionality:

The letter in front of each word gives the type: A for action!, N for native!, O for op!, R for routine! and F for function!. When a function is directly derived from another one, the two are written on one line, and the most frequently used one is written first.

14.3.1. Enquiry

see sections 4.4 and 5.7

F    action?
F    any-block?
F    any-function?
F    any-list?
F    any-object?
F    any-path?
F    any-string?
F    any-word?
F    binary?
F    bitset?
F    block?
F    body-of
F    char?
F    class-of
N    complement?
N    context?
F    datatype?
F    email?
F    error?
R    event?
F    face?
F    file?
F    float?
F    function?
F    get-path?
F    get-word?
F    handle?
F    hash?
F    image?
F    immediate?
A    index?
F    integer?
F    issue?
F    keys-of
F    lit-path?
F    lit-word?
F    logic?
F    map?
F    native?
F    none?
F    number?
F    object?
F    op?
F    pair?
F    paren?
F    path?
F    percent?
F    refinement?
A    reflect
F    routine?
F    scalar?
F    series?
F    set-path?
F    set-word?
F    spec-of
F    string?
F    tag?
F    time?
F    tuple?
N    type?
F    typeset?
F    unset?
F    url?
F    values-of
F    vector?
F    word?
F    words-of

14.3.2. Making values

see sections 5.3 and 7.5

F    charset
F    collect
N    compose
N    construct
F    context
N    does
N    extend
N    func
N    function
N    has
A    make
F    object
N    reduce
F    routine

14.3.3. Converting values

see sections 5.4 and 5.5

N    as
R    as-color
R    as-ipv4
N    as-pair
R    as-rgba
N    debase
N    enbase
F    hex-to-rgb
N    lowercase
A    to
F    to-binary
F    to-bitset
F    to-block
F    to-char
F    to-date
F    to-email
F    to-file
F    to-float
F    to-get-path
F    to-get-word
F    to-hash
N    to-hex
F    to-image
F    to-integer
F    to-issue
F    to-local-date
F    to-lit-path
F    to-lit-word
F    to-logic
F    to-map
F    to-none
F    to-pair
F    to-paren
F    to-path
F    to-percent
F    to-refinement
F    to-set-path
F    to-set-word
F    to-string
F    to-tag
F    to-time
F    to-tuple
F    to-typeset
F    to-unset
F    to-url
F    to-UTC-date
F    to-word
N    uppercase

14.3.4. Comparison

O    <        N    lesser?
O    <=       N    lesser-or-equal?
O    <>       N    not-equal?
O    =        N    equal?
O    ==       N    strict-equal?
O    =?       N    same?
O    >        N    greater?
O    >=       N    greater-or-equal?

14.3.5. Evaluation and binding

see sections 6 and 7

N    all
N    any
N    apply
N    bind
N    context?
N    do
N    get
N    in
A    index?
F    quote
N    set
N    unset
N    value?

14.3.6. Numerical and logical computation

see section 8

A    absolute
O    +           A    add
O    and         A    and~
F    acos        N    arccosine
F    asin        N    arcsine
F    atan        N    arctangent
F    atan2       N    arctangent2
F    average
N    checksum
A    complement
F    cos         N    cosine
O    /           A    divide
A    even?
N    exp
N    log-10
N    log-2
N    log-e
N    max
O    //          F    modulo           F mod
O    *           A    multiply
N    min
N    NaN?
A    negate
N    negative?
N    not
A    odd?
O    or          A    or~
N    positive?
O    **          A    power
A    random
O    %           A    remainder
A    round
O    <<          R    shift-left       N shift/left
O    >>          R    shift-right      N shift
O    >>>         R    shift-logical    N shift/logical
N    sign?
F    sin         N    sine
F    sqrt        N    square-root
O    -           A    subtract
F    sum
F    tan         N    tangent
O    xor         A    xor~
N    zero?

14.3.7. Series manipulation

see section 9

F    alter
A    append
A    at
A    back
A    change
A    clear
A    copy
F    empty?
F    extract
F    fifth
A    find
F    first
F    fourth
A    head
A    head?
A    index?
A    insert
F    last
A    length?
A    modify
A    move
A    next
F    offset?
F    pad
A    pick
A    poke
A    put
A    random
F    rejoin
A    remove
F    repend
F    replace
A    reverse
F    second
A    select
A    sort
A    skip
F    split
A    swap
A    tail
A    tail?
A    take
F    third
A    trim

14.3.8. Control

F    also
N    break
N    case
F    comment
N    continue
N    either
N    exit
N    forall
N    foreach
N    forever
F    halt
N    if
N    loop
F    q
F    quit
R    quit-return
N    remove-each
N    repeat
N    return
N    switch
N    unless
N    until
N    while

14.3.9. Input/Output

R    ask
N    browse
F    cd
F    change-dir
F    clean-path
A    close
A    create
R    create-dir
A    delete
F    dir
F    dir?
F    dirize
R    exists?
F    exists-thru?
A    form
R    get-current-dir
F    input
F    list-dir
F    ll
F    load
F    load-thru
F    ls
F    make-dir
A    modify
A    mold
N    new-line
N    new-line?
F    normalize-dir
A    open
A    open?
F    path-thru
N    prin
N    print
F    probe
F    pwd
A    query
A    read
R    read-clipboard
F    read-thru
A    rename
F    request-dir
F    request-file
F    save
R    set-current-dir
N    size?
F    split-path
F    suffix?
N    to-local-file
F    to-red-file
A    update
F    what-dir
A    write
R    write-clipboard

14.3.10. Exception handling

F    attempt
N    catch
F    cause-error
N    throw
N    try

14.3.11. Preprocessor

F    expand
F    expand-directives

14.3.12. Parser

F    on-parse-event
N    parse
F    parse-trace

14.3.13. GUI system

F    center-face
F    clear-reactions
F    distance?
F    do-actor
F    do-events
F    do-file
F    draw
R    find-flag?
F    get-scroller
F    insert-event-func
F    layout
F    overlap?
F    remove-event-func
F    request-font
F    set-focus
F    show
F    size-text
F    unview
F    view
F    within?

14.3.14. Reactivity

O    is       F is~ (hidden)
F    react
F    react?
R    set-quiet
N    call
N    get-env
N    list-env
N    now
N    set-env
N    stats
N    wait

14.3.16. Help facilities

F    ?
F    ??
F    about
F    help
F    source
F    what

15. System object

The system object is used by the run-time system to store both fixed data (e.g. codecs, error messages) and variable data (e.g. modules, script header data). All data can be retrieved by the user, and some data can also be set by the user at runtime.

(sub-)component & type              significance/value

system/   object!
    version/    tuple!              current version
    build/      object!
        date           date!        build date
        git            object!      detailed build information
        config         object!      configuration used
    words       object!             global context, see section 6.2
    platform    function!           returns a word identifying the operating system
    catalog/    object!
        datatypes
        actions
        natives
        accessors      block!       see section 5.6.2
        errors         object!      see sections 5.3.7, 12.1.1
    state/      object!
        interpreted?   function!    returns TRUE if called from the interpreter
        last-error     error!
        trace          integer!
    modules     block!
    codecs      block!              see section 11.1.2
    schemes     block!              see section 11.4.1
    ports       object!             TBD
    locale/     object!
        language
        language*
        locale
        locale*
        months         block!       see section 5.2.14
        days           block!       names of days
    options/    object!
        boot           string!
        home
        path           file!
        script
        cache          file!         cache folder used by the Red toolchain
        thru-cache     file!         see section 11.3.1
        args
        do-arg
        debug          logic!
        secure
        quiet          logic!
        binary-base    integer!
        decimal-digits integer!
        module-paths   block!
        file-types
        float          object!
    script/     object!
        title          string!
        header
        parent
        path
        args
    standard/   object!
       header          object!        see section 17
       error           object!        see section 12.1.1
       scheme          object!        see section 11.4.1
       port-state      object!        see section 11.4.1
       file-info       object!
    lexer       object!               run-time lexer program + data
    console/    object!               console program + data
        prompt         string!        see section 11.5.1
        result         string!        see section 11.5.1
        history        block!         previous inputs
        ...
    view        object!               see section 13.3
    reactivity  object!               see section 13.4

16. Errors list

The format in each sub-section is

type (code base)
    id -> string or block
    etc.

16.1. Throw Errors

throw ( 0 )
    break -> "no loop to break"
    return -> "return or exit not in function"
    throw -> ["no catch for throw:" :arg1]
    continue -> "no loop to continue"

16.2. Notes

note ( 100 )
    no-load -> ["cannot load: " :arg1]

16.3. Syntax Errors

syntax ( 200 )
    invalid -> ["invalid" :arg1 "at" :arg2]
    missing -> ["missing" :arg1 "at" :arg2]
    no-header -> ["script is missing a Red header:" :arg1]
    no-rs-header -> ["script is missing a Red/System header:" :arg1]
    bad-header -> ["script header is not valid:" :arg1]
    malconstruct -> ["invalid construction spec:" :arg1]
    bad-char -> ["invalid character in:" :arg1]

16.4. Script Errors

script ( 300 )
    no-value -> [:arg1 "has no value"]
    need-value -> [:arg1 "needs a value"]
    not-defined -> [:arg1 "word is not bound to a context"]
    not-in-context -> [:arg1 "is not in the specified context"]
    no-arg -> [:arg1 "is missing its" :arg2 "argument"]
    expect-arg -> [:arg1 "does not allow" :arg2 "for its" :arg3 "argument"]
    expect-val -> ["expected" :arg1 "not" :arg2]
    expect-type -> [:arg1 :arg2 "field must be of type" :arg3]
    cannot-use -> ["cannot use" :arg1 "on" :arg2 "value"]
    invalid-arg -> ["invalid argument:" :arg1]
    invalid-type -> [:arg1 "type is not allowed here"]
    invalid-type-spec -> ["invalid type specifier:" :arg1]
    invalid-op -> ["invalid operator:" :arg1]
    no-op-arg -> [:arg1 "operator is missing an argument"]
    bad-op-spec -> {making an op! requires a function with only 2 arguments}
    invalid-data -> ["data not in correct format:" :arg1]
    invalid-part -> ["invalid /part count:" :arg1]
    not-same-type -> "values must be of the same type"
    not-same-class -> ["cannot coerce" :arg1 "to" :arg2]
    not-related -> ["incompatible argument for" :arg1 "of" :arg2]
    bad-func-def -> ["invalid function definition:" :arg1]
    bad-func-arg -> ["function argument" :arg1 "is not valid"]
    bad-func-extern -> ["invalid /extern value:" :arg1]
    no-refine -> [:arg1 "has no refinement called" :arg2]
    bad-refines -> "incompatible or invalid refinements"
    bad-refine -> ["incompatible refinement:" :arg1]
    word-first -> ["path must start with a word:" :arg1]
    empty-path -> "cannot evaluate an empty path value"
    invalid-path -> ["cannot access" :arg2 "in path" :arg1]
    invalid-path-set -> ["unsupported type in" :arg1 "set-path"]
    invalid-path-get -> ["unsupported type in" :arg1 "get-path"]
    bad-path-type -> ["path" :arg1 "is not valid for" :arg2 "type"]
    bad-path-set -> ["cannot set" :arg2 "in path" :arg1]
    bad-field-set -> ["cannot set" :arg1 "field to" :arg2 "datatype"]
    dup-vars -> ["duplicate variable specified:" :arg1]
    past-end -> "out of range or past end"
    missing-arg -> "missing a required argument or refinement"
    out-of-range -> ["value out of range:" :arg1]
    invalid-chars -> "contains invalid characters"
    invalid-compare -> ["cannot compare" :arg1 "with" :arg2]
    wrong-type -> ["datatype assertion failed for:" :arg1]
    invalid-refine-arg -> ["invalid" :arg1 "argument:" :arg2]
    type-limit -> [:arg1 "overflow/underflow"]
    size-limit -> ["maximum limit reached:" :arg1]
    no-return -> "block did not return a value"
    throw-usage -> "invalid use of a thrown error value"
    locked-word -> ["protected word - cannot modify:" :arg1]
    bad-bad -> [:arg1 "error:" :arg2]
    bad-make-arg -> ["cannot MAKE" :arg1 "from:" :arg2]
    bad-to-arg -> ["cannot MAKE/TO" :arg1 "from:" :arg2]
    invalid-months: "invalid system/locale/month list"
    invalid-spec-field -> ["invalid" :arg1 "field in spec block"]
    missing-spec-field -> [:arg1 "not found in spec block"]
    move-bad -> ["Cannot MOVE elements from" :arg1 "to" :arg2]
    too-long -> "Content too long"
    invalid-char -> ["Invalid char! value:" :arg1]
    parse-rule -> ["PARSE - invalid rule or usage of rule:" :arg1]
    parse-end -> ["PARSE - unexpected end of rule after:" :arg1]
    parse-invalid-ref -> ["PARSE - get-word refers to a different series!" :arg1]
    parse-block -> ["PARSE - input must be of any-block! type:" :arg1]
    parse-unsupported -> {PARSE - matching by datatype not supported for any-string! input}
    parse-infinite -> ["PARSE - infinite recursion at rule: [" :arg1 "]"]
    parse-stack -> "PARSE - stack limit reached"
    parse-keep -> "PARSE - KEEP is used without a wrapping COLLECT"
    parse-into-bad -> {PARSE - COLLECT INTO/AFTER expects a series! argument}
    invalid-draw -> ["invalid Draw dialect input at:" :arg1]
    invalid-data-facet -> ["invalid DATA facet content" :arg1]
    face-type -> ["VIEW - invalid face type:" :arg1]
    not-window -> "VIEW - expected a window root face"
    bad-window -> {VIEW - a window face cannot be nested in another window}
    not-linked -> "VIEW - face not linked to a window"
    not-event-type -> ["VIEW - not a valid event type" :arg1]
    invalid-facet-type -> ["VIEW - invalid rate value:" :arg1]
    vid-invalid-syntax -> ["VID - invalid syntax at:" :arg1]
    react-bad-func -> {REACT - /LINK option requires a function! as argument}
    react-not-enough -> {REACT - reactive functions must accept at least 2 arguments}
    react-no-match -> {REACT - objects block length must match reaction function arg count}
    react-bad-obj -> "REACT - target can only contain object values"
    react-gctx -> ["REACT - word" :arg1 "is not a reactor's field"]
    lib-invalid-arg -> ["LIBRED - invalid argument for" :arg1]

16.5. Math Errors

math ( 400 )
    zero-divide -> "attempt to divide by zero"
    overflow -> "math or number overflow"
    positive -> "positive number required"

16.6. Access Errors

access ( 500 )
    cannot-open -> ["cannot open:" :arg1]
    invalid-utf8 -> ["invalid UTF-8 encoding:" :arg1]
    no-connect -> ["cannot connect:" :arg1 "reason: timeout"]

16.7. User Errors

user ( 800 )
    message -> [:arg1]

16.8. Internal Errors

internal ( 900 )
    bad-path -> ["bad path:" arg1]
    not-here -> [arg1 "not supported on your system"]
    no-memory -> "not enough memory"
    wrong-mem -> "failed to release memory"
    stack-overflow -> "stack overflow"
    too-deep -> "block or paren series is too deep to display"
    feature-na -> "feature not available"
    not-done -> "reserved for future use (or not yet implemented)"
    invalid-error -> "error object or fields were not valid"
    routines -> {routines require compilation, from OS shell: `red -c <script.red>`}
    red-system -> {contains Red/System code which requires compilation}

17. Metadata for the toolchain

It is recommended to organize the metadata as <word>: <value> pairs. This will facilitate storage and retrieval of these data by the toolchain as well as the user. Certain elements of metadata, that are used by the toolchain, must be in this format: Icon: Needs: and Config:, with prescribed types for the <value> as indicated.

The following is a list of suggested and compulsory elements. The ones marked * are contained in the object system/standard/header.

  element     type           description

* Title:      string!              application title
* Name:       string!              application name
* Type:       ???
  Purpose:    string!              short description of the application purpose
* Version:    tuple!               source code version
* Date:       date!                date of last version
* File:       file!                name of the source file
* Author:     string!              source code author name
  Rights:     string!              copyrights
  License:    [url! string!]       source license (URL or full text)
  History:    block!               source modifications history
  Note(s):    string!              any special notice

  Language:   word!                language of the comments
  Tabs:       integer!             number of spaces between tab positions


  Icon:       [file! block! word!] *.ico file(s) with icon(s) for executable,
                                   or word default/flat/old/mono indicating
                                   standard *.ico files provided by toolchain
* Needs:      [word! block!]       module(s) that is/are to be included
  Config:     block!               set-word/value pairs for toolchain options
                                   for a list of options, see source file /system/compiler.r
                                   (object system-dialect/options-class)

18. Additional documentation

The following is a list of official documents that complement the information given in this one.

  1. Usage information for the toolchain: README

  2. Wiki-style general documentation: Red Wiki

  3. Red/System: Red/System Language Specification

  4. Red Programming Language Documentation (Gitbook), notably:

  5. Overview of value conversions: Conversion matrix

  6. Parse documentation (blog article from 2013): Introducing Parse

  7. Ownership documentation (in blog article from 2016): Red GUI system

  8. Handling of NaNs, INFs, and signed zeros: in Red Wiki under Reference

19. Glossary

term                                    section

action                                  4.2.6, 7.4.2
  inherited action                      4.2.6
active type                             4.2.5
application of a function               3.3
arity of a function                     3.3
atomic type                             4.2.3
backspace (U+0008)                      5.2.6
base64 character                        5.2.12
binding                                 2.4, 3.3, 6.3
bitset spec dialect                     2.5, 5.3.5
bound word                              2.4
built-in constant                       2.4, 14.1
built-in function                       2.4, 14.3
built-in type                           2.4, 14.2.1
built-in typeset                        2.4, 4.3, 14.2.2
caret (U+005E)                          5.2.6
catch                                   12.2.3
character                               5.2.6
  backspace (U+0008)                    5.2.6
  base64 character                      5.2.12
  caret (U+005E)                        5.2.6
  control character                     5.2.5, 5.2.6
  delete (U+007F)                       5.2.6
  double quote (U+0022)                 5.2.6
  escape (U+001B)                       5.2.6
  escaped character                     5.2.6, 5.2.8-10
  form feed (U+000C)                    5.2.6
  hexadecimal codepoint                 5.2.6
  horizontal tab (U+0009)               3.1, 5.2.6
  line feed ( U+000A)                   3.1, 5.2.6
  new-line character                    5.2.7
  next line (U+0085)                    3.1, 5.2.7
  non-breaking space (U+00A0)           3.1
  null (U+0000)                         5.2.6
  semicolon                             3.1
  space (U+0020)                        3.1
  tab (U+0009)                          3.1, 5.2.6
  Unicode Code Point                    3.1
  whitespace character                  3.1
class (of object)                       5.3.6
color (RGB)                             5.2.4, 5.3.4, 14.1.5
comment                                 3.1
  end-of-line comment                   3.1, 3.2
compilation                             2.2
compiler                                2.2
compose dialect                         2.5, 7.5
composite type                          4.2.3
console                                 2.2
context                                 2.4, 6.2
  global context                        2.4, 6.2
control character                       5.2.5, 5.2.6
decaying type                           4.2.5
delete character (U+007F)               5.2.6
derived object                          5.3.6
dialect                                 2.5
  bitset spec dialect                   5.3.5
  compose dialect                       7.5
  draw dialect                          13.3
  error spec dialect                    5.3.7
  function spec dialect                 5.3.8
  image spec dialect                    5.3.4
  map spec dialect                      5.3.11
  object spec dialect                   5.3.6
  parse dialect                         13.2
  preprocessor dialect                  13.1
  routine spec dialect                  5.3.9
  shape dialect                         13.3
  system dialect                        18
  vector spec dialect                   5.3.3
  Visual Interface dialect (VID)        13.3
direct type                             4.2.2
disk-cached remote file access          11.3.1
docstring                               5.3.8, 5.3.9
Domain Specific Language (DSL)          2.5
double quote (U+0022)                   5.2.6
draw dialect                            2.5, 13.3
DSL (Domain Specific Language)          2.5
end-of-line comment                     3.1, 3.2
equality comparison                     5.8.1
error spec dialect                      2.5, 5.3.7
escape (U+001B)                         5.2.6
escaped character                       5.2.6, 5.2.8-10
evaluation                              7
  shortcut evaluation                   7.5
execution                               2.2
  of a block                            7.1, 7.5
expression                              3.3
  infix expression                      3.3
form feed (U+000C)                      5.2.6
free-form text                          3.1
function                                3.3, 5.3.8, 7.4.1
  application                           3.3, 7.4.1
  infix function                        3.3
  prefix function                       3.3
function spec dialect                   2.5, 5.3.8
function type                           4.2.2
global context                          2.4, 6.2
graphical user interface (GUI)          13.3
grouped value                           3.1
grouping token                          3.1
GUI (graphical user interface)          13.3
hexadecimal codepoint                   5.2.6
homoiconic                              2.3
horizontal tab (U+0009)                 3.1, 5.2.6
host computer                           2.2
IEEE 754 binary64 format                5.2.2
image spec dialect                      2.5, 5.3.4
image color/transparency                5.3.4
immutable value                         4.2.3
indentation                             3.1
indirect type                           4.2.2
infix expression                        3.3
inherited action                        4.2.6
interactive console                     2.2
interpretation                          2.2
ipv4                                    5.2.4
ISO 8601 date and time standard         5.2.14, 5.6.2
left associative operator               3.3
lexeme                                  3.1
lexical analysis                        3.1
line feed ( U+000A)                     3.1, 5.2.6
map spec dialect                        2.5, 5.3.11
metadata                                3.1, 16
mutable value                           4.2.3
new-line character                      5.2.7
next line (U+0085)                      3.1, 5.2.7
non-breaking space                      3.1
null (U+0000)                           5.2.6
object class                            5.3.6
object spec dialect                     2.5, 5.3.6
operator                                3.3
  left associative operator             3.3
ordering comparison                     5.8.2
parent type                             4.2.6
parse dialect                           2.5, 13.2
passive type                            4.2.5
polymorphic function                    4.2.6
pre-defined word                        2.4, 14
precedence rules                        3.3
prefix function                         3.3
preprocessor dialect                    2.5, 13.1
prologue                                3.1
pseudo-type                             4.2.6, 4.2.7
reactivity                              13.4
Read Evaluate Print Loop (REPL)         2.2
Red toolchain                           2.2
Red/System (dialect)                    2.5, 18
remote file access (disk-cached)        11.3.1
REPL (Read Evaluate Print Loop)         2.2
RFC3986 (URI)                           11.4.1
RGB color scheme                        5.2.4, 5.3.4, 14.1.5
RGBA color/transparency scheme          5.3.4
routine spec dialect                    2.5, 5.3.9
shape dialect                           2.5, 13.3
shortcut evaluation                     7.5
single value                            3.1
space (U+0020)                          3.1
symbol                                  3.2, 5.2.5, 6.1
syntactic analysis                      3.1
system dialect                          2.5, 18
system object                           15
tab (U+0009)                            3.1, 5.2.6
target computer                         2.2
throw                                   12.2.3
toolchain                               2.2
transparency (of image)                 5.3.4
type                                    2.3, 4
  active type                           4.2.5
  atomic type                           4.2.3
  composite type                        4.2.3
  decaying type                         4.2.5
  direct type                           4.2.2
  function type                         4.2.2
  indirect type                         4.2.2
  parent type                           4.2.6
  passive type                          4.2.5
  pseudo-type                           4.2.6, 4.2.7
  type hierarchy                        4.3
Unicode Code Point                      3.1
Unicode 7.0 case folding table          5.4.14
Uniform Resource Identifier (URI)       11.4
UTF-8 scheme                            3.1, 5.4.3, 5.4.7, 5.4.10, 11.1.1, 11.3.1
value                                   2.3, 5
  grouped value                         3.1
  single value                          3.1
  value casting                         5.5
  value conversion                      5.4
  value creation                        5.3
  value slot                            4.2.2
vector spec dialect                     2.5, 5.3.3
Visual Interface dialect (VID)          2.5, 13.3
whitespace                              3.1
word                                    2.4, 5.2.5, 6.1

20. List of outstanding issues

There are two types of issues: Red issues that represent a bug or other observed imperfection of the current toolchain, which are reported in the issue section of the toolchain repository and suggestions for enhancement ("wishes") that are reported separately in the REP (Red Enhancement Proposals) repository. The numbered issues can be found at https://github.com/red/red/issues/ and https://github.com/red/REP/issues/ respectively.

Red    spec
issue  section

1957   5.7
1960   5.6.3
1961   9.3
2216   8.1
2492   3.1
2554   5.6.2
2565   4.3, 14.2.2
2577   5.3.11
2609   5.3.5
2622   7.4.1
2625   5.6.3
2633   12.1
2642   5.3.9
2644   5.3.13
2645   5.4.2
2650   5.8.1
2657   5.8.1
2658   5.8.1
2662   5.8.2
2668   11.1.1
2776   8.1
2883   5.3.4, 5.6.2
3285   5.3.8
3362   5.3.6
3379   9.3
3395   8.1
3409   5.4.3
3482   5.6.1, 5.6.2
3516   5.6.1
3517   5.6.1

REP    spec
issue  section

  9    3.2, 5.1
 10    8.1, 8.4
 11    11.5.1
 12    4.2.7, 5.7
 13    5.3.3
 14    4.2.7, 5.7
 29    9.2