- 1. Introduction
- 2. Overview
- 3. Structure of Red programs
- 4. Types
- 5. Values
- 5.1. Introduction
- 5.2. Lexical structure of values
- 5.3. Creation of values (
make
) - 5.4. Conversion of values (
to
)- 5.4.1. Target types
none!
andunset!
- 5.4.2. Target type
logic!
- 5.4.3. Target types in
any-string!
- 5.4.4. Target types in
any-list!
- 5.4.5. Target type
integer!
- 5.4.6. Target types in
any-float!
- 5.4.7. Target type
char!
- 5.4.8. Target type
pair!
- 5.4.9. Target type
tuple!
- 5.4.10. Target type
binary!
- 5.4.11. Target types in
any-word!
,refinement!
andissue!
- 5.4.12. Target type
image!
- 5.4.13. Target type
date!
- 5.4.14. Target type
time!
- 5.4.15. Target type
bitset!
- 5.4.16. Additional conversion functions
- 5.4.1. Target types
- 5.5. Casting of values (
as
) - 5.6. Components of values
- 5.7. Reflection on values
- 5.8. Comparison of values
- 6. Words, contexts and binding
- 7. Evaluation rules
- 8. Numerical and logical computation
- 9. Operations on values of indirect types
- 10. Control
- 11. Input/output
- 12. Exceptions
- 13. Additional facilities
- 14. Pre-defined words list
- 14.1. Constants
- 14.2. Datatypes and typesets
- 14.3. Functions
- 14.3.1. Enquiry
- 14.3.2. Making values
- 14.3.3. Converting values
- 14.3.4. Comparison
- 14.3.5. Evaluation and binding
- 14.3.6. Numerical and logical computation
- 14.3.7. Series manipulation
- 14.3.8. Control
- 14.3.9. Input/Output
- 14.3.10. Exception handling
- 14.3.11. Preprocessor
- 14.3.12. Parser
- 14.3.13. GUI system
- 14.3.14. Reactivity
- 14.3.15. Environment and OS-related
- 14.3.16. Garbage collection
- 14.3.17. Help facilities
- 14.4. Objects/contexts
- 15. System object
- 16. Errors list
- 17. Metadata for the toolchain
- 18. Additional documentation
- 19. Glossary
- 20. List of outstanding issues
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 .
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.
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?
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.
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).
A special category of values is formed by words, that play a similar role to identifiers and keywords of other languages. Red does not have identifiers nor keywords: as will be explained in more detail below, any word may refer to another value in some context. The word is said to be bound to, or in the context. Evaluation of a word yields the value it refers to. The evaluation rules given below will state, amongst others, how words can come to refer to values in the course of program execution.
A large number of words are pre-defined to refer to certain values
in the global context, notably to built-in functions, types
(type names conventionally end in !
) and constants such as
the truth values: true
and false
, as well as none
("nil"
or "null" in other languages). See section 14 for the complete list.
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.
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. In the Red source text, whitespace characters are
space (U+0020
), tab (U+0009
), line feed (U+000A
), carriage return (U+000D
), next line (U+0085
)
and non-breaking space (U+00A0
). Consequently, Red program texts are free form,
i.e. neither their arrangement in separate lines, nor their formatting with indentation
and the like, has any significance for their interpretation.
This is most certainly short of some whitespace values, please correct See also issue #2492
In certain cases, where there can be no ambiguity, the requirement for whitespace between values
can be relaxed. For example, it is possible to omit whitespace between two consecutive block!
values and between word!
values and block!
values. These examples are all syntactically valid:
either x = 1["OK"]["NOK"] either x = 1 ["OK"] ["NOK"] either x = 1 [ "OK" ] [ "NOK" ]
Comments, which have no significance for the operation of the program, may be placed following
a semicolon ;
until the end of an input line (end-of-line comment), or they may follow the word
comment
and be formulated as a single Red value — most usefully a series of characters enclosed
in " "
or { }
— or a series of Red values enclosed in [ ]
.
A well-formed Red program begins with a prologue which may contain metadata for the toolchain
and/or the reader. The relevant data will be described in section 17.
Note that, although Red text is in general case-insensitive (barring exceptions noted in
section 5), the first three letters of the prologue must be literally R e d
.
A formal grammar corresponding to the above presentation is given below. This
omits the separation by whitespace, and the presence of end-of-line comments.
As usual, *
means zero or more instances of the non-terminal.
In the grammar fragments of subsequent sections of this document,
o
will stand for an optional instance.
Other characters outside non-terminals stand for themselves, with
the understanding that, if they immediately precede or follow a non-terminal,
they are part of the produced lexeme.
The comment to any production rule, which starts after the ;
on the line,
states the type of the single or grouped values generated by this rule.
The significance of the types is found in section 4.1.
Any non-terminal that is not further defined in this grammar is explained
in the individual sub-sections of section 5. Those sections
will also introduce the <symbol-literal>
, which by itself is not a lexeme,
and therefore does not generate a value of the
language. Its use is in explaining the common characteristics of several
lexemes, namely <word-literal>
, <refinement-literal>
and <issue-literal>
,
see sections 5.2.5 and 5.2.15/16.
S100
-
program structure
<program> ::= <prologue> <value>* <prologue> ::= Red [ <value>* ] <value> ::= <lexeme> | <group> <lexeme> ::= <integer-literal> ; integer! | <hex-literal> ; hex! | <float-literal> ; float! | <integer-literal>% | <float-literal>% ; percent! | <integer-literal>x<integer-literal> ; pair! | <time-literal> ; time! | <date-literal> ; date! | <tuple-literal> ; tuple! | <word-literal> ; word! | '<word-literal> ; lit-word! | <word-literal>: ; set-word! | :<word-literal> ; get-word! | <refinement-literal> ; refinement! | <issue-literal> ; issue! | <char-literal> ; char! | <string-literal> ; string! | <file-literal> ; file! | <url-literal> ; url! | <email-literal> ; email! | <tag-literal> ; tag! | <binary-literal> ; binary! | <path-literal> ; path! | '<path-literal> ; lit-path! | <path-literal>: ; set-path! | :<path-literal> ; get-path! <group> ::= <paren-literal> | <block-literal> | <map-literal> | <constructor> <paren-literal> ::= ( <value>* ) ; paren! <block-literal> ::= [ <value>* ] ; block! <map-literal> ::= #( <value>* ) ; map! (even number of values only) <constructor> ::= #[ <value>* ] ; reserved for general typed value constructor
At a semantic level, the constituents of a Red program are not values but expressions. An expression groups one or more values, and may be formed in three ways: as an application of a (prefix) function, as an infix expression which uses an operator, or as a binding of a word to refer to a value.
The statement made earlier: "execution of a Red program is tantamount to evaluating each of its constituent values in turn, according to the evaluation rules" can therefore be refined to: "execution of a Red program is tantamount to evaluating each of its constituent expressions in turn, according to the evaluation rules", with expression being construed as the largest sequence of values conforming to the following definition:
S101
-
expressions
<expression> ::= <operand> | <expression> <op> <operand> <operand> ::= <value> | <prefix-function> <argument>* | <word-literal>: <expression> <argument> ::= <expression>
Here <op>
is an expression which evaluates to an operator, i.e. an op!
value representing
an infix function of two arguments, and <prefix-function>
is an expression which evaluates
to a prefix function (value of type action! native! function!
or routine!
). The number of
expressions (arguments) following a prefix function is strictly dependent on the function value
and is known as the arity of the function value. Binding is expressed by a <word-literal>:
(set-word!
value) followed by an <expression>
. See further the evaluation rules given
in section 7. Evaluation of the operands of operators has precedence over function
application and binding (with a minor exception, see for details section 7.4.3);
also, as suggested in rule S101
, operators are strictly left associative,
there is no precedence between any two operators. The fact that the arguments of a function simply follow
the function itself (they are not enclosed in parentheses) means that, for the reader to understand
a program, knowledge of the arity of functions is necessary. Evaluation order can of course
be influenced by the use of parentheses, given the evaluation rule for values of paren!
type
(see section 7.3.4).
Some basic examples:
1 + 2 3 + 4 ; 6 values, 2 expressions 1 + 2 * 3 ; result is 9, not 7 1 + (2 * 3) ; result is 7 pick copy "abc" 1 ; 1 is argument to pick, since copy has 1 argument itself copy/part "abc" 2 ; with the "refinement" /part, copy now has 2 arguments mod x 2 + 1 ; mod has 2 arguments; this will be interpreted as mod x 3 1 + mod x 2 ; this is what was probably meant (mod x 2) + 1 ; another way of writing that 1 + a: 2 ; result is 3, a now refers to 2
In what follows, terms like <integer-literal>
will be used to refer to lexemes;
to indicate the corresponding values, terms like "value of type integer!
",
" integer!
value" or plain "integer" will be used. Also, in grammar fragments,
on the right-hand side of the ::=
sign, terms like <integer>
will stand for
" <expression>
evaluating to an integer!
value" etc., while
decorated non-terminals like <true-block>
will stand for <block>
etc.
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.
The full list of types of the languages is given below, with an explanation of the usage of their values.
type | values and usage |
---|---|
|
types of the language (first class values) |
|
sets of types |
|
single value: |
|
|
|
characters (Unicode Code Points) |
|
integer numbers |
|
sequences of hexadecimal characters, for identification purposes or as hexadecimal encoding of a positive number |
|
integers of arbitrary size |
|
floating point (decimal) numbers |
|
floating point numbers expressed as a percentage |
|
time intervals or points in time, stored as a floating point number of seconds |
|
dates according to the Gregorian calendar, optionally with time of day and timezone |
|
2-dimensional coordinates or size |
|
sequences of numbers 0-255, e.g. colors in RGB or other model, IPv4 addresses |
|
identifiers that can be bound |
|
quoted (unevaluated) words |
|
words to be given a value to refer to |
|
words to be evaluated |
|
indicates optional argument of function |
|
literal identifiers |
|
opaque integers for communication with operating system |
|
ordered collections of values of any type (polymorphic array), may also be used as unordered collections (sets) |
|
blocks with quick access |
|
differs from block in behaviour under evaluation |
|
specifying optional arguments in function calls, selection of components of composite values |
|
quoted (unevaluated) paths |
|
for setting a component of a composite value |
|
paths to be evaluated |
|
ordered sequences of values of identical type, which can be
|
|
sequences of characters (Unicode Code Points) |
|
files or directories (folders) |
|
URLs |
|
tags in the sense of HTML, XML etc. |
|
email addresses |
|
sequences of bytes (numbers 0-255) |
|
2-dimensional arrays of pixels (RGBA values stored in 4 bytes for each pixel, row first) |
|
sequences of |
|
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
|
|
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 |
|
specialized objects representing error conditions |
|
specialized objects for communicating with external resources |
|
pre-defined functions with built-in evaluation according to special rules |
|
pre-defined polymorphic functions of one or more arguments with built-in evaluation |
|
operators, i.e. infix functions of two arguments, each one is
derived from a |
|
user-defined functions; as with |
|
user-defined functions with body in Red/System code |
|
single value indicating the absence of a usable value |
|
representations of external activity |
TBD point! closure! ref! struct! library!
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
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> ]
.
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.
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.
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
-
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.
The notion of parent type arises in the implementation of actions, i.e. pre-defined polymorphic
functions of up to two arguments with built-in evaluation, e.g. add
, subtract
, copy
, find
, etc.
The implementation uses a dispatch table which contains a pointer to a specific run-time
function for each allowed combination of action and type of first argument. These functions
are grouped by the type to which they apply. Now for any action/type combination,
such function may be designated as inherited from the parent type, and in this way
two or more types may share the same implementation for that action. In this approach, there
are two pseudo-types defined, which function as parent types from which to inherit:
they are symbol!
for types related to word!
and series!
for types related to block!
and string!
.
A further pseudo-type context!
provides implementation of context-related functionality
(see sections 2.4 and 6).
type | value representation1 | storage | atomic/composite | reflection? | evaluation | parent type |
---|---|---|---|---|---|---|
|
using words |
direct |
atomic |
N |
passive |
|
|
using |
direct |
atomic |
N |
passive |
|
|
using words |
direct |
atomic |
N |
passive |
|
|
using words |
direct |
atomic |
N |
passive |
|
|
lexical |
direct |
atomic |
N |
passive |
|
|
lexical |
direct |
atomic |
N |
passive |
|
|
lexical |
indirect |
atomic |
N |
passive |
|
|
using |
indirect |
atomic |
N |
passive |
|
|
lexical |
direct |
atomic |
N |
passive |
|
|
lexical |
direct |
atomic |
N |
passive |
|
|
lexical |
direct |
composite |
N |
passive |
|
|
lexical |
direct |
composite |
N |
passive |
|
|
lexical |
direct |
composite |
N |
passive |
|
|
lexical |
direct |
composite |
N |
passive |
|
|
lexical |
direct |
atomic |
Y |
active |
|
|
lexical |
direct |
atomic |
Y |
decaying |
|
|
lexical |
direct |
atomic |
Y |
active |
|
|
lexical |
direct |
atomic |
Y |
active |
|
|
lexical |
direct |
atomic |
Y2 |
passive |
|
|
lexical |
direct |
atomic |
Y2 |
passive |
|
|
using words |
direct |
atomic |
N |
passive |
|
|
syntactic |
indirect |
composite |
N |
passive |
|
|
using |
indirect |
composite |
N |
passive |
|
|
syntactic |
indirect |
composite |
N |
active |
|
|
lexical |
indirect |
composite |
N |
active and function |
|
|
lexical |
indirect |
composite |
N |
decaying |
|
|
lexical |
indirect |
composite |
N |
active |
|
|
lexical |
indirect |
composite |
N |
active |
|
|
using |
indirect |
composite |
N3 |
passive |
|
|
lexical |
indirect |
composite |
N |
passive |
|
|
lexical |
indirect |
composite |
N |
passive |
|
|
lexical |
indirect |
composite |
N |
passive |
|
|
lexical |
indirect |
composite |
N |
passive |
|
|
lexical |
indirect |
composite |
N |
passive |
|
|
lexical |
indirect |
composite |
N |
passive |
|
|
using |
indirect |
composite |
N |
passive |
|
|
using |
indirect |
composite |
N |
passive |
|
|
syntactic |
indirect |
composite |
Y |
passive |
|
|
using |
indirect |
composite |
Y |
passive |
|
|
using |
indirect |
composite |
Y |
passive |
|
|
using |
indirect |
composite |
Y |
passive |
|
|
using words |
function |
atomic |
Y |
function |
|
|
using words |
function |
atomic |
Y |
function |
|
|
using words |
function |
atomic |
Y |
function |
|
|
using |
function |
atomic |
Y |
function |
|
|
using |
function |
atomic |
Y |
function |
|
|
using |
direct |
atomic |
N |
passive |
|
|
using words |
direct |
composite |
N |
passive |
Notes:
TBD point! closure! ref! struct! library!
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! | | | |--any-float! <---- see issue #2565 | | | |--float! | | | |--percent! | | |--time! | | |--date! | | |--pair! | | |--tuple! | |--all-word! | | |--any-word! | | | |--word! | | | |--lit-word! | | | |--set-word! | | | |--get-word! | | |--refinement! | | |--issue! | |--handle! |--series! | |--any-block! | | |--any-list! | | | |--block! | | | |--hash! | | | |--paren! | | |--any-path! | | |--path! | | |--lit-path! | | |--set-path! | | |--get-path! | |--vector! | |--any-string! | | |--string! | | |--file! | | |--url! | | |--tag! | | |--email! | |--binary! | |--image! |--bitset! |--map! |--any-object! | |--object! | |--error! | |--port! |--any-function! |--native! |--action! |--op! |--function! |--routine! TBD point! closure! ref! struct! library!
The built-in function type?
will yield the type of a value. It has a refinement
/word
which will yield the type as a word!
value. For every pre-defined
type and typeset there is a built-in function which will test if a value is of that type
(or a type in that typeset). These functions have the name of the type(set) with the
!
replaced by ?
.
Examples:
type? 1 ; integer! integer? 1 ; true number? 1.0 ; true
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.
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 (values of type action!
and native!
cannot
be made by the user, but new infix operators can be).
Values of types event!
and handle!
, that are used to communicate with
the operating system, can only be represented by words that are arguments
to functions handling this communication.
Because the save
and load
functions (see section 11.1.3)
will treat the predefined 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.
S111
-
An
<integer-literal>
is written as an integer number from-231
to231-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 thehex!
datatype Note: A separate datatypebigint!
(see section 5.3.13 is available for operations on integers of arbitrary size.
Examples: 123
-123
+0001
1'000
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).
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
S114
-
A
<tuple-literal>
is written as 3 to 12integer!
values in the range0..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.
S115
-
A
<word-literal>
is a restricted form of<symbol-literal>
.
A <symbol-literal>
is written as one or more characters from the entire Unicode range excluding control characters
(notably Unicode sets C0, C1), whitespace characters and the following set: / \ ^ , [ ] ( ) { } " # $ % @ : ;
.
The following punctuation characters from the ASCII subset are allowed: ! & ' * + - . < = > ? _ `
| ~
.
Symbols, i.e. instances of <symbol-literal>
are case-insensitive, i.e. changing any letter
in the symbol into the corresponding upper- or lower-case variant does not create a different symbol
in terms of the equality operator =
(see section 5.8.1).
As stated above (section 3.2), a symbol is not a value of the
language. Its use is in explaining the common characteristics of values of
several types, namely word!
, refinement!
section 5.2.15
and issue!
section 5.2.16
A <word-literal>
is a <symbol-literal>
that does not begin with 0-9
or '
.
However, the combination <>
may only occur on its own, and <…>
with any characters in
between the <
and >
character is a value of type tag!
(see section 5.2.11).
Examples: abc
Abc
ABC
+
<>
integer!
last-item?
; the first three are equal word!
values.
1a
is not a <word-literal>
; <p>
is a <tag-literal>
.
S116
<char-literal> :: = #"<single-character>" <single-character> ::= <viewable-character> | <escaped-character> | <hexadecimal-codepoint> <escaped-character> :: = ^(null) | ^@ | ^(back) | ^(tab) | ^- | ^(line) | ^/ | ^(page) | ^(esc) | ^" | ^^ | ^(del) | ^~ | ^A | ^B | ... | ^Z | ^[ | ^\ | ^] | ^_ <hexadecimal-codepoint> :: = ^(<hex-number>)
where <hex-number>
consists of 2 to 6 hexadecimal digits 0-9 A-F a-f
.
A <char-literal>
must be a valid single Unicode code point, i.e. an integer in the range 0
to 10FFFF
(hexadecimal notation).
A <viewable character>
is, in most cases, simply a displayable character. For example, e
, é
, €
or 😀
.
When a displayable character requires two or more graphemes to display it, each grapheme requires a separate Red character.
For example, when é
is encoded in its two character decomposed form e
(U+0065
) followed by
the combining ´
(U+0301
) they cannot be considered a single char!
value, and programs must
explicitly handle their interpretation.
The correspondence between the escaped characters and Unicode Code Points is given in the table below.
Named Form | Short Form | Character | Code Point | Pre-defined word(s) |
---|---|---|---|---|
#"^(null) |
#"^@" |
null |
U+0000 |
null |
#"^(back)" |
#"^H" |
backspace |
U+0008 |
|
#"^(tab)" |
#"^I" #"^-" |
horizontal tab |
U+0009 |
tab |
#"^(line)" |
#"^J" #"^/" |
line feed |
U+000A |
lf, newline |
#"^(page)" |
#"^L" |
form feed |
U+000C |
|
#"^(esc)" |
#"^[" |
escape |
U+001B |
escape |
#"^(del)" |
#"^~" |
delete |
U+007F |
|
#"^"" |
" (double quote) |
U+0022 |
dbl-quote |
|
#"^^" |
^ (caret) |
U+005E |
||
#"^A" - #"^]" |
control characters |
U+0001 - U+001D |
||
#"^_" |
control character |
U+001F |
For more pre-defined words referring to characters see section 14.1.1.
Note that code point U+001E
cannot be represented by #"^^"
as expected, since that is already taken for caret.
Note also that ^
will be ignored in front of any single character with which it does not form (the beginning of)
an <escaped-character>
or <hexadecimal-codepoint>
. Thus e.g. ^3
yields the same as 3
.
Examples: #"A" #"^/" #"^(0A)"
S117
<string-literal> ::= "<single-character>*" | {<single-character>*}
where <single-character>
is defined in rule S116
When the <string-literal>
is delimited by " "
it must not contain unescaped new-line characters
U+000A
, U+0085
, U+2028
and U+2029
. When the <string-literal>
is delimited by { }
it may contain
unescaped new-line characters and any "
as well as nested { }
pairs, but any unpaired {
or }
character that is part of the <string-literal>
must be escaped by preceding it with ^
.
Within a <string-literal>
, the same remark holds for ^
as noted above for a <char-literal>
.
Examples:
"abc^/def" {abc + def}
S118
-
A
<file-literal>
is written as%
followed by one or more non whitespace characters, or by zero or more characters enclosed in" "
in which case whitespace characters except line feed and next line may be included. The interpretation of this value is operating system dependent, but escaped characters of the form%<hex-byte>
(see section 5.2.12) are accepted, except when" "
are used. The%
character itself needs to be escaped as%25
.
S119
-
A
<url-literal>
is written as three or more non whitespace characters, of which at least one:
which must not be the first or last character. The remarks in the previous section on escaped characters apply.
S120
-
An
<email-literal>
is written as two or more characters containing one@
but not beginning with it. The remarks in section 5.2.8 on escaped characters apply.
S121
-
A
<tag-literal>
is written as one or more characters, not starting with a whitespace character or one of< = > [ ] ( ) { } " ;
, enclosed in< >
.
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>
.
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.
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
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.
S136
<refinement-literal> ::= /<symbol-literal>
For <symbol-literal>
see section 5.2.5.
A <refinement-literal>
may contain a digit 0-9
or '
as first character after the /
.
However, the combinations /<>
and /<…>
with any characters in between the <
and >
character
will be lexically analyzed as the word /
followed by the word <>
resp. a value of type tag!
(see section 5.2.11).
Note that one of the main uses of refinement values is in indicating optional arguments
of functions. As will be seen in section 5.3.8, these optional
arguments are of the restricted form /<word-literal>
.
Examples: /abc
/Abc
/ABC
/1a
; the first three are equal refinement!
values.
S137
<issue-literal> ::= #<symbol-literal>
For <symbol-literal>
see section 5.2.5.
An <issue-literal>
may contain a digit 0-9
or '
as first character after the #
.
However, the combinations #<>
and
#<…>
with any characters in between the <
and >
character are not allowed.
Examples: #abc
#Abc
#ABC
#10FFFF
; the first three are equal issue!
values.
S138
-
A
<hex-literal>
consists of0x
followed by 11 or more hexadecimal characters0-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)
For some types, the values can only be introduced in a program as a
result of the make
function. This section deals first of all with the types
for which that is the case, and with map!
which has a "parallel"
syntactic form of its own. The make
function can also be used
to construct values of other types. This is dealt with in the
latter part of the section.
Note that make routine!
is forbidden; values of type routine!
should be made
by invoking the built-in function routine
which raises an error
if called from the interpreter. As noted before (section 4.2.7)
values of type datatype!
, native!
, action!
, handle!
and event!
may not be made using make
.
In this section, non-terminals like <integer>
do not stand for
a literal integer but for a value (to be evaluated) of integer!
type etc.
Note also that, as stated above, the first argument of make
does not
have to be a datatype!
value; if it is a value of another type,
that type is taken to be the desired type. This is not made explicit
in the following rules, except in the case of make object!
where
an object!
value as second argument has a different interpretation.
Furthermore, non-terminals like <typeset-name>
stand for a bound <word-literal>
referring to a typeset!
value etc.
In addition to the following rules, it should be noted that for all types
in series!
except image!
, 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!
or map!
value with storage for the given number of components reserved.
For vector!
, the components are initialized (see section 5.3.3).
S124
<typeset> ::= make typeset! [<typeset-element>*] <typeset-element> ::= <typeset-name> | <datatype-name>
Examples:
number!: make typeset! [integer! float! percent!] scalar!: make typeset! [char! number! time! date! pair! tuple!]
Note that an empty typeset is allowed (make typeset! [ ]
).
S125
<hash> ::= make hash! <block>
The contents of the <block>
are copied (not deeply).
S126
<vector> ::= make vector! <vector-spec> <vector-spec> ::= <block> | [ <type-and-size> <block>] <type-and-size> ::= char! 8 | char! 16 | char! 32 | integer! 8 | integer! 16 | integer 32! | float! 32 | float! 64 | percent! 32 | percent! 64
The components of the <block>
should all have the same type char!
, integer!
, float!
or percent!
.
If <type-and-size>
are omitted, type is deduced from the contents of <block>
, and size is
the default size (32 bits for char!
and integer!
, 64 bits otherwise). If <block>
is empty, the assumed type
is integer!
of size 32. 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 < block>
is omitted, the vector components are 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"]
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, 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.
Note: an <integer>
is not allowed in place of the <tuple>
.See issue 2883
If a single <binary>
is specified, this should contain the sequence of colors of all pixels
(three bytes per pixel, in the order R, G, B, stored by horizontal line). The number of triplets should match
the image size, more bytes are ignored, fewer bytes are supplemented with bytes {00}
for 0
. The transparency for all
pixels is set to 255
. The second <binary>
, if present, contains the transparency values (one byte per pixel,
in the same ordering). Again, the number of bytes should match the image size. More are ignored, fewer are
supplemented with bytes #{FF}
for 255
.
Examples:
make image! 200x300, make image! [200x300 255.0.0] make image! [2x2 #{FFFFFFCCCCCCBFBFBF0C0C0C} #{FFFFFFFF}]
S128
<bitset> ::= make bitset! <bitset-spec> | charset <bitset-spec> <bitset-spec> ::= <binary> | <integer> | <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>
that is an integer!
value produces an "empty" bitset (all bits set to false)
of size the nearest multiple of 8. In all other cases the <bitset-spec>
provides a list of bit-position numbers,
or ranges of them, that are to be set to true
. The <char>
is interpreted as the Unicode Codepoint number.
A string!
value is interpreted as the collection of all its component characters.
Note that an integer!
value used as <bit-position>
should be non-negative, but
need not be a valid Unicode Codepoint number.
The length of the bitset is computed as the smallest multiple of 8 needed to fit the highest
bit number (0-origin). An "empty" bitset created by charset [ ]
is 8 bits (one byte) long.
A <bitset-spec>
that is a block starting with not
produces the bit-by-bit complement of the bitset
produced by the following bit-position numbers, while actually storing only these bit-positions.
See issue #2609
Examples:
make bitset! 16 charset "abc" charset [#"A" - #"Z" #"a" - #"z"]
The built-in function complement?
will test if the bitset is a complemented one,
i.e. if its complement is what is actually stored.
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. See issue #3362
The class
property of the newly created object is set to a unique integer.
If the first argument to make
is an object!
value, it serves as prototype.
A new object is created whose associated context is a copy of the prototype’s context.
The set-word!
values that are (first-level) components of the <object-spec>
are added to this context if they are not already present in that context.
The <object-spec>
is then treated as in the previous case.
If there are no new fields, the class
property of the new object is copied
from the prototype; the new object is then said to be derived from the prototype.
Otherwise, the new object receives a new class value.
Within the expressions making up the values of the fields of an object,
the word self
refers to the object as a whole, unless that word has
been defined as a field of the object.
Two field names have special significance: on-change*
and on-deep-change*
.
These should be defined as functions; on-change*
will be called whenever any
field of the object changes its value; on-deep-change*
will be called
whenever a component of a series or object value which is the value of a field, or a
(sub-)component of that field — at any level of nesting — changes its value.
In order to permit the triggering of the latter function, all series and object values
have an owned
property which may be set using the modify
function.
These facilities are used by the toolchain for the purposes of implementing
the reactivity feature (see section 13.4) and hence for the
implementation of the GUI system (see section 13.3). Detailed
information about the implementation details may be found in the documents
referred to in section 18.
An additional built-in function construct <spec>
creates an object,
but without executing the <spec>
block. It has a refinement /with
to specify a base object which will be extended with the (unevaluated)
set-word/value pairs in <spec>
; if any set-word in <spec>
is the same as a field name of the base object, the associated value
will replace the original field value. The words true yes on false no off
and none
will be evaluated to their logic!
or none!
value, except if
the refinement /only
is specified.
The built-in function extend
takes an object!
value as first argument
and a set of key-value pairs as second argument of type block! hash!
or map!
.
It will add the keys that are not present in the 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
S130
<error> ::= make error! <error-spec> <error-spec> ::= <integer> | <block> | <string>
For the fields of an error!
value, and the structure of the error repertoire
(system/catalog/errors
) see section 12.1.
If the <error-spec>
is an integer!
value, it is used to find values for the type
and id
fields of the error!
value which result in the code
with that integer!
value. The values of these two fields are then bound as described in section 12.1.
If the <error-spec>
is a block!
value, it should either contain two word!
values
which will be used for the type
and id
value of the intended error!
value, or
it should be an <object-spec>
containing at least type:
and id:
fields,
and possibly arg1 arg2 arg3
fields;
in the former case, the type
and id
values will be bound as described in section 12.1;
in the latter case, the <block>
will be treated as described under rule S129
;
note that also in this case, the <block>
will be executed.
Except in the case where an <object-spec>
is provided, any fields other than type
and id
cannot be set by make
, 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
.
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>
.See issue #3595
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.
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.
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]]
.
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.
See issue #2572
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.
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
.
S139
<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>
.
-
Making
integer!
values fromlogic!
values:true
gives1
,false
gives0
See issue #2644 -
Making
logic!
values fromnumber!
values:0/0.0/0%
givefalse
, all else →true
-
Making a
url!
value from anany-list!
value: the components (at least one is required) may be of any type; they will beform
ed; 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 aninteger!
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 anissue!
value — a fragment. -
Making a
date!
value from anany-list!
value: the block should have 3 to 7 components; if any of them is aword!
value, the value it refers to will be retrieved. The first 3 components should be ofinteger!
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 atime!
value for the time of day; a 5th component should be aninteger!
ortime!
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!
orfloat!
) for the time of day; a 7th component should be aninteger!
ortime!
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 give1-Feb-2017
and3 -10 0
would give02:50:00
) are not allowed. The timezone value is treated as in<date-literal>
(see section 5.2.14). -
For the following types,
make
operates in the same way asto
(see next section):none!
,char!
,float!
,percent!
,time!
,pair!
,any-word!
,refinement!
,issue!
andunset!
.
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 functions to-none
and to-unset
yield a none!
resp. unset!
value
for any argument value.
The function to-logic
yields true
for any argument value except false
and none
. Note that
to logic! 0
yields true
whereas make logic! 0
yields false
!
See issue #2645
The function to-string
yields the same result as the built-in function form
(see
section 11.1.1) except for
-
unset!
andnone!
values: conversion is not allowed -
binary!
values: these will be decoded as UTF-8 -
any-list!
values: the function will applyform
to each component and concatenate the results
Note that to-string
and form
omit the "decoration", i.e. the :
resp. '
for any-word!
and
any-path!
values. But see issue #3409
The functions to-file
, to-email
and to-tag
will perform the same conversion and yield
a result of the appropriate type. The function to-url
will operate analogously for none!
and
binary!
values; a block!
value has the same interpretation as for the make url!
function.
The function to-block
yields a block with the argument as single component except
for
-
string!
values: first appliesload
(see section 11.1.1) and appliesto-block
to the result -
typeset!
values: yields a block with the individual typenames asword!
values -
any-block!
andvector!
values: yields a block with the components -
any-object!
andmap!
values: yields the same asbody-of
The functions to-paren
etc. will perform the same conversion and yield
a result of the appropriate type.
The function to-integer
is defined for
-
any-float!
andtime!
values: truncates the floating point value (seconds in the case oftime!
) towards0
-
char!
values: yields the Unicode Code Point number -
binary!
values: interprets the first 4 bytes as an integer (two’s complement notation) if there are fewer than 4 bytes,#{00}
bytes are prepended before conversion -
issue!
values: interprets up to 8 characters, if possible, as a hexadecimal number; further characters are ignored; if the number of characters is odd and less than 8, the last one is ignored -
string!
values: yields the result ofload
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 between13-Dec-1901/20:45:52
and19-Jan-2038/3:14:07
; see alsoto-date
below
The function to-float
is defined for
-
integer!
values: yields the correspondingfloat!
value -
time!
values: yields the number of seconds -
char!
values: yields the Unicode Code Point number asfloat!
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 ofload
or an error -
any-list!
values: these should contain two components of typeinteger!
orfloat!
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!
.
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
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 twointeger!
orfloat!
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.
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, components0
are added -
string!
values: yields the result ofload
or an error -
any-list!
values: these should contain onlyinteger!
orfloat!
values in the range0..255
; yields the first 12 components or fewer as tuple components; if only 1 or 2 values are present, components0
are added
The function to-binary
is defined for
-
integer!
andany-float!
values: yields the corresponding 4 resp. 8 byte binary value -
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 -
bitset!
values: yields the corresponding binary value -
string!
values: yields the UTF-8 encoded binary value -
any-list!
values: these should contain onlyinteger!
orfloat!
values; the binary equivalents are concatenated, using as few bytes as needed for eachinteger!
value and 8 bytes for eachfloat!
value -
image!
values: yields a binary value with 4 bytes for each pixel
The function to-word
is defined for:
-
char!
values: makes aword!
value with that single character -
logic!
anddatatype!
values: yields the word that refers to the value -
string!
values: yields the result ofload
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.
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).
The function to-date
is defined for integer!
values which are interpreted as
Unix epoch time, i.e. the difference in number of seconds between midnight on 1 January 1970 and
the desired date and time. This number can be both positive and
negative and because of the limitation of integer numbers will yield dates between
13-Dec-1901/20:45:52
and 19-Jan-2038/3:14:07
. Furthermore, it is defined
for any-list!
values which have the same interpretation as for make date!
(see section 5.2.14) except that in this case, over- and under-flow are allowed
and taken into account.
The function to-time
is defined for
-
number!
values: yields the corresponding number of seconds -
string!
values: yields the result ofload
or an error -
any-list!
values: these should contain one to three values; the first aninteger!
value for the hours; the second, if present, aninteger!
value for the minutes; and the third, if present, aninteger!
orfloat!
value for the seconds.
The function to-bitset
operates in the same way as charset
(i.e. make bitset!
),
except that an integer argument is not allowed.
-
to-hex
takes an integer argument and produces the hexadecimal equivalent as a 16 characterissue!
value, with leading zeroes if needed -
to-local-date
returns the date with local zone -
to-UTC-date
returns the date with UTC zone -
as-pair
takes two integer or float arguments and combines them into apair!
value, thusas-pair x y
is equivalent toto-pair reduce [x y]
-
as-color
takes three integer arguments0..255
and makes atuple!
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 anissue!
value representing a color with each component as one or two hexadecimal digits, to an equivalenttuple!
value; single digit values are scaled by 16, thushex-to-rgb #123
→16.32.48
-
uppercase
andlowercase
will work on values of typechar!
andany-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 andto-red-file
converts a local system file path to a Red file path (see section 11.3.2 -
dehex
converts astring!
,file!
,url!
oremail!
value containing hex-encoded characters (%<hex-byte>
, see sections 5.2.8/9/10 and 12) into astring!
value in which the characters have been decoded -
debase`and `enbase
have been described in section 5.2.12 -
decompress
TBD
The casting facility applies to most of the series!
types, and makes use of the fact
that values of several different but related types have their component values
stored in identical fashion. Therefore a change of type can be performed without copying
any component values. Two groups of related types are involved: block!
, paren!
, any-path!
on the one hand, and any-string!
on the other. The type of the second argument should
be in the same group as the (type of the) first argument. The result is a new value
of the desired type, pointing to the components of the old value.
Note the absence of hash!
from the first group, explained by the fact that hash!
values are stored differently from other any-block!
values.
See also REP #30
Composite values can have their components extracted and changed by various means.
Values that are sequences (with types in series!
and bitset!
) admit indexing by integers.
As explained earlier, components of series!
values are indexed from 1
, while components
of bitset!
values are indexed from 0
.
Built-in functions for indexing are pick
for extraction and poke
for changing, with the
following specifications:
pick <source> <index> poke <destination> <index> <value>
where <index>
evaluates to a value of permitted index type given the type
of <source>
resp. <destination>
and <value>
evaluates to a value for the component
type of <destination>
.
Values of type integer!
are permitted as <index>
for all sequences.
Additionally, for programming convenience, values of series!
types may be indexed
by logic!
values, where true
yields the first component and false
the second component.
Also, for pick
, bitsets admit indexing by characters, strings and blocks
(interpreted as in <bitset-spec>
, see section 5.3.5),
with the result being true
if the component(s) with the corresponding
Unicode Code Point number(s) is/are all true
. For poke
, the bitset component(s)
thus indexed will (all) be set to the given <value>
(true
or false
).
In this connection if should be noted that, although the components of a value of type bitset!
are of type logic!
, with poke
it is allowed to use values of any other type,
where 0
and none
set the bit to false
, and all other values
(including 0.0
and 0%
) set the bit to true
.
Finally, images may also be indexed by pairs as coordinates, with the index
being computed in accordance with the row-oriented storage of the pixels.
Path expressions may also be used. The correspondence is as follows:
pick <source> <index> <==> <source>/<index> poke <destination> <index> <value> <==> <destination>/<index>: <value>
Here <source>
and <destination>
must be a <path-head>
, see rule S113.
The <index>
must be a single value or an expression of an allowed type.
Note that for lexical reasons, a char!
, string!
or pair!
value used as index
in path expressions must be enclosed in parentheses. A block!
value is not allowed
in this position, not even in parentheses, and neither is a logic!
value.
Note also that selecting a component which is a value of type any-function!
by means of a
path expression will evaluate the component, and thus lead to its application,
whereas selection by pick
will not. See issue #3482
Note further that path expressions cannot be used to index file!
and url!
values,
as these path expressions will be interpreted as "extending" the file or url path,
as explained in section 7.3.5.
Values of the direct types time!
, date!
, pair!
and tuple!
also admit component selection
by "indexing", 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
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) and2 ~ 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.
This is possible for values that are sequences (with types in series!
,
but not bitset!
), and for values of types object!
, error!
, port!
and map!
.
A restricted facility also exists for values of type time!
, date!
, pair!
, email!
, image!
and event!
.
Built-in functions for selection are select
for extraction and put
for changing, with the
following definitions:
select <source> <key> put <destination> <key> <value>
The semantics are different in the two main cases (sequences vs. objects/maps).
-
For extraction in sequences, a case-insensitive
find
action is performed on the components using the key, which should be a single value of a type allowable forfind
, or a sequence of such values, and the result is the component after the first occurrence of the key (single or sequence) if found, andnone
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 isnone
; in case of anobject!
,port!
orerror!
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!
orbinary!
, and the destination should be of a type inany-block!
. See issue #1960 If thefind
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!
orbinary!
. 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, useremove/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 anobject!
first argument, and a block of component values as second argument. If the second argument isnone
, all components will be set tonone
. -
Fields of
error!
values cannot be set.See issue #2554 -
Fields of
port!
values TBD
Path expressions may also be used for selection. The correspondence is as follows:
select <source> <key> <==> <source>/<key> put <destination> <key> <value> <==> <destination>/<key>: <value>
The same lexical restrictions 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 time!
, date!
, pair!
, email!
and image!
also admit component selection
by specific words, and values of type event!
have this as the only way of selection.
However, here the selection is only possible by <path>
and <path>:
expressions,
not by select
and put
. The allowed values of the keys for each of these types
are stored in system/catalog/accessors
.
In case of time!
, date!
, email!
, image!
and event!
, the result is obtained by performing
a certain calculation, as follows.
Extracting a component:
-
time!
values: given the stored number of seconds, thehour
andminute
components are the result of finding the whole number of3600
seconds in the total, and then the whole number of60
seconds in the remainder; thesecond
component is what remains after that (this is afloat!
value) -
date!
values: thedate year month day zone time hour minute
andsecond
components are extracted either directly or as in the case oftime!
; thetimezone
component is equal to thezone
component on extraction; the others are the result of a calculation: theweekday
component is a number between 1 and 7 (1 = Monday), theyearday
component is the ordinal number of the date in the current year (1 = first of January), theweek
component is the week number according to a casual definition (week starts on Sunday, first week starts on January 1st), and theisoweek
component is the week number according to the ISO 8601 standard; -
email!
values: theuser
component is the part before the@
and thehost
component is the part after the@
; both are of typestring!
-
image!
values: thesize
component is thepair!
value that holds the dimensions, theargb
,rgb
andalpha
components are thebinary!
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: thehour
,minute
andsecond
components can be individually set and will replace the values they had before -
date!
values: thedate
,year
,month
,day
,hour
,minute
,second
andzone
components can be set directly; the value for thetime
component (which can be negative) is used modulo24:00
with adjustment of the date; the same holds for the resulting time when any of the values of thehour
,minute
andsecond
components is changed; setting thetimezone
component results in adate!
value with the correspondingzone
component and a changedtime
component such that the UTC time value is unchanged; setting theweek
orisoweek
component results in adate!
value having the date of the first day in the indicated week; setting theweekday
component results in adate!
value with the corresponding date in the same week; setting thetime
component tonone
will ensure that thetime
andtimezone
components will not be displayed, and that for computations they have the value0:00
-
email!
values: theuser
andhost
component values should be supplied as strings -
image!
values: thesize
component cannot be set; the other components can be set to abinary!
value of the required length; if the value is shorter, bytes#{00}
are appended; if the value is longer, the remainder is ignored; atuple!
value can also be supplied, its components will be used for each pixel; if aninteger!
value is supplied, its 4 bytes will be similarly used see issue #2883 -
event!
values: only thetype
component can be set to aword!
value
Selection by a key of the wrong type or wrong value leads to an error.
type | index values | built-in functions | key values or types | built-in functions |
---|---|---|---|---|
time! |
1 2 3 |
pick |
hour minute second |
|
date! |
1 .. 14 |
pick |
date year month day zone time hour minute second weekday yearday julian timezone week isoweek |
|
pair! |
1 2 |
pick |
x y |
|
tuple! |
1 .. 12 |
pick |
||
any-block! |
integer! logic!1 |
pick poke |
any-type! |
select put |
vector! |
integer! logic!1 |
pick poke |
char! integer! float!2 |
select3 |
string! |
integer! logic!1 |
pick poke |
char! any-string! binary! |
select3 |
email! |
integer! logic!1 |
pick poke |
char! any-string! binary! host user |
select3 |
file! url! |
integer!1 logic!1 |
pick poke |
char! any-string! binary! |
select3 |
binary! |
integer! logic!1 |
pick poke |
integer! char! any-string! binary! |
select3 |
image! |
integer! pair! |
pick poke |
size rgb alpha argb |
|
bitset! |
integer! char! string! block! |
pick poke |
||
map! |
scalar! any-word! any-string! binary! |
select put |
||
object! |
word! |
select put |
||
error! |
code type id arg1 arg2 arg3 near where stack |
select |
||
port! |
spec scheme actor awake state data extra |
select |
||
event! |
type face window offset key picked flags away? down? mid-down? alt-down? aux-down? ctrl? shift? |
Notes:
-
not in path expressions
-
See issue #2625
-
See issue #1960
Values of some types have (internal) properties of interest to the user which may usefully be exposed.
This concerns first of all any-word!
values for which information on their
binding may be obtained by means of two built-in functions: context?
and index?
.
These are explained in section 6.2. See REP #14.
The function complement?
is described in section 5.3.5.
The function face?
tests if an object is derived of the face!
object which is
explained in section 13.3.
Functions on vector! values have been requested see REP #12
For values of types date! email! event! image! pair! time!
which admit component selection
by "key" (see section 5.6.2), the allowed key values are available
from system/catalog/accessors
which is a block of pairs <type-name><block of key words>
.
For values of type object!
, error!
, port!
and map!
, which consist of key/value pairs,
the collection of keys, that of values, and the set of key/value pairs may each
be obtained as a block by means of the built-in functions words-of values-of
and body-of
. For convenience, keys-of
is defined as synonym for words-of
.
In addition, for objects there is the property class-of
which yields
the unique number that is given to each object that is created from a <spec>
, and is
inherited by objects derived from it (see rule S129
).
This property is 1
for error!
values, and 2
for port!
values.
For any-function!
values, one can obtain the full <argument-spec>
through
the built-in function spec-of
and the list of formal argument names through
the function words-of
not yet implemented. For function!
and routine!
values, there is in
addition the function body-of
which yields the function/routine body.
All functions <property>-of <expression>
are shorthand for the general function
reflect <expression> <property>
e.g. words-of <expression>
is defined as reflect <expression> 'words
.
For series!
values, the property owned
has been defined which is notably used
by the reactivity facility (see section 13.4).
This property can only be obtained by reflect <expression> 'owned
.
see issue #1957
Note that the help
built-in function is typically making good use of these reflection facilities.
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? |
The strictest equality test is same?
which yields true
only if the two values
are of the same type and the two value slots (see section 4.2.2)
have identical content. For values of direct types this comes down to simple equality,
but for values of other types it is quite possible to be equal but not the same
(e.g. two strings of identical content, but one a string literal and the
other the result of decoding a binary!
value).
For two values to succeed the strict-equal?
test, they have to be of the same
type and also have exactly the same value, i.e. not have the differences allowed
for the equal?
test.
The equal?
test ignores case differences in the spelling of words
(values of types in all-word!
) and strings (values of types in any-string!
),
and in the case of floating point numbers, a very small difference (1 in 1016)
in actual value.See also issue #2658
For values of any-block!
type, the strict-equal?
and equal?
tests apply pairwise
to the components. For any-object!
the requirements are identity of field names
and (strict) equality of field values. If the components or field values are also of
any-block!
or any-object!
type, there is recursion involved, with cycle detection.
For values of vector!
type, these tests also apply pairwise to the components. In
addition, the component type (char! integer! float!
or percent!
) must be the same,
but the component size in bits may be different.
In all cases, for the equal?
and not-equal?
test, the requirement of equal type
is relaxed for several combinations of types of the two values.
-
char!
andinteger!
See issue #2650 -
integer! float!
andpercent!
-
any-word!
andrefinement!
(note the absence ofissue!
) -
any-string!
-
any-object!
See issue #2657
If the combination of types of the two values is not allowed as detailed above,
the not-equal?
test will yield true
and the other three equality tests will yield false
.
Note that the function find
uses an equality test which differs from strict-equal?
in that it ignores case differences in values of types in any-word!
and any-string!
(see section 9.2).
The following cases can be distinguished:
-
straightforward numerical ordering:
char! integer! float! percent! time!
anddate!
-
lexicographic ordering (case sensitive):
pair! tuple! any-word! refinement! issue! vector! any-string! binary!
andbitset!
; with pairs, they
component is tested before thex
component -
lexicographic ordering (with recursion and cycle detection):
any-block!
andobject!
; 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!
andunset!
.
As a rule, for ordering comparisons the types of the two values have to be the same.
See issue #2662
For vector!
values, the component type (char! integer! float!
or percent!
) must also be the same
(the size in bits of the components may differ).
For some combinations of types this requirement is relaxed, in the same manner as for equality comparisons.
If the combination of types of the two values is not allowed as detailed above, or if no comparison is defined, the comparison will raise an error.
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.
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 value
is yielded as an object having the same field names and values as the error.
The context of a word which is not a field name of an object is the global context,
and is thus yielded as the object system/words
. Otherwise, the context is
yielded as the object of which the word is a field name. The index of a word
in its context may be obtained through the built-in function index?
.
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.
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.
The evaluation of <word-literal>: <expression>
is treated in rule E105
.
Equivalent to this is the application of the built-in function set
:
<word-literal>: <expression>
~ set '<word-literal> <expression>
.
The counterpart to set
is unset
: this will make the word argument
refer to the unset value.
Both set
and unset
may have a block!
argument instead of a word!
one. The set/unset
action is applied to all the words in the block.
This is treated in rule S129
.
This is treated in rule E110
.
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
.
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
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).
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.
These are lit-word!
and lit-path!
.
E101
-
Evaluating a
lit-word!
value results in itsword!
counterpart. E102
-
Evaluating a
lit-path!
value results in itspath!
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>
.
E103
-
Evaluating a
word!
value proceeds as follows:-
Determine the context to which the word is bound.
-
Obtain the value that the word refers to in this context.
-
Determine the type of this value.
-
If the type is
unset!
raise an error. -
If the type is in
any-function!
apply the function (see rulesE110-114
). -
Otherwise, the result is the value referred to.
-
-
Note: there are cases in which a <word>
is not to be evaluated, e.g. when it occurs as
<key>
or <value>
in a <map-spec>
, or when it is an actual argument to a function
where the formal argument is a lit-word!
. In these cases, all predefined words,
in particular true false
and none
will be interpreted as word!
values rather than as
logic!
or none!
values. To represent values of the desired type in such cases one may use
the generalized value construction syntax: #[true], #[false], #[none]
.
The built-in function get
with a word!
argument applies the above rule except when the type of
the value referred to is in any-function!
in which case no function application occurs.
Moreover, with the refinement /any
no error occurs if the word!
value refers to the unset value.
E104
-
Evaluating a
get-word!
value proceeds as follows:-
Determine the context to which the word is bound.
-
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.
E105
-
Evaluating a
set-word!
value outside an<object-spec>
or a<map-spec>
has the effect that the<word>
in its context is made to refer to the value obtained by evaluating the next expression. An error occurs if no expression is following or if the value obtained is unset. The result of the evaluation is the value obtained from the expression. As a consequence, set-words may be "chained", thus:a: b: c: 1
is equivalent toa: (b: (c: 1))
and thus toa: 1 b: 1 c: 1
.
As stated before, the alternative to <word-literal>: <expression>
is set <word-literal> <expression>
which is a special case of set <word> <expression>
. The built-in function set
has
a refinement /any
which will ensure that no error occurs if the expression yields the unset value.
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
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:-
Start with the first path component. Evaluate this
<path-head>
, which is a<word>
, as per ruleE103
. -
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.-
Otherwise, determine the type of the evaluated
<path-head>
. -
If the result is a value of composite type (except
file!
andurl!
), and there is a next element which is a<selector>
, this will yield a component of the composite value as described in step 3. -
If the result is of
file!
orurl!
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>/…
-
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 aword!
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). -
Otherwise, the path is in error.
-
-
Determine the type of the
<selector>
.-
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. -
If the
<selector>
is an<integer>
, and the composite type is notmap!
orany-object!
, the intermediate result is the component of the composite value at the index given by theinteger!
value (0-origin forbitset!
values, 1-origin for values of all other composite types). -
If the composite type is
any-object!
and the<selector>
is not a<word>
the path is in error. -
If the composite type is
map!
and the<selector>
is not of a type inscalar! any-word! any-string!
orbinary!
the path is in error. -
If the
<selector>
is a<word>
, and the composite value is of direct type,image!
,email!
orevent!
, an intermediate result is obtained as explained in section 5.6.2. -
If the composite value is of indirect type (except
image!
andemail!
), an intermediate result is obtained by applying the built-in functionselect
with as arguments the composite value and the<selector>
. -
Otherwise, the path is in error.
-
If a further
<selector>
is present, use the intermediate result just obtained as evaluated<path-head>
and go to step 2.
-
-
Determine the type of the intermediate result just obtained.
-
If the type is
unset!
raise an error and yield the unset value as result. -
If the type is in
any-function!
apply the function (see rulesE110-114
). -
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.
See also rule E107
.
E108
-
The evaluation of a
get-path!
value proceeds as follows:-
Start with the first path component. Evaluate this
<path-head>
, which is a<word>
, as per ruleE103
. -
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.-
Otherwise, determine the type of the evaluated
<path-head>
. -
If the result is a value of composite type (except
file!
andurl!
), and there is a next element which is a<selector>
, this will yield a component of the composite value as described in step 3. -
If the result is of
file!
orurl!
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>/…
-
If the result is a value of
any-function!
type, no following<selector>
is allowed and the result is the function value. -
Otherwise, the path is in error.
-
-
Determine the type of the
<selector>
.-
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. -
If the
<selector>
is an<integer>
, and the composite type is notmap!
orany-object!
, the intermediate result is the component of the composite value at the index given by theinteger!
value (0-origin forbitset!
values, 1-origin for values of all other composite types). -
If the composite type is
any-object!
and the<selector>
is not a<word>
the path is in error. -
If the composite type is
map!
and the<selector>
is not of a type inscalar! any-word! any-string!
orbinary!
the path is in error. -
If the
<selector>
is a<word>
, and the composite value is of direct type,image!
,email!
orevent!
, an intermediate result is obtained as explained in section 5.6.2. -
If the composite value is of indirect type (except
image!
andemail!
), an intermediate result is obtained by applying the built-in functionselect
with as arguments the composite value and the<selector>
. -
Otherwise, the path is in error.
-
If a further
<selector>
is present, use the intermediate result just obtained as evaluated<path-head>
and go to step 2
-
-
Determine the type of the intermediate result just obtained.
-
If the type is
unset!
yield the unset value as result. -
Otherwise, the result is the intermediate result just obtained.
-
-
E109
-
The evaluation of a
set-path!
value proceeds as follows:-
Start with the first path component. Evaluate this
<path-head>
, which is a<word>
, as per ruleE103
. -
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.-
Otherwise, determine the type of the evaluated
<path-head>
. -
If the result is a value of composite type (except
file!
andurl!
), and there is a next element which is a<selector>
, proceed to step 3. -
Otherwise, the path is in error.
-
-
Determine the type of the
<selector>
.-
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. -
If the
<selector>
is an<integer>
, and the composite type is notmap!
orany-object!
, the intermediate result is composite value at the index given by theinteger!
value (0-origin forbitset!
values, 1-origin for values of all other composite types). -
If the composite type is
any-object!
and the<selector>
is not a<word>
the path is in error. -
If the composite type is
map!
and the<selector>
is not of a type inscalar! any-word! any-string!
orbinary!
the path is in error. -
If the
<selector>
is a<word>
, and the composite value is of indirect type (exceptany-object! map! image!
andemail!
), the intermediate result is the composite value at the index found by applying the built-in functionfind
with as arguments the composite value and the<selector>
. -
If the
<selector>
is a<word>
, and the composite value is of direct type,image!
oremail!
, an intermediate result is obtained which is the component found as as explained in section 5.6.2. -
If the composite value is of type
object!
ormap!
, the intermediate result is the key/value pair whose key is the<selector>
-
Otherwise, the path is in error.
-
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
-
-
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 toa/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.
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
orselect
(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
E110
-
The application of a
function!
value (also called function call or function application) proceeds as follows:-
If the function does not have any arguments (optional or not), execute the body of the function to yield the result of the function.
-
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!
andrefinement!
) occurring in the<argument-spec>
. Make all these words initially refer tonone
.-
Evaluate as many subsequent expressions as needed to obtain values corresponding to the non-optional arguments, except: When the
<argument-name>
is a'<word>
, then if the next value is a:<word>
or:<path>
or<paren>
, evaluate this to fetch the value it refers to; else pass the next value as-is. If the<argument-name>
is:<word>
, do not evaluate the corresponding expression but yield its first<value>
as-is; do not raise an error if this value is unset. See issue #2622 Make the<word>
of each<argument name>
refer to the corresponding value. Check the type of each value against the type(set)s specified for the argument. -
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 totrue
. 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. -
Bind the body of the function to the context (see section 6.3.6).
-
Execute the body of the function to yield the result of the function. Check the type of the resulting value against the type(set)s specified with
return:
, if any 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>
.
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 anaction!
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:
-
From the action number, determine the
<argument-spec>
of the action. -
Evaluate one or two expressions corresponding to the non-optional arguments. Evaluate expressions as needed for the optional arguments corresponding to the refinements specified, if any, and determine default values for the others.
-
Call the primary Red/System function that handles the action with all the arguments in standard order. This will do the following:
-
Determine the type of the first argument and look up the appropriate entry in the dispatch table.
-
Call the Red/System function that the entry refers to, with all the arguments
-
This Red/System function will check the type of the second argument, if any, and determine its operation on the basis of the (combination of the) argument type(s).
-
As with function!
evaluation, the order of the expressions to be supplied
for the optional arguments is dictated by the order of the actual refinements present,
not by the order of the <function-refinement>
s in the <argument-spec>
.
E112
-
A value of
op!
type is always derived from a value of anotherany-function!
type:function! action! native!
orroutine!
. Moreover, anop!
value always has exactly two arguments and no refinements. Therefore, the application proceeds as for the function etc. it is derived from, with the expression that precedes theop!
value corresponding to the first argument and the expression following theop!
value corresponding to the second one. The precedence rule stated in section 3.3 applies, except if the first argument is a function call with a literal first argument, and there is no second argument provided.
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 anative!
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:
-
From the native number, determine the
<argument-spec>
of the native function. -
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.
-
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>
.
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:
-
The
<routine-spec>
is converted into a Red/System function specification block by changing every Red type mentioned in it, exceptinteger! logic!
andfloat!
to the corresponding Red/Systemstruct!
alias that describes the value slot, thusstring!
becomesred-string!
etc. -
A routine argument or return without a type is given Red/System alias
red-value!
which corresponds toany-type!
. -
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.
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 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
.
The built-in function do
will evaluate its argument, which may be of any
type, as follows:
-
if the argument is a
block!
value, the block will be executed as described in section 7.1 -
if the arument is a
path!
value, the path will be evaluated as described in section 7.3.5 -
if the argument is a
string!
value, the built-in functionload
(see section 11.1.1) will be invoked on the string, anddo
will be invoked on the result -
if the argument is a
url!
orfile!
value, this should contain a text which is a valid Red program (see section 3); the text string will be obtained byread
(see section 11.3.1) and the previous step will be taken -
if the argument is an
error!
value, the error will be raised (see section 12.1.2) -
for an argument of type
op!
, the application ofdo
is not implemented -
otherwise, the argument will be evaluated according to the appropriate rule of section 7; note that resulting values of type
function!
,native!
,action!
androutine!
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).
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.
Red makes available the usual arithmetic operations through + - * /
as operators
and their prefix counterparts: add subtract multiply divide
.
In addition, there are operators and prefix functions for exponentiation (**
or power
),
modulo (//
or modulo
) and remainder (%
or remainder
). Enquiry functions are:
sign? positive? negative? zero? even? odd? NaN?
. The unary minus function is only represented
by a prefix function negate
, not by an operator, since these have always two arguments.
Lastly, there are functions for rounding a number (round
) and for determining
the absolute value of a number (absolute
), the maximum and minimum of two numbers (max min
),
and the sum and average of a set of numbers (sum
and average
).
The arity (number of arguments) and the argument and result types for these functions are as follows.
function | arity | operand 1 type | operand 2 type | result type |
---|---|---|---|---|
|
2 |
|
|
see next table |
|
2 |
|
|
|
|
1 |
|
|
|
|
1 |
|
|
|
|
1 |
|
|
|
|
1 |
|
|
|
|
1 |
|
|
|
|
1 |
|
same as operand3 |
|
|
1 |
|
|
same as operand3 |
|
2 |
|
|
same as greatest/smallest operand |
|
1 |
|
same as individual numbers |
|
|
1 |
|
|
Notes:
-
result type is
integer!
only if both operands are integer, and the result value fits in 32 bits; otherwise result type isfloat!
-
result is
-1
0
or1
-
see REP #10
-
components must be of type
number!
orchar!
-
result type is
percent!
if sum is of that type, otherwisefloat!
The result types for the 6 arithmetic operations + - * / // %
are detailed in the following table.
When no result type is mentioned, all 6 operations are forbidden. Individual restrictions are
mentioned through notes 1 to 10. The operations on values of type pair! tuple!
and vector!
take place component-by-component. When the two operand types are different,
the result type is determined as (in decreasing order of precedence):
-
the higher dimension type
-
the higher precision type
-
the type of operand 1
See issue #2776
operand 2 → operand 1 |
char! | integer! | float! | percent! | time! | date! | pair! | tuple! | vector! |
---|---|---|---|---|---|---|---|---|---|
char! |
char!1 |
char!1 |
char!1 |
vector!1,6 |
|||||
integer! |
integer!1 |
integer! |
float! |
float! |
time! |
date!9 |
pair!1,2 |
tuple!1,2,3 |
vector!1,6 |
float! |
float!1 |
float! |
float! |
float! |
time! |
pair! |
tuple! |
vector! |
|
percent! |
percent! |
percent! |
percent! |
time! |
pair!1,2 |
tuple!1,2,3 |
vector!1,6 |
||
time! |
time! |
time! |
time! |
time!4,5 |
date!9 |
||||
date! |
date!8 |
date!8 |
integer!10 |
||||||
pair! |
pair!1 |
pair!1 |
pair!1 |
pair!1 |
|||||
tuple! |
tuple!1 |
tuple!1 |
tuple!1 |
tuple!1,11 |
|||||
vector! |
vector!1,6 |
vector!1,6 |
vector!1,6 |
vector!1,7 |
Notes:
-
modulo not allowed
-
divide not allowed
-
subtract not allowed
-
divide has float! result
-
multiply not allowed
-
result has element type of vector operand see also issue #2216
-
operand 1 and 2 must have same element type
-
only add/subtract allowed
-
only add allowed
-
only subtract allowed; result is number of days, ignoring any time components; for exact difference use built-in function difference
-
with tuples of unequal length, the shortest one is extended with values
0
The difference between the modulo
and remainder
functions is as follows:
-
for positive first argument, the result of both is the positive remainder of division by the second argument
-
for negative first argument, the result of
modulo
is the positive remainder, and the result ofremainder
is the negative remainder
The results of division by zero are as follows:
-
any integer divided by
0
gives an error -
any non-zero non-integer number divided by
0
0.0
or0%
gives positive or negative infinity -
0
0.0
or0%
divided by0.0
or0%
gives "not a number" -
computing modulo and remainder with
0
0.0
or0%
as second operand gives an error
More information on the handling of the special numbers positive and negativity infinity and "not a number" is to be found in the additional documentation (see section 18).
Note that round
has a number of refinements:
/to => Return the nearest multiple of the scale parameter scale [number!] "Must be a non-zero value" /even => Halves round toward even results /down => Round toward zero, ignoring discarded digits. (truncate) /half-down => Halves round toward zero /floor => Round in negative direction /ceiling => Round in positive direction /half-ceiling => Halves round in positive direction
The functions max min
on arguments of type pair!
and tuple!
are applied on a component-by-component basis
(tuples must be of equal length). See issue #3395
These functions are also defined for series!
arguments.
See section 9.3.
The function math
takes a block containing expressions involving multiplication and division,
and executes it using normal mathematical precendece 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.
This concerns first of all the familiar functions exp
for raising
e = 2.718281828459045
to a power, the logarithms log-e log-2 log-10
,
and the square root sqrt
. Furthermore the trigonometric functions
sin cos tan asin acos atan atan2
, and the functions random
and
checksum
.
The arity (number of arguments) and the argument and result types for these functions are as follows. Result types are only indicated if different from argument types.
function | arity | argument type(s) | result type |
---|---|---|---|
exp log-e log-2 log-10 sqrt |
1 |
number! |
float! |
sin cos tan asin acos atan |
1 |
float! |
|
atan2 |
2 |
float! |
|
random |
1 |
logic! scalar! |
|
checksum |
2 |
binary! string! file!, word! |
binary! |
Notes: all trigonometric functions take an argument in radians, except atan2
which takes two float!
arguments representing y
and x
coordinates.
The function random
yields a random value between zero and its argument
value or one of false
and true
for logic!
; for pair!
and tuple!
values
it operates per component; it is also defined for series!
arguments
(see section 9.3).
The word!
argument to checksum
indicates the method; allowed are
MD5 SHA1 SHA256 SHA384 SHA512 CRC32 TCP ADLER32 hash
.
The following functions operate on values that can be conceived as representing
sets of other values; this concerns some series types: block! hash! string!
,
as well as bitset!
and typeset!
.
The functions intersect union difference
and exclude
have two arguments
of one of the types mentioned, and yield a result of the same type. The function
unique
has one argument of type block! hash! string!
, and again yields
a result of the same type. The operation of these functions follows from their names.
Note that the function difference
is also defined on two date!
values; in this case
it yields a time!
value as the result of subtracting one date with its time from the other.
The following functions operate on the bit patterns underlying Red values of suitable types.
The function complement
yields the bit-by-bit complement, thus for integers
it yields the two’s complement, e.g. complement 2
is -3
.
The operators and or xor
with prefix counterparts and~ or~ xor~
operate
bit-by-bit on their arguments.
Three bit-shift operators are defined on integers, with positive integer shift count:
-
<<
for left shift: highest bits are shifted out, zero bits are added to the right -
>>
for right shift: lowest bits are shifted out, highest bit is duplicated -
>>>
for "logical" shift: lowest bits are shifted out, zero bits are added to the left
These operators have their equivalent in three routines: shift-left
, shift-right
and shift-logical
which in their turn call upon a single native function shift
(default: right shift) with
refinements /left
and /logical
.
The arity (number of arguments) and the argument and result types for these functions are as follows.
function | arity | argument type(s) |
---|---|---|
complement |
1 |
integer! bitset! typeset! binary!1 |
and or xor |
2 |
integer! char! pair! tuple! bitset! typeset! binary! vector! |
<< >> >>> |
2 |
integer! |
Note:
-
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).
The bitwise functions complement and or xor
are also applicable to
logic!
values; on these values, not
is equivalent to complement
.
On values of other types, not
will always yield false
except on
none
, where it will yield true
.
Note that and or xor
evaluate both their arguments. In many programming
situations, it is preferable to use the shortcut evaluation functions
any
and all
, which only evaluate subsequent arguments if an earlier one
is false
or none
for any
or not none
(i.e.true
) for all
.
See section 7.5.
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.
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!
.
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!
)
and any-object!
and map!
(with <expression>
evaluating to a field value).
The result of find
in these cases is true
if there is a match, and false
otherwise.
Furthermore, if the <series>
argument is of type any-block!
except hash!
and the <expression>
is of type datatype!
the result is the <series>
at the index of the first occurrence of a component of that type.
See REP #29
Note that find
has a rich set of refinements:
/part => Limit the length of the search length [number! series!] /only => Treat a series search value as a single value /case => Perform a case-sensitive search /same => Use "same?" as comparator /any => TBD: Use * and ? wildcards in string searches /with => TBD: Use custom wildcards in place of * and ? wild [string!] /skip => Treat the series as fixed size records size [integer!] /last => Find the last occurrence of value, from the tail /reverse => Find the last occurrence of value, from the current index /tail => Return the tail of the match found, rather than the head /match => Match at current index only and return tail of match
The following enquiry functions are available: head? tail? length? index?
. The function
empty?
is a synonym for tail?
. The built-in function offset?
yields the difference
of the index?
values of its two series!
arguments.
Note: for programming convenience, the functions length?
and empty?
(but not tail?
)
accept none
as an argument, yielding none
respectively true
as result.
The function length?
is also defined for values of type bitset!
, tuple!
and map!
.
The following built-in functions have been described in section 5.6:
pick poke select put first second third fourth fifth last
.
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`.
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 |
after current component |
replace <series> <pattern> |
components equal to <pattern> |
at head |
alter <series> <expression> |
if value of expression in <series> |
(at head, result is true if appended, else false) |
insert <series> <expression> |
value of <expression> inserted |
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, |
at head |
pad <series> |
string padded on right side with spaces |
at head |
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).
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 |
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
.
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
.
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) |
find <map> <key> |
yield true if key indicated by <key> exists, else none |
remove/key <map><key> |
removes the key indicated by <key> if it exists |
length? <map> |
yield the number of key-value pairs |
empty? <map> |
yield true on #( ), false otherwise |
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 following built-in functions are also defined on objects, errors and ports, with the following semantics:
function | operation |
---|---|
copy <any-object> |
yield a copy of the object, error or port |
find <any-object> <word> |
yield true if key indicated by <word> exists, else none |
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.
The available constructs are the following:
<forever> ::= forever <body-block> <while> ::= while <condition-block> <body-block> <until> ::= until <condition-block> <loop> ::= loop <integer> <body-block> <repeat> ::= repeat <word> <integer> <body-block> <foreach> ::= foreach <counter> <series> <body-block> | foreach <counter> <map> <body-block> <forall> ::= forall <word> <body-block> <remove-each> ::= remove-each <counter> <series> <condition-block> <counter> ::= <word> | <block>
Semantics:
-
forever
: the<body-block>
is executed until an exception is encountered (see section 12). -
while
: the<condition-block>
is executed and if does not yieldfalse
ornone
, 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 yieldfalse
ornone
. -
loop
: the<body-block>
is executed an integer number of times. -
repeat
: the<body-block>
is executed repeatedly with the<word>
assuming values from 1 to the integer. Note that the<word>
is not local to the loop, i.e. there is no separate context for therepeat
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 (seenext
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 inforeach
. 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.
The built-in functions break continue exit return
are described
in section 12.
The built-in functions halt
and quit
or q
stop the execution
of the program. Difference?? The built-in function quit-return
delivers its integer argument as status code back to the Operating System.
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
.
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 |
---|---|---|
|
basic I/O |
|
|
basic I/O |
|
|
ports |
|
|
ports (planned) |
|
Note that modify
is defined but not yet implemented. See issue #3570
The built-in function load
will convert textual input (or its binary UTF-8 encoded
equivalent), specified as its argument, to one or more values by calling upon
the lexical/syntactic analysis facilities of the toolchain. The result is either one
value or a block of values.
There are three mechanisms for converting values to readable strings:
the built-in function form
will produce a basic representation intended for human readers,
the built-in function mold
will produce a representation that mirrors the source code
of the value, while its variant mold/all
will produce a representation that can be read
back by load
to yield the original value. As stated in section 5.4.3 the
operation of form
is the same as that of to-string
with the exception of
argument types unset! none! binary!
and any-list!
. Especially values of the
last group of types, as well as values of types vector!
and object!
merit special attention since the are converted to strings showing
the essentials without conserving type information.
Examples:
load "1" ; 1 string analyzed as representing an integer load "1 + 2" ; [1 + 2] load produces a block for more than one value load "[1 2 3]" ; [1 2 3] one (grouped) value detected load #{5B31203220335D} ; [1 2 3] same input as binary value form () ; "" unset! value form #{414243} ; "#{414243}" to-string gives "ABC" form [1 2 3] ; "1 2 3" block brackets omitted form quote (1 2 3) ; "1 2 3" parens also omitted form make hash! [1 2 3] ; "1 2 3" hash property not shown form make vector! [1 2 3] ; "1 2 3" vector property not shown form object [a: 1] ; "a: 1" object property not shown mold [1 2 3] ; "[1 2 3]" load is guaranteed to recognize this mold make hash! [1 2 3] ; "make hash! [1 2 3]" hash property conserved mold make vector! [1 2 3] ; "make vector! [1 2 3]" vector property conserved 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.
The built-in function save
will apply mold/all
to the expression which is its
second argument. If the destination specified as its first argument is a string,
it will append the result of mold/all
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/all
and append that value to the destination .
See issue #2668
For any-list!
values the user can control the way they are presented by mold
,
by instructing it to insert line feed characters (U+000A
) before selected components.
The built-in function new-line
with an any-list!
first argument will
set a new-line marker in the value slot of the current component of
its argument (if the second argument evaluates to true
) or clear this marker
if the second argument evaluates to false
.
Example:
b: [1 2 3 4] forall b [new-line b true] print mold b
gives
[ 1 2 3 4 ]
The state of the new-line marker may be tested with the built-in function
new-line?
which has an any-list!
argument, and yields true
or false
.
The built-in functions load
and save
each have an /as
refinement
with a word!
argument: the value none
indicates Red code (Red data)
and makes load
and save
operate as already described;
other values implemented are first of all png jpeg bmp gif
; for each of these values
load
will accept binary data in the indicated format and yield an image!
value, and save
will take an image!
value and produce the encoded binary
value. The necessary decoding and encoding routines are stored in system/codecs
.
This is a block of pairs: <word><object>
, where the <word>
indicates
the encoding e.g. jpeg
, and the corresponding <object>
has the following
content:
key | value type | content |
---|---|---|
title |
string! |
(not filled in) |
name |
word! |
'JPEG |
mime-type |
block! |
[image/jpeg] |
suffixes |
block! |
[%.jpg %.jpeg %.jpe %.jfif] |
encode |
routine! |
routine [img [image!] where [any-type!]][…] |
decode |
routine! |
routine [data [any-type!]][…] |
An additional "codec" is provided for JSON data (see https://www.json.org/):
the argument to /as
is json
. The corresponding object in system/codecs
is
key | value type | content |
---|---|---|
title |
string! |
"JSON codec" |
name |
word! |
'JSON |
mime-type |
block! |
[application/json] |
suffixes |
block! |
[%.json] |
encode |
function! |
func [data [any-type!] where [file! url! none!]][…] |
decode |
function! |
func [data [any-type!]][…] |
Note that conversion between "raw" binary data (values of type binary!
) and strings
is quasi automatic if the binary data uses UTF-8 character encoding: to-binary <string>
and to-string <binary>
will perform the necessary encoding/decoding.
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"
The built-in function prin
will take an expression
and send a string to the standard output device. If the expression
is not a block, the string is the result of applying form
to the
result of evaluating the expression; in the case of a block, the individual
expressions it contains are evaluated and converted by form
and separated by
single spaces. The built-in function print
calls prin
and outputs
a line feed afterwards.
The built-in function probe
will call mold
and then print
, and
yield its argument as a result. This is useful for debugging intermediate
results; note that print
itself will yield the unset value.
Examples:
print [1 + 2 3 + 4] ; prints "3 7" and yields unset probe [1 + 2 3 + 4] ; prints "[1 + 2 3 + 4]" and yields [1 + 2 3 + 4]
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.
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
.
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 functionclean-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 yieldtrue
if the file indicated by itsfile!
argument exists in the file system, andfalse
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, ornone
if there is no suffix -
size?
will yield the size of the file in bytes -
dir?
will yieldtrue
if the file indicated by its`file!` argument is a directory andfalse
otherwise -
dirize
will add a trailing/
to itsfile!
argument if needed -
what-dir
will yield the current working directory as afile!
value -
cd
orchange-dir
will set the current working directory to the argument which may be afile!
,word!
orpath!
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 (typefile!
word!
orpath!
) 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
anddir
will calllist-dir
without refinement andll
will call it with 1 column specified; all three will use the current working directory if they are called with no argument; note thatread <directory>
will yield a block with the content of the directory -
make-dir
will create the directory that is indicated by itsfile!
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 itsfile!
argument to an absolute path where.
and..
are eliminated -
normalize-dir
will invokeclean-path
and prefix the current working directory if the file path indicated by its argument (word! path!
orfile!
) is relative, and invokedirize
afterwards -
split-path
will take afile!
argument and yield a block of twofile!
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 itsurl!
argument (see section 11.3.1) -
delete
will take afile!
argument and delete the file or directory indicated; the result istrue
if the operation was succesful, andfalse
otherwise -
request-file
will invoke an interactive file requestor and yield afile!
value or a block offile!
values -
request-dir
will do the same for directories
Ports represent a generalization of files and urls. They implement the concept of Uniform Resource Identifier (URI), as defined in RFC3986, and the various operations on the resources represented by URIs; the functionality offered by ports will be more complete than the basic I/O currently provided. In addition to the I/O actions described in section 11.4.2, all series actions (see sections 9.2/3) are allowed on ports; their implementation on ports is specific to the port’s scheme (see next section).
Ports, i.e.values of type port!
, are specialized objects with a fixed number of fields,
that contain the necessary information for handling the communication
with a wide variety of external resources.
As also shown in section 5.6 the fields are:
name | type |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
A prototype port value is contained in system/standard/port
.
The significance of the fields is as follows:
-
The
spec
field is an object representing a resource. The fields of this object correspond to the components of an URI as detailed in RFC3986. The type of resource, which RFC3986 calls its scheme, is represented by thescheme
field of thespec
object. -
The
scheme
field of the port is initially aword!
value equal to the value of thescheme
field of thespec
object; during operation it is replaced by ascheme
object whose fields are described below. -
The
actor
field is either ahandle!
value (opaque integer pointing to an action table containing Red/System functions for all possible actions allowed on ports) or an object whose field names are the allowable action names and whose field values are the functions implementing these actions -
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 objects containing the actor functions for the different schemes are stored in
system/schemes
, a block of word/object pairs. New schemes may be added to system/schemes
by calling register-scheme
with as arguments the name of the scheme and its content
as a scheme
object.
The fields of the spec
object are:
name | type | content |
---|---|---|
|
|
e.g. |
|
|
e.g. |
|
|
e.g |
|
|
e.g. |
|
|
e.g. |
|
|
e.g. |
|
|
|
|
|
|
|
|
the source of the above fields |
All fields except scheme
may be none
. A prototype spec
object is contained in system/standard/url-parts
.
The 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
.
The fields of a scheme
object are:
name | type | content |
---|---|---|
|
|
e.g. |
|
|
|
|
||
|
|
see |
|
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 following I/O operations (functions) are defined on ports:
function | description |
---|---|
create |
Send port a create request |
open |
Opens a port |
open? |
Tests if port is open |
close |
Closes a port |
query |
|
read |
|
write |
|
update |
|
modify |
|
rename |
|
delete |
As stated above, these functions are implemented for the various schemes by actors, 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.
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.
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.
Errors are values of type error!
that can be produced as a result of
any evaluation; they are specialized objects with a fixed number of fields,
that contain the necessary information for identifying the nature and the place
of the error. A prototype error value is contained in system/standard/error
.
As also shown in section 5.6 the fields are:
name | type | content |
---|---|---|
code |
integer! |
unique identifying number |
type |
word! |
characterizes a group of errors |
id |
word! |
identifier for the error within the group |
arg1 |
any-type! |
additional information for the error message |
arg2 |
any-type! |
further additional information |
arg3 |
any-type! |
still further additional information |
near |
block! |
program fragment |
where |
any-type! |
value whose evaluation triggered the error |
stack |
integer! |
machine address |
Any field except type
and id
can also be none
. If arg1
is none
arg2
and arg3
will also be none
; likewise, if arg2
is none
,
arg3
will also be none
.
The type
field may contain one of the following words: throw note syntax
script math access user internal
.
There is initially a fixed repertoire of errors; identifying information
and (parametrized) error messages for each possible error are stored
in the object system/catalog/errors
. This has the following sub-objects,
whose field names correspond to the contents of the type
field
of the error value and which group related errors:
system/catalog/errors/… | code field | type field |
---|---|---|
throw |
0 |
"Throw Error" |
note |
100 |
"note" |
syntax |
200 |
"Syntax Error" |
script |
300 |
"Script Error" |
math |
400 |
"Math Error" |
access |
500 |
"Access Error" |
user |
800 |
"User Error" |
internal |
900 |
"Internal Error" |
As indicated in the table, each of the sub-objects has two fixed fields:
code
which contains the base number for the codes of the individual
errors, and type
which is a string that can be used in forming the
error message; this serves to sufficiently characterize the group.
Each sub-object has furthermore a number of fields, whose names
correspond to the id
field of the error value, and which identify
the individual error. E.g. the math
group has fields zero-divide, overflow
and positive
. The contents of each of these fields is either a string,
which is a complete error message, or a block of strings and instances
of :arg1, :arg2
and :arg3
, which needs to be bound
to the context of the error value, in order for the values of
arg1
to arg3
to be inserted; the block then can be used
to construct the error message. The full list of possible
errors is shown in section 16.
When the error value is produced,
the word which is the value of its type
field is bound such that
it refers to the sub-object whose field name is that word;
also, the word which is the value of id
field is bound such that
it refers to the error message (string or block) within that sub-object
whose field name is that word. See issue #2633
Thus the following code will produce
the full message information for an error value, say err
:
either err/arg1 ; test if insertion is necessary [ reduce bind (get err/id) (in err 'id) ; yields a block of strings and values ][ get err/id ; yields a string ]
Note the use of the in
built-in function to obtain the context of the
error value.
Examples:
system/catalog/errors/math is an object! of value: code integer! 400 type string! "Math Error" zero-divide string! "attempt to divide by zero" overflow string! "math or number overflow" positive string! "positive number required" system/catalog/errors/access is an object! of value: code integer! 500 type string! "Access Error" cannot-open block! ["cannot open:" :arg1] invalid-utf8 block! ["invalid UTF-8 encoding:" :arg1] no-connect block! ["cannot connect:" :arg1 "reason: timeout"]
The code
for each individual error is the base number + the ordinal number
of the error in the sub-object (0-origin), e.g. for no-connect
it is 502
.
Because the catalog is an object like any other, the user may extend it with their own error groups which can then be raised as described below. An example follows:
; add at end, using the next available code last-type: last keys-of system/catalog/errors new-code: system/catalog/errors/:last-type/code + 100 system/catalog/errors: make system/catalog/errors [ my-exceptions: make object! [ code: new-code type: "My Exception" WRONG_DOCUMENT_ERR: [:arg1] NO_MODIFICATION_ALLOWED_ERR: ["field" :arg1 "is read-only"] ] ]
In this example, care is taken to set the code
field to a value that is not yet used.
Of course the name of the sub-object must also be different from an existing one.
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
.
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"
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.
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.
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.
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
.
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 afile!
argument -
when the
expand-directives
built-in function is called on ablock!
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.
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 (returningtrue
) -
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.
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.
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 amap!
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 innone
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.
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.
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
For convenience, the values are indicated.
See also section 5.2.6
comma #"," CR #"^(0D)" dbl-quote #"^"" dot #"." escape #"^[" lf #"^/" newline #"^/" null #"^@" slash #"/" sp #" " space #" " tab #"^-"
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
See also section 4.1
action! binary! bitset! block! char! datatype! date! email! error! event! file! float! function! get-path! get-word! handle! hash! image! integer! issue! lit-path! lit-word! logic! map! native! none! object! op! pair! paren! path! percent! point! port! refinement! routine! set-path! set-word! string! tag! time! tuple! typeset! unset! url! vector! word!
See also section 4.3
all-word! any-block! any-float! <---- see issue #2565 any-function! any-list! any-object! any-path! any-string! any-type! any-word! default! external! immediate! internal! number! scalar! series!
The functions are classified by functionality:
-
enquiry, i.e. properties of types and values
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.
see sections 4.4 and 5.7
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 body-of F char? F class-of N complement? N context? 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? A index? F integer? F issue? F keys-of F lit-path? F lit-word? F logic? F map? F native? F none? F number? F object? F op? F pair? F paren? F path? F percent? F refinement? A reflect F routine? F scalar? F series? F set-path? F set-word? F spec-of F string? F tag? F time? F tuple? N type? F typeset? F unset? F url? F values-of F vector? F word? F words-of
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
see sections 5.4 and 5.5
N as R as-color R as-ipv4 N as-pair R as-rgba N debase N dehex N enbase F hex-to-rgb N lowercase A to F to-binary F to-bitset F to-block F to-char F to-date F to-email F to-file F to-float F to-get-path F to-get-word F to-hash N to-hex F to-image F to-integer F to-issue F to-local-date F to-lit-path F to-lit-word F to-logic F to-map F to-none F to-pair F to-paren F to-path F to-percent F to-refinement F to-set-path F to-set-word F to-string F to-tag F to-time F to-tuple F to-typeset F to-unset F to-url F to-UTC-date F to-word N uppercase
see section 5.8
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?
see sections 6 and 7
N all N any N apply N bind N context? N do F do-thru N get N in A index? F quote N set N unset N value?
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 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?
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
see section 10
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
see section 11
F alert R ask N browse F cd F change-dir F clean-path A close A create R create-dir A delete F dir F dir? F dirize F ellipsize-at R exists? F exists-thru? A form R get-current-dir F input F list-dir F ll F load F load-thru F ls F make-dir A modify A mold N new-line N new-line? F normalize-dir A open A open? F path-thru N prin N print F probe F pwd A query A read R read-clipboard F read-thru A rename F request-dir F request-file F save R set-current-dir N size? F split-path F suffix? N to-local-file F to-red-file A update F what-dir A write R write-clipboard R write-stdout
see section 13.3
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-reactor F unview F update-font-faces F view F within?
see section 13.5
N call N get-env N list-env N now R os-info N set-env N stats N wait
see section 13.7
F ? F ?? F a-an F about F fetch-help F help F help-string F source F what
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
The system object is used by the run-time system to store both fixed data (e.g. codecs, error messages) and variable data (e.g. modules, script header data). All data can be retrieved by the user, and some data can also be set by the user at runtime.
(sub-)component & type significance/value system/ object! version/ tuple! current version build/ object! date date! build date git object! detailed build information config object! configuration used words object! global context, see section 6.2 platform function! returns a word identifying the operating system catalog/ object! datatypes actions natives accessors block! see section 5.6.2 errors object! see sections 5.3.7, 12.1.1 state/ object! interpreted? function! returns TRUE if called from the interpreter last-error error! trace integer! modules block! codecs block! see section 11.1.2 schemes block! see section 11.4.1 ports object! TBD locale/ object! language language* locale locale* months block! see section 5.2.14 days block! names of days options/ object! boot file! location of Red (console) executable 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! decimal-digits integer! module-paths block! file-types float object! script/ object! title string! header parent path args standard/ object! header object! see section 17 error object! see section 12.1.1 scheme object! see section 11.4.1 url-parts object! see section 11.4.1 file-info object! lexer object! run-time lexer program + data console/ object! console program + data prompt string! see section 11.5.1 result string! see section 11.5.1 history block! previous inputs ... view object! see section 13.3 reactivity object! see section 13.4
The format in each sub-section is
type (code base) id -> string or block etc.
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}
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]
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] 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]
math ( 400 ) zero-divide -> "attempt to divide by zero" overflow -> "math or number overflow" positive -> "positive number required"
access ( 500 ) cannot-open -> ["cannot open:" :arg1] invalid-utf8 -> ["invalid UTF-8 encoding:" :arg1] no-connect -> ["cannot connect:" :arg1 "reason: timeout"]
internal ( 900 ) bad-path -> ["bad path:" arg1] not-here -> [arg1 "not supported on your system"] no-memory -> "not enough memory" wrong-mem -> "failed to release memory" stack-overflow -> "stack overflow" too-deep -> "block or paren series is too deep to display" feature-na -> "feature not available" not-done -> "reserved for future use (or not yet implemented)" invalid-error -> "error object or fields were not valid" routines -> {routines require compilation, from OS shell: `red -c <script.red>`} red-system -> {contains Red/System code which requires compilation}
It is recommended to organize the metadata as <word>: <value>
pairs. This
will facilitate storage and retrieval of these data by the toolchain as well
as the user. Certain elements of metadata, that are used by the toolchain,
must be in this format: Icon: Needs:
and Config:
, with prescribed types for
the <value>
as indicated.
The following is a list of suggested and compulsory elements. The ones marked *
are contained in the object system/standard/header
.
element type description * Title: string! application title * Name: string! application name * Type: ??? Purpose: string! short description of the application purpose * Version: tuple! source code version * Date: date! date of last version * File: file! name of the source file * Author: string! source code author name Rights: string! copyrights License: [url! string!] source license (URL or full text) History: block! source modifications history Note(s): string! any special notice Language: word! language of the comments Tabs: integer! number of spaces between tab positions Icon: [file! block! word!] *.ico file(s) with icon(s) for executable, or word default/flat/old/mono indicating standard *.ico files provided by toolchain * Needs: [word! block!] module(s) that is/are to be included Config: block! set-word/value pairs for toolchain options for a list of options, see source file /system/compiler.r (object system-dialect/options-class)
The following is a list of official documents that complement the information given in this one.
-
Usage information for the toolchain: README
-
Wiki-style general documentation: Red Wiki
-
Red/System: Red/System Language Specification
-
Red Programming Language Documentation (Gitbook), notably:
-
Overview of value conversions: Conversion matrix
-
Parse documentation (blog article from 2013): Introducing Parse
-
Ownership documentation (in blog article from 2016): Red GUI system
-
Handling of NaNs, INFs, and signed zeros: in Red Wiki under Reference
term section action 4.2.6, 7.4.2 inherited action 4.2.6 active type 4.2.5 application of a function 3.3 arity of a function 3.3 atomic type 4.2.3 backspace (U+0008) 5.2.6 base64 character 5.2.12 binding 2.4, 3.3, 6.3 bitset spec dialect 2.5, 5.3.5 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 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 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 infix expression 3.3 form feed (U+000C) 5.2.6 free-form text 3.1 function 3.3, 5.3.8, 7.4.1 application 3.3, 7.4.1 infix function 3.3 prefix function 3.3 function spec dialect 2.5, 5.3.8 function type 4.2.2 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 infix expression 3.3 inherited action 4.2.6 interactive console 2.2 interpretation 2.2 ipv4 5.2.4 ISO 8601 date and time standard 5.2.14, 5.6.2 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 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 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 remote file access (disk-cached) 11.3.1 REPL (Read Evaluate Print Loop) 2.2 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 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.16 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 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
There are two types of issues: Red issues that represent a bug or other observed imperfection of the current toolchain, which are reported in the issue section of the toolchain repository and suggestions for enhancement ("wishes") that are reported separately in the REP (Red Enhancement Proposals) repository. The numbered issues can be found at https://github.com/red/red/issues/ and https://github.com/red/REP/issues/ respectively.
Red spec issue section 324 5.3.8 1957 5.7 1960 5.6.3 1961 9.3 2216 8.1 2492 3.1 2554 5.6.2 2565 4.3, 14.2.2 2577 5.3.11 2609 5.3.5 2622 7.4.1 2625 5.6.3 2633 12.1 2642 5.3.9 2644 5.3.14 2645 5.4.2 2650 5.8.1 2657 5.8.1 2658 5.8.1 2662 5.8.2 2668 11.1.1 2776 8.1 2883 5.3.4, 5.6.2 3285 5.3.8 3362 5.3.6 3395 8.1 3409 5.4.3 3482 5.6.1, 5.6.2 3570 11 3595 5.3.8 REP spec issue section 9 3.2, 5.1 10 8.1, 8.4 11 11.5.1 12 4.2.7, 5.7 14 4.2.7, 5.7 29 9.2 30 5.5