Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
5777 lines (4917 sloc) 282 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.7.

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 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 symbolic constants such as the truth values: true and false, as well as none ("nil" or "null" in other languages). The complete list, which is considerably larger, is given in section 14.

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 its shape sub-dialect, the various spec dialects involved in defining vectors, images, bitsets, objects, errors, ports, maps, functions and routines, furthermore the compose and construct dialects and the system dialect (Red/System). A new Red dialect, Red/C3, is being designed for smart contracts programming in the framework of blockchain technologies which are a new infrastructure that should help solve many issues in bringing back the decentralization of the Internet.

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).

Red/C3 will compile to the Ethereum Virtual Machine (EVM) bytecode directly as first target, and more backends will be added later to support other chains, like NEO.

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 character encoding 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 (see e.g. this Wikipedia article). In the Red source text, whitespace characters include at least space (U+0020), tab (U+0009), line feed (U+000A), carriage return (U+000D) 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.

Note that the set of whitespace characters may be extended in future to include some more (or even all) of the ones defined as such in the Unicode standard.

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.

S100

program structure

<program>  ::= <prologue> <value>*
<prologue> ::= Red [ <value>* ]
<value>    ::= <lexeme> | <group>
<lexeme>   ::= <integer-literal>                        ; integer!
             | <hex-literal>                            ; hex!
             | <float-literal>                          ; float!
             | <integer-literal>% | <float-literal>%    ; percent!
             | <money-literal>                          ; money!
             | <time-literal>                           ; time!
             | <date-literal>                           ; date!
             | <integer-literal>x<integer-literal>      ; pair!
             | <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!
             | <ref-literal>                            ; ref!
             | <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> <value>* ]           ; reserved for general typed value constructor
                                                        ; ("construction syntax")

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> ::= <value>
               | <value> <op> <expression>
               | <prefix-function> <expression>*
               | <word-literal>: <expression>

Here <op> is 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 (with a minor exception, see for details section 7.4.3); also, operators are strictly left associative, and 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

Note: the official Red Programming Language Documentation will contain a systematic description of all Red types and values in its Red Core Language section, currently under development.

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

hex!

sequences of hexadecimal characters, for identification purposes or as hexadecimal encoding of a positive number

bigint!

integers of arbitrary size

float!

floating point (decimal) numbers, binary encoding

percent!

floating point numbers expressed as a percentage

money!

monetary amounts, 22-digit decimal encoding, with currency code

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!

sequences of numbers 0-255, e.g. colors in RGB or other model, 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!, integer!, percent! or float!

string!

sequences of characters (Unicode Code Points)

file!

files or directories (folders)

url!

URLs

tag!

tags in the sense of HTML, XML etc.

ref!

references, e.g. user-ids in social media

email!

email addresses

binary!

sequences of bytes (numbers 0-255)

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 more 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!
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 the representation of their values

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. As also explained there, an alternative, syntactical representation of values 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. Many composite types (notably types in series! and bitset!) have their components arranged as a (ordered) sequence of values, i.e. there is the notion of a component’s ordinal number (index) and of next/previous component.

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 one or more 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

hex!

lexical

indirect

atomic

N

passive

bigint!

bigint!

using make

indirect

atomic

N

passive

float!

lexical

direct

atomic

N

passive

percent!

lexical

direct

atomic

N

passive

float!

money!

lexical

direct

composite

N

passive

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!

ref!

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, make

function

atomic

Y

function

native!

function!

using make

function

atomic

Y

function

context!

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!, routine!, handle! and event!; the pre-defined values of type action! and native! are produced during initialization of the toolchain using make, and the expressions used are allowed also in user programs, but it is not recommended to do so

  2. See REP #14

  3. See REP #12

TBD
point!
closure!
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!
   |  |  |  |--hex!
   |  |  |  |--bigint!
   |  |  |  |--float!
   |  |  |  |--percent!
   |  |  |--money!
   |  |  |--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!
   |  |  |--ref!
   |  |  |--email!
   |  |--binary!
   |  |--image!
   |--bitset!
   |--map!
   |--any-object!
   |  |--object!
   |  |--error!
   |  |--port!
   |--any-function!
      |--native!
      |--action!
      |--op!
      |--function!
      |--routine!

TBD
point!
closure!
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

Note: the official Red Programming Language Documentation will contain a systematic description of all Red types and values in its Red Core Language section, currently under development.

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>.

An alternative syntax will exist for making values of various types: the general typed value constructor #[ <type> <spec> ].See REP #9

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 (new infix operators can be made by the user). 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.

Because the save and load functions (see section 11.1.3) will treat the pre-defined words, referred to in the previous paragraph, as word! values, the typed value constructor is used to denote the values referred to by these words:

#[none] #[true] #[false] #[none!] #[logic!] #[char!] #[integer!] #[word!] #[lit-word!] #[set-word!] #[get-word!]
#[refinement!] #[issue!] #[block!] #[paren!] #[path!] #[lit-path!] #[set-path!] #[get-path!] #[string!] #[bitset!]
#[native!] #[action!] #[op!] #[function!] #[routine!]

More such applications of the value constructor may follow. See again 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 to be replaced by the hex! datatype Note: A separate datatype bigint! (see section 5.3.13 is available for operations on integers of arbitrary size.

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).

For mathematical computations, the word pi is pre-defined to represent π to 15 decimals.

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 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: ! \ & ' ^ * + - . < = > ? _ ` | ~. A <word-literal> does not begin with 0-9 or ', and does not contain \. A < character cannot be part of a <word-literal> if it follows anything but another < character. Furthermore, <…​> with any characters in between the < and > character is a <tag-literal>. (see section 5.2.11). Words, i.e. instances of <word-literal> are case-insensitive, i.e. changing any letter in the literal into the corresponding upper- or lower-case variant does not create a different word in terms of the equality operator = (see section 5.8.1).

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 1 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>*} | <raw-string>

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 ^.

A <raw-string> provides a way to input a literal string without any special treatment of its content such as indicated in the preceding paragraph. It is delimited by %{ }% or %%{ }%% or %%%{ }%%% etc. Any number of % characters can be used in order to make the ending sequence not collide with string’s content. The leading count of % must match the trailing count.

Within a <string-literal> that is not a <raw-string>, the same remark holds for ^ as noted above for a <char-literal>.

Examples:

"abc^/def"
{abc +
def}
%{^ is used for escaping }}%

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 new-line characters may be included. The interpretation of this value is operating system dependent.

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. Escaped characters of the form %<hex-byte> (see section 5.2.12) are accepted; the % character itself needs to be escaped as %25.

5.2.10. email!

S120

An <email-literal> is written as two or more characters containing one @ but not beginning with it.

5.2.11. tag!

S121

A <tag-literal> is written as one or more characters, not starting with a whitespace character or one of < = > [ ] ( ) { } " and not containing ;, enclosed in < >.

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: <hex-byte> or <base64-char> may be separated from the brackets and from each other by whitespace. The same goes for the individual 0 and 1 digits making up each <base2-byte>. For computational purposes, binary! values have components that are (unsigned) integers 0..255.

Examples:

2#{0000 0001 0000 0010 0000 00 1 1}
#{ 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). An argument value of 58 is also allowed, for applications related to cryptocurrencies.

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.14 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:

A <refinement-literal> consists of a / followed by a sequence of one or more characters, It is delimited by end-of-text, whitespace, semicolon, or any character from the set [ ] ( ) { } " @ : / subject to the exceptions below.

A / followed by one or more / and possibly further characters is not a <refinement-literal> but a <word-literal>. This is delimited by the above-mentioned delimiters and also by #. The same goes for a single / before any of these delimiters, except obviously /. See further section 5.2.5. 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

An <issue-literal> consists of # followed by a sequence of one or more characters. It is delimited by end-of-text, whitespace, semicolon, or any character from the set [ ] ( ) { } " < @ . Note that any of #[ #( #{ #" introduces a (grouped) value of another type than issue!.

Restrictions: / is only allowed as first character of the sequence, while < > and , are only allowed if they are not the first character. Also, the combinations <> and <…> with any characters in between the < and > characters are not allowed anywhere in the sequence.

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

5.2.17. hex!

S138

A <hex-literal> consists of 0x followed by 11 or more hexadecimal characters 0-9 A-F a-f. There is no upper limit to the number of such characters. The value of the <hex-literal> is the sequence of hexadecimal characters.

Example: 0x76960dccd5a1fe799f7c29be9f19ceb4627aeb2f ; the contract number for the Red Community Token (RED)

5.2.18. money!

S139

A <money-literal> consists of an optional sign (+ or -), followed by an optional 3 letter currency code, followed by $ and 1 to 17 significant digits (not counting leading zeroes) optionally followed by a decimal point and 1 to 5 digits of fraction. Digits may be separated by ' signs. The allowable currency codes are to be found in system/locale/currencies/list which initially contains the internationally standardized ones (ISO 4217) in addition to some crypto ones; user-defined codes may be appended to it; these must be words of 3 letters, different from already existing ones, and not making the total number of codes greater than 255. If the metadata (see section 17) contains a Currencies: field with a block of appropriate words, these will be added to the list by the toolchain.

Examples: $123.45 $12'345'678'901'234'567.12345 USD$1.07 EUR$0002.50

5.2.19. ref!

S141

A <ref-literal> consists of a @ sign followed by zero or more characters other than # ' > = , @ $ ^ \ and it is terminated by any of the following [ ] ( ) { } " ; <, and whitespace of course.

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!, handle! and event! may not be made using make, and using make to create values of types action! and native! is possible but not recommended, and will not be documented here.

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 earlier, 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 first argument has a different interpretation.

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

In addition to the following rules, it should be noted that for all types in series! except image!, for bitset! and for map!, make is also 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!, map! or bitset! value with storage for the given number of components reserved; for maps, the number of components refers to key-value pairs; for bitsets, the number of components is rounded up to the nearest multiple of 8, and they are initialized to false See issue #2609; for vector!, the components are initialized to 0 (see section 5.3.3).

5.3.1. typeset!

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

A number of typesets are pre-defined, see section 4.3.

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> <integer>]
<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. If <block> is not empty, and some of its values cannot be represented by the number of bits specified by <type-and-size>, these values are truncated to that number of bits. If an <integer> is specified, it indicates the number of components, which will be initialized to "zero" (0 for integer!, 0.0 for float!, 0% for percent! and #"^(null)" for char!).

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>

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>] | [<pair> <tuple>] | [<pair> <binary> <binary>°]

An image! value stores a sequence of RGBA (color + transparency) values for pixels, representing a rectangular array (width x height, left to right then top to bottom), and 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> or [<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. 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.

Examples:

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

5.3.5. bitset!

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

The built-in function charset is defined as shorthand for make bitset!. The <bitset-spec> that is 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 <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). A bitset of length 0 is created by a <bitset-spec> of [ ], "" or #{ }. 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.7). The bound block is then executed. 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 object, 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.

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 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, and are none initially. 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>*] <return-doc>°
<return-doc> ::= <string>
<function-body> ::= <block>

For <typeset-element> see rule S124. Note that for a program to be compiled, 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. For interpreted programs this restriction does not apply. 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>. Likewise for the <return-doc>. 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 not implemented yet. 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 except the ones that occur in a block following the /extern refinement see issue #324.

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>

The constituents of <map-spec> are not evaluated. 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.

If the key is of any-word! type, the key type is converted to set-word! in the map. Nevertheless, in order to access any-word! keys, there is no requirement to provide a set-word! value; for practical reasons (easier construction, especially in paths), word! values can be used. Similarly, the keys-of reflector (see section 5.7.3), will return words instead of set-words, as it simplifies further processing.

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> ::= <object> | <block>

If the <port-spec> is an object, this should contain one or more relevant fields (see section 11.4.1 for their names and significance) for the port. If the <port-spec> is a block, this is treated in the same way as an <object-spec> (see section 5.3.6).

Note that port! values all have class = 2.

5.3.13. bigint!

S140
<bigint> ::= make bigint! <bigint-spec>
<bigint-spec> ::= <integer> | <hex> | <binary>

An <integer> produces a bigint! value equal to the integer value. A <hex> produces a bigint! value computed by considering the <hex> as a (positive) integer in hexadecimal notation. The same holds for a <binary>.

5.3.14. Other types

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

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

  • Making money! values from block! values: at most three elements are allowed in the block; an optional word! value for a valid currency code; a signed integer! or float! value for the numerical value (float! values are truncated to 5 decimals), and an optional unsigned integer of maximum 5 digits which istaken as decimal fraction, after being padded to the left with zeroes if necessary (only if the preceding value is integer)

  • Making money! values from binary! values: the binary string must contain at most 11 bytes; if fewer than 11 bytes are present, they are padded to the left with 00 bytes; each byte is interpreted as two "nibbles" (half bytes), each of which must be a digit 0 - 9; the first 17 of the resulting 22 digits are interpreted as the integer part of the money value and the last 5 as the fractional part

  • Making money! values from integer! float! and any-string! values: this follows the rules for conversion by to; refer to the next section

  • Making money! values from word! values: the word should be a valid currency code; the result is a money! value of $0.0000 with the given currency

  • 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 would give 1-Feb-2017 and 3 -10 0 would give 02:50:00) are not allowed. The timezone value is treated as in <date-literal> (see section 5.2.14).

  • 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 (see section 11.1.1); the first component is assumed to be the scheme (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.

  • For the following types, make operates in the same way as to (see next section): none!, char!, ref!, float!, percent!, time!, pair!, any-word!, refinement!, issue! and 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. The following types may not occur as target type: datatype! native! action! op! function! routine! object! error! vector! handle! port! event! See REP #71. For typeset! bitset! and map!, to is identical to make, except that for bitset! and map!, to does not allow an integer! or float! argument.

Note also, that conversion with to may lead to values being created, that would not be allowed in a Red program, or even be interpreted differently. Such values may still be useful in dialects. Example: to-path [1 2 3] gives 1/2/3, and 1/2/3 in a Red program is the date! value 1-Feb-2003.

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!

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

  • tag! values: the brackets < > are omitted by to-string but not by form

  • binary! values: these will be decoded as UTF-8; incorrect encodings will lead to an error

  • 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, to-tag and to-ref 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-block!

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 typenames as word! values

  • 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 and to-hash will perform the same conversion and yield a result of the appropriate type. The functions to-path etc. will do the same, but only with values of string! and any-block! type. For the other argument types mentioned the result is a path! etc. value with the argument as single component.

5.4.5. Target type integer!

The function to-integer is defined for

  • float!, percent! 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 See issue #2329

  • 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 float! and percent!

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, multiplied by 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!.

5.4.7. Target type money!

  • integer! and float! values: they yield the corresponding money! value; float! values are truncated to 5 decimals

  • any-string! values: these should conform to the <money-literal> format (see section 5.2.18)

5.4.8. 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.9. Target type pair!

The function to-pair is defined for

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

  • block! 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.10. 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

  • issue! values: interprets up to 24 characters, if possible, as tuple components, taking each two as a hexadecimal number 0..255; further characters are ignored; if only 1 or 2 numbers are present, components 0 are added; if the number of characters is odd and less than 24, the last one is ignored See issue #2329

  • 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.11. Target type binary!

The function to-binary is defined for

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

  • money! values: yields an 11 byte binary! value of 17 + 5 half-bytes corresponding to the digits of the money! value, disregarding the sign and the currency code, if any

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

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

  • issue! values: interprets the characters following the #, if possible, as base16 representation of a binary value; if the number of characters is odd, the last one is ignored See issue #2329

  • bitset! values: yields the corresponding binary value

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

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

  • any-list! values: these should contain only values of the types indicated above, or other any-list! values; the results for the components are concatenated; any-list! components are treated recursively see issue #4273

5.4.12. 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.13. 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.14. 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.3.14) except that in this case, over- and under-flow are allowed and taken into account.

5.4.15. Target type time!

The function to-time is defined for

  • number! values: yields the corresponding number of seconds

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

  • any-list! values: these 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.16. 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-money takes a word argument and an integer or float argument and combines them into a money! value; thus as-money w a is equivalent to make money! reduce [w a]

  • as-pair takes two integer or float 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; single digit values are scaled by 16, thus hex-to-rgb #12316.32.48

  • 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)

  • dehex converts a string!, file!, url! or email! value containing hex-encoded characters (%<hex-byte>, see sections 5.2.8/9/10 and 12) into a string! value in which the characters have been decoded

  • debase and enbase have been described in section 5.2.12

  • load-csv converts a CSV text (string! value) to a block of rows, where each row is a block of fields

  • to-csv converts data in the form of a block of fixed size records, a block of block records, a map of columns or an object, into CSV text (string! value)

  • load-json converts a JSON text (string! value) to a Red value

  • to-json converts a Red value into JSON text (string! value)

  • compress takes a binary! or any-string! argument and compresses it according to GZIP (default), ZLIB or DEFLATE format; the any-string! argument is first converted to binary! using UTF-8 encoding

  • decompress takes a binary! argument and decompresses it according to GZIP (default), ZLIB or DEFLATE format

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! and binary! on the other See issue #4131. 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.

See also REP #30

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 (row-first, 1-origin), with the resulting linear 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 money!, time!, date!, pair! and tuple! also admit component selection by "indexing", using both path expressions and pick (but not poke). 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 money! values: 1 ~ code 2 ~ amount

  • 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. The built-in function last is defined as pick <expression> length? <expression> for values with types in series! and tuple!. For length? see section 9.2.

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.

Finally, note that the components of a binary! value are yielded as (unsigned) integers 0..255, on extraction; on changing, any integer! or char! value is allowed, but its binary representation is truncated to the lowest 8 bits.

See also issue #3729

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 money!, 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!. If there is no such key in the map, both the key and the corresponding value are added to the map; otherwise, the value associated with the found key is replaced. To remove a key and its value from a map, use remove/key (see section 9.5).

  • 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.

  • 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 for the path expression apply as noted above for indexing. Moreover, if the <destination> is of a type in any-block!, and the <key> is not present, the path expression will not add the key/value pair, but an error is raised. Analogous to the case of indexing, 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 money!, 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 which is a block of pairs <type-name><block of key words>.

In case of money!, time!, date!, email!, image! and event!, the result is obtained as follows.

Extracting a component:

  • money! values: the code component is retrieved as a word! value, using a stored index, from the list of allowed currencies, or it is none; the amount component is retrieved as a money! value without the currency indicated

  • 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 See issue #4047.

  • 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

money!

1 2

pick

code amount

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 extra

select

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. Enquiry and reflection on values

5.7.1. Overview

Values of some types have (internal) properties of interest to the user which may usefully be exposed. Red makes these available through various means:

  • enquiry functions, yielding a yes or no answer (logic! value)

  • reflection functions, notably the reflect built-in function, and its shorthand forms <property>-of, as well as various other built-in functions

  • accessors, which have the form of selection keys (see section 5.6.2) that select properties rather than components

All enquiry functions end in ?. Some reflection functions that do not yield a logic! value also end in ?.

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

5.7.2. Enquiry functions

As already stated in section 4.4, 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 ?.

Other enquiry functions are:

  • value? which tests if a word has a value (see section 6.3)

  • NaN? positive? negative? zero? even? odd? which test arithmetic properties (see section 8.1)

  • empty? single? head? tail? last? which test properties of series (see section 9.2)

  • new-line? which tests for the new-line marker (see section 11.1.1)

  • complement? which applies to bitset! values (see section 5.3.5)

  • exists? dir? which test properties of files (see section 11.3.2)

  • open? (see section 11.4.2)

5.7.3. Reflection functions

The general function is reflect <expression> <property>, where the <property> is expressed as a word! value. Shorthand functions <property>-of <expression> exist in almost all cases: e.g. words-of <expression> is defined as reflect <expression> '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. See also issue #3552 For native! and action! values, body-of could give the native resp. action number (see sections 7.4.2 and 7.4.4, as well as REP #51).

  • For series! values, the properties owner and owned have been defined which are notably used by the reactivity facility (see section 13.4). Note that these properties can only be obtained by reflect <expression> ’owner resp. owned. Likewise for the owned property of object! values. The property 'changed for object! values may be obtained by reflect <expression> 'changed and will yield a block of keys (word! values) indicating the fields whose value has been changed; this property can be cleared by modify <expression> 'changed none.

Other functions:

  • For any value, type? will yield its type as a datatype! value. It has a refinement /word which will yield the type as a word! value.

  • The functions length? and offset? are defined for series! values, (see section 9.2).

  • The function sign? yields the sign of a number! or money! value (see section 8.1).

  • The functions size? and suffix? are defined on file! values (see section 11.3.2).

  • For any-word! values, information on their binding may be obtained by means of two built-in functions: context? and index?. These are explained in section 6.2.

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

5.7.4. Accessors

Values of types email! and image! admit (pseudo-)component selection by "key" (see section 5.6.2). These keys may be considered reflectors since their results do not correspond to a single (indexable) component of the series value.

The components of money!, time!, date!, pair! and event! values that are selected by keys (or their equivalent indexes in the case of money!, time!, date! and pair!) are not considered the result of reflection, since they are true components.

The reflection facilities requested on vector! values might also be implemented by accessors

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. For characters (values of type char!) the equal? test is case-sensitive, but see REP #67

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!

  • integer!, float!, percent! and time!

  • money!, integer! and float!

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

  • types in any-string!

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! money! time! and date!

  • lexicographic ordering (case sensitive): pair! tuple! any-word! refinement! issue! vector! any-string! binary! and bitset!

  • lexicographic ordering (with recursion and cycle detection): any-block! and any-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. 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!) and port (value of type port!) 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 or port value is yielded as an object having the same field names and values as the error or port. 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

  • making a port! 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; see also rule E109. Equivalent to this is the application of the built-in function set: <word-literal>: <expression> ~ set '<word-literal> <expression>; likewise for <path-literal>.

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

Both set and unset may have a block! argument instead of a word! or path! one. The set/unset action is applied to all the words in the block. In addition, set may have an object! argument and an <expression> which evaluates to a block! value. This results in the fields of the object being set to the values in the block. If there are too few values, the rest of the fields will be set to none. If there are too many, these will be ignored.

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. Making a port! value

This is treated in rule S135 and in section 11.4.

6.3.6. Function application

This is treated in rule E110.

6.3.7. 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 and the next. 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, error or port 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.8. Built-in in function

The built-in function in has two arguments: an object!,error! or port! value and an any-word! value, again called "word" in the rest of this section.

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 pre-defined 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> (see section 5.3.6) or a <map-spec> (see section 5.3.11) 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 <lit-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. Note that evaluating set '<word-literal><expression> within an <object-spec> has the result that the <word-literal> is made to refer to the <expression> within the context in which the object is being made, thus outside the context which is the object itself.

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:

(S131)
<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 these words initially refer to none, except for the refinements which are initialized to false.

    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. 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 (see section 7.1) the block which is 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 not implemented yet.

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>.

See also issue #3585

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 more 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 other argument(s), 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 value that precedes the op! value corresponding to the first argument and the expression following the op! value corresponding to the second one. The precedence rule stated in section 3.3 applies, except if the first argument evaluates to a function having a literal first argument, and there is no second argument provided, in which case the op! value is not applied, but yielded as argument to that function.

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

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 function rejoin will reduce all elements of its block! argument, form each of them if not of any-string! type (see section 11.1.1), and concatenate them into a result of the type of the first element. Thus:

rejoin ["abc" %.def]      ; "abc.def"
rejoin [%abc ".def"]      ; %abc.def

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.

The functionality mentioned in point 4 also exists with disk-caching of remote files: do-thru will invoke read-thru (see section 11.3.1).

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 +, -, * and / as operators and their prefix counterparts: add, subtract, multiply`and `divide. In addition, there are operators and prefix functions for exponentiation (** or power), remainder (% or remainder) and modulo (// or modulo). Enquiry functions are: sign?, positive?, negative?, zero?, even?, odd? and NaN? ("not a number", see section 5.2.2). 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. If an arithmetic operator is not mentioned, it is not allowed for the combination of operand types. For the result type of %% see also issue #2708 See further issue #2776

function arity operand 1 type operand 2 type result type

+ - * / % //

2

char!

char!

char!

+ - * / % //

2

char!

integer! float!!

char!

+ - * / % //

2

integer! float!

char!

same as operand 1

+ - * / % //

2

number!

number!

see note 1

+ - * / %

2

vector!

number!

vector! 2

+ - * / %

2

number

vector!

vector! 2

+ - * / %

2

vector!

vector!

vector! 3

+ - * / % //

2

money!

integer! float!

money!

+ - *

2

integer! float!

money!

money!

+ - / % //

2

money!

money!

money! 4,5

+ - * / % //

2

time!

number!

time!

+ - * / % //

2

number!

time!

time!

+ - * / %

2

pair! tuple!

number!

same as operand 1

+ - * / % //

2

number!

pair! tuple!

same as operand 2

+ -

2

date!

integer!

date!

+

2

integer!

date!

date!

-

2

date!

date!

integer! 6

+ -

2

date!

time!

date!

+

2

time!

date!

date!

+ - * / % //

2

time!

time!

time! 5

+ - * / % //

2

pair!

pair!

pair!

+ - * / % //

2

tuple!

tuple!

tuple!

**

2

number!

integer! float!

integer! 7 float!

max min

2

scalar!

scalar!

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

function arity operand type result type

NaN?

1

number!

logic!

sign?

1

money! number! time!

integer!8

positive? negative?

1

money! number! time!

logic!

zero?

1

money! number! char! time! pair! tuple!

logic!

even? odd?

1

money! number! char! time!

logic!

negate

1

money! number! time! pair!

same as operand 9

absolute round

1

money! number! time! pair!

same as operand 9

sum

1

any-list! 10 vector!

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

average

1

any-list! 10 vector!

see note 11

Notes:

  1. the result is of type float!, unless both operands are integer — and in case of division only if there is no decimal fraction — then it is of type integer!; furthermore, if the first operand type is of type percent!, the result is of type percent!

  2. the result has the element type of the vector operand see also issues #2216, #4068 and #4352

  3. operand 1 and 2 must have the same element type

  4. if both operand 1 and 2 have the currency indicated, these must be the same

  5. divide has a result of type float!

  6. the result is the difference in days, disregarding time; for difference as a time! value use difference

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

  8. the result is -1 0 or 1

  9. see REP #10

  10. the components must be of type money! or scalar!

  11. the result has the type of <sum> / to-float length? <argument>

The difference between the remainder and modulo 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 remainder is the negative remainder, and the result of modulo is the positive 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 remainder and modulo 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). These functions are also defined for series! arguments; see section 9.3.

The function math takes a block containing expressions involving multiplication and division, and executes it using normal mathematical precedence rules. Example:

1 + 2 * 3          ; 9
math [1 + 2 * 3]   ; 7

Note that math only deals with * and / and not with other basic arithmetic operators.

8.2. Higher mathematical functions

This concerns first of all the familiar functions exp for raising e = 2.718281828459045235360287471 to a power, the logarithms log-e log-2 log-10, and the square root sqrt. See issue #2699 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

integer! float!

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; for pair! and tuple! arguments it operates per component; if called with argument true it yields one of false and true; for integer! arguments the lowest value is 1; likewise, for char! argumentss the lowest value is #"^(01)"; 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!. See issue #3711

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! tuple! 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 and 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 and or evaluate both their arguments. In many programming situations where several conditions are to be tested, 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, errors and ports.

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, errors and ports all have fields, and share a number of operations, although there are also differences to be taken into account. For ports, operations on series may be implemented using the actor field of the port’s scheme object (see section 11.4.1. This is not further indicated in the next sub-sections.

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> <expression>

(index calculated from <expression>)

skip <series> <expression>

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 at and skip, the <expression> should evaluate to an integer! value, except for <series> which are image! values, where 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!. See issue #4327 If the <expression> is a bitset! value, the equality test is case-sensitive, i.e. only the Unicode Code Points indicated are found, not their other case counterparts.

The functions foreach <counter> <series> <body-block> and forall <word> <body-block> are described in section 10.2.

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!). The result of find in these cases is true if there is a match, and false otherwise. It is defined in addition on values of type map! (see section 9-5).

Furthermore, if the <series> argument is of type any-block! and the <expression> is of type datatype! or typeset! the result is the <series> at the index of the first occurrence of a component of that type or of one of the types in that typeset.

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 and reflection 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 respectively true as result.

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

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 last. As stated there, select and put are not defined on image! values.

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

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`. With the refinement /type one can specify more precisely which type of components need to be copied in this way. See issues #2167 and #2254

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!, and error!.

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,
null bytes from binary, or none from block or hash value

at head

pad <series>

string padded on right side with spaces

at head

The functions change, replace, alter, insert, append and repend take an <expression> argument that evaluates to either a single component of the series or to a sub-series. For any-list! series, the argument may be of any type; if it is of any-block! or vector! type, the components are treated one by one, except if the refinement /only is used. For any-path series, the argument may be of any-block! type, with the same comment. For vector! series, the argument may be of vector! or block! type. See issue #4080 For binary! series, the argument will be converted to binary! if needed, and thus may be of any type for which to binary! is defined (see section 5.4.11_); note that for integer! values the binary equivalent is truncated to 8 bits. See issue #4367 For any-string! series, the <expression> argument may be of any type; if it is not a char! or any-string! value, is first form ed (see section 11.1.1); any-list! values will have their components concatenated after being form ed. For vector! series, the (components of the) <expression> argument will be truncated to the bit-size of the vector, if needed.

The function remove-each <counter> <series> <condition-block> is described in section 10.2.

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.

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).

In connection with trim, see issue #3663

The function pad in fact accepts an argument of any type, which will be form ed into a string! value if needed.

The function sort is only defined on values of type string!, binary!, vector!, block!, hash! and 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 (TBD) 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 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.

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> <key>

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

remove/key <map><key>

removes the key indicated by <key> if it exists
together with the associated value, otherwise nothing happens

length? <map>

yield the number of key-value pairs

empty? <map>

yield true on #( ), false otherwise

9.6. Operations on objects, errors and ports

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

The function copy is also defined on objects, errors and ports, and yields a copy of the object, error or port.

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 none of the conditions 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 <times> <body-block>
<repeat>      ::= repeat <word> <times> <body-block>
<foreach>     ::= foreach <counter> <series> <body-block>
                | foreach <counter> <map> <body-block>
<forall>      ::= forall <word> <body-block>
<remove-each> ::= remove-each <counter> <series> <condition-block>
<counter>     ::= <word> | <block>
<times>       ::= <integer> | <float>

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; if a float is provided it will be truncated to an integer.

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

  • foreach: for series, 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. For maps, the <counter> must be a block with 2 words; the <body-block> is executed repeatedly with the words being set to a key and its associated value, respectively, visiting all keys in some order. 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; the <word> should initially refer to a series value; on each subsequent iteration the <word> is set to refer to the series at the next position (see next function in section 9.2); the loop ends when the <word> refers to the tail of the series; after this, the <word> will again refer to the original series value.

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. See issue #1706

10.3. Interrupting execution

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

The built-in function quit-return stops evaluation and returns back to the Operating System, delivering its integer argument as status code. The built-in function quit or q performs a quit-return, after saving the console configuration if it was called from the console. The built-in function halt, when called from the console, stops evaluation and returns to the input prompt.

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 an initial set of basic I/O 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.

Overview-table of current and planned facilities:

resource type implemented by functions

file!

basic I/O

read write query delete modify

url!, http(s) schemes

basic I/O

read write modify open

url!, other schemes

ports

read write modify open

port!

ports (planned)

create close delete modify open open? query read rename update write

Note that modify is defined but not yet implemented. See issue #3570

11.1. Conversion of data

11.1.1. Conversion from/to textual representation

The lexical/syntactic analysis facilities of the toolchain (see section 3.1) are made available to the user in the form of the built-in function transcode which takes textual input as a string! value, or its binary UTF-8 encoded equivalent, and will produce a block of one or more values. A separate function scan will take the same input and yield the type of the (first) value or error!, without producing the analyzed value(s). See also the chapter "Lexer" in the Additional documentation

The built-in function load, when presented with textual input, will invoke transcode. If called with an argument (source) that is a file! or url! value, load will read the content of the source and — if the representation cannot be otherwise determined (see next section) — will invoke transcode on that content.

There are three mechanisms for converting Red 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! tag! 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
mold/all true             ; "#[true]"               will be loaded as logic! value, not word!

Since form and mold may produce long strings for complex values, the function ellipsize-at may be used to truncate and add ellipsis (…​) to a string.

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.

The built-in function save with a first argument (destination) of type string!, binary! or none! will apply mold to the expression which is its second argument. If the destination 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. If the destination is none, the result is the molded value, as a UTF-8 encoded binary! value. If save is called with a destination that is a file! or url! value and there is no specific representation indicated (see next section) the result will be written to the destination as a UTF-8 encoded binary! value.

11.1.2. Conversion from/to other representations

The built-in functions load and save each have an /as refinement with a word! or none! argument: the value none indicates Red code (molded Red values) and makes load and save operate as already described. Encoding/decoding functions have been implemented for various representations or data formats, notably for images (arguments png, jpeg, bmp and gif) and for JSON and CSV (arguments json and csv).

For each of the image formats load will accept binary data in the indicated format, either directly as a binary! value or from a file! or url! source, and decode it to yield an image! value; save will take an image! value and produce the encoded binary value, either directly (none! destination) or written to a file! or url! destination. For the JSON and CSV formats, load will accept a file! argument and read the content as a string! value, or a binary! or string! argument where the binary! value is converted to string according to UTF-8; save will accept a data argument of any type and produce the encoded string value, either directly (none! destination) or again written to a file! or url! destination. . For each format, the necessary decoding and encoding routines or functions are stored in system/codecs. This is a block of pairs: <word><object>, where the <word> indicates the format, and the corresponding <object> has the following fields: title, name, mime-type, suffixes, encode and decode.

If the /as refinement is not present or its argument is none, and the source or destination is a file! or url! value, an attempt is made to determine the required representation for encoding/decoding, namely for file! values through the suffix, and for url! values through the MIME type in case of decoding, and through the suffix in case of encoding. If this yields no result, the operation is as described in the preceding section.

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.

The function ellipsize-at will truncate a string and add ellipsis …​, if the string is longer than a given length.

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 (section 11.1).

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.3.1)

  • 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! or url! 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 (connections to) persistent resources in the most general sense, both external (including, but not restricted, to files and urls) and internal (e.g. in-process channels and aggregators). As 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 file and url I/O currently provided. For representing all other external and internal resources they use similar conventions.

The operations applicable to ports are described in section 11.4.2; besides I/O operations proper, these comprise most of the series operations as already described in sections 9.2/3. These operations differ according to the type of resource, which RFC3986 calls its scheme. The ports facility of Red extends this notion to all external and certain internal resources, not only those considered by RFC3986. For certain schemes, Red provides a built-in implementation of the operations, in the form of Red actions (action! values). For other schemes, the user can provide the implementation in the form of Red functions (function! values).

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 and internal resources.

As also shown in section 5.6 the fields are:

name type

spec

object!

scheme

word! object!

actor

handle! object!

awake

state

data

block! string! binary!

extra

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. If the resource has a URI, the fields of this object correspond to the components of an URI as detailed in RFC3986. In particular, the type of resource, which RFC3986 calls its scheme, is represented by the scheme field of the spec object. For other types of resources, the spec object contains at least a scheme field.

  • The scheme field of the port is initially a word! value equal to the value of the scheme field of the spec object; during operation it is replaced by a scheme object whose fields are described below.

  • The actor field is either a handle! value if the scheme has a built-in implementation (this is an opaque integer pointing to an action table containing Red/System functions for all actions allowed on ports of this scheme) or an object whose field names comprise the allowable action names, with the corresponding field values being the functions implementing these actions, as provided by the user for this scheme.

  • The awake field TBD

  • The state field contains state information.

  • The data field contains the information read from or to be written to the resource.

  • The extra field is available for the user.

The various scheme objects providing implementation information 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 the corresponding scheme object.

The fields of the spec object for URIs are:

name type content

scheme

word!

e.g. http, udp, file, mailto, gpio

user-info

string!

e.g. "username:passwd"

host

string!

e.g "domain.com"

port

integer!

e.g. 8080

path

file!

e.g. %my-dir/

target

file!

e.g. %index.html

query

string!

fragment

string!

ref

url! string!

the source of the above fields

All fields except scheme may be none. A prototypefor this spec object is contained in system/standard/url-parts. Its field names correspond to the RFC3986 nomenclature, with the exception that the path determined according to RFC3986 is split (using split-path, see section 11.3.2) into path and target. For other tpes of resources, the spec object may be differently laid out, but as stated above, it will contain a scheme field.

The fields of a scheme object are:

name type content

name

word!

e.g. HTTP, TCP, TLS, UDP, FILE, MAILTO

title

string!

e.g. "HTTP scheme implementation"

info

actor

handle! object!

see port! field of same name

awake

A prototype scheme object is contained in system/standard/scheme.

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. The counterpart to this function also exists: encode-url, which takes a spec object and produces the URI as a url! value.

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?

TBD

close

Closes a port

query

read

write

update

modify

rename

delete

As stated above, these functions are implemented for the various schemes by actors, which are either native (Red/System) functions found in an action table or Red functions supplied through an object.

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! is treated in the same way as an <object-spec> (see section 5.3.6).

In addition, each of the series actions (see sections 9.2/3) may be implemented on ports using appropriate actors.

11.5. Other functions

11.5.1. User interaction 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 alert will show a modal (pop-up) window displaying a message (supplied as string or block argument) and wait for the user to click the "OK" button.

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. 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.

Note also that the bindings described are not made when producing an error value by make error! (see section 5.3.7). In any case, the same result can be achieved by navigating system/catalog/errors thus e.g.: system/catalog/errors/(err/type)/(err/id).

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 make-face …​) 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.

The function os-info will return an object! value with the following fields: OS name, architecture, version and build.

13.6. Garbage collection

Garbage-collection, i.e. freeing up of memory space that is no longer used by the program, is normally automatic. It may also be triggered by the program, through a call to the function recycle. Calling recyle/off will disable garbage collection, and calling recycle/on will enable it again.

13.7. 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!
    money!
    native!
    none!
    object!
    op!
    pair!
    paren!
    path!
    percent!
    point!
    port!
    ref!
    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-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 and reflection

see 5.7

1.   Enquiry
--   -------
F    action?
F    all-word?
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    char?
N    complement?
F    datatype?
F    date?
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?
F    integer?
F    issue?
F    lit-path?
F    lit-word?
F    logic?
F    map?
F    money?
F    native?
F    none?
F    number?
F    object?
F    op?
F    pair?
F    paren?
F    path?
F    percent?
F    ref?
F    refinement?
F    routine?
F    scalar?
F    series?
F    set-path?
F    set-word?
F    string?
F    tag?
F    time?
F    tuple?
F    typeset?
F    unset?
F    url?
F    vector?
F    word?

N    complement?
F    dir?
A    empty?
A    even?
R    exists?
A    head?
F    last?
N    NaN?
N    negative?
N    new-line?
A    odd?
A    open?
N    positive?
F    single?
A    tail?
N    value?
N    zero?

2.   Reflection
--   ----------
A    reflect
F    body-of
F    class-of
F    keys-of
F    spec-of
F    values-of
F    words-of

N    context?
A    length?
A    index?
F    offset?
N    sign?
N    size?
F    suffix?
N    type?

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-money
N    as-pair
R    as-rgba
N    compress
N    debase
N    dehex
N    decompress
N    enbase
F    hex-to-rgb
F    load-csv
F    load-json
N    lowercase
A    to
F    to-binary
F    to-bitset
F    to-block
F    to-char
F    to-csv
F    to-json
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 (TBD)
N    bind
N    context?
N    do
F    do-thru
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
O    //          F    divide-strict
N    difference
A    even?
N    exclude
N    exp
N    intersect
N    log-10
N    log-2
N    log-e
F    math
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
N    union
N    unique
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
N    remove-each
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

F    alert
R    ask
N    browse
F    cd
F    change-dir
F    clean-path
A    close
A    create
F    decode-url
A    delete
F    dir
F    dir?
F    dirize
F    ellipsize-at
F    encode-url
R    exists?
F    exists-thru?
A    form
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
F    register-scheme
A    rename
F    request-dir
F    request-file
F    save
F    scan
N    size?
F    split-path
F    suffix?
N    to-local-file
F    to-red-file
N    transcode
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    caret-to-offset
F    center-face
F    clear-reactions
F    distance?
F    do-events
F    dump-face
F    dump-reactions
F    draw
R    find-flag?
F    foreach-face
F    get-scroller
F    insert-event-func
F    layout
F    make-face
F    metrics?
F    offset-to-caret
F    offset-to-char
F    overlap?
F    remove-event-func
F    request-font
F    rtd-layout
F    set-flag
F    set-focus
F    show
F    size-text
F    stop-events
F    stop-reactor
F    unview
F    update-font-faces
F    view
F    within?

14.3.14. Reactivity

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

14.3.16. Garbage collection

(see section 13.6)

N    recycle

14.3.17. Help facilities

F    ?
F    ??
F    a-an
F    about
F    fetch-help
F    help
F    help-string
F    source
F    what

14.4. Objects/contexts

This includes, besides the system object, a number of contexts encapsulating facilities mentioned in section 13, as well as "model objects" that are used by both the reactivity facility and the GUI system.

     system                         see section 15

     preprocessor                   see section 13.1
     help-ctx                       see section 13.7
     gui-console-ctx                see section 13.3, section 11.5.1
     rich-text                      see section 13.3

     reactor!                       see section 13.4
     deep-reactor!                  idem
     face!                          see section 13.3
     font!                          idem
     para!                          idem
     tips!                          idem
     scroller!                      idem

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
        currencies     object!      names of currencies, see section 5.2.18
    options/    object!
        boot           string!      location of Red (console) executable (local file)
        home
        path           file!        current working directory, see section 11.3.2
        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!     16
        decimal-digits integer!     15
        money-digits   integer!     2
        module-paths   block!
        file-types
        float          object!
    script/     object!
        title          string!
        header
        parent
        path
        args
    standard/   object!
       header          object!        see section 17
       port            object!        see section 11.4
       error           object!        see section 12.1.1
       url-parts       object!        see section 11.4.1
       file-info       object!
       scheme          object!        see section 11.4.1
    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"
    while-cond -> {BREAK/CONTINUE cannot be used in WHILE condition block}

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 -> ["context for" :arg1 "is not available"]
    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]
    bad-loop-series -> ["Loop series changed to invalid value:" :arg1]
    invalid-obj-evt -> ["invalid object event handler:" :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]
    rtd-invalid-syntax -> ["RTD - invalid syntax at:" :arg1]
    rtd-no-match -> ["RTD - opening/closing tag not matching for:" :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]
    buffer-not-enough -> ["Buffer size too small, should be:" :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]
    cannot-close -> ["cannot close:" :arg1]
    invalid-utf8 -> ["invalid UTF-8 encoding:" :arg1]
    not-open -> ["port is not open:" :arg1]
    no-connect -> ["cannot connect:" :arg1 "reason: timeout"]
    no-scheme -> ["missing port scheme:" :arg1]
    unknown-scheme -> ["scheme is unknown:" :arg1]
    invalid-spec -> ["invalid spec or options:" :arg1]
    invalid-port -> ["invalid port object (invalid field values)"]
    invalid-actor -> ["invalid port actor (must be handle or object)"]
    no-port-action -> "port action not supported"

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"
    no-cycle -> "circular reference not allowed"
    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:, Config: and Currencies:. If present, they must have prescribed types for the <value> as indicated.

The following is a list of recommended 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)
  Currencies: block!               additional currency identifiers, must be three-letter words

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. Ownership documentation (in blog article from 2016): Red GUI system

  7. 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
accessors                               5.6, 5.7
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
blockchain technologies                 2.5
BMP                                     11.1.2
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
construction syntax                     3.2, 4.2.1, 7.3.1
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
  Red/C3                                2.5
  Red/System                            18
  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
enquiry                                 5.7
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
Ethereum Virtual Machine (EVM)          2.5
evaluation                              7
  shortcut evaluation                   7.5
execution                               2.2
  of a block                            7.1, 7.5
expression                              3.3
external resources                      11.4
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
GIF                                     11.1.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
infinity                                5.2.2
infix expression                        3.3
inherited action                        4.2.6
interactive console                     2.2
internal resources                      11.4
interpretation                          2.2
ipv4                                    5.2.4
ISO 4217 currency codes                 5.2.18
ISO 8601 date and time standard         5.2.14, 5.6.2
JPEG                                    11.1.2
JSON                                    11.1.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
NaN (not a number)                      5.2.2
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
PNG                                     11.1.2
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
rawstring                               5.2.7
reactivity                              13.4
Read Evaluate Print Loop (REPL)         2.2
Red toolchain                           2.2
Red/C3 (dialect)                        2.5
Red/System (dialect)                    2.5, 18
reflection                              5.7
remote file access (disk-cached)        11.3.1
REPL (Read Evaluate Print Loop)         2.2
resources                               11.4
RFC3986 (URI)                           11.4.1
RGB color model                         5.2.4, 5.3.4, 14.1.5
RGBA color/transparency model           5.3.4
routine spec dialect                    2.5, 5.3.9
scheme (URI component)                  5.3.14, 11.4.1
sequence                                4.2.3, 5.6
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.17
Uniform Resource Identifier (URI)       11.4
UTF-8 encoding                          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
  value constructor                     3.2, 4.2.1, 5.1, 7.3.1
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

This list summarizes the known — and reported — issues flagged in the preceding sections, which relate to the syntax and semantics described therein. Thus they do not concern the details of what is described in the additional documentation referred to in section 18. 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. In the list below, the column S gives the status of each issue, as follows:

  • N submitted, not classified (yet)

  • D deferred, i.e. recognized but not scheduled (yet) for review and/or resolution

  • R reviewed by the Red team

  • A assigned for resolution to a specific member of the team

  • F fixed, i.e. resolved by the team, but not (yet) implemented

Red   S spec
issue   section

324   R 5.3.8
1706  R 10.2
1960  A 5.6.3
1961  A 9.3
2167  A 9.3
2216  R 8.1
2254  A 9.3
2329  A 5.4.5, 5.4.10, 5.4.11
2498  A 5.3.3
2609  N 5.3, 5.3.5
2625  R 5.6.3
2642  N 5.3.9
2644  A 5.3.14
2699  N 8.2
2708  N 8.1
2776  N 8.1
3285  A 5.3.8
3344  A 5.3.10
3409  N 5.4.3
3482  N 5.6.1, 5.6.2
3552  N 5.7.3
3570  D 11
3585  N 7.4.1
3663  N 9.3
3711  N 8.3
3729  N 5.6.1
3734  N 5.3.3
4047  N 5.6.2
4068  N 8.1
4080  N 9.3
4131  F 5.5
4273  N 5.4.10
4327  N 9.2
4352  N 8.1
4367  N 9.3
4372  N 8.1

REP   S spec
issue   section

  9   N 3.2, 5.1
 10   N 8.1, 8.4
 11   N 11.5.1
 12   N 4.2.7, 5.7
 30   N 5.5
 51   F 5.7.3
 67   N 5.8
 71   N 5.4
You can’t perform that action at this time.